Implement UBIFS rootfs support
[openadk.git] / target / linux / patches / 3.18.44 / yaffs2.patch
blob2ade5bf7ee67b774bc9728006f07ca1f2e71084e
1 diff -Nur linux-3.18.14.orig/fs/Kconfig linux-3.18.14/fs/Kconfig
2 --- linux-3.18.14.orig/fs/Kconfig 2015-05-20 17:04:50.000000000 +0200
3 +++ linux-3.18.14/fs/Kconfig 2015-06-14 21:22:55.000000000 +0200
4 @@ -191,6 +191,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.18.14.orig/fs/Makefile linux-3.18.14/fs/Makefile
13 --- linux-3.18.14.orig/fs/Makefile 2015-05-20 17:04:50.000000000 +0200
14 +++ linux-3.18.14/fs/Makefile 2015-06-14 21:22:55.000000000 +0200
15 @@ -126,3 +126,4 @@
16 obj-$(CONFIG_CEPH_FS) += ceph/
17 obj-$(CONFIG_PSTORE) += pstore/
18 obj-$(CONFIG_EFIVAR_FS) += efivarfs/
19 +obj-$(CONFIG_YAFFS_FS) += yaffs2/
20 diff -Nur linux-3.18.14.orig/fs/yaffs2/Kconfig linux-3.18.14/fs/yaffs2/Kconfig
21 --- linux-3.18.14.orig/fs/yaffs2/Kconfig 1970-01-01 01:00:00.000000000 +0100
22 +++ linux-3.18.14/fs/yaffs2/Kconfig 2015-06-14 21:23:22.000000000 +0200
23 @@ -0,0 +1,171 @@
25 +# yaffs file system configurations
28 +config YAFFS_FS
29 + tristate "yaffs2 file system support"
30 + default n
31 + depends on MTD_BLOCK
32 + select YAFFS_YAFFS1
33 + select YAFFS_YAFFS2
34 + help
35 + yaffs2, or Yet Another Flash File System, is a file system
36 + optimised for NAND Flash chips.
38 + To compile the yaffs2 file system support as a module, choose M
39 + here: the module will be called yaffs2.
41 + If unsure, say N.
43 + Further information on yaffs2 is available at
44 + <http://www.aleph1.co.uk/yaffs/>.
46 +config YAFFS_YAFFS1
47 + bool "512 byte / page devices"
48 + depends on YAFFS_FS
49 + default y
50 + help
51 + Enable yaffs1 support -- yaffs for 512 byte / page devices
53 + Not needed for 2K-page devices.
55 + If unsure, say Y.
57 +config YAFFS_9BYTE_TAGS
58 + bool "Use older-style on-NAND data format with pageStatus byte"
59 + depends on YAFFS_YAFFS1
60 + default n
61 + help
63 + Older-style on-NAND data format has a "pageStatus" byte to record
64 + chunk/page state. This byte is zero when the page is discarded.
65 + Choose this option if you have existing on-NAND data using this
66 + format that you need to continue to support. New data written
67 + also uses the older-style format. Note: Use of this option
68 + generally requires that MTD's oob layout be adjusted to use the
69 + older-style format. See notes on tags formats and MTD versions
70 + in yaffs_mtdif1.c.
72 + If unsure, say N.
74 +config YAFFS_DOES_ECC
75 + bool "Lets yaffs do its own ECC"
76 + depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
77 + default n
78 + help
79 + This enables yaffs to use its own ECC functions instead of using
80 + the ones from the generic MTD-NAND driver.
82 + If unsure, say N.
84 +config YAFFS_ECC_WRONG_ORDER
85 + bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
86 + depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
87 + default n
88 + help
89 + This makes yaffs_ecc.c use the same ecc byte order as Steven
90 + Hill's nand_ecc.c. If not set, then you get the same ecc byte
91 + order as SmartMedia.
93 + If unsure, say N.
95 +config YAFFS_YAFFS2
96 + bool "2048 byte (or larger) / page devices"
97 + depends on YAFFS_FS
98 + default y
99 + help
100 + Enable yaffs2 support -- yaffs for >= 2K bytes per page devices
102 + If unsure, say Y.
104 +config YAFFS_AUTO_YAFFS2
105 + bool "Autoselect yaffs2 format"
106 + depends on YAFFS_YAFFS2
107 + default y
108 + help
109 + Without this, you need to explicitely use yaffs2 as the file
110 + system type. With this, you can say "yaffs" and yaffs or yaffs2
111 + will be used depending on the device page size (yaffs on
112 + 512-byte page devices, yaffs2 on 2K page devices).
114 + If unsure, say Y.
116 +config YAFFS_DISABLE_TAGS_ECC
117 + bool "Disable yaffs from doing ECC on tags by default"
118 + depends on YAFFS_FS && YAFFS_YAFFS2
119 + default n
120 + help
121 + This defaults yaffs to using its own ECC calculations on tags instead of
122 + just relying on the MTD.
123 + This behavior can also be overridden with tags_ecc_on and
124 + tags_ecc_off mount options.
126 + If unsure, say N.
128 +config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
129 + bool "Force chunk erase check"
130 + depends on YAFFS_FS
131 + default n
132 + help
133 + Normally yaffs only checks chunks before writing until an erased
134 + chunk is found. This helps to detect any partially written
135 + chunks that might have happened due to power loss.
137 + Enabling this forces on the test that chunks are erased in flash
138 + before writing to them. This takes more time but is potentially
139 + a bit more secure.
141 + Suggest setting Y during development and ironing out driver
142 + issues etc. Suggest setting to N if you want faster writing.
144 + If unsure, say Y.
146 +config YAFFS_EMPTY_LOST_AND_FOUND
147 + bool "Empty lost and found on boot"
148 + depends on YAFFS_FS
149 + default n
150 + help
151 + If this is enabled then the contents of lost and found is
152 + automatically dumped at mount.
154 + If unsure, say N.
156 +config YAFFS_DISABLE_BLOCK_REFRESHING
157 + bool "Disable yaffs2 block refreshing"
158 + depends on YAFFS_FS
159 + default n
160 + help
161 + If this is set, then block refreshing is disabled.
162 + Block refreshing infrequently refreshes the oldest block in
163 + a yaffs2 file system. This mechanism helps to refresh flash to
164 + mitigate against data loss. This is particularly useful for MLC.
166 + If unsure, say N.
168 +config YAFFS_DISABLE_BACKGROUND
169 + bool "Disable yaffs2 background processing"
170 + depends on YAFFS_FS
171 + default n
172 + help
173 + If this is set, then background processing is disabled.
174 + Background processing makes many foreground activities faster.
176 + If unsure, say N.
178 +config YAFFS_DISABLE_BAD_BLOCK_MARKING
179 + bool "Disable yaffs2 bad block marking"
180 + depends on YAFFS_FS
181 + default n
182 + help
183 + Useful during early flash bring up to prevent problems causing
184 + lots of bad block marking.
186 + If unsure, say N.
188 +config YAFFS_XATTR
189 + bool "Enable yaffs2 xattr support"
190 + depends on YAFFS_FS
191 + default y
192 + help
193 + If this is set then yaffs2 will provide xattr support.
194 + If unsure, say Y.
195 diff -Nur linux-3.18.14.orig/fs/yaffs2/Makefile linux-3.18.14/fs/yaffs2/Makefile
196 --- linux-3.18.14.orig/fs/yaffs2/Makefile 1970-01-01 01:00:00.000000000 +0100
197 +++ linux-3.18.14/fs/yaffs2/Makefile 2015-06-14 21:23:22.000000000 +0200
198 @@ -0,0 +1,18 @@
200 +# Makefile for the linux YAFFS filesystem routines.
203 +obj-$(CONFIG_YAFFS_FS) += yaffs.o
205 +yaffs-y := yaffs_ecc.o yaffs_vfs.o yaffs_guts.o yaffs_checkptrw.o
206 +yaffs-y += yaffs_packedtags1.o yaffs_packedtags2.o yaffs_nand.o
207 +yaffs-y += yaffs_tagscompat.o yaffs_tagsmarshall.o
208 +yaffs-y += yaffs_mtdif.o
209 +yaffs-y += yaffs_nameval.o yaffs_attribs.o
210 +yaffs-y += yaffs_allocator.o
211 +yaffs-y += yaffs_yaffs1.o
212 +yaffs-y += yaffs_yaffs2.o
213 +yaffs-y += yaffs_bitmap.o
214 +yaffs-y += yaffs_summary.o
215 +yaffs-y += yaffs_verify.o
217 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_allocator.c linux-3.18.14/fs/yaffs2/yaffs_allocator.c
218 --- linux-3.18.14.orig/fs/yaffs2/yaffs_allocator.c 1970-01-01 01:00:00.000000000 +0100
219 +++ linux-3.18.14/fs/yaffs2/yaffs_allocator.c 2015-06-14 21:23:22.000000000 +0200
220 @@ -0,0 +1,357 @@
222 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
224 + * Copyright (C) 2002-2011 Aleph One Ltd.
225 + * for Toby Churchill Ltd and Brightstar Engineering
227 + * Created by Charles Manning <charles@aleph1.co.uk>
229 + * This program is free software; you can redistribute it and/or modify
230 + * it under the terms of the GNU General Public License version 2 as
231 + * published by the Free Software Foundation.
232 + */
234 +#include "yaffs_allocator.h"
235 +#include "yaffs_guts.h"
236 +#include "yaffs_trace.h"
237 +#include "yportenv.h"
240 + * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks
241 + * of approx 100 objects that are themn allocated singly.
242 + * This is basically a simplified slab allocator.
244 + * We don't use the Linux slab allocator because slab does not allow
245 + * us to dump all the objects in one hit when we do a umount and tear
246 + * down all the tnodes and objects. slab requires that we first free
247 + * the individual objects.
249 + * Once yaffs has been mainlined I shall try to motivate for a change
250 + * to slab to provide the extra features we need here.
251 + */
253 +struct yaffs_tnode_list {
254 + struct yaffs_tnode_list *next;
255 + struct yaffs_tnode *tnodes;
258 +struct yaffs_obj_list {
259 + struct yaffs_obj_list *next;
260 + struct yaffs_obj *objects;
263 +struct yaffs_allocator {
264 + int n_tnodes_created;
265 + struct yaffs_tnode *free_tnodes;
266 + int n_free_tnodes;
267 + struct yaffs_tnode_list *alloc_tnode_list;
269 + int n_obj_created;
270 + struct list_head free_objs;
271 + int n_free_objects;
273 + struct yaffs_obj_list *allocated_obj_list;
276 +static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev)
278 + struct yaffs_allocator *allocator =
279 + (struct yaffs_allocator *)dev->allocator;
280 + struct yaffs_tnode_list *tmp;
282 + if (!allocator) {
283 + BUG();
284 + return;
287 + while (allocator->alloc_tnode_list) {
288 + tmp = allocator->alloc_tnode_list->next;
290 + kfree(allocator->alloc_tnode_list->tnodes);
291 + kfree(allocator->alloc_tnode_list);
292 + allocator->alloc_tnode_list = tmp;
295 + allocator->free_tnodes = NULL;
296 + allocator->n_free_tnodes = 0;
297 + allocator->n_tnodes_created = 0;
300 +static void yaffs_init_raw_tnodes(struct yaffs_dev *dev)
302 + struct yaffs_allocator *allocator = dev->allocator;
304 + if (!allocator) {
305 + BUG();
306 + return;
309 + allocator->alloc_tnode_list = NULL;
310 + allocator->free_tnodes = NULL;
311 + allocator->n_free_tnodes = 0;
312 + allocator->n_tnodes_created = 0;
315 +static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes)
317 + struct yaffs_allocator *allocator =
318 + (struct yaffs_allocator *)dev->allocator;
319 + int i;
320 + struct yaffs_tnode *new_tnodes;
321 + u8 *mem;
322 + struct yaffs_tnode *curr;
323 + struct yaffs_tnode *next;
324 + struct yaffs_tnode_list *tnl;
326 + if (!allocator) {
327 + BUG();
328 + return YAFFS_FAIL;
331 + if (n_tnodes < 1)
332 + return YAFFS_OK;
334 + /* make these things */
335 + new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS);
336 + mem = (u8 *) new_tnodes;
338 + if (!new_tnodes) {
339 + yaffs_trace(YAFFS_TRACE_ERROR,
340 + "yaffs: Could not allocate Tnodes");
341 + return YAFFS_FAIL;
344 + /* New hookup for wide tnodes */
345 + for (i = 0; i < n_tnodes - 1; i++) {
346 + curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size];
347 + next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size];
348 + curr->internal[0] = next;
351 + curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size];
352 + curr->internal[0] = allocator->free_tnodes;
353 + allocator->free_tnodes = (struct yaffs_tnode *)mem;
355 + allocator->n_free_tnodes += n_tnodes;
356 + allocator->n_tnodes_created += n_tnodes;
358 + /* Now add this bunch of tnodes to a list for freeing up.
359 + * NB If we can't add this to the management list it isn't fatal
360 + * but it just means we can't free this bunch of tnodes later.
361 + */
362 + tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS);
363 + if (!tnl) {
364 + yaffs_trace(YAFFS_TRACE_ERROR,
365 + "Could not add tnodes to management list");
366 + return YAFFS_FAIL;
367 + } else {
368 + tnl->tnodes = new_tnodes;
369 + tnl->next = allocator->alloc_tnode_list;
370 + allocator->alloc_tnode_list = tnl;
373 + yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added");
375 + return YAFFS_OK;
378 +struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev)
380 + struct yaffs_allocator *allocator =
381 + (struct yaffs_allocator *)dev->allocator;
382 + struct yaffs_tnode *tn = NULL;
384 + if (!allocator) {
385 + BUG();
386 + return NULL;
389 + /* If there are none left make more */
390 + if (!allocator->free_tnodes)
391 + yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES);
393 + if (allocator->free_tnodes) {
394 + tn = allocator->free_tnodes;
395 + allocator->free_tnodes = allocator->free_tnodes->internal[0];
396 + allocator->n_free_tnodes--;
399 + return tn;
402 +/* FreeTnode frees up a tnode and puts it back on the free list */
403 +void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
405 + struct yaffs_allocator *allocator = dev->allocator;
407 + if (!allocator) {
408 + BUG();
409 + return;
412 + if (tn) {
413 + tn->internal[0] = allocator->free_tnodes;
414 + allocator->free_tnodes = tn;
415 + allocator->n_free_tnodes++;
417 + dev->checkpoint_blocks_required = 0; /* force recalculation */
420 +/*--------------- yaffs_obj alloaction ------------------------
422 + * Free yaffs_objs are stored in a list using obj->siblings.
423 + * The blocks of allocated objects are stored in a linked list.
424 + */
426 +static void yaffs_init_raw_objs(struct yaffs_dev *dev)
428 + struct yaffs_allocator *allocator = dev->allocator;
430 + if (!allocator) {
431 + BUG();
432 + return;
435 + allocator->allocated_obj_list = NULL;
436 + INIT_LIST_HEAD(&allocator->free_objs);
437 + allocator->n_free_objects = 0;
440 +static void yaffs_deinit_raw_objs(struct yaffs_dev *dev)
442 + struct yaffs_allocator *allocator = dev->allocator;
443 + struct yaffs_obj_list *tmp;
445 + if (!allocator) {
446 + BUG();
447 + return;
450 + while (allocator->allocated_obj_list) {
451 + tmp = allocator->allocated_obj_list->next;
452 + kfree(allocator->allocated_obj_list->objects);
453 + kfree(allocator->allocated_obj_list);
454 + allocator->allocated_obj_list = tmp;
457 + INIT_LIST_HEAD(&allocator->free_objs);
458 + allocator->n_free_objects = 0;
459 + allocator->n_obj_created = 0;
462 +static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj)
464 + struct yaffs_allocator *allocator = dev->allocator;
465 + int i;
466 + struct yaffs_obj *new_objs;
467 + struct yaffs_obj_list *list;
469 + if (!allocator) {
470 + BUG();
471 + return YAFFS_FAIL;
474 + if (n_obj < 1)
475 + return YAFFS_OK;
477 + /* make these things */
478 + new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS);
479 + list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS);
481 + if (!new_objs || !list) {
482 + kfree(new_objs);
483 + new_objs = NULL;
484 + kfree(list);
485 + list = NULL;
486 + yaffs_trace(YAFFS_TRACE_ALLOCATE,
487 + "Could not allocate more objects");
488 + return YAFFS_FAIL;
491 + /* Hook them into the free list */
492 + for (i = 0; i < n_obj; i++)
493 + list_add(&new_objs[i].siblings, &allocator->free_objs);
495 + allocator->n_free_objects += n_obj;
496 + allocator->n_obj_created += n_obj;
498 + /* Now add this bunch of Objects to a list for freeing up. */
500 + list->objects = new_objs;
501 + list->next = allocator->allocated_obj_list;
502 + allocator->allocated_obj_list = list;
504 + return YAFFS_OK;
507 +struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev)
509 + struct yaffs_obj *obj = NULL;
510 + struct list_head *lh;
511 + struct yaffs_allocator *allocator = dev->allocator;
513 + if (!allocator) {
514 + BUG();
515 + return obj;
518 + /* If there are none left make more */
519 + if (list_empty(&allocator->free_objs))
520 + yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS);
522 + if (!list_empty(&allocator->free_objs)) {
523 + lh = allocator->free_objs.next;
524 + obj = list_entry(lh, struct yaffs_obj, siblings);
525 + list_del_init(lh);
526 + allocator->n_free_objects--;
529 + return obj;
532 +void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj)
535 + struct yaffs_allocator *allocator = dev->allocator;
537 + if (!allocator) {
538 + BUG();
539 + return;
542 + /* Link into the free list. */
543 + list_add(&obj->siblings, &allocator->free_objs);
544 + allocator->n_free_objects++;
547 +void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev)
550 + if (!dev->allocator) {
551 + BUG();
552 + return;
555 + yaffs_deinit_raw_tnodes(dev);
556 + yaffs_deinit_raw_objs(dev);
557 + kfree(dev->allocator);
558 + dev->allocator = NULL;
561 +void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev)
563 + struct yaffs_allocator *allocator;
565 + if (dev->allocator) {
566 + BUG();
567 + return;
570 + allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS);
571 + if (allocator) {
572 + dev->allocator = allocator;
573 + yaffs_init_raw_tnodes(dev);
574 + yaffs_init_raw_objs(dev);
578 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_allocator.h linux-3.18.14/fs/yaffs2/yaffs_allocator.h
579 --- linux-3.18.14.orig/fs/yaffs2/yaffs_allocator.h 1970-01-01 01:00:00.000000000 +0100
580 +++ linux-3.18.14/fs/yaffs2/yaffs_allocator.h 2015-06-14 21:23:22.000000000 +0200
581 @@ -0,0 +1,30 @@
583 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
585 + * Copyright (C) 2002-2011 Aleph One Ltd.
586 + * for Toby Churchill Ltd and Brightstar Engineering
588 + * Created by Charles Manning <charles@aleph1.co.uk>
590 + * This program is free software; you can redistribute it and/or modify
591 + * it under the terms of the GNU Lesser General Public License version 2.1 as
592 + * published by the Free Software Foundation.
594 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
595 + */
597 +#ifndef __YAFFS_ALLOCATOR_H__
598 +#define __YAFFS_ALLOCATOR_H__
600 +#include "yaffs_guts.h"
602 +void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev);
603 +void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev);
605 +struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev);
606 +void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn);
608 +struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev);
609 +void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj);
611 +#endif
612 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_attribs.c linux-3.18.14/fs/yaffs2/yaffs_attribs.c
613 --- linux-3.18.14.orig/fs/yaffs2/yaffs_attribs.c 1970-01-01 01:00:00.000000000 +0100
614 +++ linux-3.18.14/fs/yaffs2/yaffs_attribs.c 2015-06-14 21:23:22.000000000 +0200
615 @@ -0,0 +1,132 @@
617 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
619 + * Copyright (C) 2002-2011 Aleph One Ltd.
620 + * for Toby Churchill Ltd and Brightstar Engineering
622 + * Created by Charles Manning <charles@aleph1.co.uk>
624 + * This program is free software; you can redistribute it and/or modify
625 + * it under the terms of the GNU General Public License version 2 as
626 + * published by the Free Software Foundation.
627 + */
629 +#include "yaffs_guts.h"
630 +#include "yaffs_attribs.h"
632 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
633 +#define IATTR_UID ia_uid
634 +#define IATTR_GID ia_gid
635 +#else
636 +#define IATTR_UID ia_uid.val
637 +#define IATTR_GID ia_gid.val
638 +#endif
640 +void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh)
642 + obj->yst_uid = oh->yst_uid;
643 + obj->yst_gid = oh->yst_gid;
644 + obj->yst_atime = oh->yst_atime;
645 + obj->yst_mtime = oh->yst_mtime;
646 + obj->yst_ctime = oh->yst_ctime;
647 + obj->yst_rdev = oh->yst_rdev;
650 +void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj)
652 + oh->yst_uid = obj->yst_uid;
653 + oh->yst_gid = obj->yst_gid;
654 + oh->yst_atime = obj->yst_atime;
655 + oh->yst_mtime = obj->yst_mtime;
656 + oh->yst_ctime = obj->yst_ctime;
657 + oh->yst_rdev = obj->yst_rdev;
661 +void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c)
663 + obj->yst_mtime = Y_CURRENT_TIME;
664 + if (do_a)
665 + obj->yst_atime = obj->yst_mtime;
666 + if (do_c)
667 + obj->yst_ctime = obj->yst_mtime;
670 +void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev)
672 + yaffs_load_current_time(obj, 1, 1);
673 + obj->yst_rdev = rdev;
674 + obj->yst_uid = uid;
675 + obj->yst_gid = gid;
678 +static loff_t yaffs_get_file_size(struct yaffs_obj *obj)
680 + YCHAR *alias = NULL;
681 + obj = yaffs_get_equivalent_obj(obj);
683 + switch (obj->variant_type) {
684 + case YAFFS_OBJECT_TYPE_FILE:
685 + return obj->variant.file_variant.file_size;
686 + case YAFFS_OBJECT_TYPE_SYMLINK:
687 + alias = obj->variant.symlink_variant.alias;
688 + if (!alias)
689 + return 0;
690 + return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH);
691 + default:
692 + return 0;
696 +int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr)
698 + unsigned int valid = attr->ia_valid;
700 + if (valid & ATTR_MODE)
701 + obj->yst_mode = attr->ia_mode;
702 + if (valid & ATTR_UID)
703 + obj->yst_uid = attr->IATTR_UID;
704 + if (valid & ATTR_GID)
705 + obj->yst_gid = attr->IATTR_GID;
707 + if (valid & ATTR_ATIME)
708 + obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
709 + if (valid & ATTR_CTIME)
710 + obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
711 + if (valid & ATTR_MTIME)
712 + obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
714 + if (valid & ATTR_SIZE)
715 + yaffs_resize_file(obj, attr->ia_size);
717 + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
719 + return YAFFS_OK;
723 +int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr)
725 + unsigned int valid = 0;
727 + attr->ia_mode = obj->yst_mode;
728 + valid |= ATTR_MODE;
729 + attr->IATTR_UID = obj->yst_uid;
730 + valid |= ATTR_UID;
731 + attr->IATTR_GID = obj->yst_gid;
732 + valid |= ATTR_GID;
734 + Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
735 + valid |= ATTR_ATIME;
736 + Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
737 + valid |= ATTR_CTIME;
738 + Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
739 + valid |= ATTR_MTIME;
741 + attr->ia_size = yaffs_get_file_size(obj);
742 + valid |= ATTR_SIZE;
744 + attr->ia_valid = valid;
746 + return YAFFS_OK;
748 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_attribs.h linux-3.18.14/fs/yaffs2/yaffs_attribs.h
749 --- linux-3.18.14.orig/fs/yaffs2/yaffs_attribs.h 1970-01-01 01:00:00.000000000 +0100
750 +++ linux-3.18.14/fs/yaffs2/yaffs_attribs.h 2015-06-14 21:23:22.000000000 +0200
751 @@ -0,0 +1,28 @@
753 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
755 + * Copyright (C) 2002-2011 Aleph One Ltd.
756 + * for Toby Churchill Ltd and Brightstar Engineering
758 + * Created by Charles Manning <charles@aleph1.co.uk>
760 + * This program is free software; you can redistribute it and/or modify
761 + * it under the terms of the GNU Lesser General Public License version 2.1 as
762 + * published by the Free Software Foundation.
764 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
765 + */
767 +#ifndef __YAFFS_ATTRIBS_H__
768 +#define __YAFFS_ATTRIBS_H__
770 +#include "yaffs_guts.h"
772 +void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh);
773 +void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj);
774 +void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev);
775 +void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c);
776 +int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr);
777 +int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr);
779 +#endif
780 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_bitmap.c linux-3.18.14/fs/yaffs2/yaffs_bitmap.c
781 --- linux-3.18.14.orig/fs/yaffs2/yaffs_bitmap.c 1970-01-01 01:00:00.000000000 +0100
782 +++ linux-3.18.14/fs/yaffs2/yaffs_bitmap.c 2015-06-14 21:23:22.000000000 +0200
783 @@ -0,0 +1,97 @@
785 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
787 + * Copyright (C) 2002-2011 Aleph One Ltd.
788 + * for Toby Churchill Ltd and Brightstar Engineering
790 + * Created by Charles Manning <charles@aleph1.co.uk>
792 + * This program is free software; you can redistribute it and/or modify
793 + * it under the terms of the GNU General Public License version 2 as
794 + * published by the Free Software Foundation.
795 + */
797 +#include "yaffs_bitmap.h"
798 +#include "yaffs_trace.h"
800 + * Chunk bitmap manipulations
801 + */
803 +static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk)
805 + if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
806 + yaffs_trace(YAFFS_TRACE_ERROR,
807 + "BlockBits block %d is not valid",
808 + blk);
809 + BUG();
811 + return dev->chunk_bits +
812 + (dev->chunk_bit_stride * (blk - dev->internal_start_block));
815 +void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk)
817 + if (blk < dev->internal_start_block || blk > dev->internal_end_block ||
818 + chunk < 0 || chunk >= dev->param.chunks_per_block) {
819 + yaffs_trace(YAFFS_TRACE_ERROR,
820 + "Chunk Id (%d:%d) invalid",
821 + blk, chunk);
822 + BUG();
826 +void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk)
828 + u8 *blk_bits = yaffs_block_bits(dev, blk);
830 + memset(blk_bits, 0, dev->chunk_bit_stride);
833 +void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
835 + u8 *blk_bits = yaffs_block_bits(dev, blk);
837 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
838 + blk_bits[chunk / 8] &= ~(1 << (chunk & 7));
841 +void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
843 + u8 *blk_bits = yaffs_block_bits(dev, blk);
845 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
846 + blk_bits[chunk / 8] |= (1 << (chunk & 7));
849 +int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk)
851 + u8 *blk_bits = yaffs_block_bits(dev, blk);
853 + yaffs_verify_chunk_bit_id(dev, blk, chunk);
854 + return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
857 +int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk)
859 + u8 *blk_bits = yaffs_block_bits(dev, blk);
860 + int i;
862 + for (i = 0; i < dev->chunk_bit_stride; i++) {
863 + if (*blk_bits)
864 + return 1;
865 + blk_bits++;
867 + return 0;
870 +int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk)
872 + u8 *blk_bits = yaffs_block_bits(dev, blk);
873 + int i;
874 + int n = 0;
876 + for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++)
877 + n += hweight8(*blk_bits);
879 + return n;
881 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_bitmap.h linux-3.18.14/fs/yaffs2/yaffs_bitmap.h
882 --- linux-3.18.14.orig/fs/yaffs2/yaffs_bitmap.h 1970-01-01 01:00:00.000000000 +0100
883 +++ linux-3.18.14/fs/yaffs2/yaffs_bitmap.h 2015-06-14 21:23:22.000000000 +0200
884 @@ -0,0 +1,33 @@
886 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
888 + * Copyright (C) 2002-2011 Aleph One Ltd.
889 + * for Toby Churchill Ltd and Brightstar Engineering
891 + * Created by Charles Manning <charles@aleph1.co.uk>
893 + * This program is free software; you can redistribute it and/or modify
894 + * it under the terms of the GNU Lesser General Public License version 2.1 as
895 + * published by the Free Software Foundation.
897 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
898 + */
901 + * Chunk bitmap manipulations
902 + */
904 +#ifndef __YAFFS_BITMAP_H__
905 +#define __YAFFS_BITMAP_H__
907 +#include "yaffs_guts.h"
909 +void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk);
910 +void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk);
911 +void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
912 +void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
913 +int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk);
914 +int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk);
915 +int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk);
917 +#endif
918 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_checkptrw.c linux-3.18.14/fs/yaffs2/yaffs_checkptrw.c
919 --- linux-3.18.14.orig/fs/yaffs2/yaffs_checkptrw.c 1970-01-01 01:00:00.000000000 +0100
920 +++ linux-3.18.14/fs/yaffs2/yaffs_checkptrw.c 2015-06-14 21:23:22.000000000 +0200
921 @@ -0,0 +1,466 @@
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 General Public License version 2 as
932 + * published by the Free Software Foundation.
933 + */
935 +#include "yaffs_checkptrw.h"
936 +#include "yaffs_getblockinfo.h"
938 +struct yaffs_checkpt_chunk_hdr {
939 + int version;
940 + int seq;
941 + u32 sum;
942 + u32 xor;
943 +} ;
946 +static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
948 + return chunk - dev->chunk_offset;
951 +static int apply_block_offset(struct yaffs_dev *dev, int block)
953 + return block - dev->block_offset;
956 +static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev)
958 + struct yaffs_checkpt_chunk_hdr hdr;
960 + hdr.version = YAFFS_CHECKPOINT_VERSION;
961 + hdr.seq = dev->checkpt_page_seq;
962 + hdr.sum = dev->checkpt_sum;
963 + hdr.xor = dev->checkpt_xor;
965 + dev->checkpt_byte_offs = sizeof(hdr);
967 + memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr));
970 +static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev)
972 + struct yaffs_checkpt_chunk_hdr hdr;
974 + memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr));
976 + dev->checkpt_byte_offs = sizeof(hdr);
978 + return hdr.version == YAFFS_CHECKPOINT_VERSION &&
979 + hdr.seq == dev->checkpt_page_seq &&
980 + hdr.sum == dev->checkpt_sum &&
981 + hdr.xor == dev->checkpt_xor;
984 +static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev)
986 + int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
988 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
989 + "checkpt blocks_avail = %d", blocks_avail);
991 + return (blocks_avail <= 0) ? 0 : 1;
994 +static int yaffs_checkpt_erase(struct yaffs_dev *dev)
996 + int i;
998 + if (!dev->drv.drv_erase_fn)
999 + return 0;
1000 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1001 + "checking blocks %d to %d",
1002 + dev->internal_start_block, dev->internal_end_block);
1004 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
1005 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
1006 + int offset_i = apply_block_offset(dev, i);
1007 + int result;
1009 + if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
1010 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1011 + "erasing checkpt block %d", i);
1013 + dev->n_erasures++;
1015 + result = dev->drv.drv_erase_fn(dev, offset_i);
1016 + if(result) {
1017 + bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
1018 + dev->n_erased_blocks++;
1019 + dev->n_free_chunks +=
1020 + dev->param.chunks_per_block;
1021 + } else {
1022 + dev->drv.drv_mark_bad_fn(dev, offset_i);
1023 + bi->block_state = YAFFS_BLOCK_STATE_DEAD;
1028 + dev->blocks_in_checkpt = 0;
1030 + return 1;
1033 +static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev)
1035 + int i;
1036 + int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks;
1038 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1039 + "allocating checkpt block: erased %d reserved %d avail %d next %d ",
1040 + dev->n_erased_blocks, dev->param.n_reserved_blocks,
1041 + blocks_avail, dev->checkpt_next_block);
1043 + if (dev->checkpt_next_block >= 0 &&
1044 + dev->checkpt_next_block <= dev->internal_end_block &&
1045 + blocks_avail > 0) {
1047 + for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
1048 + i++) {
1049 + struct yaffs_block_info *bi;
1051 + bi = yaffs_get_block_info(dev, i);
1052 + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
1053 + dev->checkpt_next_block = i + 1;
1054 + dev->checkpt_cur_block = i;
1055 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1056 + "allocating checkpt block %d", i);
1057 + return;
1061 + yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks");
1063 + dev->checkpt_next_block = -1;
1064 + dev->checkpt_cur_block = -1;
1067 +static void yaffs2_checkpt_find_block(struct yaffs_dev *dev)
1069 + int i;
1070 + struct yaffs_ext_tags tags;
1072 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1073 + "find next checkpt block: start: blocks %d next %d",
1074 + dev->blocks_in_checkpt, dev->checkpt_next_block);
1076 + if (dev->blocks_in_checkpt < dev->checkpt_max_blocks)
1077 + for (i = dev->checkpt_next_block; i <= dev->internal_end_block;
1078 + i++) {
1079 + int chunk = i * dev->param.chunks_per_block;
1080 + enum yaffs_block_state state;
1081 + u32 seq;
1083 + dev->tagger.read_chunk_tags_fn(dev,
1084 + apply_chunk_offset(dev, chunk),
1085 + NULL, &tags);
1086 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1087 + "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d",
1088 + i, (int) state,
1089 + tags.obj_id, tags.seq_number,
1090 + tags.ecc_result);
1092 + if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
1093 + continue;
1095 + dev->tagger.query_block_fn(dev,
1096 + apply_block_offset(dev, i),
1097 + &state, &seq);
1098 + if (state == YAFFS_BLOCK_STATE_DEAD)
1099 + continue;
1101 + /* Right kind of block */
1102 + dev->checkpt_next_block = tags.obj_id;
1103 + dev->checkpt_cur_block = i;
1104 + dev->checkpt_block_list[dev->blocks_in_checkpt] = i;
1105 + dev->blocks_in_checkpt++;
1106 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1107 + "found checkpt block %d", i);
1108 + return;
1111 + yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks");
1113 + dev->checkpt_next_block = -1;
1114 + dev->checkpt_cur_block = -1;
1117 +int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing)
1119 + int i;
1121 + dev->checkpt_open_write = writing;
1123 + /* Got the functions we need? */
1124 + if (!dev->tagger.write_chunk_tags_fn ||
1125 + !dev->tagger.read_chunk_tags_fn ||
1126 + !dev->drv.drv_erase_fn ||
1127 + !dev->drv.drv_mark_bad_fn)
1128 + return 0;
1130 + if (writing && !yaffs2_checkpt_space_ok(dev))
1131 + return 0;
1133 + if (!dev->checkpt_buffer)
1134 + dev->checkpt_buffer =
1135 + kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
1136 + if (!dev->checkpt_buffer)
1137 + return 0;
1139 + dev->checkpt_page_seq = 0;
1140 + dev->checkpt_byte_count = 0;
1141 + dev->checkpt_sum = 0;
1142 + dev->checkpt_xor = 0;
1143 + dev->checkpt_cur_block = -1;
1144 + dev->checkpt_cur_chunk = -1;
1145 + dev->checkpt_next_block = dev->internal_start_block;
1147 + if (writing) {
1148 + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
1149 + yaffs2_checkpt_init_chunk_hdr(dev);
1150 + return yaffs_checkpt_erase(dev);
1153 + /* Opening for a read */
1154 + /* Set to a value that will kick off a read */
1155 + dev->checkpt_byte_offs = dev->data_bytes_per_chunk;
1156 + /* A checkpoint block list of 1 checkpoint block per 16 block is
1157 + * (hopefully) going to be way more than we need */
1158 + dev->blocks_in_checkpt = 0;
1159 + dev->checkpt_max_blocks =
1160 + (dev->internal_end_block - dev->internal_start_block) / 16 + 2;
1161 + if (!dev->checkpt_block_list)
1162 + dev->checkpt_block_list =
1163 + kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS);
1165 + if (!dev->checkpt_block_list)
1166 + return 0;
1168 + for (i = 0; i < dev->checkpt_max_blocks; i++)
1169 + dev->checkpt_block_list[i] = -1;
1171 + return 1;
1174 +int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum)
1176 + u32 composite_sum;
1178 + composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff);
1179 + *sum = composite_sum;
1180 + return 1;
1183 +static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev)
1185 + int chunk;
1186 + int offset_chunk;
1187 + struct yaffs_ext_tags tags;
1189 + if (dev->checkpt_cur_block < 0) {
1190 + yaffs2_checkpt_find_erased_block(dev);
1191 + dev->checkpt_cur_chunk = 0;
1194 + if (dev->checkpt_cur_block < 0)
1195 + return 0;
1197 + tags.is_deleted = 0;
1198 + tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */
1199 + tags.chunk_id = dev->checkpt_page_seq + 1;
1200 + tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA;
1201 + tags.n_bytes = dev->data_bytes_per_chunk;
1202 + if (dev->checkpt_cur_chunk == 0) {
1203 + /* First chunk we write for the block? Set block state to
1204 + checkpoint */
1205 + struct yaffs_block_info *bi =
1206 + yaffs_get_block_info(dev, dev->checkpt_cur_block);
1207 + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
1208 + dev->blocks_in_checkpt++;
1211 + chunk =
1212 + dev->checkpt_cur_block * dev->param.chunks_per_block +
1213 + dev->checkpt_cur_chunk;
1215 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1216 + "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d",
1217 + chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk,
1218 + tags.obj_id, tags.chunk_id);
1220 + offset_chunk = apply_chunk_offset(dev, chunk);
1222 + dev->n_page_writes++;
1224 + dev->tagger.write_chunk_tags_fn(dev, offset_chunk,
1225 + dev->checkpt_buffer, &tags);
1226 + dev->checkpt_page_seq++;
1227 + dev->checkpt_cur_chunk++;
1228 + if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) {
1229 + dev->checkpt_cur_chunk = 0;
1230 + dev->checkpt_cur_block = -1;
1232 + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk);
1234 + yaffs2_checkpt_init_chunk_hdr(dev);
1237 + return 1;
1240 +int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes)
1242 + int i = 0;
1243 + int ok = 1;
1244 + u8 *data_bytes = (u8 *) data;
1246 + if (!dev->checkpt_buffer)
1247 + return 0;
1249 + if (!dev->checkpt_open_write)
1250 + return -1;
1252 + while (i < n_bytes && ok) {
1253 + dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes;
1254 + dev->checkpt_sum += *data_bytes;
1255 + dev->checkpt_xor ^= *data_bytes;
1257 + dev->checkpt_byte_offs++;
1258 + i++;
1259 + data_bytes++;
1260 + dev->checkpt_byte_count++;
1262 + if (dev->checkpt_byte_offs < 0 ||
1263 + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk)
1264 + ok = yaffs2_checkpt_flush_buffer(dev);
1267 + return i;
1270 +int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes)
1272 + int i = 0;
1273 + struct yaffs_ext_tags tags;
1274 + int chunk;
1275 + int offset_chunk;
1276 + u8 *data_bytes = (u8 *) data;
1278 + if (!dev->checkpt_buffer)
1279 + return 0;
1281 + if (dev->checkpt_open_write)
1282 + return -1;
1284 + while (i < n_bytes) {
1286 + if (dev->checkpt_byte_offs < 0 ||
1287 + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) {
1289 + if (dev->checkpt_cur_block < 0) {
1290 + yaffs2_checkpt_find_block(dev);
1291 + dev->checkpt_cur_chunk = 0;
1294 + /* Bail out if we can't find a checpoint block */
1295 + if (dev->checkpt_cur_block < 0)
1296 + break;
1298 + chunk = dev->checkpt_cur_block *
1299 + dev->param.chunks_per_block +
1300 + dev->checkpt_cur_chunk;
1302 + offset_chunk = apply_chunk_offset(dev, chunk);
1303 + dev->n_page_reads++;
1305 + /* Read in the next chunk */
1306 + dev->tagger.read_chunk_tags_fn(dev,
1307 + offset_chunk,
1308 + dev->checkpt_buffer,
1309 + &tags);
1311 + /* Bail out if the chunk is corrupted. */
1312 + if (tags.chunk_id != (dev->checkpt_page_seq + 1) ||
1313 + tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
1314 + tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA)
1315 + break;
1317 + /* Bail out if it is not a checkpoint chunk. */
1318 + if(!yaffs2_checkpt_check_chunk_hdr(dev))
1319 + break;
1321 + dev->checkpt_page_seq++;
1322 + dev->checkpt_cur_chunk++;
1324 + if (dev->checkpt_cur_chunk >=
1325 + dev->param.chunks_per_block)
1326 + dev->checkpt_cur_block = -1;
1330 + *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs];
1331 + dev->checkpt_sum += *data_bytes;
1332 + dev->checkpt_xor ^= *data_bytes;
1333 + dev->checkpt_byte_offs++;
1334 + i++;
1335 + data_bytes++;
1336 + dev->checkpt_byte_count++;
1339 + return i; /* Number of bytes read */
1342 +int yaffs_checkpt_close(struct yaffs_dev *dev)
1344 + int i;
1346 + if (dev->checkpt_open_write) {
1347 + if (dev->checkpt_byte_offs !=
1348 + sizeof(sizeof(struct yaffs_checkpt_chunk_hdr)))
1349 + yaffs2_checkpt_flush_buffer(dev);
1350 + } else if (dev->checkpt_block_list) {
1351 + for (i = 0;
1352 + i < dev->blocks_in_checkpt &&
1353 + dev->checkpt_block_list[i] >= 0; i++) {
1354 + int blk = dev->checkpt_block_list[i];
1355 + struct yaffs_block_info *bi = NULL;
1357 + if (dev->internal_start_block <= blk &&
1358 + blk <= dev->internal_end_block)
1359 + bi = yaffs_get_block_info(dev, blk);
1360 + if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY)
1361 + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
1365 + dev->n_free_chunks -=
1366 + dev->blocks_in_checkpt * dev->param.chunks_per_block;
1367 + dev->n_erased_blocks -= dev->blocks_in_checkpt;
1369 + yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d",
1370 + dev->checkpt_byte_count);
1372 + if (dev->checkpt_buffer)
1373 + return 1;
1374 + else
1375 + return 0;
1378 +int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev)
1380 + /* Erase the checkpoint data */
1382 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
1383 + "checkpoint invalidate of %d blocks",
1384 + dev->blocks_in_checkpt);
1386 + return yaffs_checkpt_erase(dev);
1388 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_checkptrw.h linux-3.18.14/fs/yaffs2/yaffs_checkptrw.h
1389 --- linux-3.18.14.orig/fs/yaffs2/yaffs_checkptrw.h 1970-01-01 01:00:00.000000000 +0100
1390 +++ linux-3.18.14/fs/yaffs2/yaffs_checkptrw.h 2015-06-14 21:23:22.000000000 +0200
1391 @@ -0,0 +1,33 @@
1393 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1395 + * Copyright (C) 2002-2011 Aleph One Ltd.
1396 + * for Toby Churchill Ltd and Brightstar Engineering
1398 + * Created by Charles Manning <charles@aleph1.co.uk>
1400 + * This program is free software; you can redistribute it and/or modify
1401 + * it under the terms of the GNU Lesser General Public License version 2.1 as
1402 + * published by the Free Software Foundation.
1404 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
1405 + */
1407 +#ifndef __YAFFS_CHECKPTRW_H__
1408 +#define __YAFFS_CHECKPTRW_H__
1410 +#include "yaffs_guts.h"
1412 +int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing);
1414 +int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes);
1416 +int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes);
1418 +int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum);
1420 +int yaffs_checkpt_close(struct yaffs_dev *dev);
1422 +int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev);
1424 +#endif
1425 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_ecc.c linux-3.18.14/fs/yaffs2/yaffs_ecc.c
1426 --- linux-3.18.14.orig/fs/yaffs2/yaffs_ecc.c 1970-01-01 01:00:00.000000000 +0100
1427 +++ linux-3.18.14/fs/yaffs2/yaffs_ecc.c 2015-06-14 21:23:22.000000000 +0200
1428 @@ -0,0 +1,281 @@
1430 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1432 + * Copyright (C) 2002-2011 Aleph One Ltd.
1433 + * for Toby Churchill Ltd and Brightstar Engineering
1435 + * Created by Charles Manning <charles@aleph1.co.uk>
1437 + * This program is free software; you can redistribute it and/or modify
1438 + * it under the terms of the GNU General Public License version 2 as
1439 + * published by the Free Software Foundation.
1440 + */
1443 + * This code implements the ECC algorithm used in SmartMedia.
1445 + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
1446 + * The two unused bit are set to 1.
1447 + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two
1448 + * such ECC blocks are used on a 512-byte NAND page.
1450 + */
1452 +#include "yportenv.h"
1454 +#include "yaffs_ecc.h"
1456 +/* Table generated by gen-ecc.c
1457 + * Using a table means we do not have to calculate p1..p4 and p1'..p4'
1458 + * for each byte of data. These are instead provided in a table in bits7..2.
1459 + * Bit 0 of each entry indicates whether the entry has an odd or even parity,
1460 + * and therefore this bytes influence on the line parity.
1461 + */
1463 +static const unsigned char column_parity_table[] = {
1464 + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
1465 + 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
1466 + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
1467 + 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
1468 + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
1469 + 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
1470 + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
1471 + 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
1472 + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
1473 + 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
1474 + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
1475 + 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
1476 + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
1477 + 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
1478 + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
1479 + 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
1480 + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
1481 + 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
1482 + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
1483 + 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
1484 + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
1485 + 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
1486 + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
1487 + 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
1488 + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
1489 + 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
1490 + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
1491 + 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
1492 + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
1493 + 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
1494 + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
1495 + 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
1499 +/* Calculate the ECC for a 256-byte block of data */
1500 +void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc)
1502 + unsigned int i;
1503 + unsigned char col_parity = 0;
1504 + unsigned char line_parity = 0;
1505 + unsigned char line_parity_prime = 0;
1506 + unsigned char t;
1507 + unsigned char b;
1509 + for (i = 0; i < 256; i++) {
1510 + b = column_parity_table[*data++];
1511 + col_parity ^= b;
1513 + if (b & 0x01) { /* odd number of bits in the byte */
1514 + line_parity ^= i;
1515 + line_parity_prime ^= ~i;
1519 + ecc[2] = (~col_parity) | 0x03;
1521 + t = 0;
1522 + if (line_parity & 0x80)
1523 + t |= 0x80;
1524 + if (line_parity_prime & 0x80)
1525 + t |= 0x40;
1526 + if (line_parity & 0x40)
1527 + t |= 0x20;
1528 + if (line_parity_prime & 0x40)
1529 + t |= 0x10;
1530 + if (line_parity & 0x20)
1531 + t |= 0x08;
1532 + if (line_parity_prime & 0x20)
1533 + t |= 0x04;
1534 + if (line_parity & 0x10)
1535 + t |= 0x02;
1536 + if (line_parity_prime & 0x10)
1537 + t |= 0x01;
1538 + ecc[1] = ~t;
1540 + t = 0;
1541 + if (line_parity & 0x08)
1542 + t |= 0x80;
1543 + if (line_parity_prime & 0x08)
1544 + t |= 0x40;
1545 + if (line_parity & 0x04)
1546 + t |= 0x20;
1547 + if (line_parity_prime & 0x04)
1548 + t |= 0x10;
1549 + if (line_parity & 0x02)
1550 + t |= 0x08;
1551 + if (line_parity_prime & 0x02)
1552 + t |= 0x04;
1553 + if (line_parity & 0x01)
1554 + t |= 0x02;
1555 + if (line_parity_prime & 0x01)
1556 + t |= 0x01;
1557 + ecc[0] = ~t;
1561 +/* Correct the ECC on a 256 byte block of data */
1563 +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
1564 + const unsigned char *test_ecc)
1566 + unsigned char d0, d1, d2; /* deltas */
1568 + d0 = read_ecc[0] ^ test_ecc[0];
1569 + d1 = read_ecc[1] ^ test_ecc[1];
1570 + d2 = read_ecc[2] ^ test_ecc[2];
1572 + if ((d0 | d1 | d2) == 0)
1573 + return 0; /* no error */
1575 + if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
1576 + ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
1577 + ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
1578 + /* Single bit (recoverable) error in data */
1580 + unsigned byte;
1581 + unsigned bit;
1583 + bit = byte = 0;
1585 + if (d1 & 0x80)
1586 + byte |= 0x80;
1587 + if (d1 & 0x20)
1588 + byte |= 0x40;
1589 + if (d1 & 0x08)
1590 + byte |= 0x20;
1591 + if (d1 & 0x02)
1592 + byte |= 0x10;
1593 + if (d0 & 0x80)
1594 + byte |= 0x08;
1595 + if (d0 & 0x20)
1596 + byte |= 0x04;
1597 + if (d0 & 0x08)
1598 + byte |= 0x02;
1599 + if (d0 & 0x02)
1600 + byte |= 0x01;
1602 + if (d2 & 0x80)
1603 + bit |= 0x04;
1604 + if (d2 & 0x20)
1605 + bit |= 0x02;
1606 + if (d2 & 0x08)
1607 + bit |= 0x01;
1609 + data[byte] ^= (1 << bit);
1611 + return 1; /* Corrected the error */
1614 + if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) {
1615 + /* Reccoverable error in ecc */
1617 + read_ecc[0] = test_ecc[0];
1618 + read_ecc[1] = test_ecc[1];
1619 + read_ecc[2] = test_ecc[2];
1621 + return 1; /* Corrected the error */
1624 + /* Unrecoverable error */
1626 + return -1;
1631 + * ECCxxxOther does ECC calcs on arbitrary n bytes of data
1632 + */
1633 +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
1634 + struct yaffs_ecc_other *ecc_other)
1636 + unsigned int i;
1637 + unsigned char col_parity = 0;
1638 + unsigned line_parity = 0;
1639 + unsigned line_parity_prime = 0;
1640 + unsigned char b;
1642 + for (i = 0; i < n_bytes; i++) {
1643 + b = column_parity_table[*data++];
1644 + col_parity ^= b;
1646 + if (b & 0x01) {
1647 + /* odd number of bits in the byte */
1648 + line_parity ^= i;
1649 + line_parity_prime ^= ~i;
1654 + ecc_other->col_parity = (col_parity >> 2) & 0x3f;
1655 + ecc_other->line_parity = line_parity;
1656 + ecc_other->line_parity_prime = line_parity_prime;
1659 +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
1660 + struct yaffs_ecc_other *read_ecc,
1661 + const struct yaffs_ecc_other *test_ecc)
1663 + unsigned char delta_col; /* column parity delta */
1664 + unsigned delta_line; /* line parity delta */
1665 + unsigned delta_line_prime; /* line parity delta */
1666 + unsigned bit;
1668 + delta_col = read_ecc->col_parity ^ test_ecc->col_parity;
1669 + delta_line = read_ecc->line_parity ^ test_ecc->line_parity;
1670 + delta_line_prime =
1671 + read_ecc->line_parity_prime ^ test_ecc->line_parity_prime;
1673 + if ((delta_col | delta_line | delta_line_prime) == 0)
1674 + return 0; /* no error */
1676 + if (delta_line == ~delta_line_prime &&
1677 + (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) {
1678 + /* Single bit (recoverable) error in data */
1680 + bit = 0;
1682 + if (delta_col & 0x20)
1683 + bit |= 0x04;
1684 + if (delta_col & 0x08)
1685 + bit |= 0x02;
1686 + if (delta_col & 0x02)
1687 + bit |= 0x01;
1689 + if (delta_line >= n_bytes)
1690 + return -1;
1692 + data[delta_line] ^= (1 << bit);
1694 + return 1; /* corrected */
1697 + if ((hweight32(delta_line) +
1698 + hweight32(delta_line_prime) +
1699 + hweight8(delta_col)) == 1) {
1700 + /* Reccoverable error in ecc */
1702 + *read_ecc = *test_ecc;
1703 + return 1; /* corrected */
1706 + /* Unrecoverable error */
1708 + return -1;
1710 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_ecc.h linux-3.18.14/fs/yaffs2/yaffs_ecc.h
1711 --- linux-3.18.14.orig/fs/yaffs2/yaffs_ecc.h 1970-01-01 01:00:00.000000000 +0100
1712 +++ linux-3.18.14/fs/yaffs2/yaffs_ecc.h 2015-06-14 21:23:22.000000000 +0200
1713 @@ -0,0 +1,44 @@
1715 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1717 + * Copyright (C) 2002-2011 Aleph One Ltd.
1718 + * for Toby Churchill Ltd and Brightstar Engineering
1720 + * Created by Charles Manning <charles@aleph1.co.uk>
1722 + * This program is free software; you can redistribute it and/or modify
1723 + * it under the terms of the GNU Lesser General Public License version 2.1 as
1724 + * published by the Free Software Foundation.
1726 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
1727 + */
1730 + * This code implements the ECC algorithm used in SmartMedia.
1732 + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
1733 + * The two unused bit are set to 1.
1734 + * The ECC can correct single bit errors in a 256-byte page of data.
1735 + * Thus, two such ECC blocks are used on a 512-byte NAND page.
1737 + */
1739 +#ifndef __YAFFS_ECC_H__
1740 +#define __YAFFS_ECC_H__
1742 +struct yaffs_ecc_other {
1743 + unsigned char col_parity;
1744 + unsigned line_parity;
1745 + unsigned line_parity_prime;
1748 +void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc);
1749 +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc,
1750 + const unsigned char *test_ecc);
1752 +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes,
1753 + struct yaffs_ecc_other *ecc);
1754 +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes,
1755 + struct yaffs_ecc_other *read_ecc,
1756 + const struct yaffs_ecc_other *test_ecc);
1757 +#endif
1758 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_getblockinfo.h linux-3.18.14/fs/yaffs2/yaffs_getblockinfo.h
1759 --- linux-3.18.14.orig/fs/yaffs2/yaffs_getblockinfo.h 1970-01-01 01:00:00.000000000 +0100
1760 +++ linux-3.18.14/fs/yaffs2/yaffs_getblockinfo.h 2015-06-14 21:23:22.000000000 +0200
1761 @@ -0,0 +1,35 @@
1763 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1765 + * Copyright (C) 2002-2011 Aleph One Ltd.
1766 + * for Toby Churchill Ltd and Brightstar Engineering
1768 + * Created by Charles Manning <charles@aleph1.co.uk>
1770 + * This program is free software; you can redistribute it and/or modify
1771 + * it under the terms of the GNU Lesser General Public License version 2.1 as
1772 + * published by the Free Software Foundation.
1774 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
1775 + */
1777 +#ifndef __YAFFS_GETBLOCKINFO_H__
1778 +#define __YAFFS_GETBLOCKINFO_H__
1780 +#include "yaffs_guts.h"
1781 +#include "yaffs_trace.h"
1783 +/* Function to manipulate block info */
1784 +static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev
1785 + *dev, int blk)
1787 + if (blk < dev->internal_start_block || blk > dev->internal_end_block) {
1788 + yaffs_trace(YAFFS_TRACE_ERROR,
1789 + "**>> yaffs: get_block_info block %d is not valid",
1790 + blk);
1791 + BUG();
1793 + return &dev->block_info[blk - dev->internal_start_block];
1796 +#endif
1797 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_guts.c linux-3.18.14/fs/yaffs2/yaffs_guts.c
1798 --- linux-3.18.14.orig/fs/yaffs2/yaffs_guts.c 1970-01-01 01:00:00.000000000 +0100
1799 +++ linux-3.18.14/fs/yaffs2/yaffs_guts.c 2015-06-14 21:23:22.000000000 +0200
1800 @@ -0,0 +1,5140 @@
1802 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1804 + * Copyright (C) 2002-2011 Aleph One Ltd.
1805 + * for Toby Churchill Ltd and Brightstar Engineering
1807 + * Created by Charles Manning <charles@aleph1.co.uk>
1809 + * This program is free software; you can redistribute it and/or modify
1810 + * it under the terms of the GNU General Public License version 2 as
1811 + * published by the Free Software Foundation.
1812 + */
1814 +#include "yportenv.h"
1815 +#include "yaffs_trace.h"
1817 +#include "yaffs_guts.h"
1818 +#include "yaffs_getblockinfo.h"
1819 +#include "yaffs_tagscompat.h"
1820 +#include "yaffs_tagsmarshall.h"
1821 +#include "yaffs_nand.h"
1822 +#include "yaffs_yaffs1.h"
1823 +#include "yaffs_yaffs2.h"
1824 +#include "yaffs_bitmap.h"
1825 +#include "yaffs_verify.h"
1826 +#include "yaffs_nand.h"
1827 +#include "yaffs_packedtags2.h"
1828 +#include "yaffs_nameval.h"
1829 +#include "yaffs_allocator.h"
1830 +#include "yaffs_attribs.h"
1831 +#include "yaffs_summary.h"
1833 +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */
1834 +#define YAFFS_GC_GOOD_ENOUGH 2
1835 +#define YAFFS_GC_PASSIVE_THRESHOLD 4
1837 +#include "yaffs_ecc.h"
1839 +/* Forward declarations */
1841 +static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
1842 + const u8 *buffer, int n_bytes, int use_reserve);
1844 +static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
1845 + int buffer_size);
1847 +/* Function to calculate chunk and offset */
1849 +void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
1850 + int *chunk_out, u32 *offset_out)
1852 + int chunk;
1853 + u32 offset;
1855 + chunk = (u32) (addr >> dev->chunk_shift);
1857 + if (dev->chunk_div == 1) {
1858 + /* easy power of 2 case */
1859 + offset = (u32) (addr & dev->chunk_mask);
1860 + } else {
1861 + /* Non power-of-2 case */
1863 + loff_t chunk_base;
1865 + chunk /= dev->chunk_div;
1867 + chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk;
1868 + offset = (u32) (addr - chunk_base);
1871 + *chunk_out = chunk;
1872 + *offset_out = offset;
1875 +/* Function to return the number of shifts for a power of 2 greater than or
1876 + * equal to the given number
1877 + * Note we don't try to cater for all possible numbers and this does not have to
1878 + * be hellishly efficient.
1879 + */
1881 +static inline u32 calc_shifts_ceiling(u32 x)
1883 + int extra_bits;
1884 + int shifts;
1886 + shifts = extra_bits = 0;
1888 + while (x > 1) {
1889 + if (x & 1)
1890 + extra_bits++;
1891 + x >>= 1;
1892 + shifts++;
1895 + if (extra_bits)
1896 + shifts++;
1898 + return shifts;
1901 +/* Function to return the number of shifts to get a 1 in bit 0
1902 + */
1904 +static inline u32 calc_shifts(u32 x)
1906 + u32 shifts;
1908 + shifts = 0;
1910 + if (!x)
1911 + return 0;
1913 + while (!(x & 1)) {
1914 + x >>= 1;
1915 + shifts++;
1918 + return shifts;
1922 + * Temporary buffer manipulations.
1923 + */
1925 +static int yaffs_init_tmp_buffers(struct yaffs_dev *dev)
1927 + int i;
1928 + u8 *buf = (u8 *) 1;
1930 + memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer));
1932 + for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
1933 + dev->temp_buffer[i].in_use = 0;
1934 + buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
1935 + dev->temp_buffer[i].buffer = buf;
1938 + return buf ? YAFFS_OK : YAFFS_FAIL;
1941 +u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev)
1943 + int i;
1945 + dev->temp_in_use++;
1946 + if (dev->temp_in_use > dev->max_temp)
1947 + dev->max_temp = dev->temp_in_use;
1949 + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
1950 + if (dev->temp_buffer[i].in_use == 0) {
1951 + dev->temp_buffer[i].in_use = 1;
1952 + return dev->temp_buffer[i].buffer;
1956 + yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers");
1957 + /*
1958 + * If we got here then we have to allocate an unmanaged one
1959 + * This is not good.
1960 + */
1962 + dev->unmanaged_buffer_allocs++;
1963 + return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS);
1967 +void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer)
1969 + int i;
1971 + dev->temp_in_use--;
1973 + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
1974 + if (dev->temp_buffer[i].buffer == buffer) {
1975 + dev->temp_buffer[i].in_use = 0;
1976 + return;
1980 + if (buffer) {
1981 + /* assume it is an unmanaged one. */
1982 + yaffs_trace(YAFFS_TRACE_BUFFERS,
1983 + "Releasing unmanaged temp buffer");
1984 + kfree(buffer);
1985 + dev->unmanaged_buffer_deallocs++;
1991 + * Functions for robustisizing TODO
1993 + */
1995 +static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk,
1996 + const u8 *data,
1997 + const struct yaffs_ext_tags *tags)
1999 + (void) dev;
2000 + (void) nand_chunk;
2001 + (void) data;
2002 + (void) tags;
2005 +static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk,
2006 + const struct yaffs_ext_tags *tags)
2008 + (void) dev;
2009 + (void) nand_chunk;
2010 + (void) tags;
2013 +void yaffs_handle_chunk_error(struct yaffs_dev *dev,
2014 + struct yaffs_block_info *bi)
2016 + if (!bi->gc_prioritise) {
2017 + bi->gc_prioritise = 1;
2018 + dev->has_pending_prioritised_gc = 1;
2019 + bi->chunk_error_strikes++;
2021 + if (bi->chunk_error_strikes > 3) {
2022 + bi->needs_retiring = 1; /* Too many stikes, so retire */
2023 + yaffs_trace(YAFFS_TRACE_ALWAYS,
2024 + "yaffs: Block struck out");
2030 +static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk,
2031 + int erased_ok)
2033 + int flash_block = nand_chunk / dev->param.chunks_per_block;
2034 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
2036 + yaffs_handle_chunk_error(dev, bi);
2038 + if (erased_ok) {
2039 + /* Was an actual write failure,
2040 + * so mark the block for retirement.*/
2041 + bi->needs_retiring = 1;
2042 + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
2043 + "**>> Block %d needs retiring", flash_block);
2046 + /* Delete the chunk */
2047 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
2048 + yaffs_skip_rest_of_block(dev);
2052 + * Verification code
2053 + */
2056 + * Simple hash function. Needs to have a reasonable spread
2057 + */
2059 +static inline int yaffs_hash_fn(int n)
2061 + if (n < 0)
2062 + n = -n;
2063 + return n % YAFFS_NOBJECT_BUCKETS;
2067 + * Access functions to useful fake objects.
2068 + * Note that root might have a presence in NAND if permissions are set.
2069 + */
2071 +struct yaffs_obj *yaffs_root(struct yaffs_dev *dev)
2073 + return dev->root_dir;
2076 +struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev)
2078 + return dev->lost_n_found;
2082 + * Erased NAND checking functions
2083 + */
2085 +int yaffs_check_ff(u8 *buffer, int n_bytes)
2087 + /* Horrible, slow implementation */
2088 + while (n_bytes--) {
2089 + if (*buffer != 0xff)
2090 + return 0;
2091 + buffer++;
2093 + return 1;
2096 +static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk)
2098 + int retval = YAFFS_OK;
2099 + u8 *data = yaffs_get_temp_buffer(dev);
2100 + struct yaffs_ext_tags tags;
2101 + int result;
2103 + result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags);
2105 + if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR)
2106 + retval = YAFFS_FAIL;
2108 + if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) ||
2109 + tags.chunk_used) {
2110 + yaffs_trace(YAFFS_TRACE_NANDACCESS,
2111 + "Chunk %d not erased", nand_chunk);
2112 + retval = YAFFS_FAIL;
2115 + yaffs_release_temp_buffer(dev, data);
2117 + return retval;
2121 +static int yaffs_verify_chunk_written(struct yaffs_dev *dev,
2122 + int nand_chunk,
2123 + const u8 *data,
2124 + struct yaffs_ext_tags *tags)
2126 + int retval = YAFFS_OK;
2127 + struct yaffs_ext_tags temp_tags;
2128 + u8 *buffer = yaffs_get_temp_buffer(dev);
2129 + int result;
2131 + result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags);
2132 + if (memcmp(buffer, data, dev->data_bytes_per_chunk) ||
2133 + temp_tags.obj_id != tags->obj_id ||
2134 + temp_tags.chunk_id != tags->chunk_id ||
2135 + temp_tags.n_bytes != tags->n_bytes)
2136 + retval = YAFFS_FAIL;
2138 + yaffs_release_temp_buffer(dev, buffer);
2140 + return retval;
2144 +int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks)
2146 + int reserved_chunks;
2147 + int reserved_blocks = dev->param.n_reserved_blocks;
2148 + int checkpt_blocks;
2150 + checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev);
2152 + reserved_chunks =
2153 + (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block;
2155 + return (dev->n_free_chunks > (reserved_chunks + n_chunks));
2158 +static int yaffs_find_alloc_block(struct yaffs_dev *dev)
2160 + int i;
2161 + struct yaffs_block_info *bi;
2163 + if (dev->n_erased_blocks < 1) {
2164 + /* Hoosterman we've got a problem.
2165 + * Can't get space to gc
2166 + */
2167 + yaffs_trace(YAFFS_TRACE_ERROR,
2168 + "yaffs tragedy: no more erased blocks");
2170 + return -1;
2173 + /* Find an empty block. */
2175 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
2176 + dev->alloc_block_finder++;
2177 + if (dev->alloc_block_finder < dev->internal_start_block
2178 + || dev->alloc_block_finder > dev->internal_end_block) {
2179 + dev->alloc_block_finder = dev->internal_start_block;
2182 + bi = yaffs_get_block_info(dev, dev->alloc_block_finder);
2184 + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
2185 + bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;
2186 + dev->seq_number++;
2187 + bi->seq_number = dev->seq_number;
2188 + dev->n_erased_blocks--;
2189 + yaffs_trace(YAFFS_TRACE_ALLOCATE,
2190 + "Allocated block %d, seq %d, %d left" ,
2191 + dev->alloc_block_finder, dev->seq_number,
2192 + dev->n_erased_blocks);
2193 + return dev->alloc_block_finder;
2197 + yaffs_trace(YAFFS_TRACE_ALWAYS,
2198 + "yaffs tragedy: no more erased blocks, but there should have been %d",
2199 + dev->n_erased_blocks);
2201 + return -1;
2204 +static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver,
2205 + struct yaffs_block_info **block_ptr)
2207 + int ret_val;
2208 + struct yaffs_block_info *bi;
2210 + if (dev->alloc_block < 0) {
2211 + /* Get next block to allocate off */
2212 + dev->alloc_block = yaffs_find_alloc_block(dev);
2213 + dev->alloc_page = 0;
2216 + if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) {
2217 + /* No space unless we're allowed to use the reserve. */
2218 + return -1;
2221 + if (dev->n_erased_blocks < dev->param.n_reserved_blocks
2222 + && dev->alloc_page == 0)
2223 + yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve");
2225 + /* Next page please.... */
2226 + if (dev->alloc_block >= 0) {
2227 + bi = yaffs_get_block_info(dev, dev->alloc_block);
2229 + ret_val = (dev->alloc_block * dev->param.chunks_per_block) +
2230 + dev->alloc_page;
2231 + bi->pages_in_use++;
2232 + yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);
2234 + dev->alloc_page++;
2236 + dev->n_free_chunks--;
2238 + /* If the block is full set the state to full */
2239 + if (dev->alloc_page >= dev->param.chunks_per_block) {
2240 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
2241 + dev->alloc_block = -1;
2244 + if (block_ptr)
2245 + *block_ptr = bi;
2247 + return ret_val;
2250 + yaffs_trace(YAFFS_TRACE_ERROR,
2251 + "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!");
2253 + return -1;
2256 +static int yaffs_get_erased_chunks(struct yaffs_dev *dev)
2258 + int n;
2260 + n = dev->n_erased_blocks * dev->param.chunks_per_block;
2262 + if (dev->alloc_block > 0)
2263 + n += (dev->param.chunks_per_block - dev->alloc_page);
2265 + return n;
2270 + * yaffs_skip_rest_of_block() skips over the rest of the allocation block
2271 + * if we don't want to write to it.
2272 + */
2273 +void yaffs_skip_rest_of_block(struct yaffs_dev *dev)
2275 + struct yaffs_block_info *bi;
2277 + if (dev->alloc_block > 0) {
2278 + bi = yaffs_get_block_info(dev, dev->alloc_block);
2279 + if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
2280 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
2281 + dev->alloc_block = -1;
2286 +static int yaffs_write_new_chunk(struct yaffs_dev *dev,
2287 + const u8 *data,
2288 + struct yaffs_ext_tags *tags, int use_reserver)
2290 + int attempts = 0;
2291 + int write_ok = 0;
2292 + int chunk;
2294 + yaffs2_checkpt_invalidate(dev);
2296 + do {
2297 + struct yaffs_block_info *bi = 0;
2298 + int erased_ok = 0;
2300 + chunk = yaffs_alloc_chunk(dev, use_reserver, &bi);
2301 + if (chunk < 0) {
2302 + /* no space */
2303 + break;
2306 + /* First check this chunk is erased, if it needs
2307 + * checking. The checking policy (unless forced
2308 + * always on) is as follows:
2310 + * Check the first page we try to write in a block.
2311 + * If the check passes then we don't need to check any
2312 + * more. If the check fails, we check again...
2313 + * If the block has been erased, we don't need to check.
2315 + * However, if the block has been prioritised for gc,
2316 + * then we think there might be something odd about
2317 + * this block and stop using it.
2319 + * Rationale: We should only ever see chunks that have
2320 + * not been erased if there was a partially written
2321 + * chunk due to power loss. This checking policy should
2322 + * catch that case with very few checks and thus save a
2323 + * lot of checks that are most likely not needed.
2325 + * Mods to the above
2326 + * If an erase check fails or the write fails we skip the
2327 + * rest of the block.
2328 + */
2330 + /* let's give it a try */
2331 + attempts++;
2333 + if (dev->param.always_check_erased)
2334 + bi->skip_erased_check = 0;
2336 + if (!bi->skip_erased_check) {
2337 + erased_ok = yaffs_check_chunk_erased(dev, chunk);
2338 + if (erased_ok != YAFFS_OK) {
2339 + yaffs_trace(YAFFS_TRACE_ERROR,
2340 + "**>> yaffs chunk %d was not erased",
2341 + chunk);
2343 + /* If not erased, delete this one,
2344 + * skip rest of block and
2345 + * try another chunk */
2346 + yaffs_chunk_del(dev, chunk, 1, __LINE__);
2347 + yaffs_skip_rest_of_block(dev);
2348 + continue;
2352 + write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags);
2354 + if (!bi->skip_erased_check)
2355 + write_ok =
2356 + yaffs_verify_chunk_written(dev, chunk, data, tags);
2358 + if (write_ok != YAFFS_OK) {
2359 + /* Clean up aborted write, skip to next block and
2360 + * try another chunk */
2361 + yaffs_handle_chunk_wr_error(dev, chunk, erased_ok);
2362 + continue;
2365 + bi->skip_erased_check = 1;
2367 + /* Copy the data into the robustification buffer */
2368 + yaffs_handle_chunk_wr_ok(dev, chunk, data, tags);
2370 + } while (write_ok != YAFFS_OK &&
2371 + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
2373 + if (!write_ok)
2374 + chunk = -1;
2376 + if (attempts > 1) {
2377 + yaffs_trace(YAFFS_TRACE_ERROR,
2378 + "**>> yaffs write required %d attempts",
2379 + attempts);
2380 + dev->n_retried_writes += (attempts - 1);
2383 + return chunk;
2387 + * Block retiring for handling a broken block.
2388 + */
2390 +static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block)
2392 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block);
2394 + yaffs2_checkpt_invalidate(dev);
2396 + yaffs2_clear_oldest_dirty_seq(dev, bi);
2398 + if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) {
2399 + if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) {
2400 + yaffs_trace(YAFFS_TRACE_ALWAYS,
2401 + "yaffs: Failed to mark bad and erase block %d",
2402 + flash_block);
2403 + } else {
2404 + struct yaffs_ext_tags tags;
2405 + int chunk_id =
2406 + flash_block * dev->param.chunks_per_block;
2408 + u8 *buffer = yaffs_get_temp_buffer(dev);
2410 + memset(buffer, 0xff, dev->data_bytes_per_chunk);
2411 + memset(&tags, 0, sizeof(tags));
2412 + tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK;
2413 + if (dev->tagger.write_chunk_tags_fn(dev, chunk_id -
2414 + dev->chunk_offset,
2415 + buffer,
2416 + &tags) != YAFFS_OK)
2417 + yaffs_trace(YAFFS_TRACE_ALWAYS,
2418 + "yaffs: Failed to write bad block marker to block %d",
2419 + flash_block);
2421 + yaffs_release_temp_buffer(dev, buffer);
2425 + bi->block_state = YAFFS_BLOCK_STATE_DEAD;
2426 + bi->gc_prioritise = 0;
2427 + bi->needs_retiring = 0;
2429 + dev->n_retired_blocks++;
2432 +/*---------------- Name handling functions ------------*/
2434 +static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name,
2435 + const YCHAR *oh_name, int buff_size)
2437 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
2438 + if (dev->param.auto_unicode) {
2439 + if (*oh_name) {
2440 + /* It is an ASCII name, do an ASCII to
2441 + * unicode conversion */
2442 + const char *ascii_oh_name = (const char *)oh_name;
2443 + int n = buff_size - 1;
2444 + while (n > 0 && *ascii_oh_name) {
2445 + *name = *ascii_oh_name;
2446 + name++;
2447 + ascii_oh_name++;
2448 + n--;
2450 + } else {
2451 + strncpy(name, oh_name + 1, buff_size - 1);
2453 + } else {
2454 +#else
2455 + (void) dev;
2457 +#endif
2458 + strncpy(name, oh_name, buff_size - 1);
2462 +static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name,
2463 + const YCHAR *name)
2465 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
2467 + int is_ascii;
2468 + const YCHAR *w;
2470 + if (dev->param.auto_unicode) {
2472 + is_ascii = 1;
2473 + w = name;
2475 + /* Figure out if the name will fit in ascii character set */
2476 + while (is_ascii && *w) {
2477 + if ((*w) & 0xff00)
2478 + is_ascii = 0;
2479 + w++;
2482 + if (is_ascii) {
2483 + /* It is an ASCII name, so convert unicode to ascii */
2484 + char *ascii_oh_name = (char *)oh_name;
2485 + int n = YAFFS_MAX_NAME_LENGTH - 1;
2486 + while (n > 0 && *name) {
2487 + *ascii_oh_name = *name;
2488 + name++;
2489 + ascii_oh_name++;
2490 + n--;
2492 + } else {
2493 + /* Unicode name, so save starting at the second YCHAR */
2494 + *oh_name = 0;
2495 + strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2);
2497 + } else {
2498 +#else
2499 + dev = dev;
2501 +#endif
2502 + strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1);
2506 +static u16 yaffs_calc_name_sum(const YCHAR *name)
2508 + u16 sum = 0;
2509 + u16 i = 1;
2511 + if (!name)
2512 + return 0;
2514 + while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) {
2516 + /* 0x1f mask is case insensitive */
2517 + sum += ((*name) & 0x1f) * i;
2518 + i++;
2519 + name++;
2521 + return sum;
2525 +void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name)
2527 + memset(obj->short_name, 0, sizeof(obj->short_name));
2529 + if (name && !name[0]) {
2530 + yaffs_fix_null_name(obj, obj->short_name,
2531 + YAFFS_SHORT_NAME_LENGTH);
2532 + name = obj->short_name;
2533 + } else if (name &&
2534 + strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <=
2535 + YAFFS_SHORT_NAME_LENGTH) {
2536 + strcpy(obj->short_name, name);
2539 + obj->sum = yaffs_calc_name_sum(name);
2542 +void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
2543 + const struct yaffs_obj_hdr *oh)
2545 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
2546 + YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1];
2547 + memset(tmp_name, 0, sizeof(tmp_name));
2548 + yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name,
2549 + YAFFS_MAX_NAME_LENGTH + 1);
2550 + yaffs_set_obj_name(obj, tmp_name);
2551 +#else
2552 + yaffs_set_obj_name(obj, oh->name);
2553 +#endif
2556 +loff_t yaffs_max_file_size(struct yaffs_dev *dev)
2558 + if(sizeof(loff_t) < 8)
2559 + return YAFFS_MAX_FILE_SIZE_32;
2560 + else
2561 + return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk;
2564 +/*-------------------- TNODES -------------------
2566 + * List of spare tnodes
2567 + * The list is hooked together using the first pointer
2568 + * in the tnode.
2569 + */
2571 +struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)
2573 + struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);
2575 + if (tn) {
2576 + memset(tn, 0, dev->tnode_size);
2577 + dev->n_tnodes++;
2580 + dev->checkpoint_blocks_required = 0; /* force recalculation */
2582 + return tn;
2585 +/* FreeTnode frees up a tnode and puts it back on the free list */
2586 +static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn)
2588 + yaffs_free_raw_tnode(dev, tn);
2589 + dev->n_tnodes--;
2590 + dev->checkpoint_blocks_required = 0; /* force recalculation */
2593 +static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev)
2595 + yaffs_deinit_raw_tnodes_and_objs(dev);
2596 + dev->n_obj = 0;
2597 + dev->n_tnodes = 0;
2600 +static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn,
2601 + unsigned pos, unsigned val)
2603 + u32 *map = (u32 *) tn;
2604 + u32 bit_in_map;
2605 + u32 bit_in_word;
2606 + u32 word_in_map;
2607 + u32 mask;
2609 + pos &= YAFFS_TNODES_LEVEL0_MASK;
2610 + val >>= dev->chunk_grp_bits;
2612 + bit_in_map = pos * dev->tnode_width;
2613 + word_in_map = bit_in_map / 32;
2614 + bit_in_word = bit_in_map & (32 - 1);
2616 + mask = dev->tnode_mask << bit_in_word;
2618 + map[word_in_map] &= ~mask;
2619 + map[word_in_map] |= (mask & (val << 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 + mask =
2625 + dev->tnode_mask >> bit_in_word;
2626 + map[word_in_map] &= ~mask;
2627 + map[word_in_map] |= (mask & (val >> bit_in_word));
2631 +u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
2632 + unsigned pos)
2634 + u32 *map = (u32 *) tn;
2635 + u32 bit_in_map;
2636 + u32 bit_in_word;
2637 + u32 word_in_map;
2638 + u32 val;
2640 + pos &= YAFFS_TNODES_LEVEL0_MASK;
2642 + bit_in_map = pos * dev->tnode_width;
2643 + word_in_map = bit_in_map / 32;
2644 + bit_in_word = bit_in_map & (32 - 1);
2646 + val = map[word_in_map] >> bit_in_word;
2648 + if (dev->tnode_width > (32 - bit_in_word)) {
2649 + bit_in_word = (32 - bit_in_word);
2650 + word_in_map++;
2651 + val |= (map[word_in_map] << bit_in_word);
2654 + val &= dev->tnode_mask;
2655 + val <<= dev->chunk_grp_bits;
2657 + return val;
2660 +/* ------------------- End of individual tnode manipulation -----------------*/
2662 +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
2663 + * The look up tree is represented by the top tnode and the number of top_level
2664 + * in the tree. 0 means only the level 0 tnode is in the tree.
2665 + */
2667 +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
2668 +struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
2669 + struct yaffs_file_var *file_struct,
2670 + u32 chunk_id)
2672 + struct yaffs_tnode *tn = file_struct->top;
2673 + u32 i;
2674 + int required_depth;
2675 + int level = file_struct->top_level;
2677 + (void) dev;
2679 + /* Check sane level and chunk Id */
2680 + if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
2681 + return NULL;
2683 + if (chunk_id > YAFFS_MAX_CHUNK_ID)
2684 + return NULL;
2686 + /* First check we're tall enough (ie enough top_level) */
2688 + i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
2689 + required_depth = 0;
2690 + while (i) {
2691 + i >>= YAFFS_TNODES_INTERNAL_BITS;
2692 + required_depth++;
2695 + if (required_depth > file_struct->top_level)
2696 + return NULL; /* Not tall enough, so we can't find it */
2698 + /* Traverse down to level 0 */
2699 + while (level > 0 && tn) {
2700 + tn = tn->internal[(chunk_id >>
2701 + (YAFFS_TNODES_LEVEL0_BITS +
2702 + (level - 1) *
2703 + YAFFS_TNODES_INTERNAL_BITS)) &
2704 + YAFFS_TNODES_INTERNAL_MASK];
2705 + level--;
2708 + return tn;
2711 +/* add_find_tnode_0 finds the level 0 tnode if it exists,
2712 + * otherwise first expands the tree.
2713 + * This happens in two steps:
2714 + * 1. If the tree isn't tall enough, then make it taller.
2715 + * 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
2717 + * Used when modifying the tree.
2719 + * If the tn argument is NULL, then a fresh tnode will be added otherwise the
2720 + * specified tn will be plugged into the ttree.
2721 + */
2723 +struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
2724 + struct yaffs_file_var *file_struct,
2725 + u32 chunk_id,
2726 + struct yaffs_tnode *passed_tn)
2728 + int required_depth;
2729 + int i;
2730 + int l;
2731 + struct yaffs_tnode *tn;
2732 + u32 x;
2734 + /* Check sane level and page Id */
2735 + if (file_struct->top_level < 0 ||
2736 + file_struct->top_level > YAFFS_TNODES_MAX_LEVEL)
2737 + return NULL;
2739 + if (chunk_id > YAFFS_MAX_CHUNK_ID)
2740 + return NULL;
2742 + /* First check we're tall enough (ie enough top_level) */
2744 + x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS;
2745 + required_depth = 0;
2746 + while (x) {
2747 + x >>= YAFFS_TNODES_INTERNAL_BITS;
2748 + required_depth++;
2751 + if (required_depth > file_struct->top_level) {
2752 + /* Not tall enough, gotta make the tree taller */
2753 + for (i = file_struct->top_level; i < required_depth; i++) {
2755 + tn = yaffs_get_tnode(dev);
2757 + if (tn) {
2758 + tn->internal[0] = file_struct->top;
2759 + file_struct->top = tn;
2760 + file_struct->top_level++;
2761 + } else {
2762 + yaffs_trace(YAFFS_TRACE_ERROR,
2763 + "yaffs: no more tnodes");
2764 + return NULL;
2769 + /* Traverse down to level 0, adding anything we need */
2771 + l = file_struct->top_level;
2772 + tn = file_struct->top;
2774 + if (l > 0) {
2775 + while (l > 0 && tn) {
2776 + x = (chunk_id >>
2777 + (YAFFS_TNODES_LEVEL0_BITS +
2778 + (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
2779 + YAFFS_TNODES_INTERNAL_MASK;
2781 + if ((l > 1) && !tn->internal[x]) {
2782 + /* Add missing non-level-zero tnode */
2783 + tn->internal[x] = yaffs_get_tnode(dev);
2784 + if (!tn->internal[x])
2785 + return NULL;
2786 + } else if (l == 1) {
2787 + /* Looking from level 1 at level 0 */
2788 + if (passed_tn) {
2789 + /* If we already have one, release it */
2790 + if (tn->internal[x])
2791 + yaffs_free_tnode(dev,
2792 + tn->internal[x]);
2793 + tn->internal[x] = passed_tn;
2795 + } else if (!tn->internal[x]) {
2796 + /* Don't have one, none passed in */
2797 + tn->internal[x] = yaffs_get_tnode(dev);
2798 + if (!tn->internal[x])
2799 + return NULL;
2803 + tn = tn->internal[x];
2804 + l--;
2806 + } else {
2807 + /* top is level 0 */
2808 + if (passed_tn) {
2809 + memcpy(tn, passed_tn,
2810 + (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8);
2811 + yaffs_free_tnode(dev, passed_tn);
2815 + return tn;
2818 +static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id,
2819 + int chunk_obj)
2821 + return (tags->chunk_id == chunk_obj &&
2822 + tags->obj_id == obj_id &&
2823 + !tags->is_deleted) ? 1 : 0;
2827 +static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk,
2828 + struct yaffs_ext_tags *tags, int obj_id,
2829 + int inode_chunk)
2831 + int j;
2833 + for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) {
2834 + if (yaffs_check_chunk_bit
2835 + (dev, the_chunk / dev->param.chunks_per_block,
2836 + the_chunk % dev->param.chunks_per_block)) {
2838 + if (dev->chunk_grp_size == 1)
2839 + return the_chunk;
2840 + else {
2841 + yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
2842 + tags);
2843 + if (yaffs_tags_match(tags,
2844 + obj_id, inode_chunk)) {
2845 + /* found it; */
2846 + return the_chunk;
2850 + the_chunk++;
2852 + return -1;
2855 +int yaffs_find_chunk_in_file(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 + int ret_val = -1;
2863 + struct yaffs_dev *dev = in->my_dev;
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);
2879 + return ret_val;
2882 +static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk,
2883 + struct yaffs_ext_tags *tags)
2885 + /* Get the Tnode, then get the level 0 offset chunk offset */
2886 + struct yaffs_tnode *tn;
2887 + int the_chunk = -1;
2888 + struct yaffs_ext_tags local_tags;
2889 + struct yaffs_dev *dev = in->my_dev;
2890 + int ret_val = -1;
2892 + if (!tags) {
2893 + /* Passed a NULL, so use our own tags space */
2894 + tags = &local_tags;
2897 + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk);
2899 + if (!tn)
2900 + return ret_val;
2902 + the_chunk = yaffs_get_group_base(dev, tn, inode_chunk);
2904 + ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id,
2905 + inode_chunk);
2907 + /* Delete the entry in the filestructure (if found) */
2908 + if (ret_val != -1)
2909 + yaffs_load_tnode_0(dev, tn, inode_chunk, 0);
2911 + return ret_val;
2914 +int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
2915 + int nand_chunk, int in_scan)
2917 + /* NB in_scan is zero unless scanning.
2918 + * For forward scanning, in_scan is > 0;
2919 + * for backward scanning in_scan is < 0
2921 + * nand_chunk = 0 is a dummy insert to make sure the tnodes are there.
2922 + */
2924 + struct yaffs_tnode *tn;
2925 + struct yaffs_dev *dev = in->my_dev;
2926 + int existing_cunk;
2927 + struct yaffs_ext_tags existing_tags;
2928 + struct yaffs_ext_tags new_tags;
2929 + unsigned existing_serial, new_serial;
2931 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) {
2932 + /* Just ignore an attempt at putting a chunk into a non-file
2933 + * during scanning.
2934 + * If it is not during Scanning then something went wrong!
2935 + */
2936 + if (!in_scan) {
2937 + yaffs_trace(YAFFS_TRACE_ERROR,
2938 + "yaffs tragedy:attempt to put data chunk into a non-file"
2939 + );
2940 + BUG();
2943 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
2944 + return YAFFS_OK;
2947 + tn = yaffs_add_find_tnode_0(dev,
2948 + &in->variant.file_variant,
2949 + inode_chunk, NULL);
2950 + if (!tn)
2951 + return YAFFS_FAIL;
2953 + if (!nand_chunk)
2954 + /* Dummy insert, bail now */
2955 + return YAFFS_OK;
2957 + existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk);
2959 + if (in_scan != 0) {
2960 + /* If we're scanning then we need to test for duplicates
2961 + * NB This does not need to be efficient since it should only
2962 + * happen when the power fails during a write, then only one
2963 + * chunk should ever be affected.
2965 + * Correction for YAFFS2: This could happen quite a lot and we
2966 + * need to think about efficiency! TODO
2967 + * Update: For backward scanning we don't need to re-read tags
2968 + * so this is quite cheap.
2969 + */
2971 + if (existing_cunk > 0) {
2972 + /* NB Right now existing chunk will not be real
2973 + * chunk_id if the chunk group size > 1
2974 + * thus we have to do a FindChunkInFile to get the
2975 + * real chunk id.
2977 + * We have a duplicate now we need to decide which
2978 + * one to use:
2980 + * Backwards scanning YAFFS2: The old one is what
2981 + * we use, dump the new one.
2982 + * YAFFS1: Get both sets of tags and compare serial
2983 + * numbers.
2984 + */
2986 + if (in_scan > 0) {
2987 + /* Only do this for forward scanning */
2988 + yaffs_rd_chunk_tags_nand(dev,
2989 + nand_chunk,
2990 + NULL, &new_tags);
2992 + /* Do a proper find */
2993 + existing_cunk =
2994 + yaffs_find_chunk_in_file(in, inode_chunk,
2995 + &existing_tags);
2998 + if (existing_cunk <= 0) {
2999 + /*Hoosterman - how did this happen? */
3001 + yaffs_trace(YAFFS_TRACE_ERROR,
3002 + "yaffs tragedy: existing chunk < 0 in scan"
3003 + );
3007 + /* NB The deleted flags should be false, otherwise
3008 + * the chunks will not be loaded during a scan
3009 + */
3011 + if (in_scan > 0) {
3012 + new_serial = new_tags.serial_number;
3013 + existing_serial = existing_tags.serial_number;
3016 + if ((in_scan > 0) &&
3017 + (existing_cunk <= 0 ||
3018 + ((existing_serial + 1) & 3) == new_serial)) {
3019 + /* Forward scanning.
3020 + * Use new
3021 + * Delete the old one and drop through to
3022 + * update the tnode
3023 + */
3024 + yaffs_chunk_del(dev, existing_cunk, 1,
3025 + __LINE__);
3026 + } else {
3027 + /* Backward scanning or we want to use the
3028 + * existing one
3029 + * Delete the new one and return early so that
3030 + * the tnode isn't changed
3031 + */
3032 + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__);
3033 + return YAFFS_OK;
3039 + if (existing_cunk == 0)
3040 + in->n_data_chunks++;
3042 + yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk);
3044 + return YAFFS_OK;
3047 +static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk)
3049 + struct yaffs_block_info *the_block;
3050 + unsigned block_no;
3052 + yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk);
3054 + block_no = chunk / dev->param.chunks_per_block;
3055 + the_block = yaffs_get_block_info(dev, block_no);
3056 + if (the_block) {
3057 + the_block->soft_del_pages++;
3058 + dev->n_free_chunks++;
3059 + yaffs2_update_oldest_dirty_seq(dev, block_no, the_block);
3063 +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all
3064 + * the chunks in the file.
3065 + * All soft deleting does is increment the block's softdelete count and pulls
3066 + * the chunk out of the tnode.
3067 + * Thus, essentially this is the same as DeleteWorker except that the chunks
3068 + * are soft deleted.
3069 + */
3071 +static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn,
3072 + u32 level, int chunk_offset)
3074 + int i;
3075 + int the_chunk;
3076 + int all_done = 1;
3077 + struct yaffs_dev *dev = in->my_dev;
3079 + if (!tn)
3080 + return 1;
3082 + if (level > 0) {
3083 + for (i = YAFFS_NTNODES_INTERNAL - 1;
3084 + all_done && i >= 0;
3085 + i--) {
3086 + if (tn->internal[i]) {
3087 + all_done =
3088 + yaffs_soft_del_worker(in,
3089 + tn->internal[i],
3090 + level - 1,
3091 + (chunk_offset <<
3092 + YAFFS_TNODES_INTERNAL_BITS)
3093 + + i);
3094 + if (all_done) {
3095 + yaffs_free_tnode(dev,
3096 + tn->internal[i]);
3097 + tn->internal[i] = NULL;
3098 + } else {
3099 + /* Can this happen? */
3103 + return (all_done) ? 1 : 0;
3106 + /* level 0 */
3107 + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
3108 + the_chunk = yaffs_get_group_base(dev, tn, i);
3109 + if (the_chunk) {
3110 + yaffs_soft_del_chunk(dev, the_chunk);
3111 + yaffs_load_tnode_0(dev, tn, i, 0);
3114 + return 1;
3117 +static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj)
3119 + struct yaffs_dev *dev = obj->my_dev;
3120 + struct yaffs_obj *parent;
3122 + yaffs_verify_obj_in_dir(obj);
3123 + parent = obj->parent;
3125 + yaffs_verify_dir(parent);
3127 + if (dev && dev->param.remove_obj_fn)
3128 + dev->param.remove_obj_fn(obj);
3130 + list_del_init(&obj->siblings);
3131 + obj->parent = NULL;
3133 + yaffs_verify_dir(parent);
3136 +void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj)
3138 + if (!directory) {
3139 + yaffs_trace(YAFFS_TRACE_ALWAYS,
3140 + "tragedy: Trying to add an object to a null pointer directory"
3141 + );
3142 + BUG();
3143 + return;
3145 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
3146 + yaffs_trace(YAFFS_TRACE_ALWAYS,
3147 + "tragedy: Trying to add an object to a non-directory"
3148 + );
3149 + BUG();
3152 + if (obj->siblings.prev == NULL) {
3153 + /* Not initialised */
3154 + BUG();
3157 + yaffs_verify_dir(directory);
3159 + yaffs_remove_obj_from_dir(obj);
3161 + /* Now add it */
3162 + list_add(&obj->siblings, &directory->variant.dir_variant.children);
3163 + obj->parent = directory;
3165 + if (directory == obj->my_dev->unlinked_dir
3166 + || directory == obj->my_dev->del_dir) {
3167 + obj->unlinked = 1;
3168 + obj->my_dev->n_unlinked_files++;
3169 + obj->rename_allowed = 0;
3172 + yaffs_verify_dir(directory);
3173 + yaffs_verify_obj_in_dir(obj);
3176 +static int yaffs_change_obj_name(struct yaffs_obj *obj,
3177 + struct yaffs_obj *new_dir,
3178 + const YCHAR *new_name, int force, int shadows)
3180 + int unlink_op;
3181 + int del_op;
3182 + struct yaffs_obj *existing_target;
3184 + if (new_dir == NULL)
3185 + new_dir = obj->parent; /* use the old directory */
3187 + if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
3188 + yaffs_trace(YAFFS_TRACE_ALWAYS,
3189 + "tragedy: yaffs_change_obj_name: new_dir is not a directory"
3190 + );
3191 + BUG();
3194 + unlink_op = (new_dir == obj->my_dev->unlinked_dir);
3195 + del_op = (new_dir == obj->my_dev->del_dir);
3197 + existing_target = yaffs_find_by_name(new_dir, new_name);
3199 + /* If the object is a file going into the unlinked directory,
3200 + * then it is OK to just stuff it in since duplicate names are OK.
3201 + * else only proceed if the new name does not exist and we're putting
3202 + * it into a directory.
3203 + */
3204 + if (!(unlink_op || del_op || force ||
3205 + shadows > 0 || !existing_target) ||
3206 + new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
3207 + return YAFFS_FAIL;
3209 + yaffs_set_obj_name(obj, new_name);
3210 + obj->dirty = 1;
3211 + yaffs_add_obj_to_dir(new_dir, obj);
3213 + if (unlink_op)
3214 + obj->unlinked = 1;
3216 + /* If it is a deletion then we mark it as a shrink for gc */
3217 + if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0)
3218 + return YAFFS_OK;
3220 + return YAFFS_FAIL;
3223 +/*------------------------ Short Operations Cache ------------------------------
3224 + * In many situations where there is no high level buffering a lot of
3225 + * reads might be short sequential reads, and a lot of writes may be short
3226 + * sequential writes. eg. scanning/writing a jpeg file.
3227 + * In these cases, a short read/write cache can provide a huge perfomance
3228 + * benefit with dumb-as-a-rock code.
3229 + * In Linux, the page cache provides read buffering and the short op cache
3230 + * provides write buffering.
3232 + * There are a small number (~10) of cache chunks per device so that we don't
3233 + * need a very intelligent search.
3234 + */
3236 +static int yaffs_obj_cache_dirty(struct yaffs_obj *obj)
3238 + struct yaffs_dev *dev = obj->my_dev;
3239 + int i;
3240 + struct yaffs_cache *cache;
3241 + int n_caches = obj->my_dev->param.n_caches;
3243 + for (i = 0; i < n_caches; i++) {
3244 + cache = &dev->cache[i];
3245 + if (cache->object == obj && cache->dirty)
3246 + return 1;
3249 + return 0;
3252 +static void yaffs_flush_single_cache(struct yaffs_cache *cache, int discard)
3255 + if (!cache || cache->locked)
3256 + return;
3258 + /* Write it out and free it up if need be.*/
3259 + if (cache->dirty) {
3260 + yaffs_wr_data_obj(cache->object,
3261 + cache->chunk_id,
3262 + cache->data,
3263 + cache->n_bytes,
3264 + 1);
3266 + cache->dirty = 0;
3269 + if (discard)
3270 + cache->object = NULL;
3273 +static void yaffs_flush_file_cache(struct yaffs_obj *obj, int discard)
3275 + struct yaffs_dev *dev = obj->my_dev;
3276 + int i;
3277 + struct yaffs_cache *cache;
3278 + int n_caches = obj->my_dev->param.n_caches;
3280 + if (n_caches < 1)
3281 + return;
3284 + /* Find the chunks for this object and flush them. */
3285 + for (i = 0; i < n_caches; i++) {
3286 + cache = &dev->cache[i];
3287 + if (cache->object == obj)
3288 + yaffs_flush_single_cache(cache, discard);
3294 +void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard)
3296 + struct yaffs_obj *obj;
3297 + int n_caches = dev->param.n_caches;
3298 + int i;
3300 + /* Find a dirty object in the cache and flush it...
3301 + * until there are no further dirty objects.
3302 + */
3303 + do {
3304 + obj = NULL;
3305 + for (i = 0; i < n_caches && !obj; i++) {
3306 + if (dev->cache[i].object && dev->cache[i].dirty)
3307 + obj = dev->cache[i].object;
3309 + if (obj)
3310 + yaffs_flush_file_cache(obj, discard);
3311 + } while (obj);
3315 +/* Grab us an unused cache chunk for use.
3316 + * First look for an empty one.
3317 + * Then look for the least recently used non-dirty one.
3318 + * Then look for the least recently used dirty one...., flush and look again.
3319 + */
3320 +static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev)
3322 + int i;
3324 + if (dev->param.n_caches > 0) {
3325 + for (i = 0; i < dev->param.n_caches; i++) {
3326 + if (!dev->cache[i].object)
3327 + return &dev->cache[i];
3331 + return NULL;
3334 +static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev)
3336 + struct yaffs_cache *cache;
3337 + int usage;
3338 + int i;
3340 + if (dev->param.n_caches < 1)
3341 + return NULL;
3343 + /* First look for an unused cache */
3345 + cache = yaffs_grab_chunk_worker(dev);
3347 + if (cache)
3348 + return cache;
3350 + /*
3351 + * Thery were all in use.
3352 + * Find the LRU cache and flush it if it is dirty.
3353 + */
3355 + usage = -1;
3356 + cache = NULL;
3358 + for (i = 0; i < dev->param.n_caches; i++) {
3359 + if (dev->cache[i].object &&
3360 + !dev->cache[i].locked &&
3361 + (dev->cache[i].last_use < usage || !cache)) {
3362 + usage = dev->cache[i].last_use;
3363 + cache = &dev->cache[i];
3367 +#if 1
3368 + yaffs_flush_single_cache(cache, 1);
3369 +#else
3370 + yaffs_flush_file_cache(cache->object, 1);
3371 + cache = yaffs_grab_chunk_worker(dev);
3372 +#endif
3374 + return cache;
3377 +/* Find a cached chunk */
3378 +static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj,
3379 + int chunk_id)
3381 + struct yaffs_dev *dev = obj->my_dev;
3382 + int i;
3384 + if (dev->param.n_caches < 1)
3385 + return NULL;
3387 + for (i = 0; i < dev->param.n_caches; i++) {
3388 + if (dev->cache[i].object == obj &&
3389 + dev->cache[i].chunk_id == chunk_id) {
3390 + dev->cache_hits++;
3392 + return &dev->cache[i];
3395 + return NULL;
3398 +/* Mark the chunk for the least recently used algorithym */
3399 +static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache,
3400 + int is_write)
3402 + int i;
3404 + if (dev->param.n_caches < 1)
3405 + return;
3407 + if (dev->cache_last_use < 0 ||
3408 + dev->cache_last_use > 100000000) {
3409 + /* Reset the cache usages */
3410 + for (i = 1; i < dev->param.n_caches; i++)
3411 + dev->cache[i].last_use = 0;
3413 + dev->cache_last_use = 0;
3415 + dev->cache_last_use++;
3416 + cache->last_use = dev->cache_last_use;
3418 + if (is_write)
3419 + cache->dirty = 1;
3422 +/* Invalidate a single cache page.
3423 + * Do this when a whole page gets written,
3424 + * ie the short cache for this page is no longer valid.
3425 + */
3426 +static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id)
3428 + struct yaffs_cache *cache;
3430 + if (object->my_dev->param.n_caches > 0) {
3431 + cache = yaffs_find_chunk_cache(object, chunk_id);
3433 + if (cache)
3434 + cache->object = NULL;
3438 +/* Invalidate all the cache pages associated with this object
3439 + * Do this whenever ther file is deleted or resized.
3440 + */
3441 +static void yaffs_invalidate_whole_cache(struct yaffs_obj *in)
3443 + int i;
3444 + struct yaffs_dev *dev = in->my_dev;
3446 + if (dev->param.n_caches > 0) {
3447 + /* Invalidate it. */
3448 + for (i = 0; i < dev->param.n_caches; i++) {
3449 + if (dev->cache[i].object == in)
3450 + dev->cache[i].object = NULL;
3455 +static void yaffs_unhash_obj(struct yaffs_obj *obj)
3457 + int bucket;
3458 + struct yaffs_dev *dev = obj->my_dev;
3460 + /* If it is still linked into the bucket list, free from the list */
3461 + if (!list_empty(&obj->hash_link)) {
3462 + list_del_init(&obj->hash_link);
3463 + bucket = yaffs_hash_fn(obj->obj_id);
3464 + dev->obj_bucket[bucket].count--;
3468 +/* FreeObject frees up a Object and puts it back on the free list */
3469 +static void yaffs_free_obj(struct yaffs_obj *obj)
3471 + struct yaffs_dev *dev;
3473 + if (!obj) {
3474 + BUG();
3475 + return;
3477 + dev = obj->my_dev;
3478 + yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p",
3479 + obj, obj->my_inode);
3480 + if (obj->parent)
3481 + BUG();
3482 + if (!list_empty(&obj->siblings))
3483 + BUG();
3485 + if (obj->my_inode) {
3486 + /* We're still hooked up to a cached inode.
3487 + * Don't delete now, but mark for later deletion
3488 + */
3489 + obj->defered_free = 1;
3490 + return;
3493 + yaffs_unhash_obj(obj);
3495 + yaffs_free_raw_obj(dev, obj);
3496 + dev->n_obj--;
3497 + dev->checkpoint_blocks_required = 0; /* force recalculation */
3500 +void yaffs_handle_defered_free(struct yaffs_obj *obj)
3502 + if (obj->defered_free)
3503 + yaffs_free_obj(obj);
3506 +static int yaffs_generic_obj_del(struct yaffs_obj *in)
3508 + /* Iinvalidate the file's data in the cache, without flushing. */
3509 + yaffs_invalidate_whole_cache(in);
3511 + if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) {
3512 + /* Move to unlinked directory so we have a deletion record */
3513 + yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0,
3514 + 0);
3517 + yaffs_remove_obj_from_dir(in);
3518 + yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__);
3519 + in->hdr_chunk = 0;
3521 + yaffs_free_obj(in);
3522 + return YAFFS_OK;
3526 +static void yaffs_soft_del_file(struct yaffs_obj *obj)
3528 + if (!obj->deleted ||
3529 + obj->variant_type != YAFFS_OBJECT_TYPE_FILE ||
3530 + obj->soft_del)
3531 + return;
3533 + if (obj->n_data_chunks <= 0) {
3534 + /* Empty file with no duplicate object headers,
3535 + * just delete it immediately */
3536 + yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
3537 + obj->variant.file_variant.top = NULL;
3538 + yaffs_trace(YAFFS_TRACE_TRACING,
3539 + "yaffs: Deleting empty file %d",
3540 + obj->obj_id);
3541 + yaffs_generic_obj_del(obj);
3542 + } else {
3543 + yaffs_soft_del_worker(obj,
3544 + obj->variant.file_variant.top,
3545 + obj->variant.
3546 + file_variant.top_level, 0);
3547 + obj->soft_del = 1;
3551 +/* Pruning removes any part of the file structure tree that is beyond the
3552 + * bounds of the file (ie that does not point to chunks).
3554 + * A file should only get pruned when its size is reduced.
3556 + * Before pruning, the chunks must be pulled from the tree and the
3557 + * level 0 tnode entries must be zeroed out.
3558 + * Could also use this for file deletion, but that's probably better handled
3559 + * by a special case.
3561 + * This function is recursive. For levels > 0 the function is called again on
3562 + * any sub-tree. For level == 0 we just check if the sub-tree has data.
3563 + * If there is no data in a subtree then it is pruned.
3564 + */
3566 +static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev,
3567 + struct yaffs_tnode *tn, u32 level,
3568 + int del0)
3570 + int i;
3571 + int has_data;
3573 + if (!tn)
3574 + return tn;
3576 + has_data = 0;
3578 + if (level > 0) {
3579 + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
3580 + if (tn->internal[i]) {
3581 + tn->internal[i] =
3582 + yaffs_prune_worker(dev,
3583 + tn->internal[i],
3584 + level - 1,
3585 + (i == 0) ? del0 : 1);
3588 + if (tn->internal[i])
3589 + has_data++;
3591 + } else {
3592 + int tnode_size_u32 = dev->tnode_size / sizeof(u32);
3593 + u32 *map = (u32 *) tn;
3595 + for (i = 0; !has_data && i < tnode_size_u32; i++) {
3596 + if (map[i])
3597 + has_data++;
3601 + if (has_data == 0 && del0) {
3602 + /* Free and return NULL */
3603 + yaffs_free_tnode(dev, tn);
3604 + tn = NULL;
3606 + return tn;
3609 +static int yaffs_prune_tree(struct yaffs_dev *dev,
3610 + struct yaffs_file_var *file_struct)
3612 + int i;
3613 + int has_data;
3614 + int done = 0;
3615 + struct yaffs_tnode *tn;
3617 + if (file_struct->top_level < 1)
3618 + return YAFFS_OK;
3620 + file_struct->top =
3621 + yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0);
3623 + /* Now we have a tree with all the non-zero branches NULL but
3624 + * the height is the same as it was.
3625 + * Let's see if we can trim internal tnodes to shorten the tree.
3626 + * We can do this if only the 0th element in the tnode is in use
3627 + * (ie all the non-zero are NULL)
3628 + */
3630 + while (file_struct->top_level && !done) {
3631 + tn = file_struct->top;
3633 + has_data = 0;
3634 + for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
3635 + if (tn->internal[i])
3636 + has_data++;
3639 + if (!has_data) {
3640 + file_struct->top = tn->internal[0];
3641 + file_struct->top_level--;
3642 + yaffs_free_tnode(dev, tn);
3643 + } else {
3644 + done = 1;
3648 + return YAFFS_OK;
3651 +/*-------------------- End of File Structure functions.-------------------*/
3653 +/* alloc_empty_obj gets us a clean Object.*/
3654 +static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev)
3656 + struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev);
3658 + if (!obj)
3659 + return obj;
3661 + dev->n_obj++;
3663 + /* Now sweeten it up... */
3665 + memset(obj, 0, sizeof(struct yaffs_obj));
3666 + obj->being_created = 1;
3668 + obj->my_dev = dev;
3669 + obj->hdr_chunk = 0;
3670 + obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN;
3671 + INIT_LIST_HEAD(&(obj->hard_links));
3672 + INIT_LIST_HEAD(&(obj->hash_link));
3673 + INIT_LIST_HEAD(&obj->siblings);
3675 + /* Now make the directory sane */
3676 + if (dev->root_dir) {
3677 + obj->parent = dev->root_dir;
3678 + list_add(&(obj->siblings),
3679 + &dev->root_dir->variant.dir_variant.children);
3682 + /* Add it to the lost and found directory.
3683 + * NB Can't put root or lost-n-found in lost-n-found so
3684 + * check if lost-n-found exists first
3685 + */
3686 + if (dev->lost_n_found)
3687 + yaffs_add_obj_to_dir(dev->lost_n_found, obj);
3689 + obj->being_created = 0;
3691 + dev->checkpoint_blocks_required = 0; /* force recalculation */
3693 + return obj;
3696 +static int yaffs_find_nice_bucket(struct yaffs_dev *dev)
3698 + int i;
3699 + int l = 999;
3700 + int lowest = 999999;
3702 + /* Search for the shortest list or one that
3703 + * isn't too long.
3704 + */
3706 + for (i = 0; i < 10 && lowest > 4; i++) {
3707 + dev->bucket_finder++;
3708 + dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS;
3709 + if (dev->obj_bucket[dev->bucket_finder].count < lowest) {
3710 + lowest = dev->obj_bucket[dev->bucket_finder].count;
3711 + l = dev->bucket_finder;
3715 + return l;
3718 +static int yaffs_new_obj_id(struct yaffs_dev *dev)
3720 + int bucket = yaffs_find_nice_bucket(dev);
3721 + int found = 0;
3722 + struct list_head *i;
3723 + u32 n = (u32) bucket;
3725 + /*
3726 + * Now find an object value that has not already been taken
3727 + * by scanning the list, incrementing each time by number of buckets.
3728 + */
3729 + while (!found) {
3730 + found = 1;
3731 + n += YAFFS_NOBJECT_BUCKETS;
3732 + list_for_each(i, &dev->obj_bucket[bucket].list) {
3733 + /* Check if this value is already taken. */
3734 + if (i && list_entry(i, struct yaffs_obj,
3735 + hash_link)->obj_id == n)
3736 + found = 0;
3739 + return n;
3742 +static void yaffs_hash_obj(struct yaffs_obj *in)
3744 + int bucket = yaffs_hash_fn(in->obj_id);
3745 + struct yaffs_dev *dev = in->my_dev;
3747 + list_add(&in->hash_link, &dev->obj_bucket[bucket].list);
3748 + dev->obj_bucket[bucket].count++;
3751 +struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number)
3753 + int bucket = yaffs_hash_fn(number);
3754 + struct list_head *i;
3755 + struct yaffs_obj *in;
3757 + list_for_each(i, &dev->obj_bucket[bucket].list) {
3758 + /* Look if it is in the list */
3759 + in = list_entry(i, struct yaffs_obj, hash_link);
3760 + if (in->obj_id == number) {
3761 + /* Don't show if it is defered free */
3762 + if (in->defered_free)
3763 + return NULL;
3764 + return in;
3768 + return NULL;
3771 +static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number,
3772 + enum yaffs_obj_type type)
3774 + struct yaffs_obj *the_obj = NULL;
3775 + struct yaffs_tnode *tn = NULL;
3777 + if (number < 0)
3778 + number = yaffs_new_obj_id(dev);
3780 + if (type == YAFFS_OBJECT_TYPE_FILE) {
3781 + tn = yaffs_get_tnode(dev);
3782 + if (!tn)
3783 + return NULL;
3786 + the_obj = yaffs_alloc_empty_obj(dev);
3787 + if (!the_obj) {
3788 + if (tn)
3789 + yaffs_free_tnode(dev, tn);
3790 + return NULL;
3793 + the_obj->fake = 0;
3794 + the_obj->rename_allowed = 1;
3795 + the_obj->unlink_allowed = 1;
3796 + the_obj->obj_id = number;
3797 + yaffs_hash_obj(the_obj);
3798 + the_obj->variant_type = type;
3799 + yaffs_load_current_time(the_obj, 1, 1);
3801 + switch (type) {
3802 + case YAFFS_OBJECT_TYPE_FILE:
3803 + the_obj->variant.file_variant.file_size = 0;
3804 + the_obj->variant.file_variant.scanned_size = 0;
3805 + the_obj->variant.file_variant.shrink_size =
3806 + yaffs_max_file_size(dev);
3807 + the_obj->variant.file_variant.top_level = 0;
3808 + the_obj->variant.file_variant.top = tn;
3809 + break;
3810 + case YAFFS_OBJECT_TYPE_DIRECTORY:
3811 + INIT_LIST_HEAD(&the_obj->variant.dir_variant.children);
3812 + INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty);
3813 + break;
3814 + case YAFFS_OBJECT_TYPE_SYMLINK:
3815 + case YAFFS_OBJECT_TYPE_HARDLINK:
3816 + case YAFFS_OBJECT_TYPE_SPECIAL:
3817 + /* No action required */
3818 + break;
3819 + case YAFFS_OBJECT_TYPE_UNKNOWN:
3820 + /* todo this should not happen */
3821 + break;
3823 + return the_obj;
3826 +static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev,
3827 + int number, u32 mode)
3830 + struct yaffs_obj *obj =
3831 + yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
3833 + if (!obj)
3834 + return NULL;
3836 + obj->fake = 1; /* it is fake so it might not use NAND */
3837 + obj->rename_allowed = 0;
3838 + obj->unlink_allowed = 0;
3839 + obj->deleted = 0;
3840 + obj->unlinked = 0;
3841 + obj->yst_mode = mode;
3842 + obj->my_dev = dev;
3843 + obj->hdr_chunk = 0; /* Not a valid chunk. */
3844 + return obj;
3849 +static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev)
3851 + int i;
3853 + dev->n_obj = 0;
3854 + dev->n_tnodes = 0;
3855 + yaffs_init_raw_tnodes_and_objs(dev);
3857 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
3858 + INIT_LIST_HEAD(&dev->obj_bucket[i].list);
3859 + dev->obj_bucket[i].count = 0;
3863 +struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
3864 + int number,
3865 + enum yaffs_obj_type type)
3867 + struct yaffs_obj *the_obj = NULL;
3869 + if (number > 0)
3870 + the_obj = yaffs_find_by_number(dev, number);
3872 + if (!the_obj)
3873 + the_obj = yaffs_new_obj(dev, number, type);
3875 + return the_obj;
3879 +YCHAR *yaffs_clone_str(const YCHAR *str)
3881 + YCHAR *new_str = NULL;
3882 + int len;
3884 + if (!str)
3885 + str = _Y("");
3887 + len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH);
3888 + new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS);
3889 + if (new_str) {
3890 + strncpy(new_str, str, len);
3891 + new_str[len] = 0;
3893 + return new_str;
3897 + *yaffs_update_parent() handles fixing a directories mtime and ctime when a new
3898 + * link (ie. name) is created or deleted in the directory.
3900 + * ie.
3901 + * create dir/a : update dir's mtime/ctime
3902 + * rm dir/a: update dir's mtime/ctime
3903 + * modify dir/a: don't update dir's mtimme/ctime
3905 + * This can be handled immediately or defered. Defering helps reduce the number
3906 + * of updates when many files in a directory are changed within a brief period.
3908 + * If the directory updating is defered then yaffs_update_dirty_dirs must be
3909 + * called periodically.
3910 + */
3912 +static void yaffs_update_parent(struct yaffs_obj *obj)
3914 + struct yaffs_dev *dev;
3916 + if (!obj)
3917 + return;
3918 + dev = obj->my_dev;
3919 + obj->dirty = 1;
3920 + yaffs_load_current_time(obj, 0, 1);
3921 + if (dev->param.defered_dir_update) {
3922 + struct list_head *link = &obj->variant.dir_variant.dirty;
3924 + if (list_empty(link)) {
3925 + list_add(link, &dev->dirty_dirs);
3926 + yaffs_trace(YAFFS_TRACE_BACKGROUND,
3927 + "Added object %d to dirty directories",
3928 + obj->obj_id);
3931 + } else {
3932 + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
3936 +void yaffs_update_dirty_dirs(struct yaffs_dev *dev)
3938 + struct list_head *link;
3939 + struct yaffs_obj *obj;
3940 + struct yaffs_dir_var *d_s;
3941 + union yaffs_obj_var *o_v;
3943 + yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories");
3945 + while (!list_empty(&dev->dirty_dirs)) {
3946 + link = dev->dirty_dirs.next;
3947 + list_del_init(link);
3949 + d_s = list_entry(link, struct yaffs_dir_var, dirty);
3950 + o_v = list_entry(d_s, union yaffs_obj_var, dir_variant);
3951 + obj = list_entry(o_v, struct yaffs_obj, variant);
3953 + yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d",
3954 + obj->obj_id);
3956 + if (obj->dirty)
3957 + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL);
3962 + * Mknod (create) a new object.
3963 + * equiv_obj only has meaning for a hard link;
3964 + * alias_str only has meaning for a symlink.
3965 + * rdev only has meaning for devices (a subset of special objects)
3966 + */
3968 +static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type,
3969 + struct yaffs_obj *parent,
3970 + const YCHAR *name,
3971 + u32 mode,
3972 + u32 uid,
3973 + u32 gid,
3974 + struct yaffs_obj *equiv_obj,
3975 + const YCHAR *alias_str, u32 rdev)
3977 + struct yaffs_obj *in;
3978 + YCHAR *str = NULL;
3979 + struct yaffs_dev *dev = parent->my_dev;
3981 + /* Check if the entry exists.
3982 + * If it does then fail the call since we don't want a dup. */
3983 + if (yaffs_find_by_name(parent, name))
3984 + return NULL;
3986 + if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
3987 + str = yaffs_clone_str(alias_str);
3988 + if (!str)
3989 + return NULL;
3992 + in = yaffs_new_obj(dev, -1, type);
3994 + if (!in) {
3995 + kfree(str);
3996 + return NULL;
3999 + in->hdr_chunk = 0;
4000 + in->valid = 1;
4001 + in->variant_type = type;
4003 + in->yst_mode = mode;
4005 + yaffs_attribs_init(in, gid, uid, rdev);
4007 + in->n_data_chunks = 0;
4009 + yaffs_set_obj_name(in, name);
4010 + in->dirty = 1;
4012 + yaffs_add_obj_to_dir(parent, in);
4014 + in->my_dev = parent->my_dev;
4016 + switch (type) {
4017 + case YAFFS_OBJECT_TYPE_SYMLINK:
4018 + in->variant.symlink_variant.alias = str;
4019 + break;
4020 + case YAFFS_OBJECT_TYPE_HARDLINK:
4021 + in->variant.hardlink_variant.equiv_obj = equiv_obj;
4022 + in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id;
4023 + list_add(&in->hard_links, &equiv_obj->hard_links);
4024 + break;
4025 + case YAFFS_OBJECT_TYPE_FILE:
4026 + case YAFFS_OBJECT_TYPE_DIRECTORY:
4027 + case YAFFS_OBJECT_TYPE_SPECIAL:
4028 + case YAFFS_OBJECT_TYPE_UNKNOWN:
4029 + /* do nothing */
4030 + break;
4033 + if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) {
4034 + /* Could not create the object header, fail */
4035 + yaffs_del_obj(in);
4036 + in = NULL;
4039 + if (in)
4040 + yaffs_update_parent(parent);
4042 + return in;
4045 +struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
4046 + const YCHAR *name, u32 mode, u32 uid,
4047 + u32 gid)
4049 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
4050 + uid, gid, NULL, NULL, 0);
4053 +struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
4054 + u32 mode, u32 uid, u32 gid)
4056 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
4057 + mode, uid, gid, NULL, NULL, 0);
4060 +struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
4061 + const YCHAR *name, u32 mode, u32 uid,
4062 + u32 gid, u32 rdev)
4064 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
4065 + uid, gid, NULL, NULL, rdev);
4068 +struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
4069 + const YCHAR *name, u32 mode, u32 uid,
4070 + u32 gid, const YCHAR *alias)
4072 + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
4073 + uid, gid, NULL, alias, 0);
4076 +/* yaffs_link_obj returns the object id of the equivalent object.*/
4077 +struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name,
4078 + struct yaffs_obj *equiv_obj)
4080 + /* Get the real object in case we were fed a hard link obj */
4081 + equiv_obj = yaffs_get_equivalent_obj(equiv_obj);
4083 + if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK,
4084 + parent, name, 0, 0, 0,
4085 + equiv_obj, NULL, 0))
4086 + return equiv_obj;
4088 + return NULL;
4094 +/*---------------------- Block Management and Page Allocation -------------*/
4096 +static void yaffs_deinit_blocks(struct yaffs_dev *dev)
4098 + if (dev->block_info_alt && dev->block_info)
4099 + vfree(dev->block_info);
4100 + else
4101 + kfree(dev->block_info);
4103 + dev->block_info_alt = 0;
4105 + dev->block_info = NULL;
4107 + if (dev->chunk_bits_alt && dev->chunk_bits)
4108 + vfree(dev->chunk_bits);
4109 + else
4110 + kfree(dev->chunk_bits);
4111 + dev->chunk_bits_alt = 0;
4112 + dev->chunk_bits = NULL;
4115 +static int yaffs_init_blocks(struct yaffs_dev *dev)
4117 + int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
4119 + dev->block_info = NULL;
4120 + dev->chunk_bits = NULL;
4121 + dev->alloc_block = -1; /* force it to get a new one */
4123 + /* If the first allocation strategy fails, thry the alternate one */
4124 + dev->block_info =
4125 + kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS);
4126 + if (!dev->block_info) {
4127 + dev->block_info =
4128 + vmalloc(n_blocks * sizeof(struct yaffs_block_info));
4129 + dev->block_info_alt = 1;
4130 + } else {
4131 + dev->block_info_alt = 0;
4134 + if (!dev->block_info)
4135 + goto alloc_error;
4137 + /* Set up dynamic blockinfo stuff. Round up bytes. */
4138 + dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8;
4139 + dev->chunk_bits =
4140 + kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS);
4141 + if (!dev->chunk_bits) {
4142 + dev->chunk_bits =
4143 + vmalloc(dev->chunk_bit_stride * n_blocks);
4144 + dev->chunk_bits_alt = 1;
4145 + } else {
4146 + dev->chunk_bits_alt = 0;
4148 + if (!dev->chunk_bits)
4149 + goto alloc_error;
4152 + memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info));
4153 + memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks);
4154 + return YAFFS_OK;
4156 +alloc_error:
4157 + yaffs_deinit_blocks(dev);
4158 + return YAFFS_FAIL;
4162 +void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no)
4164 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no);
4165 + int erased_ok = 0;
4166 + int i;
4168 + /* If the block is still healthy erase it and mark as clean.
4169 + * If the block has had a data failure, then retire it.
4170 + */
4172 + yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
4173 + "yaffs_block_became_dirty block %d state %d %s",
4174 + block_no, bi->block_state,
4175 + (bi->needs_retiring) ? "needs retiring" : "");
4177 + yaffs2_clear_oldest_dirty_seq(dev, bi);
4179 + bi->block_state = YAFFS_BLOCK_STATE_DIRTY;
4181 + /* If this is the block being garbage collected then stop gc'ing */
4182 + if (block_no == dev->gc_block)
4183 + dev->gc_block = 0;
4185 + /* If this block is currently the best candidate for gc
4186 + * then drop as a candidate */
4187 + if (block_no == dev->gc_dirtiest) {
4188 + dev->gc_dirtiest = 0;
4189 + dev->gc_pages_in_use = 0;
4192 + if (!bi->needs_retiring) {
4193 + yaffs2_checkpt_invalidate(dev);
4194 + erased_ok = yaffs_erase_block(dev, block_no);
4195 + if (!erased_ok) {
4196 + dev->n_erase_failures++;
4197 + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
4198 + "**>> Erasure failed %d", block_no);
4202 + /* Verify erasure if needed */
4203 + if (erased_ok &&
4204 + ((yaffs_trace_mask & YAFFS_TRACE_ERASE) ||
4205 + !yaffs_skip_verification(dev))) {
4206 + for (i = 0; i < dev->param.chunks_per_block; i++) {
4207 + if (!yaffs_check_chunk_erased(dev,
4208 + block_no * dev->param.chunks_per_block + i)) {
4209 + yaffs_trace(YAFFS_TRACE_ERROR,
4210 + ">>Block %d erasure supposedly OK, but chunk %d not erased",
4211 + block_no, i);
4216 + if (!erased_ok) {
4217 + /* We lost a block of free space */
4218 + dev->n_free_chunks -= dev->param.chunks_per_block;
4219 + yaffs_retire_block(dev, block_no);
4220 + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
4221 + "**>> Block %d retired", block_no);
4222 + return;
4225 + /* Clean it up... */
4226 + bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
4227 + bi->seq_number = 0;
4228 + dev->n_erased_blocks++;
4229 + bi->pages_in_use = 0;
4230 + bi->soft_del_pages = 0;
4231 + bi->has_shrink_hdr = 0;
4232 + bi->skip_erased_check = 1; /* Clean, so no need to check */
4233 + bi->gc_prioritise = 0;
4234 + bi->has_summary = 0;
4236 + yaffs_clear_chunk_bits(dev, block_no);
4238 + yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no);
4241 +static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev,
4242 + struct yaffs_block_info *bi,
4243 + int old_chunk, u8 *buffer)
4245 + int new_chunk;
4246 + int mark_flash = 1;
4247 + struct yaffs_ext_tags tags;
4248 + struct yaffs_obj *object;
4249 + int matching_chunk;
4250 + int ret_val = YAFFS_OK;
4252 + memset(&tags, 0, sizeof(tags));
4253 + yaffs_rd_chunk_tags_nand(dev, old_chunk,
4254 + buffer, &tags);
4255 + object = yaffs_find_by_number(dev, tags.obj_id);
4257 + yaffs_trace(YAFFS_TRACE_GC_DETAIL,
4258 + "Collecting chunk in block %d, %d %d %d ",
4259 + dev->gc_chunk, tags.obj_id,
4260 + tags.chunk_id, tags.n_bytes);
4262 + if (object && !yaffs_skip_verification(dev)) {
4263 + if (tags.chunk_id == 0)
4264 + matching_chunk =
4265 + object->hdr_chunk;
4266 + else if (object->soft_del)
4267 + /* Defeat the test */
4268 + matching_chunk = old_chunk;
4269 + else
4270 + matching_chunk =
4271 + yaffs_find_chunk_in_file
4272 + (object, tags.chunk_id,
4273 + NULL);
4275 + if (old_chunk != matching_chunk)
4276 + yaffs_trace(YAFFS_TRACE_ERROR,
4277 + "gc: page in gc mismatch: %d %d %d %d",
4278 + old_chunk,
4279 + matching_chunk,
4280 + tags.obj_id,
4281 + tags.chunk_id);
4284 + if (!object) {
4285 + yaffs_trace(YAFFS_TRACE_ERROR,
4286 + "page %d in gc has no object: %d %d %d ",
4287 + old_chunk,
4288 + tags.obj_id, tags.chunk_id,
4289 + tags.n_bytes);
4292 + if (object &&
4293 + object->deleted &&
4294 + object->soft_del && tags.chunk_id != 0) {
4295 + /* Data chunk in a soft deleted file,
4296 + * throw it away.
4297 + * It's a soft deleted data chunk,
4298 + * No need to copy this, just forget
4299 + * about it and fix up the object.
4300 + */
4302 + /* Free chunks already includes
4303 + * softdeleted chunks, how ever this
4304 + * chunk is going to soon be really
4305 + * deleted which will increment free
4306 + * chunks. We have to decrement free
4307 + * chunks so this works out properly.
4308 + */
4309 + dev->n_free_chunks--;
4310 + bi->soft_del_pages--;
4312 + object->n_data_chunks--;
4313 + if (object->n_data_chunks <= 0) {
4314 + /* remeber to clean up obj */
4315 + dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id;
4316 + dev->n_clean_ups++;
4318 + mark_flash = 0;
4319 + } else if (object) {
4320 + /* It's either a data chunk in a live
4321 + * file or an ObjectHeader, so we're
4322 + * interested in it.
4323 + * NB Need to keep the ObjectHeaders of
4324 + * deleted files until the whole file
4325 + * has been deleted off
4326 + */
4327 + tags.serial_number++;
4328 + dev->n_gc_copies++;
4330 + if (tags.chunk_id == 0) {
4331 + /* It is an object Id,
4332 + * We need to nuke the
4333 + * shrinkheader flags since its
4334 + * work is done.
4335 + * Also need to clean up
4336 + * shadowing.
4337 + */
4338 + struct yaffs_obj_hdr *oh;
4339 + oh = (struct yaffs_obj_hdr *) buffer;
4341 + oh->is_shrink = 0;
4342 + tags.extra_is_shrink = 0;
4343 + oh->shadows_obj = 0;
4344 + oh->inband_shadowed_obj_id = 0;
4345 + tags.extra_shadows = 0;
4347 + /* Update file size */
4348 + if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) {
4349 + yaffs_oh_size_load(oh,
4350 + object->variant.file_variant.file_size);
4351 + tags.extra_file_size =
4352 + object->variant.file_variant.file_size;
4355 + yaffs_verify_oh(object, oh, &tags, 1);
4356 + new_chunk =
4357 + yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1);
4358 + } else {
4359 + new_chunk =
4360 + yaffs_write_new_chunk(dev, buffer, &tags, 1);
4363 + if (new_chunk < 0) {
4364 + ret_val = YAFFS_FAIL;
4365 + } else {
4367 + /* Now fix up the Tnodes etc. */
4369 + if (tags.chunk_id == 0) {
4370 + /* It's a header */
4371 + object->hdr_chunk = new_chunk;
4372 + object->serial = tags.serial_number;
4373 + } else {
4374 + /* It's a data chunk */
4375 + yaffs_put_chunk_in_file(object, tags.chunk_id,
4376 + new_chunk, 0);
4380 + if (ret_val == YAFFS_OK)
4381 + yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__);
4382 + return ret_val;
4385 +static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block)
4387 + int old_chunk;
4388 + int ret_val = YAFFS_OK;
4389 + int i;
4390 + int is_checkpt_block;
4391 + int max_copies;
4392 + int chunks_before = yaffs_get_erased_chunks(dev);
4393 + int chunks_after;
4394 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, block);
4396 + is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT);
4398 + yaffs_trace(YAFFS_TRACE_TRACING,
4399 + "Collecting block %d, in use %d, shrink %d, whole_block %d",
4400 + block, bi->pages_in_use, bi->has_shrink_hdr,
4401 + whole_block);
4403 + /*yaffs_verify_free_chunks(dev); */
4405 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL)
4406 + bi->block_state = YAFFS_BLOCK_STATE_COLLECTING;
4408 + bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */
4410 + dev->gc_disable = 1;
4412 + yaffs_summary_gc(dev, block);
4414 + if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) {
4415 + yaffs_trace(YAFFS_TRACE_TRACING,
4416 + "Collecting block %d that has no chunks in use",
4417 + block);
4418 + yaffs_block_became_dirty(dev, block);
4419 + } else {
4421 + u8 *buffer = yaffs_get_temp_buffer(dev);
4423 + yaffs_verify_blk(dev, bi, block);
4425 + max_copies = (whole_block) ? dev->param.chunks_per_block : 5;
4426 + old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk;
4428 + for (/* init already done */ ;
4429 + ret_val == YAFFS_OK &&
4430 + dev->gc_chunk < dev->param.chunks_per_block &&
4431 + (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) &&
4432 + max_copies > 0;
4433 + dev->gc_chunk++, old_chunk++) {
4434 + if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) {
4435 + /* Page is in use and might need to be copied */
4436 + max_copies--;
4437 + ret_val = yaffs_gc_process_chunk(dev, bi,
4438 + old_chunk, buffer);
4441 + yaffs_release_temp_buffer(dev, buffer);
4444 + yaffs_verify_collected_blk(dev, bi, block);
4446 + if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
4447 + /*
4448 + * The gc did not complete. Set block state back to FULL
4449 + * because checkpointing does not restore gc.
4450 + */
4451 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
4452 + } else {
4453 + /* The gc completed. */
4454 + /* Do any required cleanups */
4455 + for (i = 0; i < dev->n_clean_ups; i++) {
4456 + /* Time to delete the file too */
4457 + struct yaffs_obj *object =
4458 + yaffs_find_by_number(dev, dev->gc_cleanup_list[i]);
4459 + if (object) {
4460 + yaffs_free_tnode(dev,
4461 + object->variant.file_variant.top);
4462 + object->variant.file_variant.top = NULL;
4463 + yaffs_trace(YAFFS_TRACE_GC,
4464 + "yaffs: About to finally delete object %d",
4465 + object->obj_id);
4466 + yaffs_generic_obj_del(object);
4467 + object->my_dev->n_deleted_files--;
4471 + chunks_after = yaffs_get_erased_chunks(dev);
4472 + if (chunks_before >= chunks_after)
4473 + yaffs_trace(YAFFS_TRACE_GC,
4474 + "gc did not increase free chunks before %d after %d",
4475 + chunks_before, chunks_after);
4476 + dev->gc_block = 0;
4477 + dev->gc_chunk = 0;
4478 + dev->n_clean_ups = 0;
4481 + dev->gc_disable = 0;
4483 + return ret_val;
4487 + * find_gc_block() selects the dirtiest block (or close enough)
4488 + * for garbage collection.
4489 + */
4491 +static unsigned yaffs_find_gc_block(struct yaffs_dev *dev,
4492 + int aggressive, int background)
4494 + int i;
4495 + int iterations;
4496 + unsigned selected = 0;
4497 + int prioritised = 0;
4498 + int prioritised_exist = 0;
4499 + struct yaffs_block_info *bi;
4500 + int threshold;
4502 + /* First let's see if we need to grab a prioritised block */
4503 + if (dev->has_pending_prioritised_gc && !aggressive) {
4504 + dev->gc_dirtiest = 0;
4505 + bi = dev->block_info;
4506 + for (i = dev->internal_start_block;
4507 + i <= dev->internal_end_block && !selected; i++) {
4509 + if (bi->gc_prioritise) {
4510 + prioritised_exist = 1;
4511 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
4512 + yaffs_block_ok_for_gc(dev, bi)) {
4513 + selected = i;
4514 + prioritised = 1;
4517 + bi++;
4520 + /*
4521 + * If there is a prioritised block and none was selected then
4522 + * this happened because there is at least one old dirty block
4523 + * gumming up the works. Let's gc the oldest dirty block.
4524 + */
4526 + if (prioritised_exist &&
4527 + !selected && dev->oldest_dirty_block > 0)
4528 + selected = dev->oldest_dirty_block;
4530 + if (!prioritised_exist) /* None found, so we can clear this */
4531 + dev->has_pending_prioritised_gc = 0;
4534 + /* If we're doing aggressive GC then we are happy to take a less-dirty
4535 + * block, and search harder.
4536 + * else (leasurely gc), then we only bother to do this if the
4537 + * block has only a few pages in use.
4538 + */
4540 + if (!selected) {
4541 + int pages_used;
4542 + int n_blocks =
4543 + dev->internal_end_block - dev->internal_start_block + 1;
4544 + if (aggressive) {
4545 + threshold = dev->param.chunks_per_block;
4546 + iterations = n_blocks;
4547 + } else {
4548 + int max_threshold;
4550 + if (background)
4551 + max_threshold = dev->param.chunks_per_block / 2;
4552 + else
4553 + max_threshold = dev->param.chunks_per_block / 8;
4555 + if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD)
4556 + max_threshold = YAFFS_GC_PASSIVE_THRESHOLD;
4558 + threshold = background ? (dev->gc_not_done + 2) * 2 : 0;
4559 + if (threshold < YAFFS_GC_PASSIVE_THRESHOLD)
4560 + threshold = YAFFS_GC_PASSIVE_THRESHOLD;
4561 + if (threshold > max_threshold)
4562 + threshold = max_threshold;
4564 + iterations = n_blocks / 16 + 1;
4565 + if (iterations > 100)
4566 + iterations = 100;
4569 + for (i = 0;
4570 + i < iterations &&
4571 + (dev->gc_dirtiest < 1 ||
4572 + dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH);
4573 + i++) {
4574 + dev->gc_block_finder++;
4575 + if (dev->gc_block_finder < dev->internal_start_block ||
4576 + dev->gc_block_finder > dev->internal_end_block)
4577 + dev->gc_block_finder =
4578 + dev->internal_start_block;
4580 + bi = yaffs_get_block_info(dev, dev->gc_block_finder);
4582 + pages_used = bi->pages_in_use - bi->soft_del_pages;
4584 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL &&
4585 + pages_used < dev->param.chunks_per_block &&
4586 + (dev->gc_dirtiest < 1 ||
4587 + pages_used < dev->gc_pages_in_use) &&
4588 + yaffs_block_ok_for_gc(dev, bi)) {
4589 + dev->gc_dirtiest = dev->gc_block_finder;
4590 + dev->gc_pages_in_use = pages_used;
4594 + if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold)
4595 + selected = dev->gc_dirtiest;
4598 + /*
4599 + * If nothing has been selected for a while, try the oldest dirty
4600 + * because that's gumming up the works.
4601 + */
4603 + if (!selected && dev->param.is_yaffs2 &&
4604 + dev->gc_not_done >= (background ? 10 : 20)) {
4605 + yaffs2_find_oldest_dirty_seq(dev);
4606 + if (dev->oldest_dirty_block > 0) {
4607 + selected = dev->oldest_dirty_block;
4608 + dev->gc_dirtiest = selected;
4609 + dev->oldest_dirty_gc_count++;
4610 + bi = yaffs_get_block_info(dev, selected);
4611 + dev->gc_pages_in_use =
4612 + bi->pages_in_use - bi->soft_del_pages;
4613 + } else {
4614 + dev->gc_not_done = 0;
4618 + if (selected) {
4619 + yaffs_trace(YAFFS_TRACE_GC,
4620 + "GC Selected block %d with %d free, prioritised:%d",
4621 + selected,
4622 + dev->param.chunks_per_block - dev->gc_pages_in_use,
4623 + prioritised);
4625 + dev->n_gc_blocks++;
4626 + if (background)
4627 + dev->bg_gcs++;
4629 + dev->gc_dirtiest = 0;
4630 + dev->gc_pages_in_use = 0;
4631 + dev->gc_not_done = 0;
4632 + if (dev->refresh_skip > 0)
4633 + dev->refresh_skip--;
4634 + } else {
4635 + dev->gc_not_done++;
4636 + yaffs_trace(YAFFS_TRACE_GC,
4637 + "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s",
4638 + dev->gc_block_finder, dev->gc_not_done, threshold,
4639 + dev->gc_dirtiest, dev->gc_pages_in_use,
4640 + dev->oldest_dirty_block, background ? " bg" : "");
4643 + return selected;
4646 +/* New garbage collector
4647 + * If we're very low on erased blocks then we do aggressive garbage collection
4648 + * otherwise we do "leasurely" garbage collection.
4649 + * Aggressive gc looks further (whole array) and will accept less dirty blocks.
4650 + * Passive gc only inspects smaller areas and only accepts more dirty blocks.
4652 + * The idea is to help clear out space in a more spread-out manner.
4653 + * Dunno if it really does anything useful.
4654 + */
4655 +static int yaffs_check_gc(struct yaffs_dev *dev, int background)
4657 + int aggressive = 0;
4658 + int gc_ok = YAFFS_OK;
4659 + int max_tries = 0;
4660 + int min_erased;
4661 + int erased_chunks;
4662 + int checkpt_block_adjust;
4664 + if (dev->param.gc_control_fn &&
4665 + (dev->param.gc_control_fn(dev) & 1) == 0)
4666 + return YAFFS_OK;
4668 + if (dev->gc_disable)
4669 + /* Bail out so we don't get recursive gc */
4670 + return YAFFS_OK;
4672 + /* This loop should pass the first time.
4673 + * Only loops here if the collection does not increase space.
4674 + */
4676 + do {
4677 + max_tries++;
4679 + checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev);
4681 + min_erased =
4682 + dev->param.n_reserved_blocks + checkpt_block_adjust + 1;
4683 + erased_chunks =
4684 + dev->n_erased_blocks * dev->param.chunks_per_block;
4686 + /* If we need a block soon then do aggressive gc. */
4687 + if (dev->n_erased_blocks < min_erased)
4688 + aggressive = 1;
4689 + else {
4690 + if (!background
4691 + && erased_chunks > (dev->n_free_chunks / 4))
4692 + break;
4694 + if (dev->gc_skip > 20)
4695 + dev->gc_skip = 20;
4696 + if (erased_chunks < dev->n_free_chunks / 2 ||
4697 + dev->gc_skip < 1 || background)
4698 + aggressive = 0;
4699 + else {
4700 + dev->gc_skip--;
4701 + break;
4705 + dev->gc_skip = 5;
4707 + /* If we don't already have a block being gc'd then see if we
4708 + * should start another */
4710 + if (dev->gc_block < 1 && !aggressive) {
4711 + dev->gc_block = yaffs2_find_refresh_block(dev);
4712 + dev->gc_chunk = 0;
4713 + dev->n_clean_ups = 0;
4715 + if (dev->gc_block < 1) {
4716 + dev->gc_block =
4717 + yaffs_find_gc_block(dev, aggressive, background);
4718 + dev->gc_chunk = 0;
4719 + dev->n_clean_ups = 0;
4722 + if (dev->gc_block > 0) {
4723 + dev->all_gcs++;
4724 + if (!aggressive)
4725 + dev->passive_gc_count++;
4727 + yaffs_trace(YAFFS_TRACE_GC,
4728 + "yaffs: GC n_erased_blocks %d aggressive %d",
4729 + dev->n_erased_blocks, aggressive);
4731 + gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive);
4734 + if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) &&
4735 + dev->gc_block > 0) {
4736 + yaffs_trace(YAFFS_TRACE_GC,
4737 + "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d",
4738 + dev->n_erased_blocks, max_tries,
4739 + dev->gc_block);
4741 + } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) &&
4742 + (dev->gc_block > 0) && (max_tries < 2));
4744 + return aggressive ? gc_ok : YAFFS_OK;
4748 + * yaffs_bg_gc()
4749 + * Garbage collects. Intended to be called from a background thread.
4750 + * Returns non-zero if at least half the free chunks are erased.
4751 + */
4752 +int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency)
4754 + int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block;
4756 + yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency);
4758 + yaffs_check_gc(dev, 1);
4759 + return erased_chunks > dev->n_free_chunks / 2;
4762 +/*-------------------- Data file manipulation -----------------*/
4764 +static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer)
4766 + int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL);
4768 + if (nand_chunk >= 0)
4769 + return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk,
4770 + buffer, NULL);
4771 + else {
4772 + yaffs_trace(YAFFS_TRACE_NANDACCESS,
4773 + "Chunk %d not found zero instead",
4774 + nand_chunk);
4775 + /* get sane (zero) data if you read a hole */
4776 + memset(buffer, 0, in->my_dev->data_bytes_per_chunk);
4777 + return 0;
4782 +void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
4783 + int lyn)
4785 + int block;
4786 + int page;
4787 + struct yaffs_ext_tags tags;
4788 + struct yaffs_block_info *bi;
4790 + if (chunk_id <= 0)
4791 + return;
4793 + dev->n_deletions++;
4794 + block = chunk_id / dev->param.chunks_per_block;
4795 + page = chunk_id % dev->param.chunks_per_block;
4797 + if (!yaffs_check_chunk_bit(dev, block, page))
4798 + yaffs_trace(YAFFS_TRACE_VERIFY,
4799 + "Deleting invalid chunk %d", chunk_id);
4801 + bi = yaffs_get_block_info(dev, block);
4803 + yaffs2_update_oldest_dirty_seq(dev, block, bi);
4805 + yaffs_trace(YAFFS_TRACE_DELETION,
4806 + "line %d delete of chunk %d",
4807 + lyn, chunk_id);
4809 + if (!dev->param.is_yaffs2 && mark_flash &&
4810 + bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) {
4812 + memset(&tags, 0, sizeof(tags));
4813 + tags.is_deleted = 1;
4814 + yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags);
4815 + yaffs_handle_chunk_update(dev, chunk_id, &tags);
4816 + } else {
4817 + dev->n_unmarked_deletions++;
4820 + /* Pull out of the management area.
4821 + * If the whole block became dirty, this will kick off an erasure.
4822 + */
4823 + if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING ||
4824 + bi->block_state == YAFFS_BLOCK_STATE_FULL ||
4825 + bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
4826 + bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) {
4827 + dev->n_free_chunks++;
4828 + yaffs_clear_chunk_bit(dev, block, page);
4829 + bi->pages_in_use--;
4831 + if (bi->pages_in_use == 0 &&
4832 + !bi->has_shrink_hdr &&
4833 + bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING &&
4834 + bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) {
4835 + yaffs_block_became_dirty(dev, block);
4840 +static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk,
4841 + const u8 *buffer, int n_bytes, int use_reserve)
4843 + /* Find old chunk Need to do this to get serial number
4844 + * Write new one and patch into tree.
4845 + * Invalidate old tags.
4846 + */
4848 + int prev_chunk_id;
4849 + struct yaffs_ext_tags prev_tags;
4850 + int new_chunk_id;
4851 + struct yaffs_ext_tags new_tags;
4852 + struct yaffs_dev *dev = in->my_dev;
4854 + yaffs_check_gc(dev, 0);
4856 + /* Get the previous chunk at this location in the file if it exists.
4857 + * If it does not exist then put a zero into the tree. This creates
4858 + * the tnode now, rather than later when it is harder to clean up.
4859 + */
4860 + prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags);
4861 + if (prev_chunk_id < 1 &&
4862 + !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0))
4863 + return 0;
4865 + /* Set up new tags */
4866 + memset(&new_tags, 0, sizeof(new_tags));
4868 + new_tags.chunk_id = inode_chunk;
4869 + new_tags.obj_id = in->obj_id;
4870 + new_tags.serial_number =
4871 + (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1;
4872 + new_tags.n_bytes = n_bytes;
4874 + if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) {
4875 + yaffs_trace(YAFFS_TRACE_ERROR,
4876 + "Writing %d bytes to chunk!!!!!!!!!",
4877 + n_bytes);
4878 + BUG();
4881 + new_chunk_id =
4882 + yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve);
4884 + if (new_chunk_id > 0) {
4885 + yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0);
4887 + if (prev_chunk_id > 0)
4888 + yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
4890 + yaffs_verify_file_sane(in);
4892 + return new_chunk_id;
4898 +static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set,
4899 + const YCHAR *name, const void *value, int size,
4900 + int flags)
4902 + struct yaffs_xattr_mod xmod;
4903 + int result;
4905 + xmod.set = set;
4906 + xmod.name = name;
4907 + xmod.data = value;
4908 + xmod.size = size;
4909 + xmod.flags = flags;
4910 + xmod.result = -ENOSPC;
4912 + result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod);
4914 + if (result > 0)
4915 + return xmod.result;
4916 + else
4917 + return -ENOSPC;
4920 +static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer,
4921 + struct yaffs_xattr_mod *xmod)
4923 + int retval = 0;
4924 + int x_offs = sizeof(struct yaffs_obj_hdr);
4925 + struct yaffs_dev *dev = obj->my_dev;
4926 + int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
4927 + char *x_buffer = buffer + x_offs;
4929 + if (xmod->set)
4930 + retval =
4931 + nval_set(x_buffer, x_size, xmod->name, xmod->data,
4932 + xmod->size, xmod->flags);
4933 + else
4934 + retval = nval_del(x_buffer, x_size, xmod->name);
4936 + obj->has_xattr = nval_hasvalues(x_buffer, x_size);
4937 + obj->xattr_known = 1;
4938 + xmod->result = retval;
4940 + return retval;
4943 +static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name,
4944 + void *value, int size)
4946 + char *buffer = NULL;
4947 + int result;
4948 + struct yaffs_ext_tags tags;
4949 + struct yaffs_dev *dev = obj->my_dev;
4950 + int x_offs = sizeof(struct yaffs_obj_hdr);
4951 + int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr);
4952 + char *x_buffer;
4953 + int retval = 0;
4955 + if (obj->hdr_chunk < 1)
4956 + return -ENODATA;
4958 + /* If we know that the object has no xattribs then don't do all the
4959 + * reading and parsing.
4960 + */
4961 + if (obj->xattr_known && !obj->has_xattr) {
4962 + if (name)
4963 + return -ENODATA;
4964 + else
4965 + return 0;
4968 + buffer = (char *)yaffs_get_temp_buffer(dev);
4969 + if (!buffer)
4970 + return -ENOMEM;
4972 + result =
4973 + yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags);
4975 + if (result != YAFFS_OK)
4976 + retval = -ENOENT;
4977 + else {
4978 + x_buffer = buffer + x_offs;
4980 + if (!obj->xattr_known) {
4981 + obj->has_xattr = nval_hasvalues(x_buffer, x_size);
4982 + obj->xattr_known = 1;
4985 + if (name)
4986 + retval = nval_get(x_buffer, x_size, name, value, size);
4987 + else
4988 + retval = nval_list(x_buffer, x_size, value, size);
4990 + yaffs_release_temp_buffer(dev, (u8 *) buffer);
4991 + return retval;
4994 +int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name,
4995 + const void *value, int size, int flags)
4997 + return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags);
5000 +int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name)
5002 + return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0);
5005 +int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value,
5006 + int size)
5008 + return yaffs_do_xattrib_fetch(obj, name, value, size);
5011 +int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size)
5013 + return yaffs_do_xattrib_fetch(obj, NULL, buffer, size);
5016 +static void yaffs_check_obj_details_loaded(struct yaffs_obj *in)
5018 + u8 *buf;
5019 + struct yaffs_obj_hdr *oh;
5020 + struct yaffs_dev *dev;
5021 + struct yaffs_ext_tags tags;
5022 + int result;
5023 + int alloc_failed = 0;
5025 + if (!in || !in->lazy_loaded || in->hdr_chunk < 1)
5026 + return;
5028 + dev = in->my_dev;
5029 + in->lazy_loaded = 0;
5030 + buf = yaffs_get_temp_buffer(dev);
5032 + result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags);
5033 + oh = (struct yaffs_obj_hdr *)buf;
5035 + in->yst_mode = oh->yst_mode;
5036 + yaffs_load_attribs(in, oh);
5037 + yaffs_set_obj_name_from_oh(in, oh);
5039 + if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
5040 + in->variant.symlink_variant.alias =
5041 + yaffs_clone_str(oh->alias);
5042 + if (!in->variant.symlink_variant.alias)
5043 + alloc_failed = 1; /* Not returned */
5045 + yaffs_release_temp_buffer(dev, buf);
5048 +/* UpdateObjectHeader updates the header on NAND for an object.
5049 + * If name is not NULL, then that new name is used.
5050 + */
5051 +int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force,
5052 + int is_shrink, int shadows, struct yaffs_xattr_mod *xmod)
5055 + struct yaffs_block_info *bi;
5056 + struct yaffs_dev *dev = in->my_dev;
5057 + int prev_chunk_id;
5058 + int ret_val = 0;
5059 + int result = 0;
5060 + int new_chunk_id;
5061 + struct yaffs_ext_tags new_tags;
5062 + struct yaffs_ext_tags old_tags;
5063 + const YCHAR *alias = NULL;
5064 + u8 *buffer = NULL;
5065 + YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1];
5066 + struct yaffs_obj_hdr *oh = NULL;
5067 + loff_t file_size = 0;
5069 + strcpy(old_name, _Y("silly old name"));
5071 + if (in->fake && in != dev->root_dir && !force && !xmod)
5072 + return ret_val;
5074 + yaffs_check_gc(dev, 0);
5075 + yaffs_check_obj_details_loaded(in);
5077 + buffer = yaffs_get_temp_buffer(in->my_dev);
5078 + oh = (struct yaffs_obj_hdr *)buffer;
5080 + prev_chunk_id = in->hdr_chunk;
5082 + if (prev_chunk_id > 0) {
5083 + result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id,
5084 + buffer, &old_tags);
5086 + yaffs_verify_oh(in, oh, &old_tags, 0);
5087 + memcpy(old_name, oh->name, sizeof(oh->name));
5088 + memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr));
5089 + } else {
5090 + memset(buffer, 0xff, dev->data_bytes_per_chunk);
5093 + oh->type = in->variant_type;
5094 + oh->yst_mode = in->yst_mode;
5095 + oh->shadows_obj = oh->inband_shadowed_obj_id = shadows;
5097 + yaffs_load_attribs_oh(oh, in);
5099 + if (in->parent)
5100 + oh->parent_obj_id = in->parent->obj_id;
5101 + else
5102 + oh->parent_obj_id = 0;
5104 + if (name && *name) {
5105 + memset(oh->name, 0, sizeof(oh->name));
5106 + yaffs_load_oh_from_name(dev, oh->name, name);
5107 + } else if (prev_chunk_id > 0) {
5108 + memcpy(oh->name, old_name, sizeof(oh->name));
5109 + } else {
5110 + memset(oh->name, 0, sizeof(oh->name));
5113 + oh->is_shrink = is_shrink;
5115 + switch (in->variant_type) {
5116 + case YAFFS_OBJECT_TYPE_UNKNOWN:
5117 + /* Should not happen */
5118 + break;
5119 + case YAFFS_OBJECT_TYPE_FILE:
5120 + if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED &&
5121 + oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED)
5122 + file_size = in->variant.file_variant.file_size;
5123 + yaffs_oh_size_load(oh, file_size);
5124 + break;
5125 + case YAFFS_OBJECT_TYPE_HARDLINK:
5126 + oh->equiv_id = in->variant.hardlink_variant.equiv_id;
5127 + break;
5128 + case YAFFS_OBJECT_TYPE_SPECIAL:
5129 + /* Do nothing */
5130 + break;
5131 + case YAFFS_OBJECT_TYPE_DIRECTORY:
5132 + /* Do nothing */
5133 + break;
5134 + case YAFFS_OBJECT_TYPE_SYMLINK:
5135 + alias = in->variant.symlink_variant.alias;
5136 + if (!alias)
5137 + alias = _Y("no alias");
5138 + strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH);
5139 + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
5140 + break;
5143 + /* process any xattrib modifications */
5144 + if (xmod)
5145 + yaffs_apply_xattrib_mod(in, (char *)buffer, xmod);
5147 + /* Tags */
5148 + memset(&new_tags, 0, sizeof(new_tags));
5149 + in->serial++;
5150 + new_tags.chunk_id = 0;
5151 + new_tags.obj_id = in->obj_id;
5152 + new_tags.serial_number = in->serial;
5154 + /* Add extra info for file header */
5155 + new_tags.extra_available = 1;
5156 + new_tags.extra_parent_id = oh->parent_obj_id;
5157 + new_tags.extra_file_size = file_size;
5158 + new_tags.extra_is_shrink = oh->is_shrink;
5159 + new_tags.extra_equiv_id = oh->equiv_id;
5160 + new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0;
5161 + new_tags.extra_obj_type = in->variant_type;
5162 + yaffs_verify_oh(in, oh, &new_tags, 1);
5164 + /* Create new chunk in NAND */
5165 + new_chunk_id =
5166 + yaffs_write_new_chunk(dev, buffer, &new_tags,
5167 + (prev_chunk_id > 0) ? 1 : 0);
5169 + if (buffer)
5170 + yaffs_release_temp_buffer(dev, buffer);
5172 + if (new_chunk_id < 0)
5173 + return new_chunk_id;
5175 + in->hdr_chunk = new_chunk_id;
5177 + if (prev_chunk_id > 0)
5178 + yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__);
5180 + if (!yaffs_obj_cache_dirty(in))
5181 + in->dirty = 0;
5183 + /* If this was a shrink, then mark the block
5184 + * that the chunk lives on */
5185 + if (is_shrink) {
5186 + bi = yaffs_get_block_info(in->my_dev,
5187 + new_chunk_id /
5188 + in->my_dev->param.chunks_per_block);
5189 + bi->has_shrink_hdr = 1;
5193 + return new_chunk_id;
5196 +/*--------------------- File read/write ------------------------
5197 + * Read and write have very similar structures.
5198 + * In general the read/write has three parts to it
5199 + * An incomplete chunk to start with (if the read/write is not chunk-aligned)
5200 + * Some complete chunks
5201 + * An incomplete chunk to end off with
5203 + * Curve-balls: the first chunk might also be the last chunk.
5204 + */
5206 +int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes)
5208 + int chunk;
5209 + u32 start;
5210 + int n_copy;
5211 + int n = n_bytes;
5212 + int n_done = 0;
5213 + struct yaffs_cache *cache;
5214 + struct yaffs_dev *dev;
5216 + dev = in->my_dev;
5218 + while (n > 0) {
5219 + yaffs_addr_to_chunk(dev, offset, &chunk, &start);
5220 + chunk++;
5222 + /* OK now check for the curveball where the start and end are in
5223 + * the same chunk.
5224 + */
5225 + if ((start + n) < dev->data_bytes_per_chunk)
5226 + n_copy = n;
5227 + else
5228 + n_copy = dev->data_bytes_per_chunk - start;
5230 + cache = yaffs_find_chunk_cache(in, chunk);
5232 + /* If the chunk is already in the cache or it is less than
5233 + * a whole chunk or we're using inband tags then use the cache
5234 + * (if there is caching) else bypass the cache.
5235 + */
5236 + if (cache || n_copy != dev->data_bytes_per_chunk ||
5237 + dev->param.inband_tags) {
5238 + if (dev->param.n_caches > 0) {
5240 + /* If we can't find the data in the cache,
5241 + * then load it up. */
5243 + if (!cache) {
5244 + cache =
5245 + yaffs_grab_chunk_cache(in->my_dev);
5246 + cache->object = in;
5247 + cache->chunk_id = chunk;
5248 + cache->dirty = 0;
5249 + cache->locked = 0;
5250 + yaffs_rd_data_obj(in, chunk,
5251 + cache->data);
5252 + cache->n_bytes = 0;
5255 + yaffs_use_cache(dev, cache, 0);
5257 + cache->locked = 1;
5259 + memcpy(buffer, &cache->data[start], n_copy);
5261 + cache->locked = 0;
5262 + } else {
5263 + /* Read into the local buffer then copy.. */
5265 + u8 *local_buffer =
5266 + yaffs_get_temp_buffer(dev);
5267 + yaffs_rd_data_obj(in, chunk, local_buffer);
5269 + memcpy(buffer, &local_buffer[start], n_copy);
5271 + yaffs_release_temp_buffer(dev, local_buffer);
5273 + } else {
5274 + /* A full chunk. Read directly into the buffer. */
5275 + yaffs_rd_data_obj(in, chunk, buffer);
5277 + n -= n_copy;
5278 + offset += n_copy;
5279 + buffer += n_copy;
5280 + n_done += n_copy;
5282 + return n_done;
5285 +int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
5286 + int n_bytes, int write_through)
5289 + int chunk;
5290 + u32 start;
5291 + int n_copy;
5292 + int n = n_bytes;
5293 + int n_done = 0;
5294 + int n_writeback;
5295 + loff_t start_write = offset;
5296 + int chunk_written = 0;
5297 + u32 n_bytes_read;
5298 + loff_t chunk_start;
5299 + struct yaffs_dev *dev;
5301 + dev = in->my_dev;
5303 + while (n > 0 && chunk_written >= 0) {
5304 + yaffs_addr_to_chunk(dev, offset, &chunk, &start);
5306 + if (((loff_t)chunk) *
5307 + dev->data_bytes_per_chunk + start != offset ||
5308 + start >= dev->data_bytes_per_chunk) {
5309 + yaffs_trace(YAFFS_TRACE_ERROR,
5310 + "AddrToChunk of offset %lld gives chunk %d start %d",
5311 + offset, chunk, start);
5313 + chunk++; /* File pos to chunk in file offset */
5315 + /* OK now check for the curveball where the start and end are in
5316 + * the same chunk.
5317 + */
5319 + if ((start + n) < dev->data_bytes_per_chunk) {
5320 + n_copy = n;
5322 + /* Now calculate how many bytes to write back....
5323 + * If we're overwriting and not writing to then end of
5324 + * file then we need to write back as much as was there
5325 + * before.
5326 + */
5328 + chunk_start = (((loff_t)(chunk - 1)) *
5329 + dev->data_bytes_per_chunk);
5331 + if (chunk_start > in->variant.file_variant.file_size)
5332 + n_bytes_read = 0; /* Past end of file */
5333 + else
5334 + n_bytes_read =
5335 + in->variant.file_variant.file_size -
5336 + chunk_start;
5338 + if (n_bytes_read > dev->data_bytes_per_chunk)
5339 + n_bytes_read = dev->data_bytes_per_chunk;
5341 + n_writeback =
5342 + (n_bytes_read >
5343 + (start + n)) ? n_bytes_read : (start + n);
5345 + if (n_writeback < 0 ||
5346 + n_writeback > dev->data_bytes_per_chunk)
5347 + BUG();
5349 + } else {
5350 + n_copy = dev->data_bytes_per_chunk - start;
5351 + n_writeback = dev->data_bytes_per_chunk;
5354 + if (n_copy != dev->data_bytes_per_chunk ||
5355 + !dev->param.cache_bypass_aligned ||
5356 + dev->param.inband_tags) {
5357 + /* An incomplete start or end chunk (or maybe both
5358 + * start and end chunk), or we're using inband tags,
5359 + * or we're forcing writes through the cache,
5360 + * so we want to use the cache buffers.
5361 + */
5362 + if (dev->param.n_caches > 0) {
5363 + struct yaffs_cache *cache;
5365 + /* If we can't find the data in the cache, then
5366 + * load the cache */
5367 + cache = yaffs_find_chunk_cache(in, chunk);
5369 + if (!cache &&
5370 + yaffs_check_alloc_available(dev, 1)) {
5371 + cache = yaffs_grab_chunk_cache(dev);
5372 + cache->object = in;
5373 + cache->chunk_id = chunk;
5374 + cache->dirty = 0;
5375 + cache->locked = 0;
5376 + yaffs_rd_data_obj(in, chunk,
5377 + cache->data);
5378 + } else if (cache &&
5379 + !cache->dirty &&
5380 + !yaffs_check_alloc_available(dev,
5381 + 1)) {
5382 + /* Drop the cache if it was a read cache
5383 + * item and no space check has been made
5384 + * for it.
5385 + */
5386 + cache = NULL;
5389 + if (cache) {
5390 + yaffs_use_cache(dev, cache, 1);
5391 + cache->locked = 1;
5393 + memcpy(&cache->data[start], buffer,
5394 + n_copy);
5396 + cache->locked = 0;
5397 + cache->n_bytes = n_writeback;
5399 + if (write_through) {
5400 + chunk_written =
5401 + yaffs_wr_data_obj
5402 + (cache->object,
5403 + cache->chunk_id,
5404 + cache->data,
5405 + cache->n_bytes, 1);
5406 + cache->dirty = 0;
5408 + } else {
5409 + chunk_written = -1; /* fail write */
5411 + } else {
5412 + /* An incomplete start or end chunk (or maybe
5413 + * both start and end chunk). Read into the
5414 + * local buffer then copy over and write back.
5415 + */
5417 + u8 *local_buffer = yaffs_get_temp_buffer(dev);
5419 + yaffs_rd_data_obj(in, chunk, local_buffer);
5420 + memcpy(&local_buffer[start], buffer, n_copy);
5422 + chunk_written =
5423 + yaffs_wr_data_obj(in, chunk,
5424 + local_buffer,
5425 + n_writeback, 0);
5427 + yaffs_release_temp_buffer(dev, local_buffer);
5429 + } else {
5430 + /* A full chunk. Write directly from the buffer. */
5432 + chunk_written =
5433 + yaffs_wr_data_obj(in, chunk, buffer,
5434 + dev->data_bytes_per_chunk, 0);
5436 + /* Since we've overwritten the cached data,
5437 + * we better invalidate it. */
5438 + yaffs_invalidate_chunk_cache(in, chunk);
5441 + if (chunk_written >= 0) {
5442 + n -= n_copy;
5443 + offset += n_copy;
5444 + buffer += n_copy;
5445 + n_done += n_copy;
5449 + /* Update file object */
5451 + if ((start_write + n_done) > in->variant.file_variant.file_size)
5452 + in->variant.file_variant.file_size = (start_write + n_done);
5454 + in->dirty = 1;
5455 + return n_done;
5458 +int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
5459 + int n_bytes, int write_through)
5461 + yaffs2_handle_hole(in, offset);
5462 + return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through);
5465 +/* ---------------------- File resizing stuff ------------------ */
5467 +static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size)
5470 + struct yaffs_dev *dev = in->my_dev;
5471 + loff_t old_size = in->variant.file_variant.file_size;
5472 + int i;
5473 + int chunk_id;
5474 + u32 dummy;
5475 + int last_del;
5476 + int start_del;
5478 + if (old_size > 0)
5479 + yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy);
5480 + else
5481 + last_del = 0;
5483 + yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1,
5484 + &start_del, &dummy);
5485 + last_del++;
5486 + start_del++;
5488 + /* Delete backwards so that we don't end up with holes if
5489 + * power is lost part-way through the operation.
5490 + */
5491 + for (i = last_del; i >= start_del; i--) {
5492 + /* NB this could be optimised somewhat,
5493 + * eg. could retrieve the tags and write them without
5494 + * using yaffs_chunk_del
5495 + */
5497 + chunk_id = yaffs_find_del_file_chunk(in, i, NULL);
5499 + if (chunk_id < 1)
5500 + continue;
5502 + if (chunk_id <
5503 + (dev->internal_start_block * dev->param.chunks_per_block) ||
5504 + chunk_id >=
5505 + ((dev->internal_end_block + 1) *
5506 + dev->param.chunks_per_block)) {
5507 + yaffs_trace(YAFFS_TRACE_ALWAYS,
5508 + "Found daft chunk_id %d for %d",
5509 + chunk_id, i);
5510 + } else {
5511 + in->n_data_chunks--;
5512 + yaffs_chunk_del(dev, chunk_id, 1, __LINE__);
5517 +void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size)
5519 + int new_full;
5520 + u32 new_partial;
5521 + struct yaffs_dev *dev = obj->my_dev;
5523 + yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial);
5525 + yaffs_prune_chunks(obj, new_size);
5527 + if (new_partial != 0) {
5528 + int last_chunk = 1 + new_full;
5529 + u8 *local_buffer = yaffs_get_temp_buffer(dev);
5531 + /* Rewrite the last chunk with its new size and zero pad */
5532 + yaffs_rd_data_obj(obj, last_chunk, local_buffer);
5533 + memset(local_buffer + new_partial, 0,
5534 + dev->data_bytes_per_chunk - new_partial);
5536 + yaffs_wr_data_obj(obj, last_chunk, local_buffer,
5537 + new_partial, 1);
5539 + yaffs_release_temp_buffer(dev, local_buffer);
5542 + obj->variant.file_variant.file_size = new_size;
5544 + yaffs_prune_tree(dev, &obj->variant.file_variant);
5547 +int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size)
5549 + struct yaffs_dev *dev = in->my_dev;
5550 + loff_t old_size = in->variant.file_variant.file_size;
5552 + yaffs_flush_file_cache(in, 1);
5553 + yaffs_invalidate_whole_cache(in);
5555 + yaffs_check_gc(dev, 0);
5557 + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE)
5558 + return YAFFS_FAIL;
5560 + if (new_size == old_size)
5561 + return YAFFS_OK;
5563 + if (new_size > old_size) {
5564 + yaffs2_handle_hole(in, new_size);
5565 + in->variant.file_variant.file_size = new_size;
5566 + } else {
5567 + /* new_size < old_size */
5568 + yaffs_resize_file_down(in, new_size);
5571 + /* Write a new object header to reflect the resize.
5572 + * show we've shrunk the file, if need be
5573 + * Do this only if the file is not in the deleted directories
5574 + * and is not shadowed.
5575 + */
5576 + if (in->parent &&
5577 + !in->is_shadowed &&
5578 + in->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
5579 + in->parent->obj_id != YAFFS_OBJECTID_DELETED)
5580 + yaffs_update_oh(in, NULL, 0, 0, 0, NULL);
5582 + return YAFFS_OK;
5585 +int yaffs_flush_file(struct yaffs_obj *in,
5586 + int update_time,
5587 + int data_sync,
5588 + int discard_cache)
5590 + if (!in->dirty)
5591 + return YAFFS_OK;
5593 + yaffs_flush_file_cache(in, discard_cache);
5595 + if (data_sync)
5596 + return YAFFS_OK;
5598 + if (update_time)
5599 + yaffs_load_current_time(in, 0, 0);
5601 + return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ?
5602 + YAFFS_OK : YAFFS_FAIL;
5606 +/* yaffs_del_file deletes the whole file data
5607 + * and the inode associated with the file.
5608 + * It does not delete the links associated with the file.
5609 + */
5610 +static int yaffs_unlink_file_if_needed(struct yaffs_obj *in)
5612 + int ret_val;
5613 + int del_now = 0;
5614 + struct yaffs_dev *dev = in->my_dev;
5616 + if (!in->my_inode)
5617 + del_now = 1;
5619 + if (del_now) {
5620 + ret_val =
5621 + yaffs_change_obj_name(in, in->my_dev->del_dir,
5622 + _Y("deleted"), 0, 0);
5623 + yaffs_trace(YAFFS_TRACE_TRACING,
5624 + "yaffs: immediate deletion of file %d",
5625 + in->obj_id);
5626 + in->deleted = 1;
5627 + in->my_dev->n_deleted_files++;
5628 + if (dev->param.disable_soft_del || dev->param.is_yaffs2)
5629 + yaffs_resize_file(in, 0);
5630 + yaffs_soft_del_file(in);
5631 + } else {
5632 + ret_val =
5633 + yaffs_change_obj_name(in, in->my_dev->unlinked_dir,
5634 + _Y("unlinked"), 0, 0);
5636 + return ret_val;
5639 +static int yaffs_del_file(struct yaffs_obj *in)
5641 + int ret_val = YAFFS_OK;
5642 + int deleted; /* Need to cache value on stack if in is freed */
5643 + struct yaffs_dev *dev = in->my_dev;
5645 + if (dev->param.disable_soft_del || dev->param.is_yaffs2)
5646 + yaffs_resize_file(in, 0);
5648 + if (in->n_data_chunks > 0) {
5649 + /* Use soft deletion if there is data in the file.
5650 + * That won't be the case if it has been resized to zero.
5651 + */
5652 + if (!in->unlinked)
5653 + ret_val = yaffs_unlink_file_if_needed(in);
5655 + deleted = in->deleted;
5657 + if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) {
5658 + in->deleted = 1;
5659 + deleted = 1;
5660 + in->my_dev->n_deleted_files++;
5661 + yaffs_soft_del_file(in);
5663 + return deleted ? YAFFS_OK : YAFFS_FAIL;
5664 + } else {
5665 + /* The file has no data chunks so we toss it immediately */
5666 + yaffs_free_tnode(in->my_dev, in->variant.file_variant.top);
5667 + in->variant.file_variant.top = NULL;
5668 + yaffs_generic_obj_del(in);
5670 + return YAFFS_OK;
5674 +int yaffs_is_non_empty_dir(struct yaffs_obj *obj)
5676 + return (obj &&
5677 + obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) &&
5678 + !(list_empty(&obj->variant.dir_variant.children));
5681 +static int yaffs_del_dir(struct yaffs_obj *obj)
5683 + /* First check that the directory is empty. */
5684 + if (yaffs_is_non_empty_dir(obj))
5685 + return YAFFS_FAIL;
5687 + return yaffs_generic_obj_del(obj);
5690 +static int yaffs_del_symlink(struct yaffs_obj *in)
5692 + kfree(in->variant.symlink_variant.alias);
5693 + in->variant.symlink_variant.alias = NULL;
5695 + return yaffs_generic_obj_del(in);
5698 +static int yaffs_del_link(struct yaffs_obj *in)
5700 + /* remove this hardlink from the list associated with the equivalent
5701 + * object
5702 + */
5703 + list_del_init(&in->hard_links);
5704 + return yaffs_generic_obj_del(in);
5707 +int yaffs_del_obj(struct yaffs_obj *obj)
5709 + int ret_val = -1;
5711 + switch (obj->variant_type) {
5712 + case YAFFS_OBJECT_TYPE_FILE:
5713 + ret_val = yaffs_del_file(obj);
5714 + break;
5715 + case YAFFS_OBJECT_TYPE_DIRECTORY:
5716 + if (!list_empty(&obj->variant.dir_variant.dirty)) {
5717 + yaffs_trace(YAFFS_TRACE_BACKGROUND,
5718 + "Remove object %d from dirty directories",
5719 + obj->obj_id);
5720 + list_del_init(&obj->variant.dir_variant.dirty);
5722 + return yaffs_del_dir(obj);
5723 + break;
5724 + case YAFFS_OBJECT_TYPE_SYMLINK:
5725 + ret_val = yaffs_del_symlink(obj);
5726 + break;
5727 + case YAFFS_OBJECT_TYPE_HARDLINK:
5728 + ret_val = yaffs_del_link(obj);
5729 + break;
5730 + case YAFFS_OBJECT_TYPE_SPECIAL:
5731 + ret_val = yaffs_generic_obj_del(obj);
5732 + break;
5733 + case YAFFS_OBJECT_TYPE_UNKNOWN:
5734 + ret_val = 0;
5735 + break; /* should not happen. */
5737 + return ret_val;
5741 +static void yaffs_empty_dir_to_dir(struct yaffs_obj *from_dir,
5742 + struct yaffs_obj *to_dir)
5744 + struct yaffs_obj *obj;
5745 + struct list_head *lh;
5746 + struct list_head *n;
5748 + list_for_each_safe(lh, n, &from_dir->variant.dir_variant.children) {
5749 + obj = list_entry(lh, struct yaffs_obj, siblings);
5750 + yaffs_add_obj_to_dir(to_dir, obj);
5754 +struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
5755 + enum yaffs_obj_type type)
5757 + /* Tear down the old variant */
5758 + switch (obj->variant_type) {
5759 + case YAFFS_OBJECT_TYPE_FILE:
5760 + /* Nuke file data */
5761 + yaffs_resize_file(obj, 0);
5762 + yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top);
5763 + obj->variant.file_variant.top = NULL;
5764 + break;
5765 + case YAFFS_OBJECT_TYPE_DIRECTORY:
5766 + /* Put the children in lost and found. */
5767 + yaffs_empty_dir_to_dir(obj, obj->my_dev->lost_n_found);
5768 + if (!list_empty(&obj->variant.dir_variant.dirty))
5769 + list_del_init(&obj->variant.dir_variant.dirty);
5770 + break;
5771 + case YAFFS_OBJECT_TYPE_SYMLINK:
5772 + /* Nuke symplink data */
5773 + kfree(obj->variant.symlink_variant.alias);
5774 + obj->variant.symlink_variant.alias = NULL;
5775 + break;
5776 + case YAFFS_OBJECT_TYPE_HARDLINK:
5777 + list_del_init(&obj->hard_links);
5778 + break;
5779 + default:
5780 + break;
5783 + memset(&obj->variant, 0, sizeof(obj->variant));
5785 + /*Set up new variant if the memset is not enough. */
5786 + switch (type) {
5787 + case YAFFS_OBJECT_TYPE_DIRECTORY:
5788 + INIT_LIST_HEAD(&obj->variant.dir_variant.children);
5789 + INIT_LIST_HEAD(&obj->variant.dir_variant.dirty);
5790 + break;
5791 + case YAFFS_OBJECT_TYPE_FILE:
5792 + case YAFFS_OBJECT_TYPE_SYMLINK:
5793 + case YAFFS_OBJECT_TYPE_HARDLINK:
5794 + default:
5795 + break;
5798 + obj->variant_type = type;
5800 + return obj;
5804 +static int yaffs_unlink_worker(struct yaffs_obj *obj)
5806 + int del_now = 0;
5808 + if (!obj)
5809 + return YAFFS_FAIL;
5811 + if (!obj->my_inode)
5812 + del_now = 1;
5814 + yaffs_update_parent(obj->parent);
5816 + if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
5817 + return yaffs_del_link(obj);
5818 + } else if (!list_empty(&obj->hard_links)) {
5819 + /* Curve ball: We're unlinking an object that has a hardlink.
5821 + * This problem arises because we are not strictly following
5822 + * The Linux link/inode model.
5824 + * We can't really delete the object.
5825 + * Instead, we do the following:
5826 + * - Select a hardlink.
5827 + * - Unhook it from the hard links
5828 + * - Move it from its parent directory so that the rename works.
5829 + * - Rename the object to the hardlink's name.
5830 + * - Delete the hardlink
5831 + */
5833 + struct yaffs_obj *hl;
5834 + struct yaffs_obj *parent;
5835 + int ret_val;
5836 + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
5838 + hl = list_entry(obj->hard_links.next, struct yaffs_obj,
5839 + hard_links);
5841 + yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
5842 + parent = hl->parent;
5844 + list_del_init(&hl->hard_links);
5846 + yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl);
5848 + ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0);
5850 + if (ret_val == YAFFS_OK)
5851 + ret_val = yaffs_generic_obj_del(hl);
5853 + return ret_val;
5855 + } else if (del_now) {
5856 + switch (obj->variant_type) {
5857 + case YAFFS_OBJECT_TYPE_FILE:
5858 + return yaffs_del_file(obj);
5859 + break;
5860 + case YAFFS_OBJECT_TYPE_DIRECTORY:
5861 + list_del_init(&obj->variant.dir_variant.dirty);
5862 + return yaffs_del_dir(obj);
5863 + break;
5864 + case YAFFS_OBJECT_TYPE_SYMLINK:
5865 + return yaffs_del_symlink(obj);
5866 + break;
5867 + case YAFFS_OBJECT_TYPE_SPECIAL:
5868 + return yaffs_generic_obj_del(obj);
5869 + break;
5870 + case YAFFS_OBJECT_TYPE_HARDLINK:
5871 + case YAFFS_OBJECT_TYPE_UNKNOWN:
5872 + default:
5873 + return YAFFS_FAIL;
5875 + } else if (yaffs_is_non_empty_dir(obj)) {
5876 + return YAFFS_FAIL;
5877 + } else {
5878 + return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir,
5879 + _Y("unlinked"), 0, 0);
5883 +static int yaffs_unlink_obj(struct yaffs_obj *obj)
5885 + if (obj && obj->unlink_allowed)
5886 + return yaffs_unlink_worker(obj);
5888 + return YAFFS_FAIL;
5891 +int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name)
5893 + struct yaffs_obj *obj;
5895 + obj = yaffs_find_by_name(dir, name);
5896 + return yaffs_unlink_obj(obj);
5899 +/* Note:
5900 + * If old_name is NULL then we take old_dir as the object to be renamed.
5901 + */
5902 +int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name,
5903 + struct yaffs_obj *new_dir, const YCHAR *new_name)
5905 + struct yaffs_obj *obj = NULL;
5906 + struct yaffs_obj *existing_target = NULL;
5907 + int force = 0;
5908 + int result;
5909 + struct yaffs_dev *dev;
5911 + if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
5912 + BUG();
5913 + return YAFFS_FAIL;
5915 + if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
5916 + BUG();
5917 + return YAFFS_FAIL;
5920 + dev = old_dir->my_dev;
5922 +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
5923 + /* Special case for case insemsitive systems.
5924 + * While look-up is case insensitive, the name isn't.
5925 + * Therefore we might want to change x.txt to X.txt
5926 + */
5927 + if (old_dir == new_dir &&
5928 + old_name && new_name &&
5929 + strcmp(old_name, new_name) == 0)
5930 + force = 1;
5931 +#endif
5933 + if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) >
5934 + YAFFS_MAX_NAME_LENGTH)
5935 + /* ENAMETOOLONG */
5936 + return YAFFS_FAIL;
5938 + if (old_name)
5939 + obj = yaffs_find_by_name(old_dir, old_name);
5940 + else{
5941 + obj = old_dir;
5942 + old_dir = obj->parent;
5945 + if (obj && obj->rename_allowed) {
5946 + /* Now handle an existing target, if there is one */
5947 + existing_target = yaffs_find_by_name(new_dir, new_name);
5948 + if (yaffs_is_non_empty_dir(existing_target)) {
5949 + return YAFFS_FAIL; /* ENOTEMPTY */
5950 + } else if (existing_target && existing_target != obj) {
5951 + /* Nuke the target first, using shadowing,
5952 + * but only if it isn't the same object.
5954 + * Note we must disable gc here otherwise it can mess
5955 + * up the shadowing.
5957 + */
5958 + dev->gc_disable = 1;
5959 + yaffs_change_obj_name(obj, new_dir, new_name, force,
5960 + existing_target->obj_id);
5961 + existing_target->is_shadowed = 1;
5962 + yaffs_unlink_obj(existing_target);
5963 + dev->gc_disable = 0;
5966 + result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0);
5968 + yaffs_update_parent(old_dir);
5969 + if (new_dir != old_dir)
5970 + yaffs_update_parent(new_dir);
5972 + return result;
5974 + return YAFFS_FAIL;
5977 +/*----------------------- Initialisation Scanning ---------------------- */
5979 +void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
5980 + int backward_scanning)
5982 + struct yaffs_obj *obj;
5984 + if (backward_scanning) {
5985 + /* Handle YAFFS2 case (backward scanning)
5986 + * If the shadowed object exists then ignore.
5987 + */
5988 + obj = yaffs_find_by_number(dev, obj_id);
5989 + if (obj)
5990 + return;
5993 + /* Let's create it (if it does not exist) assuming it is a file so that
5994 + * it can do shrinking etc.
5995 + * We put it in unlinked dir to be cleaned up after the scanning
5996 + */
5997 + obj =
5998 + yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE);
5999 + if (!obj)
6000 + return;
6001 + obj->is_shadowed = 1;
6002 + yaffs_add_obj_to_dir(dev->unlinked_dir, obj);
6003 + obj->variant.file_variant.shrink_size = 0;
6004 + obj->valid = 1; /* So that we don't read any other info. */
6007 +void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list)
6009 + struct list_head *lh;
6010 + struct list_head *save;
6011 + struct yaffs_obj *hl;
6012 + struct yaffs_obj *in;
6014 + list_for_each_safe(lh, save, hard_list) {
6015 + hl = list_entry(lh, struct yaffs_obj, hard_links);
6016 + in = yaffs_find_by_number(dev,
6017 + hl->variant.hardlink_variant.equiv_id);
6019 + if (in) {
6020 + /* Add the hardlink pointers */
6021 + hl->variant.hardlink_variant.equiv_obj = in;
6022 + list_add(&hl->hard_links, &in->hard_links);
6023 + } else {
6024 + /* Todo Need to report/handle this better.
6025 + * Got a problem... hardlink to a non-existant object
6026 + */
6027 + hl->variant.hardlink_variant.equiv_obj = NULL;
6028 + INIT_LIST_HEAD(&hl->hard_links);
6033 +static void yaffs_strip_deleted_objs(struct yaffs_dev *dev)
6035 + /*
6036 + * Sort out state of unlinked and deleted objects after scanning.
6037 + */
6038 + struct list_head *i;
6039 + struct list_head *n;
6040 + struct yaffs_obj *l;
6042 + if (dev->read_only)
6043 + return;
6045 + /* Soft delete all the unlinked files */
6046 + list_for_each_safe(i, n,
6047 + &dev->unlinked_dir->variant.dir_variant.children) {
6048 + l = list_entry(i, struct yaffs_obj, siblings);
6049 + yaffs_del_obj(l);
6052 + list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) {
6053 + l = list_entry(i, struct yaffs_obj, siblings);
6054 + yaffs_del_obj(l);
6059 + * This code iterates through all the objects making sure that they are rooted.
6060 + * Any unrooted objects are re-rooted in lost+found.
6061 + * An object needs to be in one of:
6062 + * - Directly under deleted, unlinked
6063 + * - Directly or indirectly under root.
6065 + * Note:
6066 + * This code assumes that we don't ever change the current relationships
6067 + * between directories:
6068 + * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL
6069 + * lost-n-found->parent == root_dir
6071 + * This fixes the problem where directories might have inadvertently been
6072 + * deleted leaving the object "hanging" without being rooted in the
6073 + * directory tree.
6074 + */
6076 +static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj)
6078 + return (obj == dev->del_dir ||
6079 + obj == dev->unlinked_dir || obj == dev->root_dir);
6082 +static void yaffs_fix_hanging_objs(struct yaffs_dev *dev)
6084 + struct yaffs_obj *obj;
6085 + struct yaffs_obj *parent;
6086 + int i;
6087 + struct list_head *lh;
6088 + struct list_head *n;
6089 + int depth_limit;
6090 + int hanging;
6092 + if (dev->read_only)
6093 + return;
6095 + /* Iterate through the objects in each hash entry,
6096 + * looking at each object.
6097 + * Make sure it is rooted.
6098 + */
6100 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
6101 + list_for_each_safe(lh, n, &dev->obj_bucket[i].list) {
6102 + obj = list_entry(lh, struct yaffs_obj, hash_link);
6103 + parent = obj->parent;
6105 + if (yaffs_has_null_parent(dev, obj)) {
6106 + /* These directories are not hanging */
6107 + hanging = 0;
6108 + } else if (!parent ||
6109 + parent->variant_type !=
6110 + YAFFS_OBJECT_TYPE_DIRECTORY) {
6111 + hanging = 1;
6112 + } else if (yaffs_has_null_parent(dev, parent)) {
6113 + hanging = 0;
6114 + } else {
6115 + /*
6116 + * Need to follow the parent chain to
6117 + * see if it is hanging.
6118 + */
6119 + hanging = 0;
6120 + depth_limit = 100;
6122 + while (parent != dev->root_dir &&
6123 + parent->parent &&
6124 + parent->parent->variant_type ==
6125 + YAFFS_OBJECT_TYPE_DIRECTORY &&
6126 + depth_limit > 0) {
6127 + parent = parent->parent;
6128 + depth_limit--;
6130 + if (parent != dev->root_dir)
6131 + hanging = 1;
6133 + if (hanging) {
6134 + yaffs_trace(YAFFS_TRACE_SCAN,
6135 + "Hanging object %d moved to lost and found",
6136 + obj->obj_id);
6137 + yaffs_add_obj_to_dir(dev->lost_n_found, obj);
6144 + * Delete directory contents for cleaning up lost and found.
6145 + */
6146 +static void yaffs_del_dir_contents(struct yaffs_obj *dir)
6148 + struct yaffs_obj *obj;
6149 + struct list_head *lh;
6150 + struct list_head *n;
6152 + if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
6153 + BUG();
6155 + list_for_each_safe(lh, n, &dir->variant.dir_variant.children) {
6156 + obj = list_entry(lh, struct yaffs_obj, siblings);
6157 + if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
6158 + yaffs_del_dir_contents(obj);
6159 + yaffs_trace(YAFFS_TRACE_SCAN,
6160 + "Deleting lost_found object %d",
6161 + obj->obj_id);
6162 + yaffs_unlink_obj(obj);
6166 +static void yaffs_empty_l_n_f(struct yaffs_dev *dev)
6168 + yaffs_del_dir_contents(dev->lost_n_found);
6172 +struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory,
6173 + const YCHAR *name)
6175 + int sum;
6176 + struct list_head *i;
6177 + YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
6178 + struct yaffs_obj *l;
6180 + if (!name)
6181 + return NULL;
6183 + if (!directory) {
6184 + yaffs_trace(YAFFS_TRACE_ALWAYS,
6185 + "tragedy: yaffs_find_by_name: null pointer directory"
6186 + );
6187 + BUG();
6188 + return NULL;
6190 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
6191 + yaffs_trace(YAFFS_TRACE_ALWAYS,
6192 + "tragedy: yaffs_find_by_name: non-directory"
6193 + );
6194 + BUG();
6197 + sum = yaffs_calc_name_sum(name);
6199 + list_for_each(i, &directory->variant.dir_variant.children) {
6200 + l = list_entry(i, struct yaffs_obj, siblings);
6202 + if (l->parent != directory)
6203 + BUG();
6205 + yaffs_check_obj_details_loaded(l);
6207 + /* Special case for lost-n-found */
6208 + if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
6209 + if (!strcmp(name, YAFFS_LOSTNFOUND_NAME))
6210 + return l;
6211 + } else if (l->sum == sum || l->hdr_chunk <= 0) {
6212 + /* LostnFound chunk called Objxxx
6213 + * Do a real check
6214 + */
6215 + yaffs_get_obj_name(l, buffer,
6216 + YAFFS_MAX_NAME_LENGTH + 1);
6217 + if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH))
6218 + return l;
6221 + return NULL;
6224 +/* GetEquivalentObject dereferences any hard links to get to the
6225 + * actual object.
6226 + */
6228 +struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj)
6230 + if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) {
6231 + obj = obj->variant.hardlink_variant.equiv_obj;
6232 + yaffs_check_obj_details_loaded(obj);
6234 + return obj;
6238 + * A note or two on object names.
6239 + * * If the object name is missing, we then make one up in the form objnnn
6241 + * * ASCII names are stored in the object header's name field from byte zero
6242 + * * Unicode names are historically stored starting from byte zero.
6244 + * Then there are automatic Unicode names...
6245 + * The purpose of these is to save names in a way that can be read as
6246 + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII
6247 + * system to share files.
6249 + * These automatic unicode are stored slightly differently...
6250 + * - If the name can fit in the ASCII character space then they are saved as
6251 + * ascii names as per above.
6252 + * - If the name needs Unicode then the name is saved in Unicode
6253 + * starting at oh->name[1].
6255 + */
6256 +static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name,
6257 + int buffer_size)
6259 + /* Create an object name if we could not find one. */
6260 + if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) {
6261 + YCHAR local_name[20];
6262 + YCHAR num_string[20];
6263 + YCHAR *x = &num_string[19];
6264 + unsigned v = obj->obj_id;
6265 + num_string[19] = 0;
6266 + while (v > 0) {
6267 + x--;
6268 + *x = '0' + (v % 10);
6269 + v /= 10;
6271 + /* make up a name */
6272 + strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX);
6273 + strcat(local_name, x);
6274 + strncpy(name, local_name, buffer_size - 1);
6278 +int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size)
6280 + memset(name, 0, buffer_size * sizeof(YCHAR));
6281 + yaffs_check_obj_details_loaded(obj);
6282 + if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) {
6283 + strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1);
6284 + } else if (obj->short_name[0]) {
6285 + strcpy(name, obj->short_name);
6286 + } else if (obj->hdr_chunk > 0) {
6287 + int result;
6288 + u8 *buffer = yaffs_get_temp_buffer(obj->my_dev);
6290 + struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer;
6292 + memset(buffer, 0, obj->my_dev->data_bytes_per_chunk);
6294 + if (obj->hdr_chunk > 0) {
6295 + result = yaffs_rd_chunk_tags_nand(obj->my_dev,
6296 + obj->hdr_chunk,
6297 + buffer, NULL);
6299 + yaffs_load_name_from_oh(obj->my_dev, name, oh->name,
6300 + buffer_size);
6302 + yaffs_release_temp_buffer(obj->my_dev, buffer);
6305 + yaffs_fix_null_name(obj, name, buffer_size);
6307 + return strnlen(name, YAFFS_MAX_NAME_LENGTH);
6310 +loff_t yaffs_get_obj_length(struct yaffs_obj *obj)
6312 + /* Dereference any hard linking */
6313 + obj = yaffs_get_equivalent_obj(obj);
6315 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
6316 + return obj->variant.file_variant.file_size;
6317 + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
6318 + if (!obj->variant.symlink_variant.alias)
6319 + return 0;
6320 + return strnlen(obj->variant.symlink_variant.alias,
6321 + YAFFS_MAX_ALIAS_LENGTH);
6322 + } else {
6323 + /* Only a directory should drop through to here */
6324 + return obj->my_dev->data_bytes_per_chunk;
6328 +int yaffs_get_obj_link_count(struct yaffs_obj *obj)
6330 + int count = 0;
6331 + struct list_head *i;
6333 + if (!obj->unlinked)
6334 + count++; /* the object itself */
6336 + list_for_each(i, &obj->hard_links)
6337 + count++; /* add the hard links; */
6339 + return count;
6342 +int yaffs_get_obj_inode(struct yaffs_obj *obj)
6344 + obj = yaffs_get_equivalent_obj(obj);
6346 + return obj->obj_id;
6349 +unsigned yaffs_get_obj_type(struct yaffs_obj *obj)
6351 + obj = yaffs_get_equivalent_obj(obj);
6353 + switch (obj->variant_type) {
6354 + case YAFFS_OBJECT_TYPE_FILE:
6355 + return DT_REG;
6356 + break;
6357 + case YAFFS_OBJECT_TYPE_DIRECTORY:
6358 + return DT_DIR;
6359 + break;
6360 + case YAFFS_OBJECT_TYPE_SYMLINK:
6361 + return DT_LNK;
6362 + break;
6363 + case YAFFS_OBJECT_TYPE_HARDLINK:
6364 + return DT_REG;
6365 + break;
6366 + case YAFFS_OBJECT_TYPE_SPECIAL:
6367 + if (S_ISFIFO(obj->yst_mode))
6368 + return DT_FIFO;
6369 + if (S_ISCHR(obj->yst_mode))
6370 + return DT_CHR;
6371 + if (S_ISBLK(obj->yst_mode))
6372 + return DT_BLK;
6373 + if (S_ISSOCK(obj->yst_mode))
6374 + return DT_SOCK;
6375 + return DT_REG;
6376 + break;
6377 + default:
6378 + return DT_REG;
6379 + break;
6383 +YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj)
6385 + obj = yaffs_get_equivalent_obj(obj);
6386 + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
6387 + return yaffs_clone_str(obj->variant.symlink_variant.alias);
6388 + else
6389 + return yaffs_clone_str(_Y(""));
6392 +/*--------------------------- Initialisation code -------------------------- */
6394 +static int yaffs_check_dev_fns(struct yaffs_dev *dev)
6396 + struct yaffs_driver *drv = &dev->drv;
6397 + struct yaffs_tags_handler *tagger = &dev->tagger;
6399 + /* Common functions, gotta have */
6400 + if (!drv->drv_read_chunk_fn ||
6401 + !drv->drv_write_chunk_fn ||
6402 + !drv->drv_erase_fn)
6403 + return 0;
6405 + if (dev->param.is_yaffs2 &&
6406 + (!drv->drv_mark_bad_fn || !drv->drv_check_bad_fn))
6407 + return 0;
6409 + /* Install the default tags marshalling functions if needed. */
6410 + yaffs_tags_compat_install(dev);
6411 + yaffs_tags_marshall_install(dev);
6413 + /* Check we now have the marshalling functions required. */
6414 + if (!tagger->write_chunk_tags_fn ||
6415 + !tagger->read_chunk_tags_fn ||
6416 + !tagger->query_block_fn ||
6417 + !tagger->mark_bad_fn)
6418 + return 0;
6420 + return 1;
6423 +static int yaffs_create_initial_dir(struct yaffs_dev *dev)
6425 + /* Initialise the unlinked, deleted, root and lost+found directories */
6426 + dev->lost_n_found = dev->root_dir = NULL;
6427 + dev->unlinked_dir = dev->del_dir = NULL;
6428 + dev->unlinked_dir =
6429 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
6430 + dev->del_dir =
6431 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
6432 + dev->root_dir =
6433 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT,
6434 + YAFFS_ROOT_MODE | S_IFDIR);
6435 + dev->lost_n_found =
6436 + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND,
6437 + YAFFS_LOSTNFOUND_MODE | S_IFDIR);
6439 + if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir
6440 + && dev->del_dir) {
6441 + yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found);
6442 + return YAFFS_OK;
6444 + return YAFFS_FAIL;
6447 +/* Low level init.
6448 + * Typically only used by yaffs_guts_initialise, but also used by the
6449 + * Low level yaffs driver tests.
6450 + */
6452 +int yaffs_guts_ll_init(struct yaffs_dev *dev)
6456 + yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_ll_init()");
6458 + if (!dev) {
6459 + yaffs_trace(YAFFS_TRACE_ALWAYS,
6460 + "yaffs: Need a device"
6461 + );
6462 + return YAFFS_FAIL;
6465 + if (dev->ll_init)
6466 + return YAFFS_OK;
6468 + dev->internal_start_block = dev->param.start_block;
6469 + dev->internal_end_block = dev->param.end_block;
6470 + dev->block_offset = 0;
6471 + dev->chunk_offset = 0;
6472 + dev->n_free_chunks = 0;
6474 + dev->gc_block = 0;
6476 + if (dev->param.start_block == 0) {
6477 + dev->internal_start_block = dev->param.start_block + 1;
6478 + dev->internal_end_block = dev->param.end_block + 1;
6479 + dev->block_offset = 1;
6480 + dev->chunk_offset = dev->param.chunks_per_block;
6483 + /* Check geometry parameters. */
6485 + if ((!dev->param.inband_tags && dev->param.is_yaffs2 &&
6486 + dev->param.total_bytes_per_chunk < 1024) ||
6487 + (!dev->param.is_yaffs2 &&
6488 + dev->param.total_bytes_per_chunk < 512) ||
6489 + (dev->param.inband_tags && !dev->param.is_yaffs2) ||
6490 + dev->param.chunks_per_block < 2 ||
6491 + dev->param.n_reserved_blocks < 2 ||
6492 + dev->internal_start_block <= 0 ||
6493 + dev->internal_end_block <= 0 ||
6494 + dev->internal_end_block <=
6495 + (dev->internal_start_block + dev->param.n_reserved_blocks + 2)
6496 + ) {
6497 + /* otherwise it is too small */
6498 + yaffs_trace(YAFFS_TRACE_ALWAYS,
6499 + "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ",
6500 + dev->param.total_bytes_per_chunk,
6501 + dev->param.is_yaffs2 ? "2" : "",
6502 + dev->param.inband_tags);
6503 + return YAFFS_FAIL;
6506 + /* Sort out space for inband tags, if required */
6507 + if (dev->param.inband_tags)
6508 + dev->data_bytes_per_chunk =
6509 + dev->param.total_bytes_per_chunk -
6510 + sizeof(struct yaffs_packed_tags2_tags_only);
6511 + else
6512 + dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk;
6514 + /* Got the right mix of functions? */
6515 + if (!yaffs_check_dev_fns(dev)) {
6516 + /* Function missing */
6517 + yaffs_trace(YAFFS_TRACE_ALWAYS,
6518 + "device function(s) missing or wrong");
6520 + return YAFFS_FAIL;
6523 + if (yaffs_init_nand(dev) != YAFFS_OK) {
6524 + yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed");
6525 + return YAFFS_FAIL;
6528 + return YAFFS_OK;
6532 +int yaffs_guts_format_dev(struct yaffs_dev *dev)
6534 + int i;
6535 + enum yaffs_block_state state;
6536 + u32 dummy;
6538 + if(yaffs_guts_ll_init(dev) != YAFFS_OK)
6539 + return YAFFS_FAIL;
6541 + if(dev->is_mounted)
6542 + return YAFFS_FAIL;
6544 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
6545 + yaffs_query_init_block_state(dev, i, &state, &dummy);
6546 + if (state != YAFFS_BLOCK_STATE_DEAD)
6547 + yaffs_erase_block(dev, i);
6550 + return YAFFS_OK;
6554 +int yaffs_guts_initialise(struct yaffs_dev *dev)
6556 + int init_failed = 0;
6557 + unsigned x;
6558 + int bits;
6560 + if(yaffs_guts_ll_init(dev) != YAFFS_OK)
6561 + return YAFFS_FAIL;
6563 + if (dev->is_mounted) {
6564 + yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted");
6565 + return YAFFS_FAIL;
6568 + dev->is_mounted = 1;
6570 + /* OK now calculate a few things for the device */
6572 + /*
6573 + * Calculate all the chunk size manipulation numbers:
6574 + */
6575 + x = dev->data_bytes_per_chunk;
6576 + /* We always use dev->chunk_shift and dev->chunk_div */
6577 + dev->chunk_shift = calc_shifts(x);
6578 + x >>= dev->chunk_shift;
6579 + dev->chunk_div = x;
6580 + /* We only use chunk mask if chunk_div is 1 */
6581 + dev->chunk_mask = (1 << dev->chunk_shift) - 1;
6583 + /*
6584 + * Calculate chunk_grp_bits.
6585 + * We need to find the next power of 2 > than internal_end_block
6586 + */
6588 + x = dev->param.chunks_per_block * (dev->internal_end_block + 1);
6590 + bits = calc_shifts_ceiling(x);
6592 + /* Set up tnode width if wide tnodes are enabled. */
6593 + if (!dev->param.wide_tnodes_disabled) {
6594 + /* bits must be even so that we end up with 32-bit words */
6595 + if (bits & 1)
6596 + bits++;
6597 + if (bits < 16)
6598 + dev->tnode_width = 16;
6599 + else
6600 + dev->tnode_width = bits;
6601 + } else {
6602 + dev->tnode_width = 16;
6605 + dev->tnode_mask = (1 << dev->tnode_width) - 1;
6607 + /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
6608 + * so if the bitwidth of the
6609 + * chunk range we're using is greater than 16 we need
6610 + * to figure out chunk shift and chunk_grp_size
6611 + */
6613 + if (bits <= dev->tnode_width)
6614 + dev->chunk_grp_bits = 0;
6615 + else
6616 + dev->chunk_grp_bits = bits - dev->tnode_width;
6618 + dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8;
6619 + if (dev->tnode_size < sizeof(struct yaffs_tnode))
6620 + dev->tnode_size = sizeof(struct yaffs_tnode);
6622 + dev->chunk_grp_size = 1 << dev->chunk_grp_bits;
6624 + if (dev->param.chunks_per_block < dev->chunk_grp_size) {
6625 + /* We have a problem because the soft delete won't work if
6626 + * the chunk group size > chunks per block.
6627 + * This can be remedied by using larger "virtual blocks".
6628 + */
6629 + yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large");
6631 + return YAFFS_FAIL;
6634 + /* Finished verifying the device, continue with initialisation */
6636 + /* More device initialisation */
6637 + dev->all_gcs = 0;
6638 + dev->passive_gc_count = 0;
6639 + dev->oldest_dirty_gc_count = 0;
6640 + dev->bg_gcs = 0;
6641 + dev->gc_block_finder = 0;
6642 + dev->buffered_block = -1;
6643 + dev->doing_buffered_block_rewrite = 0;
6644 + dev->n_deleted_files = 0;
6645 + dev->n_bg_deletions = 0;
6646 + dev->n_unlinked_files = 0;
6647 + dev->n_ecc_fixed = 0;
6648 + dev->n_ecc_unfixed = 0;
6649 + dev->n_tags_ecc_fixed = 0;
6650 + dev->n_tags_ecc_unfixed = 0;
6651 + dev->n_erase_failures = 0;
6652 + dev->n_erased_blocks = 0;
6653 + dev->gc_disable = 0;
6654 + dev->has_pending_prioritised_gc = 1;
6655 + /* Assume the worst for now, will get fixed on first GC */
6656 + INIT_LIST_HEAD(&dev->dirty_dirs);
6657 + dev->oldest_dirty_seq = 0;
6658 + dev->oldest_dirty_block = 0;
6660 + /* Initialise temporary buffers and caches. */
6661 + if (!yaffs_init_tmp_buffers(dev))
6662 + init_failed = 1;
6664 + dev->cache = NULL;
6665 + dev->gc_cleanup_list = NULL;
6667 + if (!init_failed && dev->param.n_caches > 0) {
6668 + int i;
6669 + void *buf;
6670 + int cache_bytes =
6671 + dev->param.n_caches * sizeof(struct yaffs_cache);
6673 + if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES)
6674 + dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES;
6676 + dev->cache = kmalloc(cache_bytes, GFP_NOFS);
6678 + buf = (u8 *) dev->cache;
6680 + if (dev->cache)
6681 + memset(dev->cache, 0, cache_bytes);
6683 + for (i = 0; i < dev->param.n_caches && buf; i++) {
6684 + dev->cache[i].object = NULL;
6685 + dev->cache[i].last_use = 0;
6686 + dev->cache[i].dirty = 0;
6687 + dev->cache[i].data = buf =
6688 + kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS);
6690 + if (!buf)
6691 + init_failed = 1;
6693 + dev->cache_last_use = 0;
6696 + dev->cache_hits = 0;
6698 + if (!init_failed) {
6699 + dev->gc_cleanup_list =
6700 + kmalloc(dev->param.chunks_per_block * sizeof(u32),
6701 + GFP_NOFS);
6702 + if (!dev->gc_cleanup_list)
6703 + init_failed = 1;
6706 + if (dev->param.is_yaffs2)
6707 + dev->param.use_header_file_size = 1;
6709 + if (!init_failed && !yaffs_init_blocks(dev))
6710 + init_failed = 1;
6712 + yaffs_init_tnodes_and_objs(dev);
6714 + if (!init_failed && !yaffs_create_initial_dir(dev))
6715 + init_failed = 1;
6717 + if (!init_failed && dev->param.is_yaffs2 &&
6718 + !dev->param.disable_summary &&
6719 + !yaffs_summary_init(dev))
6720 + init_failed = 1;
6722 + if (!init_failed) {
6723 + /* Now scan the flash. */
6724 + if (dev->param.is_yaffs2) {
6725 + if (yaffs2_checkpt_restore(dev)) {
6726 + yaffs_check_obj_details_loaded(dev->root_dir);
6727 + yaffs_trace(YAFFS_TRACE_CHECKPOINT |
6728 + YAFFS_TRACE_MOUNT,
6729 + "yaffs: restored from checkpoint"
6730 + );
6731 + } else {
6733 + /* Clean up the mess caused by an aborted
6734 + * checkpoint load then scan backwards.
6735 + */
6736 + yaffs_deinit_blocks(dev);
6738 + yaffs_deinit_tnodes_and_objs(dev);
6740 + dev->n_erased_blocks = 0;
6741 + dev->n_free_chunks = 0;
6742 + dev->alloc_block = -1;
6743 + dev->alloc_page = -1;
6744 + dev->n_deleted_files = 0;
6745 + dev->n_unlinked_files = 0;
6746 + dev->n_bg_deletions = 0;
6748 + if (!init_failed && !yaffs_init_blocks(dev))
6749 + init_failed = 1;
6751 + yaffs_init_tnodes_and_objs(dev);
6753 + if (!init_failed
6754 + && !yaffs_create_initial_dir(dev))
6755 + init_failed = 1;
6757 + if (!init_failed && !yaffs2_scan_backwards(dev))
6758 + init_failed = 1;
6760 + } else if (!yaffs1_scan(dev)) {
6761 + init_failed = 1;
6764 + yaffs_strip_deleted_objs(dev);
6765 + yaffs_fix_hanging_objs(dev);
6766 + if (dev->param.empty_lost_n_found)
6767 + yaffs_empty_l_n_f(dev);
6770 + if (init_failed) {
6771 + /* Clean up the mess */
6772 + yaffs_trace(YAFFS_TRACE_TRACING,
6773 + "yaffs: yaffs_guts_initialise() aborted.");
6775 + yaffs_deinitialise(dev);
6776 + return YAFFS_FAIL;
6779 + /* Zero out stats */
6780 + dev->n_page_reads = 0;
6781 + dev->n_page_writes = 0;
6782 + dev->n_erasures = 0;
6783 + dev->n_gc_copies = 0;
6784 + dev->n_retried_writes = 0;
6786 + dev->n_retired_blocks = 0;
6788 + yaffs_verify_free_chunks(dev);
6789 + yaffs_verify_blocks(dev);
6791 + /* Clean up any aborted checkpoint data */
6792 + if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0)
6793 + yaffs2_checkpt_invalidate(dev);
6795 + yaffs_trace(YAFFS_TRACE_TRACING,
6796 + "yaffs: yaffs_guts_initialise() done.");
6797 + return YAFFS_OK;
6800 +void yaffs_deinitialise(struct yaffs_dev *dev)
6802 + if (dev->is_mounted) {
6803 + int i;
6805 + yaffs_deinit_blocks(dev);
6806 + yaffs_deinit_tnodes_and_objs(dev);
6807 + yaffs_summary_deinit(dev);
6809 + if (dev->param.n_caches > 0 && dev->cache) {
6811 + for (i = 0; i < dev->param.n_caches; i++) {
6812 + kfree(dev->cache[i].data);
6813 + dev->cache[i].data = NULL;
6816 + kfree(dev->cache);
6817 + dev->cache = NULL;
6820 + kfree(dev->gc_cleanup_list);
6822 + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
6823 + kfree(dev->temp_buffer[i].buffer);
6824 + dev->temp_buffer[i].buffer = NULL;
6827 + kfree(dev->checkpt_buffer);
6828 + dev->checkpt_buffer = NULL;
6829 + kfree(dev->checkpt_block_list);
6830 + dev->checkpt_block_list = NULL;
6832 + dev->is_mounted = 0;
6834 + yaffs_deinit_nand(dev);
6838 +int yaffs_count_free_chunks(struct yaffs_dev *dev)
6840 + int n_free = 0;
6841 + int b;
6842 + struct yaffs_block_info *blk;
6844 + blk = dev->block_info;
6845 + for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
6846 + switch (blk->block_state) {
6847 + case YAFFS_BLOCK_STATE_EMPTY:
6848 + case YAFFS_BLOCK_STATE_ALLOCATING:
6849 + case YAFFS_BLOCK_STATE_COLLECTING:
6850 + case YAFFS_BLOCK_STATE_FULL:
6851 + n_free +=
6852 + (dev->param.chunks_per_block - blk->pages_in_use +
6853 + blk->soft_del_pages);
6854 + break;
6855 + default:
6856 + break;
6858 + blk++;
6860 + return n_free;
6863 +int yaffs_get_n_free_chunks(struct yaffs_dev *dev)
6865 + /* This is what we report to the outside world */
6866 + int n_free;
6867 + int n_dirty_caches;
6868 + int blocks_for_checkpt;
6869 + int i;
6871 + n_free = dev->n_free_chunks;
6872 + n_free += dev->n_deleted_files;
6874 + /* Now count and subtract the number of dirty chunks in the cache. */
6876 + for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) {
6877 + if (dev->cache[i].dirty)
6878 + n_dirty_caches++;
6881 + n_free -= n_dirty_caches;
6883 + n_free -=
6884 + ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block);
6886 + /* Now figure checkpoint space and report that... */
6887 + blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev);
6889 + n_free -= (blocks_for_checkpt * dev->param.chunks_per_block);
6891 + if (n_free < 0)
6892 + n_free = 0;
6894 + return n_free;
6900 + * Marshalling functions to get loff_t file sizes into and out of
6901 + * object headers.
6902 + */
6903 +void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize)
6905 + oh->file_size_low = (fsize & 0xFFFFFFFF);
6906 + oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF);
6909 +loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh)
6911 + loff_t retval;
6913 + if (sizeof(loff_t) >= 8 && ~(oh->file_size_high))
6914 + retval = (((loff_t) oh->file_size_high) << 32) |
6915 + (((loff_t) oh->file_size_low) & 0xFFFFFFFF);
6916 + else
6917 + retval = (loff_t) oh->file_size_low;
6919 + return retval;
6923 +void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10])
6925 + int i;
6926 + struct yaffs_block_info *bi;
6927 + int s;
6929 + for(i = 0; i < 10; i++)
6930 + bs[i] = 0;
6932 + for(i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
6933 + bi = yaffs_get_block_info(dev, i);
6934 + s = bi->block_state;
6935 + if(s > YAFFS_BLOCK_STATE_DEAD || s < YAFFS_BLOCK_STATE_UNKNOWN)
6936 + bs[0]++;
6937 + else
6938 + bs[s]++;
6941 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_guts.h linux-3.18.14/fs/yaffs2/yaffs_guts.h
6942 --- linux-3.18.14.orig/fs/yaffs2/yaffs_guts.h 1970-01-01 01:00:00.000000000 +0100
6943 +++ linux-3.18.14/fs/yaffs2/yaffs_guts.h 2015-06-14 21:23:22.000000000 +0200
6944 @@ -0,0 +1,1010 @@
6946 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
6948 + * Copyright (C) 2002-2011 Aleph One Ltd.
6949 + * for Toby Churchill Ltd and Brightstar Engineering
6951 + * Created by Charles Manning <charles@aleph1.co.uk>
6953 + * This program is free software; you can redistribute it and/or modify
6954 + * it under the terms of the GNU Lesser General Public License version 2.1 as
6955 + * published by the Free Software Foundation.
6957 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
6958 + */
6960 +#ifndef __YAFFS_GUTS_H__
6961 +#define __YAFFS_GUTS_H__
6963 +#include "yportenv.h"
6965 +#define YAFFS_OK 1
6966 +#define YAFFS_FAIL 0
6968 +/* Give us a Y=0x59,
6969 + * Give us an A=0x41,
6970 + * Give us an FF=0xff
6971 + * Give us an S=0x53
6972 + * And what have we got...
6973 + */
6974 +#define YAFFS_MAGIC 0x5941ff53
6977 + * Tnodes form a tree with the tnodes in "levels"
6978 + * Levels greater than 0 hold 8 slots which point to other tnodes.
6979 + * Those at level 0 hold 16 slots which point to chunks in NAND.
6981 + * A maximum level of 8 thust supports files of size up to:
6983 + * 2^(3*MAX_LEVEL+4)
6985 + * Thus a max level of 8 supports files with up to 2^^28 chunks which gives
6986 + * a maximum file size of around 512Gbytees with 2k chunks.
6987 + */
6988 +#define YAFFS_NTNODES_LEVEL0 16
6989 +#define YAFFS_TNODES_LEVEL0_BITS 4
6990 +#define YAFFS_TNODES_LEVEL0_MASK 0xf
6992 +#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2)
6993 +#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1)
6994 +#define YAFFS_TNODES_INTERNAL_MASK 0x7
6995 +#define YAFFS_TNODES_MAX_LEVEL 8
6996 +#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \
6997 + YAFFS_TNODES_INTERNAL_BITS * \
6998 + YAFFS_TNODES_MAX_LEVEL)
6999 +#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1)
7001 +#define YAFFS_MAX_FILE_SIZE_32 0x7fffffff
7003 +/* Constants for YAFFS1 mode */
7004 +#define YAFFS_BYTES_PER_SPARE 16
7005 +#define YAFFS_BYTES_PER_CHUNK 512
7006 +#define YAFFS_CHUNK_SIZE_SHIFT 9
7007 +#define YAFFS_CHUNKS_PER_BLOCK 32
7008 +#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
7010 +#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024
7011 +#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32
7015 +#define YAFFS_ALLOCATION_NOBJECTS 100
7016 +#define YAFFS_ALLOCATION_NTNODES 100
7017 +#define YAFFS_ALLOCATION_NLINKS 100
7019 +#define YAFFS_NOBJECT_BUCKETS 256
7021 +#define YAFFS_OBJECT_SPACE 0x40000
7022 +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1)
7024 +/* Binary data version stamps */
7025 +#define YAFFS_SUMMARY_VERSION 1
7026 +#define YAFFS_CHECKPOINT_VERSION 7
7028 +#ifdef CONFIG_YAFFS_UNICODE
7029 +#define YAFFS_MAX_NAME_LENGTH 127
7030 +#define YAFFS_MAX_ALIAS_LENGTH 79
7031 +#else
7032 +#define YAFFS_MAX_NAME_LENGTH 255
7033 +#define YAFFS_MAX_ALIAS_LENGTH 159
7034 +#endif
7036 +#define YAFFS_SHORT_NAME_LENGTH 15
7038 +/* Some special object ids for pseudo objects */
7039 +#define YAFFS_OBJECTID_ROOT 1
7040 +#define YAFFS_OBJECTID_LOSTNFOUND 2
7041 +#define YAFFS_OBJECTID_UNLINKED 3
7042 +#define YAFFS_OBJECTID_DELETED 4
7044 +/* Fake object Id for summary data */
7045 +#define YAFFS_OBJECTID_SUMMARY 0x10
7047 +/* Pseudo object ids for checkpointing */
7048 +#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20
7049 +#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21
7051 +#define YAFFS_MAX_SHORT_OP_CACHES 20
7053 +#define YAFFS_N_TEMP_BUFFERS 6
7055 +/* We limit the number attempts at sucessfully saving a chunk of data.
7056 + * Small-page devices have 32 pages per block; large-page devices have 64.
7057 + * Default to something in the order of 5 to 10 blocks worth of chunks.
7058 + */
7059 +#define YAFFS_WR_ATTEMPTS (5*64)
7061 +/* Sequence numbers are used in YAFFS2 to determine block allocation order.
7062 + * The range is limited slightly to help distinguish bad numbers from good.
7063 + * This also allows us to perhaps in the future use special numbers for
7064 + * special purposes.
7065 + * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
7066 + * and is a larger number than the lifetime of a 2GB device.
7067 + */
7068 +#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000
7069 +#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00
7071 +/* Special sequence number for bad block that failed to be marked bad */
7072 +#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000
7074 +/* ChunkCache is used for short read/write operations.*/
7075 +struct yaffs_cache {
7076 + struct yaffs_obj *object;
7077 + int chunk_id;
7078 + int last_use;
7079 + int dirty;
7080 + int n_bytes; /* Only valid if the cache is dirty */
7081 + int locked; /* Can't push out or flush while locked. */
7082 + u8 *data;
7085 +/* yaffs1 tags structures in RAM
7086 + * NB This uses bitfield. Bitfields should not straddle a u32 boundary
7087 + * otherwise the structure size will get blown out.
7088 + */
7090 +struct yaffs_tags {
7091 + u32 chunk_id:20;
7092 + u32 serial_number:2;
7093 + u32 n_bytes_lsb:10;
7094 + u32 obj_id:18;
7095 + u32 ecc:12;
7096 + u32 n_bytes_msb:2;
7099 +union yaffs_tags_union {
7100 + struct yaffs_tags as_tags;
7101 + u8 as_bytes[8];
7105 +/* Stuff used for extended tags in YAFFS2 */
7107 +enum yaffs_ecc_result {
7108 + YAFFS_ECC_RESULT_UNKNOWN,
7109 + YAFFS_ECC_RESULT_NO_ERROR,
7110 + YAFFS_ECC_RESULT_FIXED,
7111 + YAFFS_ECC_RESULT_UNFIXED
7114 +enum yaffs_obj_type {
7115 + YAFFS_OBJECT_TYPE_UNKNOWN,
7116 + YAFFS_OBJECT_TYPE_FILE,
7117 + YAFFS_OBJECT_TYPE_SYMLINK,
7118 + YAFFS_OBJECT_TYPE_DIRECTORY,
7119 + YAFFS_OBJECT_TYPE_HARDLINK,
7120 + YAFFS_OBJECT_TYPE_SPECIAL
7123 +#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
7125 +struct yaffs_ext_tags {
7126 + unsigned chunk_used; /* Status of the chunk: used or unused */
7127 + unsigned obj_id; /* If 0 this is not used */
7128 + unsigned chunk_id; /* If 0 this is a header, else a data chunk */
7129 + unsigned n_bytes; /* Only valid for data chunks */
7131 + /* The following stuff only has meaning when we read */
7132 + enum yaffs_ecc_result ecc_result;
7133 + unsigned block_bad;
7135 + /* YAFFS 1 stuff */
7136 + unsigned is_deleted; /* The chunk is marked deleted */
7137 + unsigned serial_number; /* Yaffs1 2-bit serial number */
7139 + /* YAFFS2 stuff */
7140 + unsigned seq_number; /* The sequence number of this block */
7142 + /* Extra info if this is an object header (YAFFS2 only) */
7144 + unsigned extra_available; /* Extra info available if not zero */
7145 + unsigned extra_parent_id; /* The parent object */
7146 + unsigned extra_is_shrink; /* Is it a shrink header? */
7147 + unsigned extra_shadows; /* Does this shadow another object? */
7149 + enum yaffs_obj_type extra_obj_type; /* What object type? */
7151 + loff_t extra_file_size; /* Length if it is a file */
7152 + unsigned extra_equiv_id; /* Equivalent object for a hard link */
7155 +/* Spare structure for YAFFS1 */
7156 +struct yaffs_spare {
7157 + u8 tb0;
7158 + u8 tb1;
7159 + u8 tb2;
7160 + u8 tb3;
7161 + u8 page_status; /* set to 0 to delete the chunk */
7162 + u8 block_status;
7163 + u8 tb4;
7164 + u8 tb5;
7165 + u8 ecc1[3];
7166 + u8 tb6;
7167 + u8 tb7;
7168 + u8 ecc2[3];
7171 +/*Special structure for passing through to mtd */
7172 +struct yaffs_nand_spare {
7173 + struct yaffs_spare spare;
7174 + int eccres1;
7175 + int eccres2;
7178 +/* Block data in RAM */
7180 +enum yaffs_block_state {
7181 + YAFFS_BLOCK_STATE_UNKNOWN = 0,
7183 + YAFFS_BLOCK_STATE_SCANNING,
7184 + /* Being scanned */
7186 + YAFFS_BLOCK_STATE_NEEDS_SCAN,
7187 + /* The block might have something on it (ie it is allocating or full,
7188 + * perhaps empty) but it needs to be scanned to determine its true
7189 + * state.
7190 + * This state is only valid during scanning.
7191 + * NB We tolerate empty because the pre-scanner might be incapable of
7192 + * deciding
7193 + * However, if this state is returned on a YAFFS2 device,
7194 + * then we expect a sequence number
7195 + */
7197 + YAFFS_BLOCK_STATE_EMPTY,
7198 + /* This block is empty */
7200 + YAFFS_BLOCK_STATE_ALLOCATING,
7201 + /* This block is partially allocated.
7202 + * At least one page holds valid data.
7203 + * This is the one currently being used for page
7204 + * allocation. Should never be more than one of these.
7205 + * If a block is only partially allocated at mount it is treated as
7206 + * full.
7207 + */
7209 + YAFFS_BLOCK_STATE_FULL,
7210 + /* All the pages in this block have been allocated.
7211 + * If a block was only partially allocated when mounted we treat
7212 + * it as fully allocated.
7213 + */
7215 + YAFFS_BLOCK_STATE_DIRTY,
7216 + /* The block was full and now all chunks have been deleted.
7217 + * Erase me, reuse me.
7218 + */
7220 + YAFFS_BLOCK_STATE_CHECKPOINT,
7221 + /* This block is assigned to holding checkpoint data. */
7223 + YAFFS_BLOCK_STATE_COLLECTING,
7224 + /* This block is being garbage collected */
7226 + YAFFS_BLOCK_STATE_DEAD
7227 + /* This block has failed and is not in use */
7230 +#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
7232 +struct yaffs_block_info {
7234 + s32 soft_del_pages:10; /* number of soft deleted pages */
7235 + s32 pages_in_use:10; /* number of pages in use */
7236 + u32 block_state:4; /* One of the above block states. */
7237 + /* NB use unsigned because enum is sometimes
7238 + * an int */
7239 + u32 needs_retiring:1; /* Data has failed on this block, */
7240 + /*need to get valid data off and retire*/
7241 + u32 skip_erased_check:1;/* Skip the erased check on this block */
7242 + u32 gc_prioritise:1; /* An ECC check or blank check has failed.
7243 + Block should be prioritised for GC */
7244 + u32 chunk_error_strikes:3; /* How many times we've had ecc etc
7245 + failures on this block and tried to reuse it */
7246 + u32 has_summary:1; /* The block has a summary */
7248 + u32 has_shrink_hdr:1; /* This block has at least one shrink header */
7249 + u32 seq_number; /* block sequence number for yaffs2 */
7253 +/* -------------------------- Object structure -------------------------------*/
7254 +/* This is the object structure as stored on NAND */
7256 +struct yaffs_obj_hdr {
7257 + enum yaffs_obj_type type;
7259 + /* Apply to everything */
7260 + int parent_obj_id;
7261 + u16 sum_no_longer_used; /* checksum of name. No longer used */
7262 + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
7264 + /* The following apply to all object types except for hard links */
7265 + u32 yst_mode; /* protection */
7267 + u32 yst_uid;
7268 + u32 yst_gid;
7269 + u32 yst_atime;
7270 + u32 yst_mtime;
7271 + u32 yst_ctime;
7273 + /* File size applies to files only */
7274 + u32 file_size_low;
7276 + /* Equivalent object id applies to hard links only. */
7277 + int equiv_id;
7279 + /* Alias is for symlinks only. */
7280 + YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
7282 + u32 yst_rdev; /* stuff for block and char devices (major/min) */
7284 + u32 win_ctime[2];
7285 + u32 win_atime[2];
7286 + u32 win_mtime[2];
7288 + u32 inband_shadowed_obj_id;
7289 + u32 inband_is_shrink;
7291 + u32 file_size_high;
7292 + u32 reserved[1];
7293 + int shadows_obj; /* This object header shadows the
7294 + specified object if > 0 */
7296 + /* is_shrink applies to object headers written when wemake a hole. */
7297 + u32 is_shrink;
7301 +/*--------------------------- Tnode -------------------------- */
7303 +struct yaffs_tnode {
7304 + struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
7307 +/*------------------------ Object -----------------------------*/
7308 +/* An object can be one of:
7309 + * - a directory (no data, has children links
7310 + * - a regular file (data.... not prunes :->).
7311 + * - a symlink [symbolic link] (the alias).
7312 + * - a hard link
7313 + */
7315 +struct yaffs_file_var {
7316 + loff_t file_size;
7317 + loff_t scanned_size;
7318 + loff_t shrink_size;
7319 + int top_level;
7320 + struct yaffs_tnode *top;
7323 +struct yaffs_dir_var {
7324 + struct list_head children; /* list of child links */
7325 + struct list_head dirty; /* Entry for list of dirty directories */
7328 +struct yaffs_symlink_var {
7329 + YCHAR *alias;
7332 +struct yaffs_hardlink_var {
7333 + struct yaffs_obj *equiv_obj;
7334 + u32 equiv_id;
7337 +union yaffs_obj_var {
7338 + struct yaffs_file_var file_variant;
7339 + struct yaffs_dir_var dir_variant;
7340 + struct yaffs_symlink_var symlink_variant;
7341 + struct yaffs_hardlink_var hardlink_variant;
7344 +struct yaffs_obj {
7345 + u8 deleted:1; /* This should only apply to unlinked files. */
7346 + u8 soft_del:1; /* it has also been soft deleted */
7347 + u8 unlinked:1; /* An unlinked file.*/
7348 + u8 fake:1; /* A fake object has no presence on NAND. */
7349 + u8 rename_allowed:1; /* Some objects cannot be renamed. */
7350 + u8 unlink_allowed:1;
7351 + u8 dirty:1; /* the object needs to be written to flash */
7352 + u8 valid:1; /* When the file system is being loaded up, this
7353 + * object might be created before the data
7354 + * is available
7355 + * ie. file data chunks encountered before
7356 + * the header.
7357 + */
7358 + u8 lazy_loaded:1; /* This object has been lazy loaded and
7359 + * is missing some detail */
7361 + u8 defered_free:1; /* Object is removed from NAND, but is
7362 + * still in the inode cache.
7363 + * Free of object is defered.
7364 + * until the inode is released.
7365 + */
7366 + u8 being_created:1; /* This object is still being created
7367 + * so skip some verification checks. */
7368 + u8 is_shadowed:1; /* This object is shadowed on the way
7369 + * to being renamed. */
7371 + u8 xattr_known:1; /* We know if this has object has xattribs
7372 + * or not. */
7373 + u8 has_xattr:1; /* This object has xattribs.
7374 + * Only valid if xattr_known. */
7376 + u8 serial; /* serial number of chunk in NAND.*/
7377 + u16 sum; /* sum of the name to speed searching */
7379 + struct yaffs_dev *my_dev; /* The device I'm on */
7381 + struct list_head hash_link; /* list of objects in hash bucket */
7383 + struct list_head hard_links; /* hard linked object chain*/
7385 + /* directory structure stuff */
7386 + /* also used for linking up the free list */
7387 + struct yaffs_obj *parent;
7388 + struct list_head siblings;
7390 + /* Where's my object header in NAND? */
7391 + int hdr_chunk;
7393 + int n_data_chunks; /* Number of data chunks for this file. */
7395 + u32 obj_id; /* the object id value */
7397 + u32 yst_mode;
7399 + YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];
7401 +#ifdef CONFIG_YAFFS_WINCE
7402 + u32 win_ctime[2];
7403 + u32 win_mtime[2];
7404 + u32 win_atime[2];
7405 +#else
7406 + u32 yst_uid;
7407 + u32 yst_gid;
7408 + u32 yst_atime;
7409 + u32 yst_mtime;
7410 + u32 yst_ctime;
7411 +#endif
7413 + u32 yst_rdev;
7415 + void *my_inode;
7417 + enum yaffs_obj_type variant_type;
7419 + union yaffs_obj_var variant;
7423 +struct yaffs_obj_bucket {
7424 + struct list_head list;
7425 + int count;
7428 +/* yaffs_checkpt_obj holds the definition of an object as dumped
7429 + * by checkpointing.
7430 + */
7432 +struct yaffs_checkpt_obj {
7433 + int struct_type;
7434 + u32 obj_id;
7435 + u32 parent_id;
7436 + int hdr_chunk;
7437 + enum yaffs_obj_type variant_type:3;
7438 + u8 deleted:1;
7439 + u8 soft_del:1;
7440 + u8 unlinked:1;
7441 + u8 fake:1;
7442 + u8 rename_allowed:1;
7443 + u8 unlink_allowed:1;
7444 + u8 serial;
7445 + int n_data_chunks;
7446 + loff_t size_or_equiv_obj;
7449 +/*--------------------- Temporary buffers ----------------
7451 + * These are chunk-sized working buffers. Each device has a few.
7452 + */
7454 +struct yaffs_buffer {
7455 + u8 *buffer;
7456 + int in_use;
7459 +/*----------------- Device ---------------------------------*/
7461 +struct yaffs_param {
7462 + const YCHAR *name;
7464 + /*
7465 + * Entry parameters set up way early. Yaffs sets up the rest.
7466 + * The structure should be zeroed out before use so that unused
7467 + * and default values are zero.
7468 + */
7470 + int inband_tags; /* Use unband tags */
7471 + u32 total_bytes_per_chunk; /* Should be >= 512, does not need to
7472 + be a power of 2 */
7473 + int chunks_per_block; /* does not need to be a power of 2 */
7474 + int spare_bytes_per_chunk; /* spare area size */
7475 + int start_block; /* Start block we're allowed to use */
7476 + int end_block; /* End block we're allowed to use */
7477 + int n_reserved_blocks; /* Tuneable so that we can reduce
7478 + * reserved blocks on NOR and RAM. */
7480 + int n_caches; /* If <= 0, then short op caching is disabled,
7481 + * else the number of short op caches.
7482 + */
7483 + int cache_bypass_aligned; /* If non-zero then bypass the cache for
7484 + * aligned writes.
7485 + */
7487 + int use_nand_ecc; /* Flag to decide whether or not to use
7488 + * NAND driver ECC on data (yaffs1) */
7489 + int tags_9bytes; /* Use 9 byte tags */
7490 + int no_tags_ecc; /* Flag to decide whether or not to do ECC
7491 + * on packed tags (yaffs2) */
7493 + int is_yaffs2; /* Use yaffs2 mode on this device */
7495 + int empty_lost_n_found; /* Auto-empty lost+found directory on mount */
7497 + int refresh_period; /* How often to check for a block refresh */
7499 + /* Checkpoint control. Can be set before or after initialisation */
7500 + u8 skip_checkpt_rd;
7501 + u8 skip_checkpt_wr;
7503 + int enable_xattr; /* Enable xattribs */
7505 + int max_objects; /*
7506 + * Set to limit the number of objects created.
7507 + * 0 = no limit.
7508 + */
7510 + /* The remove_obj_fn function must be supplied by OS flavours that
7511 + * need it.
7512 + * yaffs direct uses it to implement the faster readdir.
7513 + * Linux uses it to protect the directory during unlocking.
7514 + */
7515 + void (*remove_obj_fn) (struct yaffs_obj *obj);
7517 + /* Callback to mark the superblock dirty */
7518 + void (*sb_dirty_fn) (struct yaffs_dev *dev);
7520 + /* Callback to control garbage collection. */
7521 + unsigned (*gc_control_fn) (struct yaffs_dev *dev);
7523 + /* Debug control flags. Don't use unless you know what you're doing */
7524 + int use_header_file_size; /* Flag to determine if we should use
7525 + * file sizes from the header */
7526 + int disable_lazy_load; /* Disable lazy loading on this device */
7527 + int wide_tnodes_disabled; /* Set to disable wide tnodes */
7528 + int disable_soft_del; /* yaffs 1 only: Set to disable the use of
7529 + * softdeletion. */
7531 + int defered_dir_update; /* Set to defer directory updates */
7533 +#ifdef CONFIG_YAFFS_AUTO_UNICODE
7534 + int auto_unicode;
7535 +#endif
7536 + int always_check_erased; /* Force chunk erased check always on */
7538 + int disable_summary;
7539 + int disable_bad_block_marking;
7543 +struct yaffs_driver {
7544 + int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
7545 + const u8 *data, int data_len,
7546 + const u8 *oob, int oob_len);
7547 + int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
7548 + u8 *data, int data_len,
7549 + u8 *oob, int oob_len,
7550 + enum yaffs_ecc_result *ecc_result);
7551 + int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);
7552 + int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);
7553 + int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);
7554 + int (*drv_initialise_fn) (struct yaffs_dev *dev);
7555 + int (*drv_deinitialise_fn) (struct yaffs_dev *dev);
7558 +struct yaffs_tags_handler {
7559 + int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
7560 + int nand_chunk, const u8 *data,
7561 + const struct yaffs_ext_tags *tags);
7562 + int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
7563 + int nand_chunk, u8 *data,
7564 + struct yaffs_ext_tags *tags);
7566 + int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
7567 + enum yaffs_block_state *state,
7568 + u32 *seq_number);
7569 + int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);
7572 +struct yaffs_dev {
7573 + struct yaffs_param param;
7574 + struct yaffs_driver drv;
7575 + struct yaffs_tags_handler tagger;
7577 + /* Context storage. Holds extra OS specific data for this device */
7579 + void *os_context;
7580 + void *driver_context;
7582 + struct list_head dev_list;
7584 + int ll_init;
7585 + /* Runtime parameters. Set up by YAFFS. */
7586 + int data_bytes_per_chunk;
7588 + /* Non-wide tnode stuff */
7589 + u16 chunk_grp_bits; /* Number of bits that need to be resolved if
7590 + * the tnodes are not wide enough.
7591 + */
7592 + u16 chunk_grp_size; /* == 2^^chunk_grp_bits */
7594 + /* Stuff to support wide tnodes */
7595 + u32 tnode_width;
7596 + u32 tnode_mask;
7597 + u32 tnode_size;
7599 + /* Stuff for figuring out file offset to chunk conversions */
7600 + u32 chunk_shift; /* Shift value */
7601 + u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */
7602 + u32 chunk_mask; /* Mask to use for power-of-2 case */
7604 + int is_mounted;
7605 + int read_only;
7606 + int is_checkpointed;
7608 + /* Stuff to support block offsetting to support start block zero */
7609 + int internal_start_block;
7610 + int internal_end_block;
7611 + int block_offset;
7612 + int chunk_offset;
7614 + /* Runtime checkpointing stuff */
7615 + int checkpt_page_seq; /* running sequence number of checkpt pages */
7616 + int checkpt_byte_count;
7617 + int checkpt_byte_offs;
7618 + u8 *checkpt_buffer;
7619 + int checkpt_open_write;
7620 + int blocks_in_checkpt;
7621 + int checkpt_cur_chunk;
7622 + int checkpt_cur_block;
7623 + int checkpt_next_block;
7624 + int *checkpt_block_list;
7625 + int checkpt_max_blocks;
7626 + u32 checkpt_sum;
7627 + u32 checkpt_xor;
7629 + int checkpoint_blocks_required; /* Number of blocks needed to store
7630 + * current checkpoint set */
7632 + /* Block Info */
7633 + struct yaffs_block_info *block_info;
7634 + u8 *chunk_bits; /* bitmap of chunks in use */
7635 + u8 block_info_alt:1; /* allocated using alternative alloc */
7636 + u8 chunk_bits_alt:1; /* allocated using alternative alloc */
7637 + int chunk_bit_stride; /* Number of bytes of chunk_bits per block.
7638 + * Must be consistent with chunks_per_block.
7639 + */
7641 + int n_erased_blocks;
7642 + int alloc_block; /* Current block being allocated off */
7643 + u32 alloc_page;
7644 + int alloc_block_finder; /* Used to search for next allocation block */
7646 + /* Object and Tnode memory management */
7647 + void *allocator;
7648 + int n_obj;
7649 + int n_tnodes;
7651 + int n_hardlinks;
7653 + struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
7654 + u32 bucket_finder;
7656 + int n_free_chunks;
7658 + /* Garbage collection control */
7659 + u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */
7660 + u32 n_clean_ups;
7662 + unsigned has_pending_prioritised_gc; /* We think this device might
7663 + have pending prioritised gcs */
7664 + unsigned gc_disable;
7665 + unsigned gc_block_finder;
7666 + unsigned gc_dirtiest;
7667 + unsigned gc_pages_in_use;
7668 + unsigned gc_not_done;
7669 + unsigned gc_block;
7670 + unsigned gc_chunk;
7671 + unsigned gc_skip;
7672 + struct yaffs_summary_tags *gc_sum_tags;
7674 + /* Special directories */
7675 + struct yaffs_obj *root_dir;
7676 + struct yaffs_obj *lost_n_found;
7678 + int buffered_block; /* Which block is buffered here? */
7679 + int doing_buffered_block_rewrite;
7681 + struct yaffs_cache *cache;
7682 + int cache_last_use;
7684 + /* Stuff for background deletion and unlinked files. */
7685 + struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted
7686 + files live. */
7687 + struct yaffs_obj *del_dir; /* Directory where deleted objects are
7688 + sent to disappear. */
7689 + struct yaffs_obj *unlinked_deletion; /* Current file being
7690 + background deleted. */
7691 + int n_deleted_files; /* Count of files awaiting deletion; */
7692 + int n_unlinked_files; /* Count of unlinked files. */
7693 + int n_bg_deletions; /* Count of background deletions. */
7695 + /* Temporary buffer management */
7696 + struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
7697 + int max_temp;
7698 + int temp_in_use;
7699 + int unmanaged_buffer_allocs;
7700 + int unmanaged_buffer_deallocs;
7702 + /* yaffs2 runtime stuff */
7703 + unsigned seq_number; /* Sequence number of currently
7704 + allocating block */
7705 + unsigned oldest_dirty_seq;
7706 + unsigned oldest_dirty_block;
7708 + /* Block refreshing */
7709 + int refresh_skip; /* A skip down counter.
7710 + * Refresh happens when this gets to zero. */
7712 + /* Dirty directory handling */
7713 + struct list_head dirty_dirs; /* List of dirty directories */
7715 + /* Summary */
7716 + int chunks_per_summary;
7717 + struct yaffs_summary_tags *sum_tags;
7719 + /* Statistics */
7720 + u32 n_page_writes;
7721 + u32 n_page_reads;
7722 + u32 n_erasures;
7723 + u32 n_bad_queries;
7724 + u32 n_bad_markings;
7725 + u32 n_erase_failures;
7726 + u32 n_gc_copies;
7727 + u32 all_gcs;
7728 + u32 passive_gc_count;
7729 + u32 oldest_dirty_gc_count;
7730 + u32 n_gc_blocks;
7731 + u32 bg_gcs;
7732 + u32 n_retried_writes;
7733 + u32 n_retired_blocks;
7734 + u32 n_ecc_fixed;
7735 + u32 n_ecc_unfixed;
7736 + u32 n_tags_ecc_fixed;
7737 + u32 n_tags_ecc_unfixed;
7738 + u32 n_deletions;
7739 + u32 n_unmarked_deletions;
7740 + u32 refresh_count;
7741 + u32 cache_hits;
7742 + u32 tags_used;
7743 + u32 summary_used;
7747 +/* The CheckpointDevice structure holds the device information that changes
7748 + *at runtime and must be preserved over unmount/mount cycles.
7749 + */
7750 +struct yaffs_checkpt_dev {
7751 + int struct_type;
7752 + int n_erased_blocks;
7753 + int alloc_block; /* Current block being allocated off */
7754 + u32 alloc_page;
7755 + int n_free_chunks;
7757 + int n_deleted_files; /* Count of files awaiting deletion; */
7758 + int n_unlinked_files; /* Count of unlinked files. */
7759 + int n_bg_deletions; /* Count of background deletions. */
7761 + /* yaffs2 runtime stuff */
7762 + unsigned seq_number; /* Sequence number of currently
7763 + * allocating block */
7767 +struct yaffs_checkpt_validity {
7768 + int struct_type;
7769 + u32 magic;
7770 + u32 version;
7771 + u32 head;
7774 +struct yaffs_shadow_fixer {
7775 + int obj_id;
7776 + int shadowed_id;
7777 + struct yaffs_shadow_fixer *next;
7780 +/* Structure for doing xattr modifications */
7781 +struct yaffs_xattr_mod {
7782 + int set; /* If 0 then this is a deletion */
7783 + const YCHAR *name;
7784 + const void *data;
7785 + int size;
7786 + int flags;
7787 + int result;
7790 +/*----------------------- YAFFS Functions -----------------------*/
7792 +int yaffs_guts_initialise(struct yaffs_dev *dev);
7793 +void yaffs_deinitialise(struct yaffs_dev *dev);
7795 +int yaffs_get_n_free_chunks(struct yaffs_dev *dev);
7797 +int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
7798 + struct yaffs_obj *new_dir, const YCHAR * new_name);
7800 +int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
7801 +int yaffs_del_obj(struct yaffs_obj *obj);
7802 +struct yaffs_obj *yaffs_retype_obj(struct yaffs_obj *obj,
7803 + enum yaffs_obj_type type);
7806 +int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
7807 +loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
7808 +int yaffs_get_obj_inode(struct yaffs_obj *obj);
7809 +unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
7810 +int yaffs_get_obj_link_count(struct yaffs_obj *obj);
7812 +/* File operations */
7813 +int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
7814 + int n_bytes);
7815 +int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
7816 + int n_bytes, int write_trhrough);
7817 +int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);
7819 +struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
7820 + const YCHAR *name, u32 mode, u32 uid,
7821 + u32 gid);
7823 +int yaffs_flush_file(struct yaffs_obj *in,
7824 + int update_time,
7825 + int data_sync,
7826 + int discard_cache);
7828 +/* Flushing and checkpointing */
7829 +void yaffs_flush_whole_cache(struct yaffs_dev *dev, int discard);
7831 +int yaffs_checkpoint_save(struct yaffs_dev *dev);
7832 +int yaffs_checkpoint_restore(struct yaffs_dev *dev);
7834 +/* Directory operations */
7835 +struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
7836 + u32 mode, u32 uid, u32 gid);
7837 +struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
7838 + const YCHAR *name);
7839 +struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);
7841 +/* Link operations */
7842 +struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
7843 + struct yaffs_obj *equiv_obj);
7845 +struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);
7847 +/* Symlink operations */
7848 +struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
7849 + const YCHAR *name, u32 mode, u32 uid,
7850 + u32 gid, const YCHAR *alias);
7851 +YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);
7853 +/* Special inodes (fifos, sockets and devices) */
7854 +struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
7855 + const YCHAR *name, u32 mode, u32 uid,
7856 + u32 gid, u32 rdev);
7858 +int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
7859 + const void *value, int size, int flags);
7860 +int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
7861 + int size);
7862 +int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
7863 +int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);
7865 +/* Special directories */
7866 +struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
7867 +struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);
7869 +void yaffs_handle_defered_free(struct yaffs_obj *obj);
7871 +void yaffs_update_dirty_dirs(struct yaffs_dev *dev);
7873 +int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);
7875 +/* Debug dump */
7876 +int yaffs_dump_obj(struct yaffs_obj *obj);
7878 +void yaffs_guts_test(struct yaffs_dev *dev);
7879 +int yaffs_guts_ll_init(struct yaffs_dev *dev);
7882 +/* A few useful functions to be used within the core files*/
7883 +void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
7884 + int lyn);
7885 +int yaffs_check_ff(u8 *buffer, int n_bytes);
7886 +void yaffs_handle_chunk_error(struct yaffs_dev *dev,
7887 + struct yaffs_block_info *bi);
7889 +u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
7890 +void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);
7892 +struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
7893 + int number,
7894 + enum yaffs_obj_type type);
7895 +int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
7896 + int nand_chunk, int in_scan);
7897 +void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
7898 +void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
7899 + const struct yaffs_obj_hdr *oh);
7900 +void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
7901 +YCHAR *yaffs_clone_str(const YCHAR *str);
7902 +void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
7903 +void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
7904 +int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
7905 + int force, int is_shrink, int shadows,
7906 + struct yaffs_xattr_mod *xop);
7907 +void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
7908 + int backward_scanning);
7909 +int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
7910 +struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
7911 +struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
7912 + struct yaffs_file_var *file_struct,
7913 + u32 chunk_id,
7914 + struct yaffs_tnode *passed_tn);
7916 +int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
7917 + int n_bytes, int write_trhrough);
7918 +void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
7919 +void yaffs_skip_rest_of_block(struct yaffs_dev *dev);
7921 +int yaffs_count_free_chunks(struct yaffs_dev *dev);
7923 +struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
7924 + struct yaffs_file_var *file_struct,
7925 + u32 chunk_id);
7927 +u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
7928 + unsigned pos);
7930 +int yaffs_is_non_empty_dir(struct yaffs_obj *obj);
7932 +int yaffs_guts_format_dev(struct yaffs_dev *dev);
7934 +void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
7935 + int *chunk_out, u32 *offset_out);
7937 + * Marshalling functions to get loff_t file sizes into aand out of
7938 + * object headers.
7939 + */
7940 +void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
7941 +loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
7942 +loff_t yaffs_max_file_size(struct yaffs_dev *dev);
7945 + * Debug function to count number of blocks in each state
7946 + * NB Needs to be called with correct number of integers
7947 + */
7949 +void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]);
7951 +int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
7952 + struct yaffs_ext_tags *tags);
7954 +#endif
7955 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_linux.h linux-3.18.14/fs/yaffs2/yaffs_linux.h
7956 --- linux-3.18.14.orig/fs/yaffs2/yaffs_linux.h 1970-01-01 01:00:00.000000000 +0100
7957 +++ linux-3.18.14/fs/yaffs2/yaffs_linux.h 2015-06-14 21:23:22.000000000 +0200
7958 @@ -0,0 +1,48 @@
7960 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
7962 + * Copyright (C) 2002-2011 Aleph One Ltd.
7963 + * for Toby Churchill Ltd and Brightstar Engineering
7965 + * Created by Charles Manning <charles@aleph1.co.uk>
7967 + * This program is free software; you can redistribute it and/or modify
7968 + * it under the terms of the GNU Lesser General Public License version 2.1 as
7969 + * published by the Free Software Foundation.
7971 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
7972 + */
7974 +#ifndef __YAFFS_LINUX_H__
7975 +#define __YAFFS_LINUX_H__
7977 +#include "yportenv.h"
7979 +struct yaffs_linux_context {
7980 + struct list_head context_list; /* List of these we have mounted */
7981 + struct yaffs_dev *dev;
7982 + struct super_block *super;
7983 + struct task_struct *bg_thread; /* Background thread for this device */
7984 + int bg_running;
7985 + struct mutex gross_lock; /* Gross locking mutex*/
7986 + u8 *spare_buffer; /* For mtdif2 use. Don't know the buffer size
7987 + * at compile time so we have to allocate it.
7988 + */
7989 + struct list_head search_contexts;
7990 + struct task_struct *readdir_process;
7991 + unsigned mount_id;
7992 + int dirty;
7995 +#define yaffs_dev_to_lc(dev) ((struct yaffs_linux_context *)((dev)->os_context))
7996 +#define yaffs_dev_to_mtd(dev) ((struct mtd_info *)((dev)->driver_context))
7998 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
7999 +#define WRITE_SIZE_STR "writesize"
8000 +#define WRITE_SIZE(mtd) ((mtd)->writesize)
8001 +#else
8002 +#define WRITE_SIZE_STR "oobblock"
8003 +#define WRITE_SIZE(mtd) ((mtd)->oobblock)
8004 +#endif
8006 +#endif
8007 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_mtdif.c linux-3.18.14/fs/yaffs2/yaffs_mtdif.c
8008 --- linux-3.18.14.orig/fs/yaffs2/yaffs_mtdif.c 1970-01-01 01:00:00.000000000 +0100
8009 +++ linux-3.18.14/fs/yaffs2/yaffs_mtdif.c 2015-06-14 21:23:22.000000000 +0200
8010 @@ -0,0 +1,310 @@
8012 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
8014 + * Copyright (C) 2002-2011 Aleph One Ltd.
8015 + * for Toby Churchill Ltd and Brightstar Engineering
8017 + * Created by Charles Manning <charles@aleph1.co.uk>
8019 + * This program is free software; you can redistribute it and/or modify
8020 + * it under the terms of the GNU General Public License version 2 as
8021 + * published by the Free Software Foundation.
8022 + */
8024 +#include "yportenv.h"
8026 +#include "yaffs_mtdif.h"
8028 +#include "linux/mtd/mtd.h"
8029 +#include "linux/types.h"
8030 +#include "linux/time.h"
8031 +#include "linux/mtd/nand.h"
8032 +#include "linux/kernel.h"
8033 +#include "linux/version.h"
8034 +#include "linux/types.h"
8035 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
8036 +#include "uapi/linux/major.h"
8037 +#endif
8039 +#include "yaffs_trace.h"
8040 +#include "yaffs_guts.h"
8041 +#include "yaffs_linux.h"
8043 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
8044 +#define MTD_OPS_AUTO_OOB MTD_OOB_AUTO
8045 +#endif
8048 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
8049 +#define mtd_erase(m, ei) (m)->erase(m, ei)
8050 +#define mtd_write_oob(m, addr, pops) (m)->write_oob(m, addr, pops)
8051 +#define mtd_read_oob(m, addr, pops) (m)->read_oob(m, addr, pops)
8052 +#define mtd_block_isbad(m, offs) (m)->block_isbad(m, offs)
8053 +#define mtd_block_markbad(m, offs) (m)->block_markbad(m, offs)
8054 +#endif
8058 +int nandmtd_erase_block(struct yaffs_dev *dev, int block_no)
8060 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
8061 + u32 addr =
8062 + ((loff_t) block_no) * dev->param.total_bytes_per_chunk *
8063 + dev->param.chunks_per_block;
8064 + struct erase_info ei;
8065 + int retval = 0;
8067 + ei.mtd = mtd;
8068 + ei.addr = addr;
8069 + ei.len = dev->param.total_bytes_per_chunk * dev->param.chunks_per_block;
8070 + ei.time = 1000;
8071 + ei.retries = 2;
8072 + ei.callback = NULL;
8073 + ei.priv = (u_long) dev;
8075 + retval = mtd_erase(mtd, &ei);
8077 + if (retval == 0)
8078 + return YAFFS_OK;
8080 + return YAFFS_FAIL;
8084 +static int yaffs_mtd_write(struct yaffs_dev *dev, int nand_chunk,
8085 + const u8 *data, int data_len,
8086 + const u8 *oob, int oob_len)
8088 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
8089 + loff_t addr;
8090 + struct mtd_oob_ops ops;
8091 + int retval;
8093 + yaffs_trace(YAFFS_TRACE_MTD,
8094 + "yaffs_mtd_write(%p, %d, %p, %d, %p, %d)\n",
8095 + dev, nand_chunk, data, data_len, oob, oob_len);
8097 + if (!data || !data_len) {
8098 + data = NULL;
8099 + data_len = 0;
8102 + if (!oob || !oob_len) {
8103 + oob = NULL;
8104 + oob_len = 0;
8107 + addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
8108 + memset(&ops, 0, sizeof(ops));
8109 + ops.mode = MTD_OPS_AUTO_OOB;
8110 + ops.len = (data) ? data_len : 0;
8111 + ops.ooblen = oob_len;
8112 + ops.datbuf = (u8 *)data;
8113 + ops.oobbuf = (u8 *)oob;
8115 + retval = mtd_write_oob(mtd, addr, &ops);
8116 + if (retval) {
8117 + yaffs_trace(YAFFS_TRACE_MTD,
8118 + "write_oob failed, chunk %d, mtd error %d",
8119 + nand_chunk, retval);
8121 + return retval ? YAFFS_FAIL : YAFFS_OK;
8124 +static int yaffs_mtd_read(struct yaffs_dev *dev, int nand_chunk,
8125 + u8 *data, int data_len,
8126 + u8 *oob, int oob_len,
8127 + enum yaffs_ecc_result *ecc_result)
8129 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
8130 + loff_t addr;
8131 + struct mtd_oob_ops ops;
8132 + int retval;
8134 + addr = ((loff_t) nand_chunk) * dev->param.total_bytes_per_chunk;
8135 + memset(&ops, 0, sizeof(ops));
8136 + ops.mode = MTD_OPS_AUTO_OOB;
8137 + ops.len = (data) ? data_len : 0;
8138 + ops.ooblen = oob_len;
8139 + ops.datbuf = data;
8140 + ops.oobbuf = oob;
8142 +#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
8143 + /* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
8144 + * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
8145 + */
8146 + ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
8147 +#endif
8148 + /* Read page and oob using MTD.
8149 + * Check status and determine ECC result.
8150 + */
8151 + retval = mtd_read_oob(mtd, addr, &ops);
8152 + if (retval)
8153 + yaffs_trace(YAFFS_TRACE_MTD,
8154 + "read_oob failed, chunk %d, mtd error %d",
8155 + nand_chunk, retval);
8157 + switch (retval) {
8158 + case 0:
8159 + /* no error */
8160 + if(ecc_result)
8161 + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
8162 + break;
8164 + case -EUCLEAN:
8165 + /* MTD's ECC fixed the data */
8166 + if(ecc_result)
8167 + *ecc_result = YAFFS_ECC_RESULT_FIXED;
8168 + dev->n_ecc_fixed++;
8169 + break;
8171 + case -EBADMSG:
8172 + default:
8173 + /* MTD's ECC could not fix the data */
8174 + dev->n_ecc_unfixed++;
8175 + if(ecc_result)
8176 + *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
8177 + return YAFFS_FAIL;
8180 + return YAFFS_OK;
8183 +static int yaffs_mtd_erase(struct yaffs_dev *dev, int block_no)
8185 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
8187 + loff_t addr;
8188 + struct erase_info ei;
8189 + int retval = 0;
8190 + u32 block_size;
8192 + block_size = dev->param.total_bytes_per_chunk *
8193 + dev->param.chunks_per_block;
8194 + addr = ((loff_t) block_no) * block_size;
8196 + ei.mtd = mtd;
8197 + ei.addr = addr;
8198 + ei.len = block_size;
8199 + ei.time = 1000;
8200 + ei.retries = 2;
8201 + ei.callback = NULL;
8202 + ei.priv = (u_long) dev;
8204 + retval = mtd_erase(mtd, &ei);
8206 + if (retval == 0)
8207 + return YAFFS_OK;
8209 + return YAFFS_FAIL;
8212 +static int yaffs_mtd_mark_bad(struct yaffs_dev *dev, int block_no)
8214 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
8215 + int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
8216 + int retval;
8218 + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad", block_no);
8220 + retval = mtd_block_markbad(mtd, (loff_t) blocksize * block_no);
8221 + return (retval) ? YAFFS_FAIL : YAFFS_OK;
8224 +static int yaffs_mtd_check_bad(struct yaffs_dev *dev, int block_no)
8226 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
8227 + int blocksize = dev->param.chunks_per_block * dev->param.total_bytes_per_chunk;
8228 + int retval;
8230 + yaffs_trace(YAFFS_TRACE_MTD, "checking block %d bad", block_no);
8232 + retval = mtd_block_isbad(mtd, (loff_t) blocksize * block_no);
8233 + return (retval) ? YAFFS_FAIL : YAFFS_OK;
8236 +static int yaffs_mtd_initialise(struct yaffs_dev *dev)
8238 + return YAFFS_OK;
8241 +static int yaffs_mtd_deinitialise(struct yaffs_dev *dev)
8243 + return YAFFS_OK;
8247 +void yaffs_mtd_drv_install(struct yaffs_dev *dev)
8249 + struct yaffs_driver *drv = &dev->drv;
8251 + drv->drv_write_chunk_fn = yaffs_mtd_write;
8252 + drv->drv_read_chunk_fn = yaffs_mtd_read;
8253 + drv->drv_erase_fn = yaffs_mtd_erase;
8254 + drv->drv_mark_bad_fn = yaffs_mtd_mark_bad;
8255 + drv->drv_check_bad_fn = yaffs_mtd_check_bad;
8256 + drv->drv_initialise_fn = yaffs_mtd_initialise;
8257 + drv->drv_deinitialise_fn = yaffs_mtd_deinitialise;
8261 +struct mtd_info * yaffs_get_mtd_device(dev_t sdev)
8263 + struct mtd_info *mtd;
8265 + mtd = yaffs_get_mtd_device(sdev);
8267 + /* Check it's an mtd device..... */
8268 + if (MAJOR(sdev) != MTD_BLOCK_MAJOR)
8269 + return NULL; /* This isn't an mtd device */
8271 + /* Check it's NAND */
8272 + if (mtd->type != MTD_NANDFLASH) {
8273 + yaffs_trace(YAFFS_TRACE_ALWAYS,
8274 + "yaffs: MTD device is not NAND it's type %d",
8275 + mtd->type);
8276 + return NULL;
8279 + yaffs_trace(YAFFS_TRACE_OS, " %s %d", WRITE_SIZE_STR, WRITE_SIZE(mtd));
8280 + yaffs_trace(YAFFS_TRACE_OS, " oobsize %d", mtd->oobsize);
8281 + yaffs_trace(YAFFS_TRACE_OS, " erasesize %d", mtd->erasesize);
8282 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
8283 + yaffs_trace(YAFFS_TRACE_OS, " size %u", mtd->size);
8284 +#else
8285 + yaffs_trace(YAFFS_TRACE_OS, " size %lld", mtd->size);
8286 +#endif
8288 + return mtd;
8291 +int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags)
8293 + if (yaffs_version == 2) {
8294 + if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
8295 + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
8296 + !inband_tags) {
8297 + yaffs_trace(YAFFS_TRACE_ALWAYS,
8298 + "MTD device does not have the right page sizes"
8299 + );
8300 + return -1;
8302 + } else {
8303 + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
8304 + mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
8305 + yaffs_trace(YAFFS_TRACE_ALWAYS,
8306 + "MTD device does not support have the right page sizes"
8307 + );
8308 + return -1;
8312 + return 0;
8316 +void yaffs_put_mtd_device(struct mtd_info *mtd)
8318 + if(mtd)
8319 + put_mtd_device(mtd);
8321 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_mtdif.h linux-3.18.14/fs/yaffs2/yaffs_mtdif.h
8322 --- linux-3.18.14.orig/fs/yaffs2/yaffs_mtdif.h 1970-01-01 01:00:00.000000000 +0100
8323 +++ linux-3.18.14/fs/yaffs2/yaffs_mtdif.h 2015-06-14 21:23:22.000000000 +0200
8324 @@ -0,0 +1,25 @@
8326 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
8328 + * Copyright (C) 2002-2011 Aleph One Ltd.
8329 + * for Toby Churchill Ltd and Brightstar Engineering
8331 + * Created by Charles Manning <charles@aleph1.co.uk>
8333 + * This program is free software; you can redistribute it and/or modify
8334 + * it under the terms of the GNU Lesser General Public License version 2.1 as
8335 + * published by the Free Software Foundation.
8337 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
8338 + */
8340 +#ifndef __YAFFS_MTDIF_H__
8341 +#define __YAFFS_MTDIF_H__
8343 +#include "yaffs_guts.h"
8345 +void yaffs_mtd_drv_install(struct yaffs_dev *dev);
8346 +struct mtd_info * yaffs_get_mtd_device(dev_t sdev);
8347 +void yaffs_put_mtd_device(struct mtd_info *mtd);
8348 +int yaffs_verify_mtd(struct mtd_info *mtd, int yaffs_version, int inband_tags);
8349 +#endif
8350 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_nameval.c linux-3.18.14/fs/yaffs2/yaffs_nameval.c
8351 --- linux-3.18.14.orig/fs/yaffs2/yaffs_nameval.c 1970-01-01 01:00:00.000000000 +0100
8352 +++ linux-3.18.14/fs/yaffs2/yaffs_nameval.c 2015-06-14 21:23:22.000000000 +0200
8353 @@ -0,0 +1,208 @@
8355 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
8357 + * Copyright (C) 2002-2011 Aleph One Ltd.
8358 + * for Toby Churchill Ltd and Brightstar Engineering
8360 + * Created by Charles Manning <charles@aleph1.co.uk>
8362 + * This program is free software; you can redistribute it and/or modify
8363 + * it under the terms of the GNU General Public License version 2 as
8364 + * published by the Free Software Foundation.
8365 + */
8368 + * This simple implementation of a name-value store assumes a small number of
8369 +* values and fits into a small finite buffer.
8371 + * Each attribute is stored as a record:
8372 + * sizeof(int) bytes record size.
8373 + * strnlen+1 bytes name null terminated.
8374 + * nbytes value.
8375 + * ----------
8376 + * total size stored in record size
8378 + * This code has not been tested with unicode yet.
8379 + */
8381 +#include "yaffs_nameval.h"
8383 +#include "yportenv.h"
8385 +static int nval_find(const char *xb, int xb_size, const YCHAR *name,
8386 + int *exist_size)
8388 + int pos = 0;
8389 + int size;
8391 + memcpy(&size, xb, sizeof(int));
8392 + while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
8393 + if (!strncmp((YCHAR *) (xb + pos + sizeof(int)),
8394 + name, size)) {
8395 + if (exist_size)
8396 + *exist_size = size;
8397 + return pos;
8399 + pos += size;
8400 + if (pos < xb_size - sizeof(int))
8401 + memcpy(&size, xb + pos, sizeof(int));
8402 + else
8403 + size = 0;
8405 + if (exist_size)
8406 + *exist_size = 0;
8407 + return -ENODATA;
8410 +static int nval_used(const char *xb, int xb_size)
8412 + int pos = 0;
8413 + int size;
8415 + memcpy(&size, xb + pos, sizeof(int));
8416 + while (size > 0 && (size < xb_size) && (pos + size < xb_size)) {
8417 + pos += size;
8418 + if (pos < xb_size - sizeof(int))
8419 + memcpy(&size, xb + pos, sizeof(int));
8420 + else
8421 + size = 0;
8423 + return pos;
8426 +int nval_del(char *xb, int xb_size, const YCHAR *name)
8428 + int pos = nval_find(xb, xb_size, name, NULL);
8429 + int size;
8431 + if (pos < 0 || pos >= xb_size)
8432 + return -ENODATA;
8434 + /* Find size, shift rest over this record,
8435 + * then zero out the rest of buffer */
8436 + memcpy(&size, xb + pos, sizeof(int));
8437 + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size));
8438 + memset(xb + (xb_size - size), 0, size);
8439 + return 0;
8442 +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf,
8443 + int bsize, int flags)
8445 + int pos;
8446 + int namelen = strnlen(name, xb_size);
8447 + int reclen;
8448 + int size_exist = 0;
8449 + int space;
8450 + int start;
8452 + pos = nval_find(xb, xb_size, name, &size_exist);
8454 + if (flags & XATTR_CREATE && pos >= 0)
8455 + return -EEXIST;
8456 + if (flags & XATTR_REPLACE && pos < 0)
8457 + return -ENODATA;
8459 + start = nval_used(xb, xb_size);
8460 + space = xb_size - start + size_exist;
8462 + reclen = (sizeof(int) + namelen + 1 + bsize);
8464 + if (reclen > space)
8465 + return -ENOSPC;
8467 + if (pos >= 0) {
8468 + nval_del(xb, xb_size, name);
8469 + start = nval_used(xb, xb_size);
8472 + pos = start;
8474 + memcpy(xb + pos, &reclen, sizeof(int));
8475 + pos += sizeof(int);
8476 + strncpy((YCHAR *) (xb + pos), name, reclen);
8477 + pos += (namelen + 1);
8478 + memcpy(xb + pos, buf, bsize);
8479 + return 0;
8482 +int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
8483 + int bsize)
8485 + int pos = nval_find(xb, xb_size, name, NULL);
8486 + int size;
8488 + if (pos >= 0 && pos < xb_size) {
8490 + memcpy(&size, xb + pos, sizeof(int));
8491 + pos += sizeof(int); /* advance past record length */
8492 + size -= sizeof(int);
8494 + /* Advance over name string */
8495 + while (xb[pos] && size > 0 && pos < xb_size) {
8496 + pos++;
8497 + size--;
8499 + /*Advance over NUL */
8500 + pos++;
8501 + size--;
8503 + /* If bsize is zero then this is a size query.
8504 + * Return the size, but don't copy.
8505 + */
8506 + if (!bsize)
8507 + return size;
8509 + if (size <= bsize) {
8510 + memcpy(buf, xb + pos, size);
8511 + return size;
8514 + if (pos >= 0)
8515 + return -ERANGE;
8517 + return -ENODATA;
8520 +int nval_list(const char *xb, int xb_size, char *buf, int bsize)
8522 + int pos = 0;
8523 + int size;
8524 + int name_len;
8525 + int ncopied = 0;
8526 + int filled = 0;
8528 + memcpy(&size, xb + pos, sizeof(int));
8529 + while (size > sizeof(int) &&
8530 + size <= xb_size &&
8531 + (pos + size) < xb_size &&
8532 + !filled) {
8533 + pos += sizeof(int);
8534 + size -= sizeof(int);
8535 + name_len = strnlen((YCHAR *) (xb + pos), size);
8536 + if (ncopied + name_len + 1 < bsize) {
8537 + memcpy(buf, xb + pos, name_len * sizeof(YCHAR));
8538 + buf += name_len;
8539 + *buf = '\0';
8540 + buf++;
8541 + if (sizeof(YCHAR) > 1) {
8542 + *buf = '\0';
8543 + buf++;
8545 + ncopied += (name_len + 1);
8546 + } else {
8547 + filled = 1;
8549 + pos += size;
8550 + if (pos < xb_size - sizeof(int))
8551 + memcpy(&size, xb + pos, sizeof(int));
8552 + else
8553 + size = 0;
8555 + return ncopied;
8558 +int nval_hasvalues(const char *xb, int xb_size)
8560 + return nval_used(xb, xb_size) > 0;
8562 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_nameval.h linux-3.18.14/fs/yaffs2/yaffs_nameval.h
8563 --- linux-3.18.14.orig/fs/yaffs2/yaffs_nameval.h 1970-01-01 01:00:00.000000000 +0100
8564 +++ linux-3.18.14/fs/yaffs2/yaffs_nameval.h 2015-06-14 21:23:22.000000000 +0200
8565 @@ -0,0 +1,28 @@
8567 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
8569 + * Copyright (C) 2002-2011 Aleph One Ltd.
8570 + * for Toby Churchill Ltd and Brightstar Engineering
8572 + * Created by Charles Manning <charles@aleph1.co.uk>
8574 + * This program is free software; you can redistribute it and/or modify
8575 + * it under the terms of the GNU Lesser General Public License version 2.1 as
8576 + * published by the Free Software Foundation.
8578 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
8579 + */
8581 +#ifndef __NAMEVAL_H__
8582 +#define __NAMEVAL_H__
8584 +#include "yportenv.h"
8586 +int nval_del(char *xb, int xb_size, const YCHAR * name);
8587 +int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf,
8588 + int bsize, int flags);
8589 +int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf,
8590 + int bsize);
8591 +int nval_list(const char *xb, int xb_size, char *buf, int bsize);
8592 +int nval_hasvalues(const char *xb, int xb_size);
8593 +#endif
8594 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_nand.c linux-3.18.14/fs/yaffs2/yaffs_nand.c
8595 --- linux-3.18.14.orig/fs/yaffs2/yaffs_nand.c 1970-01-01 01:00:00.000000000 +0100
8596 +++ linux-3.18.14/fs/yaffs2/yaffs_nand.c 2015-06-14 21:23:22.000000000 +0200
8597 @@ -0,0 +1,122 @@
8599 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
8601 + * Copyright (C) 2002-2011 Aleph One Ltd.
8602 + * for Toby Churchill Ltd and Brightstar Engineering
8604 + * Created by Charles Manning <charles@aleph1.co.uk>
8606 + * This program is free software; you can redistribute it and/or modify
8607 + * it under the terms of the GNU General Public License version 2 as
8608 + * published by the Free Software Foundation.
8609 + */
8611 +#include "yaffs_nand.h"
8612 +#include "yaffs_tagscompat.h"
8614 +#include "yaffs_getblockinfo.h"
8615 +#include "yaffs_summary.h"
8617 +static int apply_chunk_offset(struct yaffs_dev *dev, int chunk)
8619 + return chunk - dev->chunk_offset;
8622 +int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
8623 + u8 *buffer, struct yaffs_ext_tags *tags)
8625 + int result;
8626 + struct yaffs_ext_tags local_tags;
8627 + int flash_chunk = apply_chunk_offset(dev, nand_chunk);
8629 + dev->n_page_reads++;
8631 + /* If there are no tags provided use local tags. */
8632 + if (!tags)
8633 + tags = &local_tags;
8635 + result = dev->tagger.read_chunk_tags_fn(dev, flash_chunk, buffer, tags);
8636 + if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) {
8638 + struct yaffs_block_info *bi;
8639 + bi = yaffs_get_block_info(dev,
8640 + nand_chunk /
8641 + dev->param.chunks_per_block);
8642 + yaffs_handle_chunk_error(dev, bi);
8644 + return result;
8647 +int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
8648 + int nand_chunk,
8649 + const u8 *buffer, struct yaffs_ext_tags *tags)
8651 + int result;
8652 + int flash_chunk = apply_chunk_offset(dev, nand_chunk);
8654 + dev->n_page_writes++;
8656 + if (!tags) {
8657 + yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags");
8658 + BUG();
8659 + return YAFFS_FAIL;
8662 + tags->seq_number = dev->seq_number;
8663 + tags->chunk_used = 1;
8664 + yaffs_trace(YAFFS_TRACE_WRITE,
8665 + "Writing chunk %d tags %d %d",
8666 + nand_chunk, tags->obj_id, tags->chunk_id);
8668 + result = dev->tagger.write_chunk_tags_fn(dev, flash_chunk,
8669 + buffer, tags);
8671 + yaffs_summary_add(dev, tags, nand_chunk);
8673 + return result;
8676 +int yaffs_mark_bad(struct yaffs_dev *dev, int block_no)
8678 + block_no -= dev->block_offset;
8679 + dev->n_bad_markings++;
8681 + if (dev->param.disable_bad_block_marking)
8682 + return YAFFS_OK;
8684 + return dev->tagger.mark_bad_fn(dev, block_no);
8688 +int yaffs_query_init_block_state(struct yaffs_dev *dev,
8689 + int block_no,
8690 + enum yaffs_block_state *state,
8691 + u32 *seq_number)
8693 + block_no -= dev->block_offset;
8694 + return dev->tagger.query_block_fn(dev, block_no, state, seq_number);
8697 +int yaffs_erase_block(struct yaffs_dev *dev, int block_no)
8699 + int result;
8701 + block_no -= dev->block_offset;
8702 + dev->n_erasures++;
8703 + result = dev->drv.drv_erase_fn(dev, block_no);
8704 + return result;
8707 +int yaffs_init_nand(struct yaffs_dev *dev)
8709 + if (dev->drv.drv_initialise_fn)
8710 + return dev->drv.drv_initialise_fn(dev);
8711 + return YAFFS_OK;
8714 +int yaffs_deinit_nand(struct yaffs_dev *dev)
8716 + if (dev->drv.drv_deinitialise_fn)
8717 + return dev->drv.drv_deinitialise_fn(dev);
8718 + return YAFFS_OK;
8720 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_nand.h linux-3.18.14/fs/yaffs2/yaffs_nand.h
8721 --- linux-3.18.14.orig/fs/yaffs2/yaffs_nand.h 1970-01-01 01:00:00.000000000 +0100
8722 +++ linux-3.18.14/fs/yaffs2/yaffs_nand.h 2015-06-14 21:23:22.000000000 +0200
8723 @@ -0,0 +1,39 @@
8725 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
8727 + * Copyright (C) 2002-2011 Aleph One Ltd.
8728 + * for Toby Churchill Ltd and Brightstar Engineering
8730 + * Created by Charles Manning <charles@aleph1.co.uk>
8732 + * This program is free software; you can redistribute it and/or modify
8733 + * it under the terms of the GNU Lesser General Public License version 2.1 as
8734 + * published by the Free Software Foundation.
8736 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
8737 + */
8739 +#ifndef __YAFFS_NAND_H__
8740 +#define __YAFFS_NAND_H__
8741 +#include "yaffs_guts.h"
8743 +int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk,
8744 + u8 *buffer, struct yaffs_ext_tags *tags);
8746 +int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev,
8747 + int nand_chunk,
8748 + const u8 *buffer, struct yaffs_ext_tags *tags);
8750 +int yaffs_mark_bad(struct yaffs_dev *dev, int block_no);
8752 +int yaffs_query_init_block_state(struct yaffs_dev *dev,
8753 + int block_no,
8754 + enum yaffs_block_state *state,
8755 + unsigned *seq_number);
8757 +int yaffs_erase_block(struct yaffs_dev *dev, int flash_block);
8759 +int yaffs_init_nand(struct yaffs_dev *dev);
8760 +int yaffs_deinit_nand(struct yaffs_dev *dev);
8762 +#endif
8763 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_packedtags1.c linux-3.18.14/fs/yaffs2/yaffs_packedtags1.c
8764 --- linux-3.18.14.orig/fs/yaffs2/yaffs_packedtags1.c 1970-01-01 01:00:00.000000000 +0100
8765 +++ linux-3.18.14/fs/yaffs2/yaffs_packedtags1.c 2015-06-14 21:23:22.000000000 +0200
8766 @@ -0,0 +1,56 @@
8768 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
8770 + * Copyright (C) 2002-2011 Aleph One Ltd.
8771 + * for Toby Churchill Ltd and Brightstar Engineering
8773 + * Created by Charles Manning <charles@aleph1.co.uk>
8775 + * This program is free software; you can redistribute it and/or modify
8776 + * it under the terms of the GNU General Public License version 2 as
8777 + * published by the Free Software Foundation.
8778 + */
8780 +#include "yaffs_packedtags1.h"
8781 +#include "yportenv.h"
8783 +static const u8 all_ff[20] = {
8784 + 0xff, 0xff, 0xff, 0xff,
8785 + 0xff, 0xff, 0xff, 0xff,
8786 + 0xff, 0xff, 0xff, 0xff,
8787 + 0xff, 0xff, 0xff, 0xff,
8788 + 0xff, 0xff, 0xff, 0xff
8791 +void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
8792 + const struct yaffs_ext_tags *t)
8794 + pt->chunk_id = t->chunk_id;
8795 + pt->serial_number = t->serial_number;
8796 + pt->n_bytes = t->n_bytes;
8797 + pt->obj_id = t->obj_id;
8798 + pt->ecc = 0;
8799 + pt->deleted = (t->is_deleted) ? 0 : 1;
8800 + pt->unused_stuff = 0;
8801 + pt->should_be_ff = 0xffffffff;
8804 +void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
8805 + const struct yaffs_packed_tags1 *pt)
8808 + if (memcmp(all_ff, pt, sizeof(struct yaffs_packed_tags1))) {
8809 + t->block_bad = 0;
8810 + if (pt->should_be_ff != 0xffffffff)
8811 + t->block_bad = 1;
8812 + t->chunk_used = 1;
8813 + t->obj_id = pt->obj_id;
8814 + t->chunk_id = pt->chunk_id;
8815 + t->n_bytes = pt->n_bytes;
8816 + t->ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
8817 + t->is_deleted = (pt->deleted) ? 0 : 1;
8818 + t->serial_number = pt->serial_number;
8819 + } else {
8820 + memset(t, 0, sizeof(struct yaffs_ext_tags));
8823 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_packedtags1.h linux-3.18.14/fs/yaffs2/yaffs_packedtags1.h
8824 --- linux-3.18.14.orig/fs/yaffs2/yaffs_packedtags1.h 1970-01-01 01:00:00.000000000 +0100
8825 +++ linux-3.18.14/fs/yaffs2/yaffs_packedtags1.h 2015-06-14 21:23:22.000000000 +0200
8826 @@ -0,0 +1,39 @@
8828 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
8830 + * Copyright (C) 2002-2011 Aleph One Ltd.
8831 + * for Toby Churchill Ltd and Brightstar Engineering
8833 + * Created by Charles Manning <charles@aleph1.co.uk>
8835 + * This program is free software; you can redistribute it and/or modify
8836 + * it under the terms of the GNU Lesser General Public License version 2.1 as
8837 + * published by the Free Software Foundation.
8839 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
8840 + */
8842 +/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
8844 +#ifndef __YAFFS_PACKEDTAGS1_H__
8845 +#define __YAFFS_PACKEDTAGS1_H__
8847 +#include "yaffs_guts.h"
8849 +struct yaffs_packed_tags1 {
8850 + u32 chunk_id:20;
8851 + u32 serial_number:2;
8852 + u32 n_bytes:10;
8853 + u32 obj_id:18;
8854 + u32 ecc:12;
8855 + u32 deleted:1;
8856 + u32 unused_stuff:1;
8857 + unsigned should_be_ff;
8861 +void yaffs_pack_tags1(struct yaffs_packed_tags1 *pt,
8862 + const struct yaffs_ext_tags *t);
8863 +void yaffs_unpack_tags1(struct yaffs_ext_tags *t,
8864 + const struct yaffs_packed_tags1 *pt);
8865 +#endif
8866 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_packedtags2.c linux-3.18.14/fs/yaffs2/yaffs_packedtags2.c
8867 --- linux-3.18.14.orig/fs/yaffs2/yaffs_packedtags2.c 1970-01-01 01:00:00.000000000 +0100
8868 +++ linux-3.18.14/fs/yaffs2/yaffs_packedtags2.c 2015-06-14 21:23:22.000000000 +0200
8869 @@ -0,0 +1,197 @@
8871 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
8873 + * Copyright (C) 2002-2011 Aleph One Ltd.
8874 + * for Toby Churchill Ltd and Brightstar Engineering
8876 + * Created by Charles Manning <charles@aleph1.co.uk>
8878 + * This program is free software; you can redistribute it and/or modify
8879 + * it under the terms of the GNU General Public License version 2 as
8880 + * published by the Free Software Foundation.
8881 + */
8883 +#include "yaffs_packedtags2.h"
8884 +#include "yportenv.h"
8885 +#include "yaffs_trace.h"
8887 +/* This code packs a set of extended tags into a binary structure for
8888 + * NAND storage
8889 + */
8891 +/* Some of the information is "extra" struff which can be packed in to
8892 + * speed scanning
8893 + * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
8894 + */
8896 +/* Extra flags applied to chunk_id */
8898 +#define EXTRA_HEADER_INFO_FLAG 0x80000000
8899 +#define EXTRA_SHRINK_FLAG 0x40000000
8900 +#define EXTRA_SHADOWS_FLAG 0x20000000
8901 +#define EXTRA_SPARE_FLAGS 0x10000000
8903 +#define ALL_EXTRA_FLAGS 0xf0000000
8905 +/* Also, the top 4 bits of the object Id are set to the object type. */
8906 +#define EXTRA_OBJECT_TYPE_SHIFT (28)
8907 +#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
8909 +static void yaffs_dump_packed_tags2_tags_only(
8910 + const struct yaffs_packed_tags2_tags_only *ptt)
8912 + yaffs_trace(YAFFS_TRACE_MTD,
8913 + "packed tags obj %d chunk %d byte %d seq %d",
8914 + ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
8917 +static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
8919 + yaffs_dump_packed_tags2_tags_only(&pt->t);
8922 +static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
8924 + yaffs_trace(YAFFS_TRACE_MTD,
8925 + "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
8926 + t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
8927 + t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
8928 + t->seq_number);
8932 +static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
8934 + if (t->chunk_id != 0 || !t->extra_available)
8935 + return 0;
8937 + /* Check if the file size is too long to store */
8938 + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
8939 + (t->extra_file_size >> 31) != 0)
8940 + return 0;
8941 + return 1;
8944 +void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
8945 + const struct yaffs_ext_tags *t)
8947 + ptt->chunk_id = t->chunk_id;
8948 + ptt->seq_number = t->seq_number;
8949 + ptt->n_bytes = t->n_bytes;
8950 + ptt->obj_id = t->obj_id;
8952 + /* Only store extra tags for object headers.
8953 + * If it is a file then only store if the file size is short\
8954 + * enough to fit.
8955 + */
8956 + if (yaffs_check_tags_extra_packable(t)) {
8957 + /* Store the extra header info instead */
8958 + /* We save the parent object in the chunk_id */
8959 + ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
8960 + if (t->extra_is_shrink)
8961 + ptt->chunk_id |= EXTRA_SHRINK_FLAG;
8962 + if (t->extra_shadows)
8963 + ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
8965 + ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
8966 + ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
8968 + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
8969 + ptt->n_bytes = t->extra_equiv_id;
8970 + else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
8971 + ptt->n_bytes = (unsigned) t->extra_file_size;
8972 + else
8973 + ptt->n_bytes = 0;
8976 + yaffs_dump_packed_tags2_tags_only(ptt);
8977 + yaffs_dump_tags2(t);
8980 +void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
8981 + const struct yaffs_ext_tags *t, int tags_ecc)
8983 + yaffs_pack_tags2_tags_only(&pt->t, t);
8985 + if (tags_ecc)
8986 + yaffs_ecc_calc_other((unsigned char *)&pt->t,
8987 + sizeof(struct yaffs_packed_tags2_tags_only),
8988 + &pt->ecc);
8991 +void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
8992 + struct yaffs_packed_tags2_tags_only *ptt)
8994 + memset(t, 0, sizeof(struct yaffs_ext_tags));
8996 + if (ptt->seq_number == 0xffffffff)
8997 + return;
8999 + t->block_bad = 0;
9000 + t->chunk_used = 1;
9001 + t->obj_id = ptt->obj_id;
9002 + t->chunk_id = ptt->chunk_id;
9003 + t->n_bytes = ptt->n_bytes;
9004 + t->is_deleted = 0;
9005 + t->serial_number = 0;
9006 + t->seq_number = ptt->seq_number;
9008 + /* Do extra header info stuff */
9009 + if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
9010 + t->chunk_id = 0;
9011 + t->n_bytes = 0;
9013 + t->extra_available = 1;
9014 + t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
9015 + t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
9016 + t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
9017 + t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
9018 + t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
9020 + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
9021 + t->extra_equiv_id = ptt->n_bytes;
9022 + else
9023 + t->extra_file_size = ptt->n_bytes;
9025 + yaffs_dump_packed_tags2_tags_only(ptt);
9026 + yaffs_dump_tags2(t);
9029 +void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
9030 + int tags_ecc)
9032 + enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
9034 + if (pt->t.seq_number != 0xffffffff && tags_ecc) {
9035 + /* Chunk is in use and we need to do ECC */
9037 + struct yaffs_ecc_other ecc;
9038 + int result;
9039 + yaffs_ecc_calc_other((unsigned char *)&pt->t,
9040 + sizeof(struct yaffs_packed_tags2_tags_only),
9041 + &ecc);
9042 + result =
9043 + yaffs_ecc_correct_other((unsigned char *)&pt->t,
9044 + sizeof(struct yaffs_packed_tags2_tags_only),
9045 + &pt->ecc, &ecc);
9046 + switch (result) {
9047 + case 0:
9048 + ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
9049 + break;
9050 + case 1:
9051 + ecc_result = YAFFS_ECC_RESULT_FIXED;
9052 + break;
9053 + case -1:
9054 + ecc_result = YAFFS_ECC_RESULT_UNFIXED;
9055 + break;
9056 + default:
9057 + ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
9060 + yaffs_unpack_tags2_tags_only(t, &pt->t);
9062 + t->ecc_result = ecc_result;
9064 + yaffs_dump_packed_tags2(pt);
9065 + yaffs_dump_tags2(t);
9067 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_packedtags2.h linux-3.18.14/fs/yaffs2/yaffs_packedtags2.h
9068 --- linux-3.18.14.orig/fs/yaffs2/yaffs_packedtags2.h 1970-01-01 01:00:00.000000000 +0100
9069 +++ linux-3.18.14/fs/yaffs2/yaffs_packedtags2.h 2015-06-14 21:23:22.000000000 +0200
9070 @@ -0,0 +1,47 @@
9072 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
9074 + * Copyright (C) 2002-2011 Aleph One Ltd.
9075 + * for Toby Churchill Ltd and Brightstar Engineering
9077 + * Created by Charles Manning <charles@aleph1.co.uk>
9079 + * This program is free software; you can redistribute it and/or modify
9080 + * it under the terms of the GNU Lesser General Public License version 2.1 as
9081 + * published by the Free Software Foundation.
9083 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
9084 + */
9086 +/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
9088 +#ifndef __YAFFS_PACKEDTAGS2_H__
9089 +#define __YAFFS_PACKEDTAGS2_H__
9091 +#include "yaffs_guts.h"
9092 +#include "yaffs_ecc.h"
9094 +struct yaffs_packed_tags2_tags_only {
9095 + unsigned seq_number;
9096 + unsigned obj_id;
9097 + unsigned chunk_id;
9098 + unsigned n_bytes;
9101 +struct yaffs_packed_tags2 {
9102 + struct yaffs_packed_tags2_tags_only t;
9103 + struct yaffs_ecc_other ecc;
9106 +/* Full packed tags with ECC, used for oob tags */
9107 +void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
9108 + const struct yaffs_ext_tags *t, int tags_ecc);
9109 +void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
9110 + int tags_ecc);
9112 +/* Only the tags part (no ECC for use with inband tags */
9113 +void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt,
9114 + const struct yaffs_ext_tags *t);
9115 +void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
9116 + struct yaffs_packed_tags2_tags_only *pt);
9117 +#endif
9118 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_summary.c linux-3.18.14/fs/yaffs2/yaffs_summary.c
9119 --- linux-3.18.14.orig/fs/yaffs2/yaffs_summary.c 1970-01-01 01:00:00.000000000 +0100
9120 +++ linux-3.18.14/fs/yaffs2/yaffs_summary.c 2015-06-14 21:23:22.000000000 +0200
9121 @@ -0,0 +1,312 @@
9123 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
9125 + * Copyright (C) 2002-2011 Aleph One Ltd.
9126 + * for Toby Churchill Ltd and Brightstar Engineering
9128 + * Created by Charles Manning <charles@aleph1.co.uk>
9130 + * This program is free software; you can redistribute it and/or modify
9131 + * it under the terms of the GNU General Public License version 2 as
9132 + * published by the Free Software Foundation.
9133 + */
9135 +/* Summaries write the useful part of the tags for the chunks in a block into an
9136 + * an array which is written to the last n chunks of the block.
9137 + * Reading the summaries gives all the tags for the block in one read. Much
9138 + * faster.
9140 + * Chunks holding summaries are marked with tags making it look like
9141 + * they are part of a fake file.
9143 + * The summary could also be used during gc.
9145 + */
9147 +#include "yaffs_summary.h"
9148 +#include "yaffs_packedtags2.h"
9149 +#include "yaffs_nand.h"
9150 +#include "yaffs_getblockinfo.h"
9151 +#include "yaffs_bitmap.h"
9154 + * The summary is built up in an array of summary tags.
9155 + * This gets written to the last one or two (maybe more) chunks in a block.
9156 + * A summary header is written as the first part of each chunk of summary data.
9157 + * The summary header must match or the summary is rejected.
9158 + */
9160 +/* Summary tags don't need the sequence number because that is redundant. */
9161 +struct yaffs_summary_tags {
9162 + unsigned obj_id;
9163 + unsigned chunk_id;
9164 + unsigned n_bytes;
9167 +/* Summary header */
9168 +struct yaffs_summary_header {
9169 + unsigned version; /* Must match current version */
9170 + unsigned block; /* Must be this block */
9171 + unsigned seq; /* Must be this sequence number */
9172 + unsigned sum; /* Just add up all the bytes in the tags */
9176 +static void yaffs_summary_clear(struct yaffs_dev *dev)
9178 + if (!dev->sum_tags)
9179 + return;
9180 + memset(dev->sum_tags, 0, dev->chunks_per_summary *
9181 + sizeof(struct yaffs_summary_tags));
9185 +void yaffs_summary_deinit(struct yaffs_dev *dev)
9187 + kfree(dev->sum_tags);
9188 + dev->sum_tags = NULL;
9189 + kfree(dev->gc_sum_tags);
9190 + dev->gc_sum_tags = NULL;
9191 + dev->chunks_per_summary = 0;
9194 +int yaffs_summary_init(struct yaffs_dev *dev)
9196 + int sum_bytes;
9197 + int chunks_used; /* Number of chunks used by summary */
9198 + int sum_tags_bytes;
9200 + sum_bytes = dev->param.chunks_per_block *
9201 + sizeof(struct yaffs_summary_tags);
9203 + chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/
9204 + (dev->data_bytes_per_chunk -
9205 + sizeof(struct yaffs_summary_header));
9207 + dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used;
9208 + sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
9209 + dev->chunks_per_summary;
9210 + dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
9211 + dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS);
9212 + if (!dev->sum_tags || !dev->gc_sum_tags) {
9213 + yaffs_summary_deinit(dev);
9214 + return YAFFS_FAIL;
9217 + yaffs_summary_clear(dev);
9219 + return YAFFS_OK;
9222 +static unsigned yaffs_summary_sum(struct yaffs_dev *dev)
9224 + u8 *sum_buffer = (u8 *)dev->sum_tags;
9225 + int i;
9226 + unsigned sum = 0;
9228 + i = sizeof(struct yaffs_summary_tags) *
9229 + dev->chunks_per_summary;
9230 + while (i > 0) {
9231 + sum += *sum_buffer;
9232 + sum_buffer++;
9233 + i--;
9236 + return sum;
9239 +static int yaffs_summary_write(struct yaffs_dev *dev, int blk)
9241 + struct yaffs_ext_tags tags;
9242 + u8 *buffer;
9243 + u8 *sum_buffer = (u8 *)dev->sum_tags;
9244 + int n_bytes;
9245 + int chunk_in_nand;
9246 + int chunk_in_block;
9247 + int result;
9248 + int this_tx;
9249 + struct yaffs_summary_header hdr;
9250 + int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
9251 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
9253 + buffer = yaffs_get_temp_buffer(dev);
9254 + n_bytes = sizeof(struct yaffs_summary_tags) *
9255 + dev->chunks_per_summary;
9256 + memset(&tags, 0, sizeof(struct yaffs_ext_tags));
9257 + tags.obj_id = YAFFS_OBJECTID_SUMMARY;
9258 + tags.chunk_id = 1;
9259 + chunk_in_block = dev->chunks_per_summary;
9260 + chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block +
9261 + dev->chunks_per_summary;
9262 + hdr.version = YAFFS_SUMMARY_VERSION;
9263 + hdr.block = blk;
9264 + hdr.seq = bi->seq_number;
9265 + hdr.sum = yaffs_summary_sum(dev);
9267 + do {
9268 + this_tx = n_bytes;
9269 + if (this_tx > sum_bytes_per_chunk)
9270 + this_tx = sum_bytes_per_chunk;
9271 + memcpy(buffer, &hdr, sizeof(hdr));
9272 + memcpy(buffer + sizeof(hdr), sum_buffer, this_tx);
9273 + tags.n_bytes = this_tx + sizeof(hdr);
9274 + result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand,
9275 + buffer, &tags);
9277 + if (result != YAFFS_OK)
9278 + break;
9279 + yaffs_set_chunk_bit(dev, blk, chunk_in_block);
9280 + bi->pages_in_use++;
9281 + dev->n_free_chunks--;
9283 + n_bytes -= this_tx;
9284 + sum_buffer += this_tx;
9285 + chunk_in_nand++;
9286 + chunk_in_block++;
9287 + tags.chunk_id++;
9288 + } while (result == YAFFS_OK && n_bytes > 0);
9289 + yaffs_release_temp_buffer(dev, buffer);
9292 + if (result == YAFFS_OK)
9293 + bi->has_summary = 1;
9296 + return result;
9299 +int yaffs_summary_read(struct yaffs_dev *dev,
9300 + struct yaffs_summary_tags *st,
9301 + int blk)
9303 + struct yaffs_ext_tags tags;
9304 + u8 *buffer;
9305 + u8 *sum_buffer = (u8 *)st;
9306 + int n_bytes;
9307 + int chunk_id;
9308 + int chunk_in_nand;
9309 + int chunk_in_block;
9310 + int result;
9311 + int this_tx;
9312 + struct yaffs_summary_header hdr;
9313 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
9314 + int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr);
9315 + int sum_tags_bytes;
9317 + sum_tags_bytes = sizeof(struct yaffs_summary_tags) *
9318 + dev->chunks_per_summary;
9319 + buffer = yaffs_get_temp_buffer(dev);
9320 + n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary;
9321 + chunk_in_block = dev->chunks_per_summary;
9322 + chunk_in_nand = blk * dev->param.chunks_per_block +
9323 + dev->chunks_per_summary;
9324 + chunk_id = 1;
9325 + do {
9326 + this_tx = n_bytes;
9327 + if (this_tx > sum_bytes_per_chunk)
9328 + this_tx = sum_bytes_per_chunk;
9329 + result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand,
9330 + buffer, &tags);
9332 + if (tags.chunk_id != chunk_id ||
9333 + tags.obj_id != YAFFS_OBJECTID_SUMMARY ||
9334 + tags.chunk_used == 0 ||
9335 + tags.ecc_result > YAFFS_ECC_RESULT_FIXED ||
9336 + tags.n_bytes != (this_tx + sizeof(hdr)))
9337 + result = YAFFS_FAIL;
9338 + if (result != YAFFS_OK)
9339 + break;
9341 + if (st == dev->sum_tags) {
9342 + /* If we're scanning then update the block info */
9343 + yaffs_set_chunk_bit(dev, blk, chunk_in_block);
9344 + bi->pages_in_use++;
9346 + memcpy(&hdr, buffer, sizeof(hdr));
9347 + memcpy(sum_buffer, buffer + sizeof(hdr), this_tx);
9348 + n_bytes -= this_tx;
9349 + sum_buffer += this_tx;
9350 + chunk_in_nand++;
9351 + chunk_in_block++;
9352 + chunk_id++;
9353 + } while (result == YAFFS_OK && n_bytes > 0);
9354 + yaffs_release_temp_buffer(dev, buffer);
9356 + if (result == YAFFS_OK) {
9357 + /* Verify header */
9358 + if (hdr.version != YAFFS_SUMMARY_VERSION ||
9359 + hdr.seq != bi->seq_number ||
9360 + hdr.sum != yaffs_summary_sum(dev))
9361 + result = YAFFS_FAIL;
9364 + if (st == dev->sum_tags && result == YAFFS_OK)
9365 + bi->has_summary = 1;
9367 + return result;
9370 +int yaffs_summary_add(struct yaffs_dev *dev,
9371 + struct yaffs_ext_tags *tags,
9372 + int chunk_in_nand)
9374 + struct yaffs_packed_tags2_tags_only tags_only;
9375 + struct yaffs_summary_tags *sum_tags;
9376 + int block_in_nand = chunk_in_nand / dev->param.chunks_per_block;
9377 + int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block;
9379 + if (!dev->sum_tags)
9380 + return YAFFS_OK;
9382 + if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
9383 + yaffs_pack_tags2_tags_only(&tags_only, tags);
9384 + sum_tags = &dev->sum_tags[chunk_in_block];
9385 + sum_tags->chunk_id = tags_only.chunk_id;
9386 + sum_tags->n_bytes = tags_only.n_bytes;
9387 + sum_tags->obj_id = tags_only.obj_id;
9389 + if (chunk_in_block == dev->chunks_per_summary - 1) {
9390 + /* Time to write out the summary */
9391 + yaffs_summary_write(dev, block_in_nand);
9392 + yaffs_summary_clear(dev);
9393 + yaffs_skip_rest_of_block(dev);
9396 + return YAFFS_OK;
9399 +int yaffs_summary_fetch(struct yaffs_dev *dev,
9400 + struct yaffs_ext_tags *tags,
9401 + int chunk_in_block)
9403 + struct yaffs_packed_tags2_tags_only tags_only;
9404 + struct yaffs_summary_tags *sum_tags;
9405 + if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) {
9406 + sum_tags = &dev->sum_tags[chunk_in_block];
9407 + tags_only.chunk_id = sum_tags->chunk_id;
9408 + tags_only.n_bytes = sum_tags->n_bytes;
9409 + tags_only.obj_id = sum_tags->obj_id;
9410 + yaffs_unpack_tags2_tags_only(tags, &tags_only);
9411 + return YAFFS_OK;
9413 + return YAFFS_FAIL;
9416 +void yaffs_summary_gc(struct yaffs_dev *dev, int blk)
9418 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk);
9419 + int i;
9421 + if (!bi->has_summary)
9422 + return;
9424 + for (i = dev->chunks_per_summary;
9425 + i < dev->param.chunks_per_block;
9426 + i++) {
9427 + if (yaffs_check_chunk_bit(dev, blk, i)) {
9428 + yaffs_clear_chunk_bit(dev, blk, i);
9429 + bi->pages_in_use--;
9430 + dev->n_free_chunks++;
9434 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_summary.h linux-3.18.14/fs/yaffs2/yaffs_summary.h
9435 --- linux-3.18.14.orig/fs/yaffs2/yaffs_summary.h 1970-01-01 01:00:00.000000000 +0100
9436 +++ linux-3.18.14/fs/yaffs2/yaffs_summary.h 2015-06-14 21:23:22.000000000 +0200
9437 @@ -0,0 +1,37 @@
9439 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
9441 + * Copyright (C) 2002-2011 Aleph One Ltd.
9442 + * for Toby Churchill Ltd and Brightstar Engineering
9444 + * Created by Charles Manning <charles@aleph1.co.uk>
9446 + * This program is free software; you can redistribute it and/or modify
9447 + * it under the terms of the GNU Lesser General Public License version 2.1 as
9448 + * published by the Free Software Foundation.
9450 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
9451 + */
9453 +#ifndef __YAFFS_SUMMARY_H__
9454 +#define __YAFFS_SUMMARY_H__
9456 +#include "yaffs_packedtags2.h"
9459 +int yaffs_summary_init(struct yaffs_dev *dev);
9460 +void yaffs_summary_deinit(struct yaffs_dev *dev);
9462 +int yaffs_summary_add(struct yaffs_dev *dev,
9463 + struct yaffs_ext_tags *tags,
9464 + int chunk_in_block);
9465 +int yaffs_summary_fetch(struct yaffs_dev *dev,
9466 + struct yaffs_ext_tags *tags,
9467 + int chunk_in_block);
9468 +int yaffs_summary_read(struct yaffs_dev *dev,
9469 + struct yaffs_summary_tags *st,
9470 + int blk);
9471 +void yaffs_summary_gc(struct yaffs_dev *dev, int blk);
9474 +#endif
9475 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_tagscompat.c linux-3.18.14/fs/yaffs2/yaffs_tagscompat.c
9476 --- linux-3.18.14.orig/fs/yaffs2/yaffs_tagscompat.c 1970-01-01 01:00:00.000000000 +0100
9477 +++ linux-3.18.14/fs/yaffs2/yaffs_tagscompat.c 2015-06-14 21:23:22.000000000 +0200
9478 @@ -0,0 +1,381 @@
9480 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
9482 + * Copyright (C) 2002-2011 Aleph One Ltd.
9483 + * for Toby Churchill Ltd and Brightstar Engineering
9485 + * Created by Charles Manning <charles@aleph1.co.uk>
9487 + * This program is free software; you can redistribute it and/or modify
9488 + * it under the terms of the GNU General Public License version 2 as
9489 + * published by the Free Software Foundation.
9490 + */
9492 +#include "yaffs_guts.h"
9493 +#include "yaffs_tagscompat.h"
9494 +#include "yaffs_ecc.h"
9495 +#include "yaffs_getblockinfo.h"
9496 +#include "yaffs_trace.h"
9498 +static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk);
9501 +/********** Tags ECC calculations *********/
9504 +void yaffs_calc_tags_ecc(struct yaffs_tags *tags)
9506 + /* Calculate an ecc */
9507 + unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
9508 + unsigned i, j;
9509 + unsigned ecc = 0;
9510 + unsigned bit = 0;
9512 + tags->ecc = 0;
9514 + for (i = 0; i < 8; i++) {
9515 + for (j = 1; j & 0xff; j <<= 1) {
9516 + bit++;
9517 + if (b[i] & j)
9518 + ecc ^= bit;
9521 + tags->ecc = ecc;
9524 +int yaffs_check_tags_ecc(struct yaffs_tags *tags)
9526 + unsigned ecc = tags->ecc;
9528 + yaffs_calc_tags_ecc(tags);
9530 + ecc ^= tags->ecc;
9532 + if (ecc && ecc <= 64) {
9533 + /* TODO: Handle the failure better. Retire? */
9534 + unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes;
9536 + ecc--;
9538 + b[ecc / 8] ^= (1 << (ecc & 7));
9540 + /* Now recvalc the ecc */
9541 + yaffs_calc_tags_ecc(tags);
9543 + return 1; /* recovered error */
9544 + } else if (ecc) {
9545 + /* Wierd ecc failure value */
9546 + /* TODO Need to do somethiong here */
9547 + return -1; /* unrecovered error */
9549 + return 0;
9552 +/********** Tags **********/
9554 +static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr,
9555 + struct yaffs_tags *tags_ptr)
9557 + union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
9559 + yaffs_calc_tags_ecc(tags_ptr);
9561 + spare_ptr->tb0 = tu->as_bytes[0];
9562 + spare_ptr->tb1 = tu->as_bytes[1];
9563 + spare_ptr->tb2 = tu->as_bytes[2];
9564 + spare_ptr->tb3 = tu->as_bytes[3];
9565 + spare_ptr->tb4 = tu->as_bytes[4];
9566 + spare_ptr->tb5 = tu->as_bytes[5];
9567 + spare_ptr->tb6 = tu->as_bytes[6];
9568 + spare_ptr->tb7 = tu->as_bytes[7];
9571 +static void yaffs_get_tags_from_spare(struct yaffs_dev *dev,
9572 + struct yaffs_spare *spare_ptr,
9573 + struct yaffs_tags *tags_ptr)
9575 + union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr;
9576 + int result;
9578 + tu->as_bytes[0] = spare_ptr->tb0;
9579 + tu->as_bytes[1] = spare_ptr->tb1;
9580 + tu->as_bytes[2] = spare_ptr->tb2;
9581 + tu->as_bytes[3] = spare_ptr->tb3;
9582 + tu->as_bytes[4] = spare_ptr->tb4;
9583 + tu->as_bytes[5] = spare_ptr->tb5;
9584 + tu->as_bytes[6] = spare_ptr->tb6;
9585 + tu->as_bytes[7] = spare_ptr->tb7;
9587 + result = yaffs_check_tags_ecc(tags_ptr);
9588 + if (result > 0)
9589 + dev->n_tags_ecc_fixed++;
9590 + else if (result < 0)
9591 + dev->n_tags_ecc_unfixed++;
9594 +static void yaffs_spare_init(struct yaffs_spare *spare)
9596 + memset(spare, 0xff, sizeof(struct yaffs_spare));
9599 +static int yaffs_wr_nand(struct yaffs_dev *dev,
9600 + int nand_chunk, const u8 *data,
9601 + struct yaffs_spare *spare)
9603 + int data_size = dev->data_bytes_per_chunk;
9605 + return dev->drv.drv_write_chunk_fn(dev, nand_chunk,
9606 + data, data_size,
9607 + (u8 *) spare, sizeof(*spare));
9610 +static int yaffs_rd_chunk_nand(struct yaffs_dev *dev,
9611 + int nand_chunk,
9612 + u8 *data,
9613 + struct yaffs_spare *spare,
9614 + enum yaffs_ecc_result *ecc_result,
9615 + int correct_errors)
9617 + int ret_val;
9618 + struct yaffs_spare local_spare;
9619 + int data_size;
9620 + int spare_size;
9621 + int ecc_result1, ecc_result2;
9622 + u8 calc_ecc[3];
9624 + if (!spare) {
9625 + /* If we don't have a real spare, then we use a local one. */
9626 + /* Need this for the calculation of the ecc */
9627 + spare = &local_spare;
9629 + data_size = dev->data_bytes_per_chunk;
9630 + spare_size = sizeof(struct yaffs_spare);
9632 + if (dev->param.use_nand_ecc)
9633 + return dev->drv.drv_read_chunk_fn(dev, nand_chunk,
9634 + data, data_size,
9635 + (u8 *) spare, spare_size,
9636 + ecc_result);
9639 + /* Handle the ECC at this level. */
9641 + ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
9642 + data, data_size,
9643 + (u8 *)spare, spare_size,
9644 + NULL);
9645 + if (!data || !correct_errors)
9646 + return ret_val;
9648 + /* Do ECC correction if needed. */
9649 + yaffs_ecc_calc(data, calc_ecc);
9650 + ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc);
9651 + yaffs_ecc_calc(&data[256], calc_ecc);
9652 + ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc);
9654 + if (ecc_result1 > 0) {
9655 + yaffs_trace(YAFFS_TRACE_ERROR,
9656 + "**>>yaffs ecc error fix performed on chunk %d:0",
9657 + nand_chunk);
9658 + dev->n_ecc_fixed++;
9659 + } else if (ecc_result1 < 0) {
9660 + yaffs_trace(YAFFS_TRACE_ERROR,
9661 + "**>>yaffs ecc error unfixed on chunk %d:0",
9662 + nand_chunk);
9663 + dev->n_ecc_unfixed++;
9666 + if (ecc_result2 > 0) {
9667 + yaffs_trace(YAFFS_TRACE_ERROR,
9668 + "**>>yaffs ecc error fix performed on chunk %d:1",
9669 + nand_chunk);
9670 + dev->n_ecc_fixed++;
9671 + } else if (ecc_result2 < 0) {
9672 + yaffs_trace(YAFFS_TRACE_ERROR,
9673 + "**>>yaffs ecc error unfixed on chunk %d:1",
9674 + nand_chunk);
9675 + dev->n_ecc_unfixed++;
9678 + if (ecc_result1 || ecc_result2) {
9679 + /* We had a data problem on this page */
9680 + yaffs_handle_rd_data_error(dev, nand_chunk);
9683 + if (ecc_result1 < 0 || ecc_result2 < 0)
9684 + *ecc_result = YAFFS_ECC_RESULT_UNFIXED;
9685 + else if (ecc_result1 > 0 || ecc_result2 > 0)
9686 + *ecc_result = YAFFS_ECC_RESULT_FIXED;
9687 + else
9688 + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
9690 + return ret_val;
9694 + * Functions for robustisizing
9695 + */
9697 +static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk)
9699 + int flash_block = nand_chunk / dev->param.chunks_per_block;
9701 + /* Mark the block for retirement */
9702 + yaffs_get_block_info(dev, flash_block + dev->block_offset)->
9703 + needs_retiring = 1;
9704 + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
9705 + "**>>Block %d marked for retirement",
9706 + flash_block);
9708 + /* TODO:
9709 + * Just do a garbage collection on the affected block
9710 + * then retire the block
9711 + * NB recursion
9712 + */
9715 +static int yaffs_tags_compat_wr(struct yaffs_dev *dev,
9716 + int nand_chunk,
9717 + const u8 *data, const struct yaffs_ext_tags *ext_tags)
9719 + struct yaffs_spare spare;
9720 + struct yaffs_tags tags;
9722 + yaffs_spare_init(&spare);
9724 + if (ext_tags->is_deleted)
9725 + spare.page_status = 0;
9726 + else {
9727 + tags.obj_id = ext_tags->obj_id;
9728 + tags.chunk_id = ext_tags->chunk_id;
9730 + tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1);
9732 + if (dev->data_bytes_per_chunk >= 1024)
9733 + tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3;
9734 + else
9735 + tags.n_bytes_msb = 3;
9737 + tags.serial_number = ext_tags->serial_number;
9739 + if (!dev->param.use_nand_ecc && data) {
9740 + yaffs_ecc_calc(data, spare.ecc1);
9741 + yaffs_ecc_calc(&data[256], spare.ecc2);
9744 + yaffs_load_tags_to_spare(&spare, &tags);
9746 + return yaffs_wr_nand(dev, nand_chunk, data, &spare);
9749 +static int yaffs_tags_compat_rd(struct yaffs_dev *dev,
9750 + int nand_chunk,
9751 + u8 *data, struct yaffs_ext_tags *ext_tags)
9753 + struct yaffs_spare spare;
9754 + struct yaffs_tags tags;
9755 + enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
9756 + static struct yaffs_spare spare_ff;
9757 + static int init;
9758 + int deleted;
9760 + if (!init) {
9761 + memset(&spare_ff, 0xff, sizeof(spare_ff));
9762 + init = 1;
9765 + if (!yaffs_rd_chunk_nand(dev, nand_chunk,
9766 + data, &spare, &ecc_result, 1))
9767 + return YAFFS_FAIL;
9769 + /* ext_tags may be NULL */
9770 + if (!ext_tags)
9771 + return YAFFS_OK;
9773 + deleted = (hweight8(spare.page_status) < 7) ? 1 : 0;
9775 + ext_tags->is_deleted = deleted;
9776 + ext_tags->ecc_result = ecc_result;
9777 + ext_tags->block_bad = 0; /* We're reading it */
9778 + /* therefore it is not a bad block */
9779 + ext_tags->chunk_used =
9780 + memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0;
9782 + if (ext_tags->chunk_used) {
9783 + yaffs_get_tags_from_spare(dev, &spare, &tags);
9784 + ext_tags->obj_id = tags.obj_id;
9785 + ext_tags->chunk_id = tags.chunk_id;
9786 + ext_tags->n_bytes = tags.n_bytes_lsb;
9788 + if (dev->data_bytes_per_chunk >= 1024)
9789 + ext_tags->n_bytes |=
9790 + (((unsigned)tags.n_bytes_msb) << 10);
9792 + ext_tags->serial_number = tags.serial_number;
9795 + return YAFFS_OK;
9798 +static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block)
9800 + struct yaffs_spare spare;
9802 + memset(&spare, 0xff, sizeof(struct yaffs_spare));
9804 + spare.block_status = 'Y';
9806 + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL,
9807 + &spare);
9808 + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1,
9809 + NULL, &spare);
9811 + return YAFFS_OK;
9814 +static int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
9815 + int block_no,
9816 + enum yaffs_block_state *state,
9817 + u32 *seq_number)
9819 + struct yaffs_spare spare0, spare1;
9820 + static struct yaffs_spare spare_ff;
9821 + static int init;
9822 + enum yaffs_ecc_result dummy;
9824 + if (!init) {
9825 + memset(&spare_ff, 0xff, sizeof(spare_ff));
9826 + init = 1;
9829 + *seq_number = 0;
9831 + /* Look for bad block markers in the first two chunks */
9832 + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block,
9833 + NULL, &spare0, &dummy, 0);
9834 + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1,
9835 + NULL, &spare1, &dummy, 0);
9837 + if (hweight8(spare0.block_status & spare1.block_status) < 7)
9838 + *state = YAFFS_BLOCK_STATE_DEAD;
9839 + else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0)
9840 + *state = YAFFS_BLOCK_STATE_EMPTY;
9841 + else
9842 + *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
9844 + return YAFFS_OK;
9847 +void yaffs_tags_compat_install(struct yaffs_dev *dev)
9849 + if(dev->param.is_yaffs2)
9850 + return;
9851 + if(!dev->tagger.write_chunk_tags_fn)
9852 + dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr;
9853 + if(!dev->tagger.read_chunk_tags_fn)
9854 + dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd;
9855 + if(!dev->tagger.query_block_fn)
9856 + dev->tagger.query_block_fn = yaffs_tags_compat_query_block;
9857 + if(!dev->tagger.mark_bad_fn)
9858 + dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad;
9860 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_tagscompat.h linux-3.18.14/fs/yaffs2/yaffs_tagscompat.h
9861 --- linux-3.18.14.orig/fs/yaffs2/yaffs_tagscompat.h 1970-01-01 01:00:00.000000000 +0100
9862 +++ linux-3.18.14/fs/yaffs2/yaffs_tagscompat.h 2015-06-14 21:23:22.000000000 +0200
9863 @@ -0,0 +1,44 @@
9865 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
9867 + * Copyright (C) 2002-2011 Aleph One Ltd.
9868 + * for Toby Churchill Ltd and Brightstar Engineering
9870 + * Created by Charles Manning <charles@aleph1.co.uk>
9872 + * This program is free software; you can redistribute it and/or modify
9873 + * it under the terms of the GNU Lesser General Public License version 2.1 as
9874 + * published by the Free Software Foundation.
9876 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
9877 + */
9879 +#ifndef __YAFFS_TAGSCOMPAT_H__
9880 +#define __YAFFS_TAGSCOMPAT_H__
9883 +#include "yaffs_guts.h"
9885 +#if 0
9888 +int yaffs_tags_compat_wr(struct yaffs_dev *dev,
9889 + int nand_chunk,
9890 + const u8 *data, const struct yaffs_ext_tags *tags);
9891 +int yaffs_tags_compat_rd(struct yaffs_dev *dev,
9892 + int nand_chunk,
9893 + u8 *data, struct yaffs_ext_tags *tags);
9894 +int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no);
9895 +int yaffs_tags_compat_query_block(struct yaffs_dev *dev,
9896 + int block_no,
9897 + enum yaffs_block_state *state,
9898 + u32 *seq_number);
9900 +#endif
9903 +void yaffs_tags_compat_install(struct yaffs_dev *dev);
9904 +void yaffs_calc_tags_ecc(struct yaffs_tags *tags);
9905 +int yaffs_check_tags_ecc(struct yaffs_tags *tags);
9907 +#endif
9908 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_tagsmarshall.c linux-3.18.14/fs/yaffs2/yaffs_tagsmarshall.c
9909 --- linux-3.18.14.orig/fs/yaffs2/yaffs_tagsmarshall.c 1970-01-01 01:00:00.000000000 +0100
9910 +++ linux-3.18.14/fs/yaffs2/yaffs_tagsmarshall.c 2015-06-14 21:23:22.000000000 +0200
9911 @@ -0,0 +1,199 @@
9913 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
9915 + * Copyright (C) 2002-2011 Aleph One Ltd.
9916 + * for Toby Churchill Ltd and Brightstar Engineering
9918 + * Created by Charles Manning <charles@aleph1.co.uk>
9920 + * This program is free software; you can redistribute it and/or modify
9921 + * it under the terms of the GNU General Public License version 2 as
9922 + * published by the Free Software Foundation.
9923 + */
9925 +#include "yaffs_guts.h"
9926 +#include "yaffs_trace.h"
9927 +#include "yaffs_packedtags2.h"
9929 +static int yaffs_tags_marshall_write(struct yaffs_dev *dev,
9930 + int nand_chunk, const u8 *data,
9931 + const struct yaffs_ext_tags *tags)
9933 + struct yaffs_packed_tags2 pt;
9934 + int retval;
9936 + int packed_tags_size =
9937 + dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
9938 + void *packed_tags_ptr =
9939 + dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
9941 + yaffs_trace(YAFFS_TRACE_MTD,
9942 + "yaffs_tags_marshall_write chunk %d data %p tags %p",
9943 + nand_chunk, data, tags);
9945 + /* For yaffs2 writing there must be both data and tags.
9946 + * If we're using inband tags, then the tags are stuffed into
9947 + * the end of the data buffer.
9948 + */
9949 + if (!data || !tags)
9950 + BUG();
9951 + else if (dev->param.inband_tags) {
9952 + struct yaffs_packed_tags2_tags_only *pt2tp;
9953 + pt2tp =
9954 + (struct yaffs_packed_tags2_tags_only *)(data +
9955 + dev->
9956 + data_bytes_per_chunk);
9957 + yaffs_pack_tags2_tags_only(pt2tp, tags);
9958 + } else {
9959 + yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc);
9962 + retval = dev->drv.drv_write_chunk_fn(dev, nand_chunk,
9963 + data, dev->param.total_bytes_per_chunk,
9964 + (dev->param.inband_tags) ? NULL : packed_tags_ptr,
9965 + (dev->param.inband_tags) ? 0 : packed_tags_size);
9967 + return retval;
9970 +static int yaffs_tags_marshall_read(struct yaffs_dev *dev,
9971 + int nand_chunk, u8 *data,
9972 + struct yaffs_ext_tags *tags)
9974 + int retval = 0;
9975 + int local_data = 0;
9976 + u8 spare_buffer[100];
9977 + enum yaffs_ecc_result ecc_result;
9979 + struct yaffs_packed_tags2 pt;
9981 + int packed_tags_size =
9982 + dev->param.no_tags_ecc ? sizeof(pt.t) : sizeof(pt);
9983 + void *packed_tags_ptr =
9984 + dev->param.no_tags_ecc ? (void *)&pt.t : (void *)&pt;
9986 + yaffs_trace(YAFFS_TRACE_MTD,
9987 + "yaffs_tags_marshall_read chunk %d data %p tags %p",
9988 + nand_chunk, data, tags);
9990 + if (dev->param.inband_tags) {
9991 + if (!data) {
9992 + local_data = 1;
9993 + data = yaffs_get_temp_buffer(dev);
9997 + if (dev->param.inband_tags || (data && !tags))
9998 + retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
9999 + data, dev->param.total_bytes_per_chunk,
10000 + NULL, 0,
10001 + &ecc_result);
10002 + else if (tags)
10003 + retval = dev->drv.drv_read_chunk_fn(dev, nand_chunk,
10004 + data, dev->param.total_bytes_per_chunk,
10005 + spare_buffer, packed_tags_size,
10006 + &ecc_result);
10007 + else
10008 + BUG();
10011 + if (dev->param.inband_tags) {
10012 + if (tags) {
10013 + struct yaffs_packed_tags2_tags_only *pt2tp;
10014 + pt2tp =
10015 + (struct yaffs_packed_tags2_tags_only *)
10016 + &data[dev->data_bytes_per_chunk];
10017 + yaffs_unpack_tags2_tags_only(tags, pt2tp);
10019 + } else if (tags) {
10020 + memcpy(packed_tags_ptr, spare_buffer, packed_tags_size);
10021 + yaffs_unpack_tags2(tags, &pt, !dev->param.no_tags_ecc);
10024 + if (local_data)
10025 + yaffs_release_temp_buffer(dev, data);
10027 + if (tags && ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
10028 + tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED;
10029 + dev->n_ecc_unfixed++;
10032 + if (tags && ecc_result == -YAFFS_ECC_RESULT_FIXED) {
10033 + if (tags->ecc_result <= YAFFS_ECC_RESULT_NO_ERROR)
10034 + tags->ecc_result = YAFFS_ECC_RESULT_FIXED;
10035 + dev->n_ecc_fixed++;
10038 + if (ecc_result < YAFFS_ECC_RESULT_UNFIXED)
10039 + return YAFFS_OK;
10040 + else
10041 + return YAFFS_FAIL;
10044 +static int yaffs_tags_marshall_query_block(struct yaffs_dev *dev, int block_no,
10045 + enum yaffs_block_state *state,
10046 + u32 *seq_number)
10048 + int retval;
10050 + yaffs_trace(YAFFS_TRACE_MTD, "yaffs_tags_marshall_query_block %d",
10051 + block_no);
10053 + retval = dev->drv.drv_check_bad_fn(dev, block_no);
10055 + if (retval== YAFFS_FAIL) {
10056 + yaffs_trace(YAFFS_TRACE_MTD, "block is bad");
10058 + *state = YAFFS_BLOCK_STATE_DEAD;
10059 + *seq_number = 0;
10060 + } else {
10061 + struct yaffs_ext_tags t;
10063 + yaffs_tags_marshall_read(dev,
10064 + block_no * dev->param.chunks_per_block,
10065 + NULL, &t);
10067 + if (t.chunk_used) {
10068 + *seq_number = t.seq_number;
10069 + *state = YAFFS_BLOCK_STATE_NEEDS_SCAN;
10070 + } else {
10071 + *seq_number = 0;
10072 + *state = YAFFS_BLOCK_STATE_EMPTY;
10076 + yaffs_trace(YAFFS_TRACE_MTD,
10077 + "block query returns seq %d state %d",
10078 + *seq_number, *state);
10080 + if (retval == 0)
10081 + return YAFFS_OK;
10082 + else
10083 + return YAFFS_FAIL;
10086 +static int yaffs_tags_marshall_mark_bad(struct yaffs_dev *dev, int block_no)
10088 + return dev->drv.drv_mark_bad_fn(dev, block_no);
10093 +void yaffs_tags_marshall_install(struct yaffs_dev *dev)
10095 + if (!dev->param.is_yaffs2)
10096 + return;
10098 + if (!dev->tagger.write_chunk_tags_fn)
10099 + dev->tagger.write_chunk_tags_fn = yaffs_tags_marshall_write;
10101 + if (!dev->tagger.read_chunk_tags_fn)
10102 + dev->tagger.read_chunk_tags_fn = yaffs_tags_marshall_read;
10104 + if (!dev->tagger.query_block_fn)
10105 + dev->tagger.query_block_fn = yaffs_tags_marshall_query_block;
10107 + if (!dev->tagger.mark_bad_fn)
10108 + dev->tagger.mark_bad_fn = yaffs_tags_marshall_mark_bad;
10111 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_tagsmarshall.h linux-3.18.14/fs/yaffs2/yaffs_tagsmarshall.h
10112 --- linux-3.18.14.orig/fs/yaffs2/yaffs_tagsmarshall.h 1970-01-01 01:00:00.000000000 +0100
10113 +++ linux-3.18.14/fs/yaffs2/yaffs_tagsmarshall.h 2015-06-14 21:23:22.000000000 +0200
10114 @@ -0,0 +1,22 @@
10116 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
10118 + * Copyright (C) 2002-2011 Aleph One Ltd.
10119 + * for Toby Churchill Ltd and Brightstar Engineering
10121 + * Created by Charles Manning <charles@aleph1.co.uk>
10123 + * This program is free software; you can redistribute it and/or modify
10124 + * it under the terms of the GNU Lesser General Public License version 2.1 as
10125 + * published by the Free Software Foundation.
10127 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
10128 + */
10130 +#ifndef __YAFFS_TAGSMARSHALL_H__
10131 +#define __YAFFS_TAGSMARSHALL_H__
10133 +#include "yaffs_guts.h"
10134 +void yaffs_tags_marshall_install(struct yaffs_dev *dev);
10136 +#endif
10137 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_trace.h linux-3.18.14/fs/yaffs2/yaffs_trace.h
10138 --- linux-3.18.14.orig/fs/yaffs2/yaffs_trace.h 1970-01-01 01:00:00.000000000 +0100
10139 +++ linux-3.18.14/fs/yaffs2/yaffs_trace.h 2015-06-14 21:23:22.000000000 +0200
10140 @@ -0,0 +1,57 @@
10142 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
10144 + * Copyright (C) 2002-2011 Aleph One Ltd.
10145 + * for Toby Churchill Ltd and Brightstar Engineering
10147 + * Created by Charles Manning <charles@aleph1.co.uk>
10149 + * This program is free software; you can redistribute it and/or modify
10150 + * it under the terms of the GNU Lesser General Public License version 2.1 as
10151 + * published by the Free Software Foundation.
10153 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
10154 + */
10156 +#ifndef __YTRACE_H__
10157 +#define __YTRACE_H__
10159 +extern unsigned int yaffs_trace_mask;
10160 +extern unsigned int yaffs_wr_attempts;
10163 + * Tracing flags.
10164 + * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
10165 + */
10167 +#define YAFFS_TRACE_OS 0x00000002
10168 +#define YAFFS_TRACE_ALLOCATE 0x00000004
10169 +#define YAFFS_TRACE_SCAN 0x00000008
10170 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010
10171 +#define YAFFS_TRACE_ERASE 0x00000020
10172 +#define YAFFS_TRACE_GC 0x00000040
10173 +#define YAFFS_TRACE_WRITE 0x00000080
10174 +#define YAFFS_TRACE_TRACING 0x00000100
10175 +#define YAFFS_TRACE_DELETION 0x00000200
10176 +#define YAFFS_TRACE_BUFFERS 0x00000400
10177 +#define YAFFS_TRACE_NANDACCESS 0x00000800
10178 +#define YAFFS_TRACE_GC_DETAIL 0x00001000
10179 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000
10180 +#define YAFFS_TRACE_MTD 0x00004000
10181 +#define YAFFS_TRACE_CHECKPOINT 0x00008000
10183 +#define YAFFS_TRACE_VERIFY 0x00010000
10184 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000
10185 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000
10186 +#define YAFFS_TRACE_VERIFY_ALL 0x000f0000
10188 +#define YAFFS_TRACE_SYNC 0x00100000
10189 +#define YAFFS_TRACE_BACKGROUND 0x00200000
10190 +#define YAFFS_TRACE_LOCK 0x00400000
10191 +#define YAFFS_TRACE_MOUNT 0x00800000
10193 +#define YAFFS_TRACE_ERROR 0x40000000
10194 +#define YAFFS_TRACE_BUG 0x80000000
10195 +#define YAFFS_TRACE_ALWAYS 0xf0000000
10197 +#endif
10198 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_verify.c linux-3.18.14/fs/yaffs2/yaffs_verify.c
10199 --- linux-3.18.14.orig/fs/yaffs2/yaffs_verify.c 1970-01-01 01:00:00.000000000 +0100
10200 +++ linux-3.18.14/fs/yaffs2/yaffs_verify.c 2015-06-14 21:23:22.000000000 +0200
10201 @@ -0,0 +1,529 @@
10203 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
10205 + * Copyright (C) 2002-2011 Aleph One Ltd.
10206 + * for Toby Churchill Ltd and Brightstar Engineering
10208 + * Created by Charles Manning <charles@aleph1.co.uk>
10210 + * This program is free software; you can redistribute it and/or modify
10211 + * it under the terms of the GNU General Public License version 2 as
10212 + * published by the Free Software Foundation.
10213 + */
10215 +#include "yaffs_verify.h"
10216 +#include "yaffs_trace.h"
10217 +#include "yaffs_bitmap.h"
10218 +#include "yaffs_getblockinfo.h"
10219 +#include "yaffs_nand.h"
10221 +int yaffs_skip_verification(struct yaffs_dev *dev)
10223 + (void) dev;
10224 + return !(yaffs_trace_mask &
10225 + (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
10228 +static int yaffs_skip_full_verification(struct yaffs_dev *dev)
10230 + (void) dev;
10231 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL));
10234 +static int yaffs_skip_nand_verification(struct yaffs_dev *dev)
10236 + (void) dev;
10237 + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND));
10240 +static const char * const block_state_name[] = {
10241 + "Unknown",
10242 + "Needs scan",
10243 + "Scanning",
10244 + "Empty",
10245 + "Allocating",
10246 + "Full",
10247 + "Dirty",
10248 + "Checkpoint",
10249 + "Collecting",
10250 + "Dead"
10253 +void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n)
10255 + int actually_used;
10256 + int in_use;
10258 + if (yaffs_skip_verification(dev))
10259 + return;
10261 + /* Report illegal runtime states */
10262 + if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES)
10263 + yaffs_trace(YAFFS_TRACE_VERIFY,
10264 + "Block %d has undefined state %d",
10265 + n, bi->block_state);
10267 + switch (bi->block_state) {
10268 + case YAFFS_BLOCK_STATE_UNKNOWN:
10269 + case YAFFS_BLOCK_STATE_SCANNING:
10270 + case YAFFS_BLOCK_STATE_NEEDS_SCAN:
10271 + yaffs_trace(YAFFS_TRACE_VERIFY,
10272 + "Block %d has bad run-state %s",
10273 + n, block_state_name[bi->block_state]);
10276 + /* Check pages in use and soft deletions are legal */
10278 + actually_used = bi->pages_in_use - bi->soft_del_pages;
10280 + if (bi->pages_in_use < 0 ||
10281 + bi->pages_in_use > dev->param.chunks_per_block ||
10282 + bi->soft_del_pages < 0 ||
10283 + bi->soft_del_pages > dev->param.chunks_per_block ||
10284 + actually_used < 0 || actually_used > dev->param.chunks_per_block)
10285 + yaffs_trace(YAFFS_TRACE_VERIFY,
10286 + "Block %d has illegal values pages_in_used %d soft_del_pages %d",
10287 + n, bi->pages_in_use, bi->soft_del_pages);
10289 + /* Check chunk bitmap legal */
10290 + in_use = yaffs_count_chunk_bits(dev, n);
10291 + if (in_use != bi->pages_in_use)
10292 + yaffs_trace(YAFFS_TRACE_VERIFY,
10293 + "Block %d has inconsistent values pages_in_use %d counted chunk bits %d",
10294 + n, bi->pages_in_use, in_use);
10297 +void yaffs_verify_collected_blk(struct yaffs_dev *dev,
10298 + struct yaffs_block_info *bi, int n)
10300 + yaffs_verify_blk(dev, bi, n);
10302 + /* After collection the block should be in the erased state */
10304 + if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING &&
10305 + bi->block_state != YAFFS_BLOCK_STATE_EMPTY) {
10306 + yaffs_trace(YAFFS_TRACE_ERROR,
10307 + "Block %d is in state %d after gc, should be erased",
10308 + n, bi->block_state);
10312 +void yaffs_verify_blocks(struct yaffs_dev *dev)
10314 + int i;
10315 + int state_count[YAFFS_NUMBER_OF_BLOCK_STATES];
10316 + int illegal_states = 0;
10318 + if (yaffs_skip_verification(dev))
10319 + return;
10321 + memset(state_count, 0, sizeof(state_count));
10323 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
10324 + struct yaffs_block_info *bi = yaffs_get_block_info(dev, i);
10325 + yaffs_verify_blk(dev, bi, i);
10327 + if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES)
10328 + state_count[bi->block_state]++;
10329 + else
10330 + illegal_states++;
10333 + yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary");
10335 + yaffs_trace(YAFFS_TRACE_VERIFY,
10336 + "%d blocks have illegal states",
10337 + illegal_states);
10338 + if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
10339 + yaffs_trace(YAFFS_TRACE_VERIFY,
10340 + "Too many allocating blocks");
10342 + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
10343 + yaffs_trace(YAFFS_TRACE_VERIFY,
10344 + "%s %d blocks",
10345 + block_state_name[i], state_count[i]);
10347 + if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT])
10348 + yaffs_trace(YAFFS_TRACE_VERIFY,
10349 + "Checkpoint block count wrong dev %d count %d",
10350 + dev->blocks_in_checkpt,
10351 + state_count[YAFFS_BLOCK_STATE_CHECKPOINT]);
10353 + if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY])
10354 + yaffs_trace(YAFFS_TRACE_VERIFY,
10355 + "Erased block count wrong dev %d count %d",
10356 + dev->n_erased_blocks,
10357 + state_count[YAFFS_BLOCK_STATE_EMPTY]);
10359 + if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1)
10360 + yaffs_trace(YAFFS_TRACE_VERIFY,
10361 + "Too many collecting blocks %d (max is 1)",
10362 + state_count[YAFFS_BLOCK_STATE_COLLECTING]);
10366 + * Verify the object header. oh must be valid, but obj and tags may be NULL in
10367 + * which case those tests will not be performed.
10368 + */
10369 +void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
10370 + struct yaffs_ext_tags *tags, int parent_check)
10372 + if (obj && yaffs_skip_verification(obj->my_dev))
10373 + return;
10375 + if (!(tags && obj && oh)) {
10376 + yaffs_trace(YAFFS_TRACE_VERIFY,
10377 + "Verifying object header tags %p obj %p oh %p",
10378 + tags, obj, oh);
10379 + return;
10382 + if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
10383 + oh->type > YAFFS_OBJECT_TYPE_MAX)
10384 + yaffs_trace(YAFFS_TRACE_VERIFY,
10385 + "Obj %d header type is illegal value 0x%x",
10386 + tags->obj_id, oh->type);
10388 + if (tags->obj_id != obj->obj_id)
10389 + yaffs_trace(YAFFS_TRACE_VERIFY,
10390 + "Obj %d header mismatch obj_id %d",
10391 + tags->obj_id, obj->obj_id);
10393 + /*
10394 + * Check that the object's parent ids match if parent_check requested.
10396 + * Tests do not apply to the root object.
10397 + */
10399 + if (parent_check && tags->obj_id > 1 && !obj->parent)
10400 + yaffs_trace(YAFFS_TRACE_VERIFY,
10401 + "Obj %d header mismatch parent_id %d obj->parent is NULL",
10402 + tags->obj_id, oh->parent_obj_id);
10404 + if (parent_check && obj->parent &&
10405 + oh->parent_obj_id != obj->parent->obj_id &&
10406 + (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED ||
10407 + obj->parent->obj_id != YAFFS_OBJECTID_DELETED))
10408 + yaffs_trace(YAFFS_TRACE_VERIFY,
10409 + "Obj %d header mismatch parent_id %d parent_obj_id %d",
10410 + tags->obj_id, oh->parent_obj_id,
10411 + obj->parent->obj_id);
10413 + if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */
10414 + yaffs_trace(YAFFS_TRACE_VERIFY,
10415 + "Obj %d header name is NULL",
10416 + obj->obj_id);
10418 + if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */
10419 + yaffs_trace(YAFFS_TRACE_VERIFY,
10420 + "Obj %d header name is 0xff",
10421 + obj->obj_id);
10424 +void yaffs_verify_file(struct yaffs_obj *obj)
10426 + u32 x;
10427 + int required_depth;
10428 + int actual_depth;
10429 + int last_chunk;
10430 + u32 offset_in_chunk;
10431 + u32 the_chunk;
10433 + u32 i;
10434 + struct yaffs_dev *dev;
10435 + struct yaffs_ext_tags tags;
10436 + struct yaffs_tnode *tn;
10437 + u32 obj_id;
10439 + if (!obj)
10440 + return;
10442 + if (yaffs_skip_verification(obj->my_dev))
10443 + return;
10445 + dev = obj->my_dev;
10446 + obj_id = obj->obj_id;
10449 + /* Check file size is consistent with tnode depth */
10450 + yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size,
10451 + &last_chunk, &offset_in_chunk);
10452 + last_chunk++;
10453 + x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS;
10454 + required_depth = 0;
10455 + while (x > 0) {
10456 + x >>= YAFFS_TNODES_INTERNAL_BITS;
10457 + required_depth++;
10460 + actual_depth = obj->variant.file_variant.top_level;
10462 + /* Check that the chunks in the tnode tree are all correct.
10463 + * We do this by scanning through the tnode tree and
10464 + * checking the tags for every chunk match.
10465 + */
10467 + if (yaffs_skip_nand_verification(dev))
10468 + return;
10470 + for (i = 1; i <= last_chunk; i++) {
10471 + tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i);
10473 + if (!tn)
10474 + continue;
10476 + the_chunk = yaffs_get_group_base(dev, tn, i);
10477 + if (the_chunk > 0) {
10478 + yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL,
10479 + &tags);
10480 + if (tags.obj_id != obj_id || tags.chunk_id != i)
10481 + yaffs_trace(YAFFS_TRACE_VERIFY,
10482 + "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)",
10483 + obj_id, i, the_chunk,
10484 + tags.obj_id, tags.chunk_id);
10489 +void yaffs_verify_link(struct yaffs_obj *obj)
10491 + if (obj && yaffs_skip_verification(obj->my_dev))
10492 + return;
10494 + /* Verify sane equivalent object */
10497 +void yaffs_verify_symlink(struct yaffs_obj *obj)
10499 + if (obj && yaffs_skip_verification(obj->my_dev))
10500 + return;
10502 + /* Verify symlink string */
10505 +void yaffs_verify_special(struct yaffs_obj *obj)
10507 + if (obj && yaffs_skip_verification(obj->my_dev))
10508 + return;
10511 +void yaffs_verify_obj(struct yaffs_obj *obj)
10513 + struct yaffs_dev *dev;
10514 + u32 chunk_min;
10515 + u32 chunk_max;
10516 + u32 chunk_id_ok;
10517 + u32 chunk_in_range;
10518 + u32 chunk_wrongly_deleted;
10519 + u32 chunk_valid;
10521 + if (!obj)
10522 + return;
10524 + if (obj->being_created)
10525 + return;
10527 + dev = obj->my_dev;
10529 + if (yaffs_skip_verification(dev))
10530 + return;
10532 + /* Check sane object header chunk */
10534 + chunk_min = dev->internal_start_block * dev->param.chunks_per_block;
10535 + chunk_max =
10536 + (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1;
10538 + chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min &&
10539 + ((unsigned)(obj->hdr_chunk)) <= chunk_max);
10540 + chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0);
10541 + chunk_valid = chunk_in_range &&
10542 + yaffs_check_chunk_bit(dev,
10543 + obj->hdr_chunk / dev->param.chunks_per_block,
10544 + obj->hdr_chunk % dev->param.chunks_per_block);
10545 + chunk_wrongly_deleted = chunk_in_range && !chunk_valid;
10547 + if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted))
10548 + yaffs_trace(YAFFS_TRACE_VERIFY,
10549 + "Obj %d has chunk_id %d %s %s",
10550 + obj->obj_id, obj->hdr_chunk,
10551 + chunk_id_ok ? "" : ",out of range",
10552 + chunk_wrongly_deleted ? ",marked as deleted" : "");
10554 + if (chunk_valid && !yaffs_skip_nand_verification(dev)) {
10555 + struct yaffs_ext_tags tags;
10556 + struct yaffs_obj_hdr *oh;
10557 + u8 *buffer = yaffs_get_temp_buffer(dev);
10559 + oh = (struct yaffs_obj_hdr *)buffer;
10561 + yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags);
10563 + yaffs_verify_oh(obj, oh, &tags, 1);
10565 + yaffs_release_temp_buffer(dev, buffer);
10568 + /* Verify it has a parent */
10569 + if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) {
10570 + yaffs_trace(YAFFS_TRACE_VERIFY,
10571 + "Obj %d has parent pointer %p which does not look like an object",
10572 + obj->obj_id, obj->parent);
10575 + /* Verify parent is a directory */
10576 + if (obj->parent &&
10577 + obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
10578 + yaffs_trace(YAFFS_TRACE_VERIFY,
10579 + "Obj %d's parent is not a directory (type %d)",
10580 + obj->obj_id, obj->parent->variant_type);
10583 + switch (obj->variant_type) {
10584 + case YAFFS_OBJECT_TYPE_FILE:
10585 + yaffs_verify_file(obj);
10586 + break;
10587 + case YAFFS_OBJECT_TYPE_SYMLINK:
10588 + yaffs_verify_symlink(obj);
10589 + break;
10590 + case YAFFS_OBJECT_TYPE_DIRECTORY:
10591 + yaffs_verify_dir(obj);
10592 + break;
10593 + case YAFFS_OBJECT_TYPE_HARDLINK:
10594 + yaffs_verify_link(obj);
10595 + break;
10596 + case YAFFS_OBJECT_TYPE_SPECIAL:
10597 + yaffs_verify_special(obj);
10598 + break;
10599 + case YAFFS_OBJECT_TYPE_UNKNOWN:
10600 + default:
10601 + yaffs_trace(YAFFS_TRACE_VERIFY,
10602 + "Obj %d has illegaltype %d",
10603 + obj->obj_id, obj->variant_type);
10604 + break;
10608 +void yaffs_verify_objects(struct yaffs_dev *dev)
10610 + struct yaffs_obj *obj;
10611 + int i;
10612 + struct list_head *lh;
10614 + if (yaffs_skip_verification(dev))
10615 + return;
10617 + /* Iterate through the objects in each hash entry */
10619 + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
10620 + list_for_each(lh, &dev->obj_bucket[i].list) {
10621 + obj = list_entry(lh, struct yaffs_obj, hash_link);
10622 + yaffs_verify_obj(obj);
10627 +void yaffs_verify_obj_in_dir(struct yaffs_obj *obj)
10629 + struct list_head *lh;
10630 + struct yaffs_obj *list_obj;
10631 + int count = 0;
10633 + if (!obj) {
10634 + yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify");
10635 + BUG();
10636 + return;
10639 + if (yaffs_skip_verification(obj->my_dev))
10640 + return;
10642 + if (!obj->parent) {
10643 + yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent");
10644 + BUG();
10645 + return;
10648 + if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
10649 + yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory");
10650 + BUG();
10653 + /* Iterate through the objects in each hash entry */
10655 + list_for_each(lh, &obj->parent->variant.dir_variant.children) {
10656 + list_obj = list_entry(lh, struct yaffs_obj, siblings);
10657 + yaffs_verify_obj(list_obj);
10658 + if (obj == list_obj)
10659 + count++;
10662 + if (count != 1) {
10663 + yaffs_trace(YAFFS_TRACE_ALWAYS,
10664 + "Object in directory %d times",
10665 + count);
10666 + BUG();
10670 +void yaffs_verify_dir(struct yaffs_obj *directory)
10672 + struct list_head *lh;
10673 + struct yaffs_obj *list_obj;
10675 + if (!directory) {
10676 + BUG();
10677 + return;
10680 + if (yaffs_skip_full_verification(directory->my_dev))
10681 + return;
10683 + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
10684 + yaffs_trace(YAFFS_TRACE_ALWAYS,
10685 + "Directory has wrong type: %d",
10686 + directory->variant_type);
10687 + BUG();
10690 + /* Iterate through the objects in each hash entry */
10692 + list_for_each(lh, &directory->variant.dir_variant.children) {
10693 + list_obj = list_entry(lh, struct yaffs_obj, siblings);
10694 + if (list_obj->parent != directory) {
10695 + yaffs_trace(YAFFS_TRACE_ALWAYS,
10696 + "Object in directory list has wrong parent %p",
10697 + list_obj->parent);
10698 + BUG();
10700 + yaffs_verify_obj_in_dir(list_obj);
10704 +static int yaffs_free_verification_failures;
10706 +void yaffs_verify_free_chunks(struct yaffs_dev *dev)
10708 + int counted;
10709 + int difference;
10711 + if (yaffs_skip_verification(dev))
10712 + return;
10714 + counted = yaffs_count_free_chunks(dev);
10716 + difference = dev->n_free_chunks - counted;
10718 + if (difference) {
10719 + yaffs_trace(YAFFS_TRACE_ALWAYS,
10720 + "Freechunks verification failure %d %d %d",
10721 + dev->n_free_chunks, counted, difference);
10722 + yaffs_free_verification_failures++;
10726 +int yaffs_verify_file_sane(struct yaffs_obj *in)
10728 + (void) in;
10729 + return YAFFS_OK;
10731 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_verify.h linux-3.18.14/fs/yaffs2/yaffs_verify.h
10732 --- linux-3.18.14.orig/fs/yaffs2/yaffs_verify.h 1970-01-01 01:00:00.000000000 +0100
10733 +++ linux-3.18.14/fs/yaffs2/yaffs_verify.h 2015-06-14 21:23:22.000000000 +0200
10734 @@ -0,0 +1,43 @@
10736 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
10738 + * Copyright (C) 2002-2011 Aleph One Ltd.
10739 + * for Toby Churchill Ltd and Brightstar Engineering
10741 + * Created by Charles Manning <charles@aleph1.co.uk>
10743 + * This program is free software; you can redistribute it and/or modify
10744 + * it under the terms of the GNU Lesser General Public License version 2.1 as
10745 + * published by the Free Software Foundation.
10747 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
10748 + */
10750 +#ifndef __YAFFS_VERIFY_H__
10751 +#define __YAFFS_VERIFY_H__
10753 +#include "yaffs_guts.h"
10755 +void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi,
10756 + int n);
10757 +void yaffs_verify_collected_blk(struct yaffs_dev *dev,
10758 + struct yaffs_block_info *bi, int n);
10759 +void yaffs_verify_blocks(struct yaffs_dev *dev);
10761 +void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh,
10762 + struct yaffs_ext_tags *tags, int parent_check);
10763 +void yaffs_verify_file(struct yaffs_obj *obj);
10764 +void yaffs_verify_link(struct yaffs_obj *obj);
10765 +void yaffs_verify_symlink(struct yaffs_obj *obj);
10766 +void yaffs_verify_special(struct yaffs_obj *obj);
10767 +void yaffs_verify_obj(struct yaffs_obj *obj);
10768 +void yaffs_verify_objects(struct yaffs_dev *dev);
10769 +void yaffs_verify_obj_in_dir(struct yaffs_obj *obj);
10770 +void yaffs_verify_dir(struct yaffs_obj *directory);
10771 +void yaffs_verify_free_chunks(struct yaffs_dev *dev);
10773 +int yaffs_verify_file_sane(struct yaffs_obj *obj);
10775 +int yaffs_skip_verification(struct yaffs_dev *dev);
10777 +#endif
10778 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_vfs.c linux-3.18.14/fs/yaffs2/yaffs_vfs.c
10779 --- linux-3.18.14.orig/fs/yaffs2/yaffs_vfs.c 1970-01-01 01:00:00.000000000 +0100
10780 +++ linux-3.18.14/fs/yaffs2/yaffs_vfs.c 2015-06-15 18:42:09.000000000 +0200
10781 @@ -0,0 +1,3658 @@
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>
10789 + * Acknowledgements:
10790 + * Luc van OostenRyck for numerous patches.
10791 + * Nick Bane for numerous patches.
10792 + * Nick Bane for 2.5/2.6 integration.
10793 + * Andras Toth for mknod rdev issue.
10794 + * Michael Fischer for finding the problem with inode inconsistency.
10795 + * Some code bodily lifted from JFFS
10797 + * This program is free software; you can redistribute it and/or modify
10798 + * it under the terms of the GNU General Public License version 2 as
10799 + * published by the Free Software Foundation.
10800 + */
10804 + * This is the file system front-end to YAFFS that hooks it up to
10805 + * the VFS.
10807 + * Special notes:
10808 + * >> 2.4: sb->u.generic_sbp points to the struct yaffs_dev associated with
10809 + * this superblock
10810 + * >> 2.6: sb->s_fs_info points to the struct yaffs_dev associated with this
10811 + * superblock
10812 + * >> inode->u.generic_ip points to the associated struct yaffs_obj.
10813 + */
10816 + * There are two variants of the VFS glue code. This variant should compile
10817 + * for any version of Linux.
10818 + */
10819 +#include <linux/version.h>
10821 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
10822 +#define YAFFS_COMPILE_BACKGROUND
10823 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23))
10824 +#define YAFFS_COMPILE_FREEZER
10825 +#endif
10826 +#endif
10828 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28))
10829 +#define YAFFS_COMPILE_EXPORTFS
10830 +#endif
10832 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
10833 +#define YAFFS_USE_SETATTR_COPY
10834 +#define YAFFS_USE_TRUNCATE_SETSIZE
10835 +#endif
10836 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 35))
10837 +#define YAFFS_HAS_EVICT_INODE
10838 +#endif
10840 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
10841 +#define YAFFS_NEW_FOLLOW_LINK 1
10842 +#else
10843 +#define YAFFS_NEW_FOLLOW_LINK 0
10844 +#endif
10846 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
10847 +#define YAFFS_HAS_WRITE_SUPER
10848 +#endif
10851 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
10852 +#include <linux/config.h>
10853 +#endif
10855 +#include <linux/kernel.h>
10856 +#include <linux/module.h>
10857 +#include <linux/slab.h>
10858 +#include <linux/init.h>
10859 +#include <linux/fs.h>
10860 +#include <linux/proc_fs.h>
10861 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39))
10862 +#include <linux/smp_lock.h>
10863 +#endif
10864 +#include <linux/pagemap.h>
10865 +#include <linux/mtd/mtd.h>
10866 +#include <linux/interrupt.h>
10867 +#include <linux/string.h>
10868 +#include <linux/ctype.h>
10870 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
10871 +#include <linux/namei.h>
10872 +#endif
10874 +#ifdef YAFFS_COMPILE_EXPORTFS
10875 +#include <linux/exportfs.h>
10876 +#endif
10878 +#ifdef YAFFS_COMPILE_BACKGROUND
10879 +#include <linux/kthread.h>
10880 +#include <linux/delay.h>
10881 +#endif
10882 +#ifdef YAFFS_COMPILE_FREEZER
10883 +#include <linux/freezer.h>
10884 +#endif
10886 +#include <asm/div64.h>
10888 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
10890 +#include <linux/statfs.h>
10892 +#define UnlockPage(p) unlock_page(p)
10893 +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
10895 +/* FIXME: use sb->s_id instead ? */
10896 +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
10898 +#else
10900 +#include <linux/locks.h>
10901 +#define BDEVNAME_SIZE 0
10902 +#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
10904 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
10905 +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
10906 +#define __user
10907 +#endif
10909 +#endif
10911 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
10912 +#define YPROC_ROOT (&proc_root)
10913 +#else
10914 +#define YPROC_ROOT NULL
10915 +#endif
10917 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
10918 +#define Y_INIT_TIMER(a) init_timer(a)
10919 +#else
10920 +#define Y_INIT_TIMER(a) init_timer_on_stack(a)
10921 +#endif
10923 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
10924 +#define YAFFS_USE_WRITE_BEGIN_END 1
10925 +#else
10926 +#define YAFFS_USE_WRITE_BEGIN_END 0
10927 +#endif
10929 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
10930 +#define YAFFS_SUPER_HAS_DIRTY
10931 +#endif
10934 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0))
10935 +#define set_nlink(inode, count) do { (inode)->i_nlink = (count); } while(0)
10936 +#endif
10938 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
10939 +static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
10941 + uint64_t result = partition_size;
10942 + do_div(result, block_size);
10943 + return (uint32_t) result;
10945 +#else
10946 +#define YCALCBLOCKS(s, b) ((s)/(b))
10947 +#endif
10949 +#include <linux/uaccess.h>
10950 +#include <linux/mtd/mtd.h>
10952 +#include "yportenv.h"
10953 +#include "yaffs_trace.h"
10954 +#include "yaffs_guts.h"
10955 +#include "yaffs_attribs.h"
10957 +#include "yaffs_linux.h"
10959 +#include "yaffs_mtdif.h"
10960 +#include "yaffs_packedtags2.h"
10961 +#include "yaffs_getblockinfo.h"
10963 +unsigned int yaffs_trace_mask =
10964 + YAFFS_TRACE_BAD_BLOCKS |
10965 + YAFFS_TRACE_ALWAYS |
10966 + 0;
10968 +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
10969 +unsigned int yaffs_auto_checkpoint = 1;
10970 +unsigned int yaffs_gc_control = 1;
10971 +unsigned int yaffs_bg_enable = 1;
10972 +unsigned int yaffs_auto_select = 1;
10973 +/* Module Parameters */
10974 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
10975 +module_param(yaffs_trace_mask, uint, 0644);
10976 +module_param(yaffs_wr_attempts, uint, 0644);
10977 +module_param(yaffs_auto_checkpoint, uint, 0644);
10978 +module_param(yaffs_gc_control, uint, 0644);
10979 +module_param(yaffs_bg_enable, uint, 0644);
10980 +#else
10981 +MODULE_PARM(yaffs_trace_mask, "i");
10982 +MODULE_PARM(yaffs_wr_attempts, "i");
10983 +MODULE_PARM(yaffs_auto_checkpoint, "i");
10984 +MODULE_PARM(yaffs_gc_control, "i");
10985 +#endif
10987 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
10988 +/* use iget and read_inode */
10989 +#define Y_IGET(sb, inum) iget((sb), (inum))
10991 +#else
10992 +/* Call local equivalent */
10993 +#define YAFFS_USE_OWN_IGET
10994 +#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
10996 +#endif
10998 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
10999 +#define yaffs_inode_to_obj_lv(iptr) ((iptr)->i_private)
11000 +#else
11001 +#define yaffs_inode_to_obj_lv(iptr) ((iptr)->u.generic_ip)
11002 +#endif
11004 +#define yaffs_inode_to_obj(iptr) \
11005 + ((struct yaffs_obj *)(yaffs_inode_to_obj_lv(iptr)))
11006 +#define yaffs_dentry_to_obj(dptr) yaffs_inode_to_obj((dptr)->d_inode)
11008 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
11009 +#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->s_fs_info)
11010 +#else
11011 +#define yaffs_super_to_dev(sb) ((struct yaffs_dev *)sb->u.generic_sbp)
11012 +#endif
11014 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0))
11015 +#define Y_CLEAR_INODE(i) clear_inode(i)
11016 +#else
11017 +#define Y_CLEAR_INODE(i) end_writeback(i)
11018 +#endif
11020 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0))
11021 +#define YAFFS_USE_DIR_ITERATE
11022 +#endif
11024 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,12,0))
11025 +#define YAFFS_NEW_PROCFS
11026 +#include <linux/seq_file.h>
11027 +#endif
11030 +#define update_dir_time(dir) do {\
11031 + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
11032 + } while (0)
11034 +static void yaffs_fill_inode_from_obj(struct inode *inode,
11035 + struct yaffs_obj *obj);
11038 +static void yaffs_gross_lock(struct yaffs_dev *dev)
11040 + yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locking %p", current);
11041 + mutex_lock(&(yaffs_dev_to_lc(dev)->gross_lock));
11042 + yaffs_trace(YAFFS_TRACE_LOCK, "yaffs locked %p", current);
11045 +static void yaffs_gross_unlock(struct yaffs_dev *dev)
11047 + yaffs_trace(YAFFS_TRACE_LOCK, "yaffs unlocking %p", current);
11048 + mutex_unlock(&(yaffs_dev_to_lc(dev)->gross_lock));
11052 +static int yaffs_readpage_nolock(struct file *f, struct page *pg)
11054 + /* Lifted from jffs2 */
11056 + struct yaffs_obj *obj;
11057 + unsigned char *pg_buf;
11058 + int ret;
11059 + loff_t pos = ((loff_t) pg->index) << PAGE_CACHE_SHIFT;
11060 + struct yaffs_dev *dev;
11062 + yaffs_trace(YAFFS_TRACE_OS,
11063 + "yaffs_readpage_nolock at %lld, size %08x",
11064 + (long long)pos,
11065 + (unsigned)PAGE_CACHE_SIZE);
11067 + obj = yaffs_dentry_to_obj(f->f_dentry);
11069 + dev = obj->my_dev;
11071 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
11072 + BUG_ON(!PageLocked(pg));
11073 +#else
11074 + if (!PageLocked(pg))
11075 + PAGE_BUG(pg);
11076 +#endif
11078 + pg_buf = kmap(pg);
11079 + /* FIXME: Can kmap fail? */
11081 + yaffs_gross_lock(dev);
11083 + ret = yaffs_file_rd(obj, pg_buf, pos, PAGE_CACHE_SIZE);
11085 + yaffs_gross_unlock(dev);
11087 + if (ret >= 0)
11088 + ret = 0;
11090 + if (ret) {
11091 + ClearPageUptodate(pg);
11092 + SetPageError(pg);
11093 + } else {
11094 + SetPageUptodate(pg);
11095 + ClearPageError(pg);
11098 + flush_dcache_page(pg);
11099 + kunmap(pg);
11101 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage_nolock done");
11102 + return ret;
11105 +static int yaffs_readpage_unlock(struct file *f, struct page *pg)
11107 + int ret = yaffs_readpage_nolock(f, pg);
11108 + UnlockPage(pg);
11109 + return ret;
11112 +static int yaffs_readpage(struct file *f, struct page *pg)
11114 + int ret;
11116 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage");
11117 + ret = yaffs_readpage_unlock(f, pg);
11118 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_readpage done");
11119 + return ret;
11123 +static void yaffs_set_super_dirty_val(struct yaffs_dev *dev, int val)
11125 + struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
11127 + if (lc)
11128 + lc->dirty = val;
11130 +# ifdef YAFFS_SUPER_HAS_DIRTY
11132 + struct super_block *sb = lc->super;
11134 + if (sb)
11135 + sb->s_dirt = val;
11137 +#endif
11141 +static void yaffs_set_super_dirty(struct yaffs_dev *dev)
11143 + yaffs_set_super_dirty_val(dev, 1);
11146 +static void yaffs_clear_super_dirty(struct yaffs_dev *dev)
11148 + yaffs_set_super_dirty_val(dev, 0);
11151 +static int yaffs_check_super_dirty(struct yaffs_dev *dev)
11153 + struct yaffs_linux_context *lc = yaffs_dev_to_lc(dev);
11155 + if (lc && lc->dirty)
11156 + return 1;
11158 +# ifdef YAFFS_SUPER_HAS_DIRTY
11160 + struct super_block *sb = lc->super;
11162 + if (sb && sb->s_dirt)
11163 + return 1;
11165 +#endif
11166 + return 0;
11170 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
11171 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
11172 +#else
11173 +static int yaffs_writepage(struct page *page)
11174 +#endif
11176 + struct yaffs_dev *dev;
11177 + struct address_space *mapping = page->mapping;
11178 + struct inode *inode;
11179 + unsigned long end_index;
11180 + char *buffer;
11181 + struct yaffs_obj *obj;
11182 + int n_written = 0;
11183 + unsigned n_bytes;
11184 + loff_t i_size;
11186 + if (!mapping)
11187 + BUG();
11188 + inode = mapping->host;
11189 + if (!inode)
11190 + BUG();
11191 + i_size = i_size_read(inode);
11193 + end_index = i_size >> PAGE_CACHE_SHIFT;
11195 + if (page->index < end_index)
11196 + n_bytes = PAGE_CACHE_SIZE;
11197 + else {
11198 + n_bytes = i_size & (PAGE_CACHE_SIZE - 1);
11200 + if (page->index > end_index || !n_bytes) {
11201 + yaffs_trace(YAFFS_TRACE_OS,
11202 + "yaffs_writepage at %lld, inode size = %lld!!",
11203 + ((loff_t)page->index) << PAGE_CACHE_SHIFT,
11204 + inode->i_size);
11205 + yaffs_trace(YAFFS_TRACE_OS,
11206 + " -> don't care!!");
11208 + zero_user_segment(page, 0, PAGE_CACHE_SIZE);
11209 + set_page_writeback(page);
11210 + unlock_page(page);
11211 + end_page_writeback(page);
11212 + return 0;
11216 + if (n_bytes != PAGE_CACHE_SIZE)
11217 + zero_user_segment(page, n_bytes, PAGE_CACHE_SIZE);
11219 + get_page(page);
11221 + buffer = kmap(page);
11223 + obj = yaffs_inode_to_obj(inode);
11224 + dev = obj->my_dev;
11225 + yaffs_gross_lock(dev);
11227 + yaffs_trace(YAFFS_TRACE_OS,
11228 + "yaffs_writepage at %lld, size %08x",
11229 + ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes);
11230 + yaffs_trace(YAFFS_TRACE_OS,
11231 + "writepag0: obj = %lld, ino = %lld",
11232 + obj->variant.file_variant.file_size, inode->i_size);
11234 + n_written = yaffs_wr_file(obj, buffer,
11235 + ((loff_t)page->index) << PAGE_CACHE_SHIFT, n_bytes, 0);
11237 + yaffs_set_super_dirty(dev);
11239 + yaffs_trace(YAFFS_TRACE_OS,
11240 + "writepag1: obj = %lld, ino = %lld",
11241 + obj->variant.file_variant.file_size, inode->i_size);
11243 + yaffs_gross_unlock(dev);
11245 + kunmap(page);
11246 + set_page_writeback(page);
11247 + unlock_page(page);
11248 + end_page_writeback(page);
11249 + put_page(page);
11251 + return (n_written == n_bytes) ? 0 : -ENOSPC;
11254 +/* Space holding and freeing is done to ensure we have space available for write_begin/end */
11255 +/* For now we just assume few parallel writes and check against a small number. */
11256 +/* Todo: need to do this with a counter to handle parallel reads better */
11258 +static ssize_t yaffs_hold_space(struct file *f)
11260 + struct yaffs_obj *obj;
11261 + struct yaffs_dev *dev;
11263 + int n_free_chunks;
11265 + obj = yaffs_dentry_to_obj(f->f_dentry);
11267 + dev = obj->my_dev;
11269 + yaffs_gross_lock(dev);
11271 + n_free_chunks = yaffs_get_n_free_chunks(dev);
11273 + yaffs_gross_unlock(dev);
11275 + return (n_free_chunks > 20) ? 1 : 0;
11278 +static void yaffs_release_space(struct file *f)
11280 + struct yaffs_obj *obj;
11281 + struct yaffs_dev *dev;
11283 + obj = yaffs_dentry_to_obj(f->f_dentry);
11285 + dev = obj->my_dev;
11287 + yaffs_gross_lock(dev);
11289 + yaffs_gross_unlock(dev);
11292 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
11293 +static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
11294 + loff_t pos, unsigned len, unsigned flags,
11295 + struct page **pagep, void **fsdata)
11297 + struct page *pg = NULL;
11298 + pgoff_t index = pos >> PAGE_CACHE_SHIFT;
11300 + int ret = 0;
11301 + int space_held = 0;
11303 + /* Get a page */
11304 +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
11305 + pg = grab_cache_page_write_begin(mapping, index, flags);
11306 +#else
11307 + pg = __grab_cache_page(mapping, index);
11308 +#endif
11310 + *pagep = pg;
11311 + if (!pg) {
11312 + ret = -ENOMEM;
11313 + goto out;
11315 + yaffs_trace(YAFFS_TRACE_OS,
11316 + "start yaffs_write_begin index %d(%x) uptodate %d",
11317 + (int)index, (int)index, Page_Uptodate(pg) ? 1 : 0);
11319 + /* Get fs space */
11320 + space_held = yaffs_hold_space(filp);
11322 + if (!space_held) {
11323 + ret = -ENOSPC;
11324 + goto out;
11327 + /* Update page if required */
11329 + if (!Page_Uptodate(pg))
11330 + ret = yaffs_readpage_nolock(filp, pg);
11332 + if (ret)
11333 + goto out;
11335 + /* Happy path return */
11336 + yaffs_trace(YAFFS_TRACE_OS, "end yaffs_write_begin - ok");
11338 + return 0;
11340 +out:
11341 + yaffs_trace(YAFFS_TRACE_OS,
11342 + "end yaffs_write_begin fail returning %d", ret);
11343 + if (space_held)
11344 + yaffs_release_space(filp);
11345 + if (pg) {
11346 + unlock_page(pg);
11347 + page_cache_release(pg);
11349 + return ret;
11352 +#else
11354 +static int yaffs_prepare_write(struct file *f, struct page *pg,
11355 + unsigned offset, unsigned to)
11357 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_prepair_write");
11359 + if (!Page_Uptodate(pg))
11360 + return yaffs_readpage_nolock(f, pg);
11361 + return 0;
11363 +#endif
11366 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
11367 + loff_t * pos)
11369 + struct yaffs_obj *obj;
11370 + int n_written;
11371 + loff_t ipos;
11372 + struct inode *inode;
11373 + struct yaffs_dev *dev;
11375 + obj = yaffs_dentry_to_obj(f->f_dentry);
11377 + if (!obj) {
11378 + yaffs_trace(YAFFS_TRACE_OS,
11379 + "yaffs_file_write: hey obj is null!");
11380 + return -EINVAL;
11383 + dev = obj->my_dev;
11385 + yaffs_gross_lock(dev);
11387 + inode = f->f_dentry->d_inode;
11389 + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
11390 + ipos = inode->i_size;
11391 + else
11392 + ipos = *pos;
11394 + yaffs_trace(YAFFS_TRACE_OS,
11395 + "yaffs_file_write about to write writing %u(%x) bytes to object %d at %lld",
11396 + (unsigned)n, (unsigned)n, obj->obj_id, ipos);
11398 + n_written = yaffs_wr_file(obj, buf, ipos, n, 0);
11400 + yaffs_set_super_dirty(dev);
11402 + yaffs_trace(YAFFS_TRACE_OS,
11403 + "yaffs_file_write: %d(%x) bytes written",
11404 + (unsigned)n, (unsigned)n);
11406 + if (n_written > 0) {
11407 + ipos += n_written;
11408 + *pos = ipos;
11409 + if (ipos > inode->i_size) {
11410 + inode->i_size = ipos;
11411 + inode->i_blocks = (ipos + 511) >> 9;
11413 + yaffs_trace(YAFFS_TRACE_OS,
11414 + "yaffs_file_write size updated to %lld bytes, %d blocks",
11415 + ipos, (int)(inode->i_blocks));
11419 + yaffs_gross_unlock(dev);
11420 + return (n_written == 0) && (n > 0) ? -ENOSPC : n_written;
11424 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
11425 +static int yaffs_write_end(struct file *filp, struct address_space *mapping,
11426 + loff_t pos, unsigned len, unsigned copied,
11427 + struct page *pg, void *fsdadata)
11429 + int ret = 0;
11430 + void *addr, *kva;
11431 + uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
11433 + kva = kmap(pg);
11434 + addr = kva + offset_into_page;
11436 + yaffs_trace(YAFFS_TRACE_OS,
11437 + "yaffs_write_end addr %p pos %lld n_bytes %d",
11438 + addr, pos, copied);
11440 + ret = yaffs_file_write(filp, addr, copied, &pos);
11442 + if (ret != copied) {
11443 + yaffs_trace(YAFFS_TRACE_OS,
11444 + "yaffs_write_end not same size ret %d copied %d",
11445 + ret, copied);
11446 + SetPageError(pg);
11449 + kunmap(pg);
11451 + yaffs_release_space(filp);
11452 + unlock_page(pg);
11453 + page_cache_release(pg);
11454 + return ret;
11456 +#else
11458 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
11459 + unsigned to)
11461 + void *addr, *kva;
11463 + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
11464 + int n_bytes = to - offset;
11465 + int n_written;
11467 + kva = kmap(pg);
11468 + addr = kva + offset;
11470 + yaffs_trace(YAFFS_TRACE_OS,
11471 + "yaffs_commit_write addr %p pos %lld n_bytes %d",
11472 + addr, pos, n_bytes);
11474 + n_written = yaffs_file_write(f, addr, n_bytes, &pos);
11476 + if (n_written != n_bytes) {
11477 + yaffs_trace(YAFFS_TRACE_OS,
11478 + "yaffs_commit_write not same size n_written %d n_bytes %d",
11479 + n_written, n_bytes);
11480 + SetPageError(pg);
11482 + kunmap(pg);
11484 + yaffs_trace(YAFFS_TRACE_OS,
11485 + "yaffs_commit_write returning %d",
11486 + n_written == n_bytes ? 0 : n_written);
11488 + return n_written == n_bytes ? 0 : n_written;
11490 +#endif
11492 +static struct address_space_operations yaffs_file_address_operations = {
11493 + .readpage = yaffs_readpage,
11494 + .writepage = yaffs_writepage,
11495 +#if (YAFFS_USE_WRITE_BEGIN_END > 0)
11496 + .write_begin = yaffs_write_begin,
11497 + .write_end = yaffs_write_end,
11498 +#else
11499 + .prepare_write = yaffs_prepare_write,
11500 + .commit_write = yaffs_commit_write,
11501 +#endif
11505 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
11506 +static int yaffs_file_flush(struct file *file, fl_owner_t id)
11507 +#else
11508 +static int yaffs_file_flush(struct file *file)
11509 +#endif
11511 + struct yaffs_obj *obj = yaffs_dentry_to_obj(file->f_dentry);
11513 + struct yaffs_dev *dev = obj->my_dev;
11515 + yaffs_trace(YAFFS_TRACE_OS,
11516 + "yaffs_file_flush object %d (%s)",
11517 + obj->obj_id,
11518 + obj->dirty ? "dirty" : "clean");
11520 + yaffs_gross_lock(dev);
11522 + yaffs_flush_file(obj, 1, 0, 0);
11524 + yaffs_gross_unlock(dev);
11526 + return 0;
11530 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
11531 +static int yaffs_sync_object(struct file *file, loff_t start, loff_t end, int datasync)
11532 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
11533 +static int yaffs_sync_object(struct file *file, int datasync)
11534 +#else
11535 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
11536 + int datasync)
11537 +#endif
11539 + struct yaffs_obj *obj;
11540 + struct yaffs_dev *dev;
11541 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
11542 + struct dentry *dentry = file->f_path.dentry;
11543 +#endif
11545 + obj = yaffs_dentry_to_obj(dentry);
11547 + dev = obj->my_dev;
11549 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
11550 + "yaffs_sync_object");
11551 + yaffs_gross_lock(dev);
11552 + yaffs_flush_file(obj, 1, datasync, 0);
11553 + yaffs_gross_unlock(dev);
11554 + return 0;
11558 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
11559 +static const struct file_operations yaffs_file_operations = {
11560 + .read = do_sync_read,
11561 + .write = do_sync_write,
11562 + .read_iter = generic_file_read_iter,
11563 + .write_iter = generic_file_write_iter,
11564 + .mmap = generic_file_mmap,
11565 + .flush = yaffs_file_flush,
11566 + .fsync = yaffs_sync_object,
11567 + .splice_read = generic_file_splice_read,
11568 + .splice_write = iter_file_splice_write,
11569 + .llseek = generic_file_llseek,
11572 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
11574 +static const struct file_operations yaffs_file_operations = {
11575 + .read = do_sync_read,
11576 + .write = do_sync_write,
11577 + .aio_read = generic_file_aio_read,
11578 + .aio_write = generic_file_aio_write,
11579 + .mmap = generic_file_mmap,
11580 + .flush = yaffs_file_flush,
11581 + .fsync = yaffs_sync_object,
11582 + .sendfile = generic_file_sendfile,
11585 +#else
11587 +static const struct file_operations yaffs_file_operations = {
11588 + .read = generic_file_read,
11589 + .write = generic_file_write,
11590 + .mmap = generic_file_mmap,
11591 + .flush = yaffs_file_flush,
11592 + .fsync = yaffs_sync_object,
11593 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
11594 + .sendfile = generic_file_sendfile,
11595 +#endif
11597 +#endif
11602 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
11603 +static void zero_user_segment(struct page *page, unsigned start, unsigned end)
11605 + void *kaddr = kmap_atomic(page, KM_USER0);
11606 + memset(kaddr + start, 0, end - start);
11607 + kunmap_atomic(kaddr, KM_USER0);
11608 + flush_dcache_page(page);
11610 +#endif
11613 +static int yaffs_vfs_setsize(struct inode *inode, loff_t newsize)
11615 +#ifdef YAFFS_USE_TRUNCATE_SETSIZE
11616 + truncate_setsize(inode, newsize);
11617 + return 0;
11618 +#else
11619 + truncate_inode_pages(&inode->i_data, newsize);
11620 + return 0;
11621 +#endif
11626 +static int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
11628 +#ifdef YAFFS_USE_SETATTR_COPY
11629 + setattr_copy(inode, attr);
11630 + return 0;
11631 +#else
11632 + return inode_setattr(inode, attr);
11633 +#endif
11637 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
11639 + struct inode *inode = dentry->d_inode;
11640 + int error = 0;
11641 + struct yaffs_dev *dev;
11643 + yaffs_trace(YAFFS_TRACE_OS,
11644 + "yaffs_setattr of object %d",
11645 + yaffs_inode_to_obj(inode)->obj_id);
11646 +#if 0
11647 + /* Fail if a requested resize >= 2GB */
11648 + if (attr->ia_valid & ATTR_SIZE && (attr->ia_size >> 31))
11649 + error = -EINVAL;
11650 +#endif
11652 + if (error == 0)
11653 + error = inode_change_ok(inode, attr);
11654 + if (error == 0) {
11655 + int result;
11656 + if (!error) {
11657 + error = yaffs_vfs_setattr(inode, attr);
11658 + yaffs_trace(YAFFS_TRACE_OS, "inode_setattr called");
11659 + if (attr->ia_valid & ATTR_SIZE) {
11660 + yaffs_vfs_setsize(inode, attr->ia_size);
11661 + inode->i_blocks = (inode->i_size + 511) >> 9;
11664 + dev = yaffs_inode_to_obj(inode)->my_dev;
11665 + if (attr->ia_valid & ATTR_SIZE) {
11666 + yaffs_trace(YAFFS_TRACE_OS,
11667 + "resize to %d(%x)",
11668 + (int)(attr->ia_size),
11669 + (int)(attr->ia_size));
11671 + yaffs_gross_lock(dev);
11672 + result = yaffs_set_attribs(yaffs_inode_to_obj(inode), attr);
11673 + if (result == YAFFS_OK) {
11674 + error = 0;
11675 + } else {
11676 + error = -EPERM;
11678 + yaffs_gross_unlock(dev);
11682 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_setattr done returning %d", error);
11684 + return error;
11687 +static int yaffs_setxattr(struct dentry *dentry, const char *name,
11688 + const void *value, size_t size, int flags)
11690 + struct inode *inode = dentry->d_inode;
11691 + int error = 0;
11692 + struct yaffs_dev *dev;
11693 + struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
11695 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr of object %d", obj->obj_id);
11697 + if (error == 0) {
11698 + int result;
11699 + dev = obj->my_dev;
11700 + yaffs_gross_lock(dev);
11701 + result = yaffs_set_xattrib(obj, name, value, size, flags);
11702 + if (result == YAFFS_OK)
11703 + error = 0;
11704 + else if (result < 0)
11705 + error = result;
11706 + yaffs_gross_unlock(dev);
11709 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_setxattr done returning %d", error);
11711 + return error;
11714 +static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name,
11715 + void *buff, size_t size)
11717 + struct inode *inode = dentry->d_inode;
11718 + int error = 0;
11719 + struct yaffs_dev *dev;
11720 + struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
11722 + yaffs_trace(YAFFS_TRACE_OS,
11723 + "yaffs_getxattr \"%s\" from object %d",
11724 + name, obj->obj_id);
11726 + if (error == 0) {
11727 + dev = obj->my_dev;
11728 + yaffs_gross_lock(dev);
11729 + error = yaffs_get_xattrib(obj, name, buff, size);
11730 + yaffs_gross_unlock(dev);
11733 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_getxattr done returning %d", error);
11735 + return error;
11738 +static int yaffs_removexattr(struct dentry *dentry, const char *name)
11740 + struct inode *inode = dentry->d_inode;
11741 + int error = 0;
11742 + struct yaffs_dev *dev;
11743 + struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
11745 + yaffs_trace(YAFFS_TRACE_OS,
11746 + "yaffs_removexattr of object %d", obj->obj_id);
11748 + if (error == 0) {
11749 + int result;
11750 + dev = obj->my_dev;
11751 + yaffs_gross_lock(dev);
11752 + result = yaffs_remove_xattrib(obj, name);
11753 + if (result == YAFFS_OK)
11754 + error = 0;
11755 + else if (result < 0)
11756 + error = result;
11757 + yaffs_gross_unlock(dev);
11760 + yaffs_trace(YAFFS_TRACE_OS,
11761 + "yaffs_removexattr done returning %d", error);
11763 + return error;
11766 +static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size)
11768 + struct inode *inode = dentry->d_inode;
11769 + int error = 0;
11770 + struct yaffs_dev *dev;
11771 + struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
11773 + yaffs_trace(YAFFS_TRACE_OS,
11774 + "yaffs_listxattr of object %d", obj->obj_id);
11776 + if (error == 0) {
11777 + dev = obj->my_dev;
11778 + yaffs_gross_lock(dev);
11779 + error = yaffs_list_xattrib(obj, buff, size);
11780 + yaffs_gross_unlock(dev);
11783 + yaffs_trace(YAFFS_TRACE_OS,
11784 + "yaffs_listxattr done returning %d", error);
11786 + return error;
11790 +static const struct inode_operations yaffs_file_inode_operations = {
11791 + .setattr = yaffs_setattr,
11792 + .setxattr = yaffs_setxattr,
11793 + .getxattr = yaffs_getxattr,
11794 + .listxattr = yaffs_listxattr,
11795 + .removexattr = yaffs_removexattr,
11799 +static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
11800 + int buflen)
11802 + unsigned char *alias;
11803 + int ret;
11805 + struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
11807 + yaffs_gross_lock(dev);
11809 + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
11811 + yaffs_gross_unlock(dev);
11813 + if (!alias)
11814 + return -ENOMEM;
11816 +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)
11817 + ret = vfs_readlink(dentry, buffer, buflen, alias);
11818 +#else
11819 + ret = readlink_copy(buffer, buflen, alias);
11820 +#endif
11821 + kfree(alias);
11822 + return ret;
11825 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
11826 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
11828 + void *ret;
11829 +#else
11830 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
11832 + int ret
11833 +#endif
11834 + unsigned char *alias;
11835 + int ret_int = 0;
11836 + struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
11838 + yaffs_gross_lock(dev);
11840 + alias = yaffs_get_symlink_alias(yaffs_dentry_to_obj(dentry));
11841 + yaffs_gross_unlock(dev);
11843 + if (!alias) {
11844 + ret_int = -ENOMEM;
11845 + goto out;
11847 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
11848 + nd_set_link(nd, alias);
11849 + ret = alias;
11850 +out:
11851 + if (ret_int)
11852 + ret = ERR_PTR(ret_int);
11853 + return ret;
11854 +#else
11855 + ret = vfs_follow_link(nd, alias);
11856 + kfree(alias);
11857 +out:
11858 + if (ret_int)
11859 + ret = ret_int;
11860 + return ret;
11861 +#endif
11865 +#ifdef YAFFS_HAS_PUT_INODE
11867 +/* For now put inode is just for debugging
11868 + * Put inode is called when the inode **structure** is put.
11869 + */
11870 +static void yaffs_put_inode(struct inode *inode)
11872 + yaffs_trace(YAFFS_TRACE_OS,
11873 + "yaffs_put_inode: ino %d, count %d"),
11874 + (int)inode->i_ino, atomic_read(&inode->i_count);
11877 +#endif
11879 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
11880 +void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias)
11882 + kfree(alias);
11884 +#endif
11886 +static const struct inode_operations yaffs_symlink_inode_operations = {
11887 + .readlink = yaffs_readlink,
11888 + .follow_link = yaffs_follow_link,
11889 +#if (YAFFS_NEW_FOLLOW_LINK == 1)
11890 + .put_link = yaffs_put_link,
11891 +#endif
11892 + .setattr = yaffs_setattr,
11893 + .setxattr = yaffs_setxattr,
11894 + .getxattr = yaffs_getxattr,
11895 + .listxattr = yaffs_listxattr,
11896 + .removexattr = yaffs_removexattr,
11899 +#ifdef YAFFS_USE_OWN_IGET
11901 +static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
11903 + struct inode *inode;
11904 + struct yaffs_obj *obj;
11905 + struct yaffs_dev *dev = yaffs_super_to_dev(sb);
11907 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_iget for %lu", ino);
11909 + inode = iget_locked(sb, ino);
11910 + if (!inode)
11911 + return ERR_PTR(-ENOMEM);
11912 + if (!(inode->i_state & I_NEW))
11913 + return inode;
11915 + /* NB This is called as a side effect of other functions, but
11916 + * we had to release the lock to prevent deadlocks, so
11917 + * need to lock again.
11918 + */
11920 + yaffs_gross_lock(dev);
11922 + obj = yaffs_find_by_number(dev, inode->i_ino);
11924 + yaffs_fill_inode_from_obj(inode, obj);
11926 + yaffs_gross_unlock(dev);
11928 + unlock_new_inode(inode);
11929 + return inode;
11932 +#else
11934 +static void yaffs_read_inode(struct inode *inode)
11936 + /* NB This is called as a side effect of other functions, but
11937 + * we had to release the lock to prevent deadlocks, so
11938 + * need to lock again.
11939 + */
11941 + struct yaffs_obj *obj;
11942 + struct yaffs_dev *dev = yaffs_super_to_dev(inode->i_sb);
11944 + yaffs_trace(YAFFS_TRACE_OS,
11945 + "yaffs_read_inode for %d", (int)inode->i_ino);
11947 + if (current != yaffs_dev_to_lc(dev)->readdir_process)
11948 + yaffs_gross_lock(dev);
11950 + obj = yaffs_find_by_number(dev, inode->i_ino);
11952 + yaffs_fill_inode_from_obj(inode, obj);
11954 + if (current != yaffs_dev_to_lc(dev)->readdir_process)
11955 + yaffs_gross_unlock(dev);
11958 +#endif
11962 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
11963 + struct yaffs_obj *obj)
11965 + struct inode *inode;
11967 + if (!sb) {
11968 + yaffs_trace(YAFFS_TRACE_OS,
11969 + "yaffs_get_inode for NULL super_block!!");
11970 + return NULL;
11974 + if (!obj) {
11975 + yaffs_trace(YAFFS_TRACE_OS,
11976 + "yaffs_get_inode for NULL object!!");
11977 + return NULL;
11981 + yaffs_trace(YAFFS_TRACE_OS,
11982 + "yaffs_get_inode for object %d", obj->obj_id);
11984 + inode = Y_IGET(sb, obj->obj_id);
11985 + if (IS_ERR(inode))
11986 + return NULL;
11988 + /* NB Side effect: iget calls back to yaffs_read_inode(). */
11989 + /* iget also increments the inode's i_count */
11990 + /* NB You can't be holding gross_lock or deadlock will happen! */
11992 + return inode;
11997 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
11998 +#define YCRED(x) x
11999 +#else
12000 +#define YCRED(x) (x->cred)
12001 +#endif
12003 +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
12004 +#define YPROC_uid(p) (YCRED(p)->fsuid)
12005 +#define YPROC_gid(p) (YCRED(p)->fsgid)
12006 +#define EXTRACT_gid(x) x
12007 +#define EXTRACT_uid(x) x
12008 +#define MAKE_gid(x) x
12009 +#define MAKE_uid(x) x
12010 +#else
12011 +#define YPROC_uid(p) from_kuid(&init_user_ns, YCRED(p)->fsuid)
12012 +#define YPROC_gid(p) from_kgid(&init_user_ns, YCRED(p)->fsgid)
12013 +#define EXTRACT_gid(x) from_kgid(&init_user_ns, x)
12014 +#define EXTRACT_uid(x) from_kuid(&init_user_ns, x)
12015 +#define MAKE_gid(x) make_kgid(&init_user_ns, x)
12016 +#define MAKE_uid(x) make_kuid(&init_user_ns, x)
12017 +#endif
12020 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
12021 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
12022 + dev_t rdev)
12023 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
12024 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
12025 + dev_t rdev)
12026 +#else
12027 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
12028 + int rdev)
12029 +#endif
12031 + struct inode *inode;
12033 + struct yaffs_obj *obj = NULL;
12034 + struct yaffs_dev *dev;
12036 + struct yaffs_obj *parent = yaffs_inode_to_obj(dir);
12038 + int error = -ENOSPC;
12039 + uid_t uid = YPROC_uid(current);
12040 + gid_t gid =
12041 + (dir->i_mode & S_ISGID) ? EXTRACT_gid(dir->i_gid) : YPROC_gid(current);
12043 + if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
12044 + mode |= S_ISGID;
12046 + if (parent) {
12047 + yaffs_trace(YAFFS_TRACE_OS,
12048 + "yaffs_mknod: parent object %d type %d",
12049 + parent->obj_id, parent->variant_type);
12050 + } else {
12051 + yaffs_trace(YAFFS_TRACE_OS,
12052 + "yaffs_mknod: could not get parent object");
12053 + return -EPERM;
12056 + yaffs_trace(YAFFS_TRACE_OS,
12057 + "yaffs_mknod: making oject for %s, mode %x dev %x",
12058 + dentry->d_name.name, mode, rdev);
12060 + dev = parent->my_dev;
12062 + yaffs_gross_lock(dev);
12064 + switch (mode & S_IFMT) {
12065 + default:
12066 + /* Special (socket, fifo, device...) */
12067 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making special");
12068 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
12069 + obj =
12070 + yaffs_create_special(parent, dentry->d_name.name, mode, uid,
12071 + gid, old_encode_dev(rdev));
12072 +#else
12073 + obj =
12074 + yaffs_create_special(parent, dentry->d_name.name, mode, uid,
12075 + gid, rdev);
12076 +#endif
12077 + break;
12078 + case S_IFREG: /* file */
12079 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making file");
12080 + obj = yaffs_create_file(parent, dentry->d_name.name, mode, uid,
12081 + gid);
12082 + break;
12083 + case S_IFDIR: /* directory */
12084 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making directory");
12085 + obj = yaffs_create_dir(parent, dentry->d_name.name, mode,
12086 + uid, gid);
12087 + break;
12088 + case S_IFLNK: /* symlink */
12089 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: making symlink");
12090 + obj = NULL; /* Do we ever get here? */
12091 + break;
12094 + /* Can not call yaffs_get_inode() with gross lock held */
12095 + yaffs_gross_unlock(dev);
12097 + if (obj) {
12098 + inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
12099 + d_instantiate(dentry, inode);
12100 + update_dir_time(dir);
12101 + yaffs_trace(YAFFS_TRACE_OS,
12102 + "yaffs_mknod created object %d count = %d",
12103 + obj->obj_id, atomic_read(&inode->i_count));
12104 + error = 0;
12105 + yaffs_fill_inode_from_obj(dir, parent);
12106 + } else {
12107 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod failed making object");
12108 + error = -ENOMEM;
12111 + return error;
12114 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
12115 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
12116 +#else
12117 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
12118 +#endif
12120 + int ret_val;
12121 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mkdir");
12122 + ret_val = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
12123 + return ret_val;
12127 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
12128 +static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
12129 + bool dummy)
12130 +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0))
12131 +static int yaffs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
12132 + struct nameidata *n)
12133 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
12134 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
12135 + struct nameidata *n)
12136 +#else
12137 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
12138 +#endif
12140 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_create");
12141 + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
12144 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
12145 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
12146 + unsigned int dummy)
12147 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
12148 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
12149 + struct nameidata *n)
12150 +#else
12151 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
12152 +#endif
12154 + struct yaffs_obj *obj;
12155 + struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
12157 + struct yaffs_dev *dev = yaffs_inode_to_obj(dir)->my_dev;
12159 + if (current != yaffs_dev_to_lc(dev)->readdir_process)
12160 + yaffs_gross_lock(dev);
12162 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup for %d:%s",
12163 + yaffs_inode_to_obj(dir)->obj_id, dentry->d_name.name);
12165 + obj = yaffs_find_by_name(yaffs_inode_to_obj(dir), dentry->d_name.name);
12167 + obj = yaffs_get_equivalent_obj(obj); /* in case it was a hardlink */
12169 + /* Can't hold gross lock when calling yaffs_get_inode() */
12170 + if (current != yaffs_dev_to_lc(dev)->readdir_process)
12171 + yaffs_gross_unlock(dev);
12173 + if (obj) {
12174 + yaffs_trace(YAFFS_TRACE_OS,
12175 + "yaffs_lookup found %d", obj->obj_id);
12177 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
12178 + } else {
12179 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_lookup not found");
12183 +/* added NCB for 2.5/6 compatability - forces add even if inode is
12184 + * NULL which creates dentry hash */
12185 + d_add(dentry, inode);
12187 + return NULL;
12191 + * Create a link...
12192 + */
12193 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
12194 + struct dentry *dentry)
12196 + struct inode *inode = old_dentry->d_inode;
12197 + struct yaffs_obj *obj = NULL;
12198 + struct yaffs_obj *link = NULL;
12199 + struct yaffs_dev *dev;
12201 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_link");
12203 + obj = yaffs_inode_to_obj(inode);
12204 + dev = obj->my_dev;
12206 + yaffs_gross_lock(dev);
12208 + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
12209 + link =
12210 + yaffs_link_obj(yaffs_inode_to_obj(dir), dentry->d_name.name,
12211 + obj);
12213 + if (link) {
12214 + set_nlink(old_dentry->d_inode, yaffs_get_obj_link_count(obj));
12215 + d_instantiate(dentry, old_dentry->d_inode);
12216 + atomic_inc(&old_dentry->d_inode->i_count);
12217 + yaffs_trace(YAFFS_TRACE_OS,
12218 + "yaffs_link link count %d i_count %d",
12219 + old_dentry->d_inode->i_nlink,
12220 + atomic_read(&old_dentry->d_inode->i_count));
12223 + yaffs_gross_unlock(dev);
12225 + if (link) {
12226 + update_dir_time(dir);
12227 + return 0;
12230 + return -EPERM;
12233 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
12234 + const char *symname)
12236 + struct yaffs_obj *obj;
12237 + struct yaffs_dev *dev;
12238 + uid_t uid = YPROC_uid(current);
12239 + gid_t gid =
12240 + (dir->i_mode & S_ISGID) ? EXTRACT_gid(dir->i_gid) : YPROC_gid(current);
12242 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink");
12244 + if (strnlen(dentry->d_name.name, YAFFS_MAX_NAME_LENGTH + 1) >
12245 + YAFFS_MAX_NAME_LENGTH)
12246 + return -ENAMETOOLONG;
12248 + if (strnlen(symname, YAFFS_MAX_ALIAS_LENGTH + 1) >
12249 + YAFFS_MAX_ALIAS_LENGTH)
12250 + return -ENAMETOOLONG;
12252 + dev = yaffs_inode_to_obj(dir)->my_dev;
12253 + yaffs_gross_lock(dev);
12254 + obj = yaffs_create_symlink(yaffs_inode_to_obj(dir), dentry->d_name.name,
12255 + S_IFLNK | S_IRWXUGO, uid, gid, symname);
12256 + yaffs_gross_unlock(dev);
12258 + if (obj) {
12259 + struct inode *inode;
12261 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
12262 + d_instantiate(dentry, inode);
12263 + update_dir_time(dir);
12264 + yaffs_trace(YAFFS_TRACE_OS, "symlink created OK");
12265 + return 0;
12266 + } else {
12267 + yaffs_trace(YAFFS_TRACE_OS, "symlink not created");
12270 + return -ENOMEM;
12274 + * The VFS layer already does all the dentry stuff for rename.
12276 + * NB: POSIX says you can rename an object over an old object of the same name
12277 + */
12278 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
12279 + struct inode *new_dir, struct dentry *new_dentry)
12281 + struct yaffs_dev *dev;
12282 + int ret_val = YAFFS_FAIL;
12283 + struct yaffs_obj *target;
12285 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_rename");
12286 + dev = yaffs_inode_to_obj(old_dir)->my_dev;
12288 + yaffs_gross_lock(dev);
12290 + /* Check if the target is an existing directory that is not empty. */
12291 + target = yaffs_find_by_name(yaffs_inode_to_obj(new_dir),
12292 + new_dentry->d_name.name);
12294 + if (target && target->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
12295 + !list_empty(&target->variant.dir_variant.children)) {
12297 + yaffs_trace(YAFFS_TRACE_OS, "target is non-empty dir");
12299 + ret_val = YAFFS_FAIL;
12300 + } else {
12301 + /* Now does unlinking internally using shadowing mechanism */
12302 + yaffs_trace(YAFFS_TRACE_OS, "calling yaffs_rename_obj");
12304 + ret_val = yaffs_rename_obj(yaffs_inode_to_obj(old_dir),
12305 + old_dentry->d_name.name,
12306 + yaffs_inode_to_obj(new_dir),
12307 + new_dentry->d_name.name);
12309 + yaffs_gross_unlock(dev);
12311 + if (ret_val == YAFFS_OK) {
12312 + if (target)
12313 + inode_dec_link_count(new_dentry->d_inode);
12315 + update_dir_time(old_dir);
12316 + if (old_dir != new_dir)
12317 + update_dir_time(new_dir);
12318 + return 0;
12319 + } else {
12320 + return -ENOTEMPTY;
12327 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
12329 + int ret_val;
12331 + struct yaffs_dev *dev;
12332 + struct yaffs_obj *obj;
12334 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_unlink %d:%s",
12335 + (int)(dir->i_ino), dentry->d_name.name);
12336 + obj = yaffs_inode_to_obj(dir);
12337 + dev = obj->my_dev;
12339 + yaffs_gross_lock(dev);
12341 + ret_val = yaffs_unlinker(obj, dentry->d_name.name);
12343 + if (ret_val == YAFFS_OK) {
12344 + inode_dec_link_count(dentry->d_inode);
12345 + dir->i_version++;
12346 + yaffs_gross_unlock(dev);
12347 + update_dir_time(dir);
12348 + return 0;
12350 + yaffs_gross_unlock(dev);
12351 + return -ENOTEMPTY;
12356 +static const struct inode_operations yaffs_dir_inode_operations = {
12357 + .create = yaffs_create,
12358 + .lookup = yaffs_lookup,
12359 + .link = yaffs_link,
12360 + .unlink = yaffs_unlink,
12361 + .symlink = yaffs_symlink,
12362 + .mkdir = yaffs_mkdir,
12363 + .rmdir = yaffs_unlink,
12364 + .mknod = yaffs_mknod,
12365 + .rename = yaffs_rename,
12366 + .setattr = yaffs_setattr,
12367 + .setxattr = yaffs_setxattr,
12368 + .getxattr = yaffs_getxattr,
12369 + .listxattr = yaffs_listxattr,
12370 + .removexattr = yaffs_removexattr,
12373 +/*-----------------------------------------------------------------*/
12374 +/* Directory search context allows us to unlock access to yaffs during
12375 + * filldir without causing problems with the directory being modified.
12376 + * This is similar to the tried and tested mechanism used in yaffs direct.
12378 + * A search context iterates along a doubly linked list of siblings in the
12379 + * directory. If the iterating object is deleted then this would corrupt
12380 + * the list iteration, likely causing a crash. The search context avoids
12381 + * this by using the remove_obj_fn to move the search context to the
12382 + * next object before the object is deleted.
12384 + * Many readdirs (and thus seach conexts) may be alive simulateously so
12385 + * each struct yaffs_dev has a list of these.
12387 + * A seach context lives for the duration of a readdir.
12389 + * All these functions must be called while yaffs is locked.
12390 + */
12392 +struct yaffs_search_context {
12393 + struct yaffs_dev *dev;
12394 + struct yaffs_obj *dir_obj;
12395 + struct yaffs_obj *next_return;
12396 + struct list_head others;
12400 + * yaffs_new_search() creates a new search context, initialises it and
12401 + * adds it to the device's search context list.
12403 + * Called at start of readdir.
12404 + */
12405 +static struct yaffs_search_context *yaffs_new_search(struct yaffs_obj *dir)
12407 + struct yaffs_dev *dev = dir->my_dev;
12408 + struct yaffs_search_context *sc =
12409 + kmalloc(sizeof(struct yaffs_search_context), GFP_NOFS);
12410 + if (sc) {
12411 + sc->dir_obj = dir;
12412 + sc->dev = dev;
12413 + if (list_empty(&sc->dir_obj->variant.dir_variant.children))
12414 + sc->next_return = NULL;
12415 + else
12416 + sc->next_return =
12417 + list_entry(dir->variant.dir_variant.children.next,
12418 + struct yaffs_obj, siblings);
12419 + INIT_LIST_HEAD(&sc->others);
12420 + list_add(&sc->others, &(yaffs_dev_to_lc(dev)->search_contexts));
12422 + return sc;
12426 + * yaffs_search_end() disposes of a search context and cleans up.
12427 + */
12428 +static void yaffs_search_end(struct yaffs_search_context *sc)
12430 + if (sc) {
12431 + list_del(&sc->others);
12432 + kfree(sc);
12437 + * yaffs_search_advance() moves a search context to the next object.
12438 + * Called when the search iterates or when an object removal causes
12439 + * the search context to be moved to the next object.
12440 + */
12441 +static void yaffs_search_advance(struct yaffs_search_context *sc)
12443 + if (!sc)
12444 + return;
12446 + if (sc->next_return == NULL ||
12447 + list_empty(&sc->dir_obj->variant.dir_variant.children))
12448 + sc->next_return = NULL;
12449 + else {
12450 + struct list_head *next = sc->next_return->siblings.next;
12452 + if (next == &sc->dir_obj->variant.dir_variant.children)
12453 + sc->next_return = NULL; /* end of list */
12454 + else
12455 + sc->next_return =
12456 + list_entry(next, struct yaffs_obj, siblings);
12461 + * yaffs_remove_obj_callback() is called when an object is unlinked.
12462 + * We check open search contexts and advance any which are currently
12463 + * on the object being iterated.
12464 + */
12465 +static void yaffs_remove_obj_callback(struct yaffs_obj *obj)
12468 + struct list_head *i;
12469 + struct yaffs_search_context *sc;
12470 + struct list_head *search_contexts =
12471 + &(yaffs_dev_to_lc(obj->my_dev)->search_contexts);
12473 + /* Iterate through the directory search contexts.
12474 + * If any are currently on the object being removed, then advance
12475 + * the search context to the next object to prevent a hanging pointer.
12476 + */
12477 + list_for_each(i, search_contexts) {
12478 + sc = list_entry(i, struct yaffs_search_context, others);
12479 + if (sc->next_return == obj)
12480 + yaffs_search_advance(sc);
12486 +/*-----------------------------------------------------------------*/
12488 +#ifdef YAFFS_USE_DIR_ITERATE
12489 +static int yaffs_iterate(struct file *f, struct dir_context *dc)
12491 + struct yaffs_obj *obj;
12492 + struct yaffs_dev *dev;
12493 + struct yaffs_search_context *sc;
12494 + unsigned long curoffs;
12495 + struct yaffs_obj *l;
12496 + int ret_val = 0;
12498 + char name[YAFFS_MAX_NAME_LENGTH + 1];
12500 + obj = yaffs_dentry_to_obj(f->f_dentry);
12501 + dev = obj->my_dev;
12503 + yaffs_gross_lock(dev);
12505 + yaffs_dev_to_lc(dev)->readdir_process = current;
12507 + sc = yaffs_new_search(obj);
12508 + if (!sc) {
12509 + ret_val = -ENOMEM;
12510 + goto out;
12513 + if (!dir_emit_dots(f, dc))
12514 + return 0;
12516 + curoffs = 1;
12518 + while (sc->next_return) {
12519 + curoffs++;
12520 + l = sc->next_return;
12521 + if (curoffs >= dc->pos) {
12522 + int this_inode = yaffs_get_obj_inode(l);
12523 + int this_type = yaffs_get_obj_type(l);
12525 + yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
12526 + yaffs_trace(YAFFS_TRACE_OS,
12527 + "yaffs_readdir: %s inode %d",
12528 + name, yaffs_get_obj_inode(l));
12530 + yaffs_gross_unlock(dev);
12532 + if (!dir_emit(dc,
12533 + name,
12534 + strlen(name),
12535 + this_inode,
12536 + this_type)) {
12537 + yaffs_gross_lock(dev);
12538 + goto out;
12541 + yaffs_gross_lock(dev);
12543 + dc->pos++;
12544 + f->f_pos++;
12546 + yaffs_search_advance(sc);
12549 +out:
12550 + yaffs_search_end(sc);
12551 + yaffs_dev_to_lc(dev)->readdir_process = NULL;
12552 + yaffs_gross_unlock(dev);
12554 + return ret_val;
12557 +#else
12559 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
12561 + struct yaffs_obj *obj;
12562 + struct yaffs_dev *dev;
12563 + struct yaffs_search_context *sc;
12564 + struct inode *inode = f->f_dentry->d_inode;
12565 + unsigned long offset, curoffs;
12566 + struct yaffs_obj *l;
12567 + int ret_val = 0;
12569 + char name[YAFFS_MAX_NAME_LENGTH + 1];
12571 + obj = yaffs_dentry_to_obj(f->f_dentry);
12572 + dev = obj->my_dev;
12574 + yaffs_gross_lock(dev);
12576 + yaffs_dev_to_lc(dev)->readdir_process = current;
12578 + offset = f->f_pos;
12580 + sc = yaffs_new_search(obj);
12581 + if (!sc) {
12582 + ret_val = -ENOMEM;
12583 + goto out;
12586 + yaffs_trace(YAFFS_TRACE_OS,
12587 + "yaffs_readdir: starting at %d", (int)offset);
12589 + if (offset == 0) {
12590 + yaffs_trace(YAFFS_TRACE_OS,
12591 + "yaffs_readdir: entry . ino %d",
12592 + (int)inode->i_ino);
12593 + yaffs_gross_unlock(dev);
12594 + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) {
12595 + yaffs_gross_lock(dev);
12596 + goto out;
12598 + yaffs_gross_lock(dev);
12599 + offset++;
12600 + f->f_pos++;
12602 + if (offset == 1) {
12603 + yaffs_trace(YAFFS_TRACE_OS,
12604 + "yaffs_readdir: entry .. ino %d",
12605 + (int)f->f_dentry->d_parent->d_inode->i_ino);
12606 + yaffs_gross_unlock(dev);
12607 + if (filldir(dirent, "..", 2, offset,
12608 + f->f_dentry->d_parent->d_inode->i_ino,
12609 + DT_DIR) < 0) {
12610 + yaffs_gross_lock(dev);
12611 + goto out;
12613 + yaffs_gross_lock(dev);
12614 + offset++;
12615 + f->f_pos++;
12618 + curoffs = 1;
12620 + /* If the directory has changed since the open or last call to
12621 + readdir, rewind to after the 2 canned entries. */
12622 + if (f->f_version != inode->i_version) {
12623 + offset = 2;
12624 + f->f_pos = offset;
12625 + f->f_version = inode->i_version;
12628 + while (sc->next_return) {
12629 + curoffs++;
12630 + l = sc->next_return;
12631 + if (curoffs >= offset) {
12632 + int this_inode = yaffs_get_obj_inode(l);
12633 + int this_type = yaffs_get_obj_type(l);
12635 + yaffs_get_obj_name(l, name, YAFFS_MAX_NAME_LENGTH + 1);
12636 + yaffs_trace(YAFFS_TRACE_OS,
12637 + "yaffs_readdir: %s inode %d",
12638 + name, yaffs_get_obj_inode(l));
12640 + yaffs_gross_unlock(dev);
12642 + if (filldir(dirent,
12643 + name,
12644 + strlen(name),
12645 + offset, this_inode, this_type) < 0) {
12646 + yaffs_gross_lock(dev);
12647 + goto out;
12650 + yaffs_gross_lock(dev);
12652 + offset++;
12653 + f->f_pos++;
12655 + yaffs_search_advance(sc);
12658 +out:
12659 + yaffs_search_end(sc);
12660 + yaffs_dev_to_lc(dev)->readdir_process = NULL;
12661 + yaffs_gross_unlock(dev);
12663 + return ret_val;
12666 +#endif
12668 +static const struct file_operations yaffs_dir_operations = {
12669 + .read = generic_read_dir,
12670 +#ifdef YAFFS_USE_DIR_ITERATE
12671 + .iterate = yaffs_iterate,
12672 +#else
12673 + .readdir = yaffs_readdir,
12674 +#endif
12675 + .fsync = yaffs_sync_object,
12676 + .llseek = generic_file_llseek,
12679 +static void yaffs_fill_inode_from_obj(struct inode *inode,
12680 + struct yaffs_obj *obj)
12682 + if (inode && obj) {
12684 + /* Check mode against the variant type and attempt to repair if broken. */
12685 + u32 mode = obj->yst_mode;
12686 + switch (obj->variant_type) {
12687 + case YAFFS_OBJECT_TYPE_FILE:
12688 + if (!S_ISREG(mode)) {
12689 + obj->yst_mode &= ~S_IFMT;
12690 + obj->yst_mode |= S_IFREG;
12693 + break;
12694 + case YAFFS_OBJECT_TYPE_SYMLINK:
12695 + if (!S_ISLNK(mode)) {
12696 + obj->yst_mode &= ~S_IFMT;
12697 + obj->yst_mode |= S_IFLNK;
12700 + break;
12701 + case YAFFS_OBJECT_TYPE_DIRECTORY:
12702 + if (!S_ISDIR(mode)) {
12703 + obj->yst_mode &= ~S_IFMT;
12704 + obj->yst_mode |= S_IFDIR;
12707 + break;
12708 + case YAFFS_OBJECT_TYPE_UNKNOWN:
12709 + case YAFFS_OBJECT_TYPE_HARDLINK:
12710 + case YAFFS_OBJECT_TYPE_SPECIAL:
12711 + default:
12712 + /* TODO? */
12713 + break;
12716 + inode->i_flags |= S_NOATIME;
12718 + inode->i_ino = obj->obj_id;
12719 + inode->i_mode = obj->yst_mode;
12720 + inode->i_uid = MAKE_uid(obj->yst_uid);
12721 + inode->i_gid = MAKE_gid(obj->yst_gid);
12722 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
12723 + inode->i_blksize = inode->i_sb->s_blocksize;
12724 +#endif
12725 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
12727 + inode->i_rdev = old_decode_dev(obj->yst_rdev);
12728 + inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
12729 + inode->i_atime.tv_nsec = 0;
12730 + inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
12731 + inode->i_mtime.tv_nsec = 0;
12732 + inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
12733 + inode->i_ctime.tv_nsec = 0;
12734 +#else
12735 + inode->i_rdev = obj->yst_rdev;
12736 + inode->i_atime = obj->yst_atime;
12737 + inode->i_mtime = obj->yst_mtime;
12738 + inode->i_ctime = obj->yst_ctime;
12739 +#endif
12740 + inode->i_size = yaffs_get_obj_length(obj);
12741 + inode->i_blocks = (inode->i_size + 511) >> 9;
12743 + set_nlink(inode, yaffs_get_obj_link_count(obj));
12745 + yaffs_trace(YAFFS_TRACE_OS,
12746 + "yaffs_fill_inode mode %x uid %d gid %d size %lld count %d",
12747 + inode->i_mode, obj->yst_uid, obj->yst_gid,
12748 + inode->i_size, atomic_read(&inode->i_count));
12750 + switch (obj->yst_mode & S_IFMT) {
12751 + default: /* fifo, device or socket */
12752 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
12753 + init_special_inode(inode, obj->yst_mode,
12754 + old_decode_dev(obj->yst_rdev));
12755 +#else
12756 + init_special_inode(inode, obj->yst_mode,
12757 + (dev_t) (obj->yst_rdev));
12758 +#endif
12759 + break;
12760 + case S_IFREG: /* file */
12761 + inode->i_op = &yaffs_file_inode_operations;
12762 + inode->i_fop = &yaffs_file_operations;
12763 + inode->i_mapping->a_ops =
12764 + &yaffs_file_address_operations;
12765 + break;
12766 + case S_IFDIR: /* directory */
12767 + inode->i_op = &yaffs_dir_inode_operations;
12768 + inode->i_fop = &yaffs_dir_operations;
12769 + break;
12770 + case S_IFLNK: /* symlink */
12771 + inode->i_op = &yaffs_symlink_inode_operations;
12772 + break;
12775 + yaffs_inode_to_obj_lv(inode) = obj;
12777 + obj->my_inode = inode;
12779 + } else {
12780 + yaffs_trace(YAFFS_TRACE_OS,
12781 + "yaffs_fill_inode invalid parameters");
12789 + * yaffs background thread functions .
12790 + * yaffs_bg_thread_fn() the thread function
12791 + * yaffs_bg_start() launches the background thread.
12792 + * yaffs_bg_stop() cleans up the background thread.
12794 + * NB:
12795 + * The thread should only run after the yaffs is initialised
12796 + * The thread should be stopped before yaffs is unmounted.
12797 + * The thread should not do any writing while the fs is in read only.
12798 + */
12800 +static unsigned yaffs_bg_gc_urgency(struct yaffs_dev *dev)
12802 + unsigned erased_chunks =
12803 + dev->n_erased_blocks * dev->param.chunks_per_block;
12804 + struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
12805 + unsigned scattered = 0; /* Free chunks not in an erased block */
12807 + if (erased_chunks < dev->n_free_chunks)
12808 + scattered = (dev->n_free_chunks - erased_chunks);
12810 + if (!context->bg_running)
12811 + return 0;
12812 + else if (scattered < (dev->param.chunks_per_block * 2))
12813 + return 0;
12814 + else if (erased_chunks > dev->n_free_chunks / 2)
12815 + return 0;
12816 + else if (erased_chunks > dev->n_free_chunks / 4)
12817 + return 1;
12818 + else
12819 + return 2;
12822 +#ifdef YAFFS_COMPILE_BACKGROUND
12824 +void yaffs_background_waker(unsigned long data)
12826 + wake_up_process((struct task_struct *)data);
12829 +static int yaffs_bg_thread_fn(void *data)
12831 + struct yaffs_dev *dev = (struct yaffs_dev *)data;
12832 + struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
12833 + unsigned long now = jiffies;
12834 + unsigned long next_dir_update = now;
12835 + unsigned long next_gc = now;
12836 + unsigned long expires;
12837 + unsigned int urgency;
12839 + int gc_result;
12840 + struct timer_list timer;
12842 + yaffs_trace(YAFFS_TRACE_BACKGROUND,
12843 + "yaffs_background starting for dev %p", (void *)dev);
12845 +#ifdef YAFFS_COMPILE_FREEZER
12846 + set_freezable();
12847 +#endif
12848 + while (context->bg_running) {
12849 + yaffs_trace(YAFFS_TRACE_BACKGROUND, "yaffs_background");
12851 + if (kthread_should_stop())
12852 + break;
12854 +#ifdef YAFFS_COMPILE_FREEZER
12855 + if (try_to_freeze())
12856 + continue;
12857 +#endif
12858 + yaffs_gross_lock(dev);
12860 + now = jiffies;
12862 + if (time_after(now, next_dir_update) && yaffs_bg_enable) {
12863 + yaffs_update_dirty_dirs(dev);
12864 + next_dir_update = now + HZ;
12867 + if (time_after(now, next_gc) && yaffs_bg_enable) {
12868 + if (!dev->is_checkpointed) {
12869 + urgency = yaffs_bg_gc_urgency(dev);
12870 + gc_result = yaffs_bg_gc(dev, urgency);
12871 + if (urgency > 1)
12872 + next_gc = now + HZ / 20 + 1;
12873 + else if (urgency > 0)
12874 + next_gc = now + HZ / 10 + 1;
12875 + else
12876 + next_gc = now + HZ * 2;
12877 + } else {
12878 + /*
12879 + * gc not running so set to next_dir_update
12880 + * to cut down on wake ups
12881 + */
12882 + next_gc = next_dir_update;
12885 + yaffs_gross_unlock(dev);
12886 +#if 1
12887 + expires = next_dir_update;
12888 + if (time_before(next_gc, expires))
12889 + expires = next_gc;
12890 + if (time_before(expires, now))
12891 + expires = now + HZ;
12893 + Y_INIT_TIMER(&timer);
12894 + timer.expires = expires + 1;
12895 + timer.data = (unsigned long)current;
12896 + timer.function = yaffs_background_waker;
12898 + set_current_state(TASK_INTERRUPTIBLE);
12899 + add_timer(&timer);
12900 + schedule();
12901 + del_timer_sync(&timer);
12902 +#else
12903 + msleep(10);
12904 +#endif
12907 + return 0;
12910 +static int yaffs_bg_start(struct yaffs_dev *dev)
12912 + int retval = 0;
12913 + struct yaffs_linux_context *context = yaffs_dev_to_lc(dev);
12915 + if (dev->read_only)
12916 + return -1;
12918 + context->bg_running = 1;
12920 + context->bg_thread = kthread_run(yaffs_bg_thread_fn,
12921 + (void *)dev, "yaffs-bg-%d",
12922 + context->mount_id);
12924 + if (IS_ERR(context->bg_thread)) {
12925 + retval = PTR_ERR(context->bg_thread);
12926 + context->bg_thread = NULL;
12927 + context->bg_running = 0;
12929 + return retval;
12932 +static void yaffs_bg_stop(struct yaffs_dev *dev)
12934 + struct yaffs_linux_context *ctxt = yaffs_dev_to_lc(dev);
12936 + ctxt->bg_running = 0;
12938 + if (ctxt->bg_thread) {
12939 + kthread_stop(ctxt->bg_thread);
12940 + ctxt->bg_thread = NULL;
12943 +#else
12944 +static int yaffs_bg_thread_fn(void *data)
12946 + return 0;
12949 +static int yaffs_bg_start(struct yaffs_dev *dev)
12951 + return 0;
12954 +static void yaffs_bg_stop(struct yaffs_dev *dev)
12957 +#endif
12960 +static void yaffs_flush_inodes(struct super_block *sb)
12962 + struct inode *iptr;
12963 + struct yaffs_obj *obj;
12965 + list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) {
12966 + obj = yaffs_inode_to_obj(iptr);
12967 + if (obj) {
12968 + yaffs_trace(YAFFS_TRACE_OS,
12969 + "flushing obj %d",
12970 + obj->obj_id);
12971 + yaffs_flush_file(obj, 1, 0, 0);
12976 +static void yaffs_flush_super(struct super_block *sb, int do_checkpoint)
12978 + struct yaffs_dev *dev = yaffs_super_to_dev(sb);
12979 + if (!dev)
12980 + return;
12982 + yaffs_flush_inodes(sb);
12983 + yaffs_update_dirty_dirs(dev);
12984 + yaffs_flush_whole_cache(dev, 1);
12985 + if (do_checkpoint)
12986 + yaffs_checkpoint_save(dev);
12989 +static LIST_HEAD(yaffs_context_list);
12990 +struct mutex yaffs_context_lock;
12992 +static void yaffs_put_super(struct super_block *sb)
12994 + struct yaffs_dev *dev = yaffs_super_to_dev(sb);
12995 + struct mtd_info *mtd = yaffs_dev_to_mtd(dev);
12997 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
12998 + "yaffs_put_super");
13000 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
13001 + "Shutting down yaffs background thread");
13002 + yaffs_bg_stop(dev);
13003 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
13004 + "yaffs background thread shut down");
13006 + yaffs_gross_lock(dev);
13008 + yaffs_flush_super(sb, 1);
13010 + yaffs_deinitialise(dev);
13012 + yaffs_gross_unlock(dev);
13014 + mutex_lock(&yaffs_context_lock);
13015 + list_del_init(&(yaffs_dev_to_lc(dev)->context_list));
13016 + mutex_unlock(&yaffs_context_lock);
13018 + if (yaffs_dev_to_lc(dev)->spare_buffer) {
13019 + kfree(yaffs_dev_to_lc(dev)->spare_buffer);
13020 + yaffs_dev_to_lc(dev)->spare_buffer = NULL;
13023 + kfree(dev);
13025 + yaffs_put_mtd_device(mtd);
13027 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_ALWAYS,
13028 + "yaffs_put_super done");
13032 +static unsigned yaffs_gc_control_callback(struct yaffs_dev *dev)
13034 + return yaffs_gc_control;
13038 +#ifdef YAFFS_COMPILE_EXPORTFS
13040 +static struct inode *yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
13041 + uint32_t generation)
13043 + return Y_IGET(sb, ino);
13046 +static struct dentry *yaffs2_fh_to_dentry(struct super_block *sb,
13047 + struct fid *fid, int fh_len,
13048 + int fh_type)
13050 + return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
13051 + yaffs2_nfs_get_inode);
13054 +static struct dentry *yaffs2_fh_to_parent(struct super_block *sb,
13055 + struct fid *fid, int fh_len,
13056 + int fh_type)
13058 + return generic_fh_to_parent(sb, fid, fh_len, fh_type,
13059 + yaffs2_nfs_get_inode);
13062 +struct dentry *yaffs2_get_parent(struct dentry *dentry)
13065 + struct super_block *sb = dentry->d_inode->i_sb;
13066 + struct dentry *parent = ERR_PTR(-ENOENT);
13067 + struct inode *inode;
13068 + unsigned long parent_ino;
13069 + struct yaffs_obj *d_obj;
13070 + struct yaffs_obj *parent_obj;
13072 + d_obj = yaffs_inode_to_obj(dentry->d_inode);
13074 + if (d_obj) {
13075 + parent_obj = d_obj->parent;
13076 + if (parent_obj) {
13077 + parent_ino = yaffs_get_obj_inode(parent_obj);
13078 + inode = Y_IGET(sb, parent_ino);
13080 + if (IS_ERR(inode)) {
13081 + parent = ERR_CAST(inode);
13082 + } else {
13083 + parent = d_obtain_alias(inode);
13084 + if (!IS_ERR(parent)) {
13085 + parent = ERR_PTR(-ENOMEM);
13086 + iput(inode);
13092 + return parent;
13095 +/* Just declare a zero structure as a NULL value implies
13096 + * using the default functions of exportfs.
13097 + */
13099 +static struct export_operations yaffs_export_ops = {
13100 + .fh_to_dentry = yaffs2_fh_to_dentry,
13101 + .fh_to_parent = yaffs2_fh_to_parent,
13102 + .get_parent = yaffs2_get_parent,
13105 +#endif
13107 +static void yaffs_unstitch_obj(struct inode *inode, struct yaffs_obj *obj)
13109 + /* Clear the association between the inode and
13110 + * the struct yaffs_obj.
13111 + */
13112 + obj->my_inode = NULL;
13113 + yaffs_inode_to_obj_lv(inode) = NULL;
13115 + /* If the object freeing was deferred, then the real
13116 + * free happens now.
13117 + * This should fix the inode inconsistency problem.
13118 + */
13119 + yaffs_handle_defered_free(obj);
13122 +#ifdef YAFFS_HAS_EVICT_INODE
13123 +/* yaffs_evict_inode combines into one operation what was previously done in
13124 + * yaffs_clear_inode() and yaffs_delete_inode()
13126 + */
13127 +static void yaffs_evict_inode(struct inode *inode)
13129 + struct yaffs_obj *obj;
13130 + struct yaffs_dev *dev;
13131 + int deleteme = 0;
13133 + obj = yaffs_inode_to_obj(inode);
13135 + yaffs_trace(YAFFS_TRACE_OS,
13136 + "yaffs_evict_inode: ino %d, count %d %s",
13137 + (int)inode->i_ino, atomic_read(&inode->i_count),
13138 + obj ? "object exists" : "null object");
13140 + if (!inode->i_nlink && !is_bad_inode(inode))
13141 + deleteme = 1;
13142 + truncate_inode_pages(&inode->i_data, 0);
13143 + Y_CLEAR_INODE(inode);
13145 + if (deleteme && obj) {
13146 + dev = obj->my_dev;
13147 + yaffs_gross_lock(dev);
13148 + yaffs_del_obj(obj);
13149 + yaffs_gross_unlock(dev);
13151 + if (obj) {
13152 + dev = obj->my_dev;
13153 + yaffs_gross_lock(dev);
13154 + yaffs_unstitch_obj(inode, obj);
13155 + yaffs_gross_unlock(dev);
13158 +#else
13160 +/* clear is called to tell the fs to release any per-inode data it holds.
13161 + * The object might still exist on disk and is just being thrown out of the cache
13162 + * or else the object has actually been deleted and we're being called via
13163 + * the chain
13164 + * yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
13165 + */
13167 +static void yaffs_clear_inode(struct inode *inode)
13169 + struct yaffs_obj *obj;
13170 + struct yaffs_dev *dev;
13172 + obj = yaffs_inode_to_obj(inode);
13174 + yaffs_trace(YAFFS_TRACE_OS,
13175 + "yaffs_clear_inode: ino %d, count %d %s",
13176 + (int)inode->i_ino, atomic_read(&inode->i_count),
13177 + obj ? "object exists" : "null object");
13179 + if (obj) {
13180 + dev = obj->my_dev;
13181 + yaffs_gross_lock(dev);
13182 + yaffs_unstitch_obj(inode, obj);
13183 + yaffs_gross_unlock(dev);
13188 +/* delete is called when the link count is zero and the inode
13189 + * is put (ie. nobody wants to know about it anymore, time to
13190 + * delete the file).
13191 + * NB Must call clear_inode()
13192 + */
13193 +static void yaffs_delete_inode(struct inode *inode)
13195 + struct yaffs_obj *obj = yaffs_inode_to_obj(inode);
13196 + struct yaffs_dev *dev;
13198 + yaffs_trace(YAFFS_TRACE_OS,
13199 + "yaffs_delete_inode: ino %d, count %d %s",
13200 + (int)inode->i_ino, atomic_read(&inode->i_count),
13201 + obj ? "object exists" : "null object");
13203 + if (obj) {
13204 + dev = obj->my_dev;
13205 + yaffs_gross_lock(dev);
13206 + yaffs_del_obj(obj);
13207 + yaffs_gross_unlock(dev);
13209 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
13210 + truncate_inode_pages(&inode->i_data, 0);
13211 +#endif
13212 + clear_inode(inode);
13214 +#endif
13219 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
13220 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
13222 + struct yaffs_dev *dev = yaffs_dentry_to_obj(dentry)->my_dev;
13223 + struct super_block *sb = dentry->d_sb;
13224 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
13225 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
13227 + struct yaffs_dev *dev = yaffs_super_to_dev(sb);
13228 +#else
13229 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
13231 + struct yaffs_dev *dev = yaffs_super_to_dev(sb);
13232 +#endif
13234 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_statfs");
13236 + yaffs_gross_lock(dev);
13238 + buf->f_type = YAFFS_MAGIC;
13239 + buf->f_bsize = sb->s_blocksize;
13240 + buf->f_namelen = 255;
13242 + if (dev->data_bytes_per_chunk & (dev->data_bytes_per_chunk - 1)) {
13243 + /* Do this if chunk size is not a power of 2 */
13245 + uint64_t bytes_in_dev;
13246 + uint64_t bytes_free;
13248 + bytes_in_dev =
13249 + ((uint64_t)
13250 + ((dev->param.end_block - dev->param.start_block +
13251 + 1))) * ((uint64_t) (dev->param.chunks_per_block *
13252 + dev->data_bytes_per_chunk));
13254 + do_div(bytes_in_dev, sb->s_blocksize); /* bytes_in_dev becomes the number of blocks */
13255 + buf->f_blocks = bytes_in_dev;
13257 + bytes_free = ((uint64_t) (yaffs_get_n_free_chunks(dev))) *
13258 + ((uint64_t) (dev->data_bytes_per_chunk));
13260 + do_div(bytes_free, sb->s_blocksize);
13262 + buf->f_bfree = bytes_free;
13264 + } else if (sb->s_blocksize > dev->data_bytes_per_chunk) {
13266 + buf->f_blocks =
13267 + (dev->param.end_block - dev->param.start_block + 1) *
13268 + dev->param.chunks_per_block /
13269 + (sb->s_blocksize / dev->data_bytes_per_chunk);
13270 + buf->f_bfree =
13271 + yaffs_get_n_free_chunks(dev) /
13272 + (sb->s_blocksize / dev->data_bytes_per_chunk);
13273 + } else {
13274 + buf->f_blocks =
13275 + (dev->param.end_block - dev->param.start_block + 1) *
13276 + dev->param.chunks_per_block *
13277 + (dev->data_bytes_per_chunk / sb->s_blocksize);
13279 + buf->f_bfree =
13280 + yaffs_get_n_free_chunks(dev) *
13281 + (dev->data_bytes_per_chunk / sb->s_blocksize);
13284 + buf->f_files = 0;
13285 + buf->f_ffree = 0;
13286 + buf->f_bavail = buf->f_bfree;
13288 + yaffs_gross_unlock(dev);
13289 + return 0;
13294 +static int yaffs_do_sync_fs(struct super_block *sb, int request_checkpoint)
13297 + struct yaffs_dev *dev = yaffs_super_to_dev(sb);
13298 + unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
13299 + unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
13300 + int do_checkpoint;
13301 + int dirty = yaffs_check_super_dirty(dev);
13303 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
13304 + "yaffs_do_sync_fs: gc-urgency %d %s %s%s",
13305 + gc_urgent,
13306 + dirty ? "dirty" : "clean",
13307 + request_checkpoint ? "checkpoint requested" : "no checkpoint",
13308 + oneshot_checkpoint ? " one-shot" : "");
13310 + yaffs_gross_lock(dev);
13311 + do_checkpoint = ((request_checkpoint && !gc_urgent) ||
13312 + oneshot_checkpoint) && !dev->is_checkpointed;
13314 + if (dirty || do_checkpoint) {
13315 + yaffs_flush_super(sb, !dev->is_checkpointed && do_checkpoint);
13316 + yaffs_clear_super_dirty(dev);
13317 + if (oneshot_checkpoint)
13318 + yaffs_auto_checkpoint &= ~4;
13320 + yaffs_gross_unlock(dev);
13322 + return 0;
13326 +#ifdef YAFFS_HAS_WRITE_SUPER
13327 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
13328 +static void yaffs_write_super(struct super_block *sb)
13329 +#else
13330 +static int yaffs_write_super(struct super_block *sb)
13331 +#endif
13333 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
13335 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
13336 + "yaffs_write_super %s",
13337 + request_checkpoint ? " checkpt" : "");
13339 + yaffs_do_sync_fs(sb, request_checkpoint);
13341 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
13342 + return 0;
13343 +#endif
13345 +#endif
13347 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
13348 +static int yaffs_sync_fs(struct super_block *sb, int wait)
13349 +#else
13350 +static int yaffs_sync_fs(struct super_block *sb)
13351 +#endif
13353 + unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
13355 + yaffs_trace(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
13356 + "yaffs_sync_fs%s", request_checkpoint ? " checkpt" : "");
13358 + yaffs_do_sync_fs(sb, request_checkpoint);
13360 + return 0;
13363 +/* the function only is used to change dev->read_only when this file system
13364 + * is remounted.
13365 + */
13366 +static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
13368 + int read_only = 0;
13369 + struct mtd_info *mtd;
13370 + struct yaffs_dev *dev = 0;
13372 + /* Get the device */
13373 + mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
13374 + if (!mtd) {
13375 + yaffs_trace(YAFFS_TRACE_ALWAYS,
13376 + "MTD device #%u doesn't appear to exist",
13377 + MINOR(sb->s_dev));
13378 + return 1;
13381 + /* Check it's NAND */
13382 + if (mtd->type != MTD_NANDFLASH) {
13383 + yaffs_trace(YAFFS_TRACE_ALWAYS,
13384 + "MTD device is not NAND it's type %d",
13385 + mtd->type);
13386 + return 1;
13389 + read_only = ((*flags & MS_RDONLY) != 0);
13390 + if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
13391 + read_only = 1;
13392 + printk(KERN_INFO
13393 + "yaffs: mtd is read only, setting superblock read only");
13394 + *flags |= MS_RDONLY;
13397 + dev = sb->s_fs_info;
13398 + dev->read_only = read_only;
13400 + return 0;
13403 +static const struct super_operations yaffs_super_ops = {
13404 + .statfs = yaffs_statfs,
13406 +#ifndef YAFFS_USE_OWN_IGET
13407 + .read_inode = yaffs_read_inode,
13408 +#endif
13409 +#ifdef YAFFS_HAS_PUT_INODE
13410 + .put_inode = yaffs_put_inode,
13411 +#endif
13412 + .put_super = yaffs_put_super,
13413 +#ifdef YAFFS_HAS_EVICT_INODE
13414 + .evict_inode = yaffs_evict_inode,
13415 +#else
13416 + .delete_inode = yaffs_delete_inode,
13417 + .clear_inode = yaffs_clear_inode,
13418 +#endif
13419 + .sync_fs = yaffs_sync_fs,
13420 +#ifdef YAFFS_HAS_WRITE_SUPER
13421 + .write_super = yaffs_write_super,
13422 +#endif
13423 + .remount_fs = yaffs_remount_fs,
13426 +struct yaffs_options {
13427 + int inband_tags;
13428 + int skip_checkpoint_read;
13429 + int skip_checkpoint_write;
13430 + int no_cache;
13431 + int tags_ecc_on;
13432 + int tags_ecc_overridden;
13433 + int lazy_loading_enabled;
13434 + int lazy_loading_overridden;
13435 + int empty_lost_and_found;
13436 + int empty_lost_and_found_overridden;
13437 + int disable_summary;
13440 +#define MAX_OPT_LEN 30
13441 +static int yaffs_parse_options(struct yaffs_options *options,
13442 + const char *options_str)
13444 + char cur_opt[MAX_OPT_LEN + 1];
13445 + int p;
13446 + int error = 0;
13448 + /* Parse through the options which is a comma seperated list */
13450 + while (options_str && *options_str && !error) {
13451 + memset(cur_opt, 0, MAX_OPT_LEN + 1);
13452 + p = 0;
13454 + while (*options_str == ',')
13455 + options_str++;
13457 + while (*options_str && *options_str != ',') {
13458 + if (p < MAX_OPT_LEN) {
13459 + cur_opt[p] = *options_str;
13460 + p++;
13462 + options_str++;
13465 + if (!strcmp(cur_opt, "inband-tags")) {
13466 + options->inband_tags = 1;
13467 + } else if (!strcmp(cur_opt, "tags-ecc-off")) {
13468 + options->tags_ecc_on = 0;
13469 + options->tags_ecc_overridden = 1;
13470 + } else if (!strcmp(cur_opt, "tags-ecc-on")) {
13471 + options->tags_ecc_on = 1;
13472 + options->tags_ecc_overridden = 1;
13473 + } else if (!strcmp(cur_opt, "lazy-loading-off")) {
13474 + options->lazy_loading_enabled = 0;
13475 + options->lazy_loading_overridden = 1;
13476 + } else if (!strcmp(cur_opt, "lazy-loading-on")) {
13477 + options->lazy_loading_enabled = 1;
13478 + options->lazy_loading_overridden = 1;
13479 + } else if (!strcmp(cur_opt, "disable-summary")) {
13480 + options->disable_summary = 1;
13481 + } else if (!strcmp(cur_opt, "empty-lost-and-found-off")) {
13482 + options->empty_lost_and_found = 0;
13483 + options->empty_lost_and_found_overridden = 1;
13484 + } else if (!strcmp(cur_opt, "empty-lost-and-found-on")) {
13485 + options->empty_lost_and_found = 1;
13486 + options->empty_lost_and_found_overridden = 1;
13487 + } else if (!strcmp(cur_opt, "no-cache")) {
13488 + options->no_cache = 1;
13489 + } else if (!strcmp(cur_opt, "no-checkpoint-read")) {
13490 + options->skip_checkpoint_read = 1;
13491 + } else if (!strcmp(cur_opt, "no-checkpoint-write")) {
13492 + options->skip_checkpoint_write = 1;
13493 + } else if (!strcmp(cur_opt, "no-checkpoint")) {
13494 + options->skip_checkpoint_read = 1;
13495 + options->skip_checkpoint_write = 1;
13496 + } else {
13497 + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
13498 + cur_opt);
13499 + error = 1;
13503 + return error;
13507 +static struct dentry *yaffs_make_root(struct inode *inode)
13509 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 4, 0))
13510 + struct dentry *root = d_alloc_root(inode);
13512 + if (!root)
13513 + iput(inode);
13515 + return root;
13516 +#else
13517 + return d_make_root(inode);
13518 +#endif
13524 +static struct super_block *yaffs_internal_read_super(int yaffs_version,
13525 + struct super_block *sb,
13526 + void *data, int silent)
13528 + int n_blocks;
13529 + struct inode *inode = NULL;
13530 + struct dentry *root;
13531 + struct yaffs_dev *dev = 0;
13532 + char devname_buf[BDEVNAME_SIZE + 1];
13533 + struct mtd_info *mtd;
13534 + int err;
13535 + char *data_str = (char *)data;
13536 + struct yaffs_linux_context *context = NULL;
13537 + struct yaffs_param *param;
13539 + int read_only = 0;
13540 + int inband_tags = 0;
13542 + struct yaffs_options options;
13544 + unsigned mount_id;
13545 + int found;
13546 + struct yaffs_linux_context *context_iterator;
13547 + struct list_head *l;
13549 + if (!sb) {
13550 + printk(KERN_INFO "yaffs: sb is NULL\n");
13551 + return NULL;
13554 + sb->s_magic = YAFFS_MAGIC;
13555 + sb->s_op = &yaffs_super_ops;
13556 + sb->s_flags |= MS_NOATIME;
13558 + read_only = ((sb->s_flags & MS_RDONLY) != 0);
13560 +#ifdef YAFFS_COMPILE_EXPORTFS
13561 + sb->s_export_op = &yaffs_export_ops;
13562 +#endif
13564 + if (!sb->s_dev)
13565 + printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
13566 + else if (!yaffs_devname(sb, devname_buf))
13567 + printk(KERN_INFO "yaffs: devname is NULL\n");
13568 + else
13569 + printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
13570 + sb->s_dev,
13571 + yaffs_devname(sb, devname_buf), read_only ? "ro" : "rw");
13573 + if (!data_str)
13574 + data_str = "";
13576 + printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
13578 + memset(&options, 0, sizeof(options));
13580 + if (yaffs_parse_options(&options, data_str)) {
13581 + /* Option parsing failed */
13582 + return NULL;
13585 + sb->s_blocksize = PAGE_CACHE_SIZE;
13586 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
13588 + yaffs_trace(YAFFS_TRACE_OS,
13589 + "yaffs_read_super: Using yaffs%d", yaffs_version);
13590 + yaffs_trace(YAFFS_TRACE_OS,
13591 + "yaffs_read_super: block size %d", (int)(sb->s_blocksize));
13593 + yaffs_trace(YAFFS_TRACE_ALWAYS,
13594 + "yaffs: Attempting MTD mount of %u.%u,\"%s\"",
13595 + MAJOR(sb->s_dev), MINOR(sb->s_dev),
13596 + yaffs_devname(sb, devname_buf));
13598 + /* Get the device */
13599 + mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
13600 + if (IS_ERR(mtd)) {
13601 + yaffs_trace(YAFFS_TRACE_ALWAYS,
13602 + "yaffs: MTD device %u either not valid or unavailable",
13603 + MINOR(sb->s_dev));
13604 + return NULL;
13607 + if (yaffs_auto_select && yaffs_version == 1 && WRITE_SIZE(mtd) >= 2048) {
13608 + yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs2");
13609 + yaffs_version = 2;
13612 + /* Added NCB 26/5/2006 for completeness */
13613 + if (yaffs_version == 2 && !options.inband_tags
13614 + && WRITE_SIZE(mtd) == 512) {
13615 + yaffs_trace(YAFFS_TRACE_ALWAYS, "auto selecting yaffs1");
13616 + yaffs_version = 1;
13619 + if (mtd->oobavail < sizeof(struct yaffs_packed_tags2) ||
13620 + options.inband_tags)
13621 + inband_tags = 1;
13623 + if(yaffs_verify_mtd(mtd, yaffs_version, inband_tags) < 0)
13624 + return NULL;
13626 + /* OK, so if we got here, we have an MTD that's NAND and looks
13627 + * like it has the right capabilities
13628 + * Set the struct yaffs_dev up for mtd
13629 + */
13631 + if (!read_only && !(mtd->flags & MTD_WRITEABLE)) {
13632 + read_only = 1;
13633 + printk(KERN_INFO
13634 + "yaffs: mtd is read only, setting superblock read only\n"
13635 + );
13636 + sb->s_flags |= MS_RDONLY;
13639 + dev = kmalloc(sizeof(struct yaffs_dev), GFP_KERNEL);
13640 + context = kmalloc(sizeof(struct yaffs_linux_context), GFP_KERNEL);
13642 + if (!dev || !context) {
13643 + kfree(dev);
13644 + kfree(context);
13645 + dev = NULL;
13646 + context = NULL;
13648 + /* Deep shit could not allocate device structure */
13649 + yaffs_trace(YAFFS_TRACE_ALWAYS,
13650 + "yaffs_read_super: Failed trying to allocate struct yaffs_dev."
13651 + );
13652 + return NULL;
13654 + memset(dev, 0, sizeof(struct yaffs_dev));
13655 + param = &(dev->param);
13657 + memset(context, 0, sizeof(struct yaffs_linux_context));
13658 + dev->os_context = context;
13659 + INIT_LIST_HEAD(&(context->context_list));
13660 + context->dev = dev;
13661 + context->super = sb;
13663 + dev->read_only = read_only;
13665 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
13666 + sb->s_fs_info = dev;
13667 +#else
13668 + sb->u.generic_sbp = dev;
13669 +#endif
13672 + dev->driver_context = mtd;
13673 + param->name = mtd->name;
13675 + /* Set up the memory size parameters.... */
13678 + param->n_reserved_blocks = 5;
13679 + param->n_caches = (options.no_cache) ? 0 : 10;
13680 + param->inband_tags = inband_tags;
13682 + param->enable_xattr = 1;
13683 + if (options.lazy_loading_overridden)
13684 + param->disable_lazy_load = !options.lazy_loading_enabled;
13686 + param->defered_dir_update = 1;
13688 + if (options.tags_ecc_overridden)
13689 + param->no_tags_ecc = !options.tags_ecc_on;
13691 + param->empty_lost_n_found = 1;
13692 + param->refresh_period = 500;
13693 + param->disable_summary = options.disable_summary;
13696 +#ifdef CONFIG_YAFFS_DISABLE_BAD_BLOCK_MARKING
13697 + param->disable_bad_block_marking = 1;
13698 +#endif
13699 + if (options.empty_lost_and_found_overridden)
13700 + param->empty_lost_n_found = options.empty_lost_and_found;
13702 + /* ... and the functions. */
13703 + if (yaffs_version == 2) {
13704 + param->is_yaffs2 = 1;
13705 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
13706 + param->total_bytes_per_chunk = mtd->writesize;
13707 + param->chunks_per_block = mtd->erasesize / mtd->writesize;
13708 +#else
13709 + param->total_bytes_per_chunk = mtd->oobblock;
13710 + param->chunks_per_block = mtd->erasesize / mtd->oobblock;
13711 +#endif
13712 + n_blocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
13714 + param->start_block = 0;
13715 + param->end_block = n_blocks - 1;
13716 + } else {
13717 + param->is_yaffs2 = 0;
13718 + n_blocks = YCALCBLOCKS(mtd->size,
13719 + YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
13721 + param->chunks_per_block = YAFFS_CHUNKS_PER_BLOCK;
13722 + param->total_bytes_per_chunk = YAFFS_BYTES_PER_CHUNK;
13725 + param->start_block = 0;
13726 + param->end_block = n_blocks - 1;
13728 + yaffs_mtd_drv_install(dev);
13730 + param->sb_dirty_fn = yaffs_set_super_dirty;
13731 + param->gc_control_fn = yaffs_gc_control_callback;
13733 + yaffs_dev_to_lc(dev)->super = sb;
13735 + param->use_nand_ecc = 1;
13737 + param->skip_checkpt_rd = options.skip_checkpoint_read;
13738 + param->skip_checkpt_wr = options.skip_checkpoint_write;
13740 + mutex_lock(&yaffs_context_lock);
13741 + /* Get a mount id */
13742 + found = 0;
13743 + for (mount_id = 0; !found; mount_id++) {
13744 + found = 1;
13745 + list_for_each(l, &yaffs_context_list) {
13746 + context_iterator =
13747 + list_entry(l, struct yaffs_linux_context,
13748 + context_list);
13749 + if (context_iterator->mount_id == mount_id)
13750 + found = 0;
13753 + context->mount_id = mount_id;
13755 + list_add_tail(&(yaffs_dev_to_lc(dev)->context_list),
13756 + &yaffs_context_list);
13757 + mutex_unlock(&yaffs_context_lock);
13759 + /* Directory search handling... */
13760 + INIT_LIST_HEAD(&(yaffs_dev_to_lc(dev)->search_contexts));
13761 + param->remove_obj_fn = yaffs_remove_obj_callback;
13763 + mutex_init(&(yaffs_dev_to_lc(dev)->gross_lock));
13765 + yaffs_gross_lock(dev);
13767 + err = yaffs_guts_initialise(dev);
13769 + yaffs_trace(YAFFS_TRACE_OS,
13770 + "yaffs_read_super: guts initialised %s",
13771 + (err == YAFFS_OK) ? "OK" : "FAILED");
13773 + if (err == YAFFS_OK)
13774 + yaffs_bg_start(dev);
13776 + if (!context->bg_thread)
13777 + param->defered_dir_update = 0;
13779 + sb->s_maxbytes = yaffs_max_file_size(dev);
13781 + /* Release lock before yaffs_get_inode() */
13782 + yaffs_gross_unlock(dev);
13784 + /* Create root inode */
13785 + if (err == YAFFS_OK)
13786 + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0, yaffs_root(dev));
13788 + if (!inode)
13789 + return NULL;
13791 + inode->i_op = &yaffs_dir_inode_operations;
13792 + inode->i_fop = &yaffs_dir_operations;
13794 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: got root inode");
13796 + root = yaffs_make_root(inode);
13798 + if (!root)
13799 + return NULL;
13801 + sb->s_root = root;
13802 + if(!dev->is_checkpointed)
13803 + yaffs_set_super_dirty(dev);
13805 + yaffs_trace(YAFFS_TRACE_ALWAYS,
13806 + "yaffs_read_super: is_checkpointed %d",
13807 + dev->is_checkpointed);
13809 + yaffs_trace(YAFFS_TRACE_OS, "yaffs_read_super: done");
13810 + return sb;
13813 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
13814 +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
13815 + int silent)
13817 + return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
13820 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
13821 +static struct dentry *yaffs_mount(struct file_system_type *fs_type, int flags,
13822 + const char *dev_name, void *data)
13824 + return mount_bdev(fs_type, flags, dev_name, data, yaffs_internal_read_super_mtd);
13826 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
13827 +static int yaffs_read_super(struct file_system_type *fs,
13828 + int flags, const char *dev_name,
13829 + void *data, struct vfsmount *mnt)
13832 + return get_sb_bdev(fs, flags, dev_name, data,
13833 + yaffs_internal_read_super_mtd, mnt);
13835 +#else
13836 +static struct super_block *yaffs_read_super(struct file_system_type *fs,
13837 + int flags, const char *dev_name,
13838 + void *data)
13841 + return get_sb_bdev(fs, flags, dev_name, data,
13842 + yaffs_internal_read_super_mtd);
13844 +#endif
13846 +static struct file_system_type yaffs_fs_type = {
13847 + .owner = THIS_MODULE,
13848 + .name = "yaffs",
13849 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
13850 + .mount = yaffs_mount,
13851 +#else
13852 + .get_sb = yaffs_read_super,
13853 +#endif
13854 + .kill_sb = kill_block_super,
13855 + .fs_flags = FS_REQUIRES_DEV,
13857 +#else
13858 +static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
13859 + int silent)
13861 + return yaffs_internal_read_super(1, sb, data, silent);
13864 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
13865 + FS_REQUIRES_DEV);
13866 +#endif
13869 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
13870 +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
13871 + int silent)
13873 + return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
13876 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
13877 +static struct dentry *yaffs2_mount(struct file_system_type *fs_type, int flags,
13878 + const char *dev_name, void *data)
13880 + return mount_bdev(fs_type, flags, dev_name, data, yaffs2_internal_read_super_mtd);
13882 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
13883 +static int yaffs2_read_super(struct file_system_type *fs,
13884 + int flags, const char *dev_name, void *data,
13885 + struct vfsmount *mnt)
13887 + return get_sb_bdev(fs, flags, dev_name, data,
13888 + yaffs2_internal_read_super_mtd, mnt);
13890 +#else
13891 +static struct super_block *yaffs2_read_super(struct file_system_type *fs,
13892 + int flags, const char *dev_name,
13893 + void *data)
13896 + return get_sb_bdev(fs, flags, dev_name, data,
13897 + yaffs2_internal_read_super_mtd);
13899 +#endif
13901 +static struct file_system_type yaffs2_fs_type = {
13902 + .owner = THIS_MODULE,
13903 + .name = "yaffs2",
13904 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
13905 + .mount = yaffs2_mount,
13906 +#else
13907 + .get_sb = yaffs2_read_super,
13908 +#endif
13909 + .kill_sb = kill_block_super,
13910 + .fs_flags = FS_REQUIRES_DEV,
13912 +#else
13913 +static struct super_block *yaffs2_read_super(struct super_block *sb,
13914 + void *data, int silent)
13916 + return yaffs_internal_read_super(2, sb, data, silent);
13919 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
13920 + FS_REQUIRES_DEV);
13921 +#endif
13924 +static struct proc_dir_entry *my_proc_entry;
13926 +static char *yaffs_dump_dev_part0(char *buf, struct yaffs_dev *dev)
13928 + struct yaffs_param *param = &dev->param;
13929 + int bs[10];
13931 + yaffs_count_blocks_by_state(dev,bs);
13933 + buf += sprintf(buf, "start_block.......... %d\n", param->start_block);
13934 + buf += sprintf(buf, "end_block............ %d\n", param->end_block);
13935 + buf += sprintf(buf, "total_bytes_per_chunk %d\n",
13936 + param->total_bytes_per_chunk);
13937 + buf += sprintf(buf, "use_nand_ecc......... %d\n", param->use_nand_ecc);
13938 + buf += sprintf(buf, "no_tags_ecc.......... %d\n", param->no_tags_ecc);
13939 + buf += sprintf(buf, "is_yaffs2............ %d\n", param->is_yaffs2);
13940 + buf += sprintf(buf, "inband_tags.......... %d\n", param->inband_tags);
13941 + buf += sprintf(buf, "empty_lost_n_found... %d\n",
13942 + param->empty_lost_n_found);
13943 + buf += sprintf(buf, "disable_lazy_load.... %d\n",
13944 + param->disable_lazy_load);
13945 + buf += sprintf(buf, "disable_bad_block_mrk %d\n",
13946 + param->disable_bad_block_marking);
13947 + buf += sprintf(buf, "refresh_period....... %d\n",
13948 + param->refresh_period);
13949 + buf += sprintf(buf, "n_caches............. %d\n", param->n_caches);
13950 + buf += sprintf(buf, "n_reserved_blocks.... %d\n",
13951 + param->n_reserved_blocks);
13952 + buf += sprintf(buf, "always_check_erased.. %d\n",
13953 + param->always_check_erased);
13954 + buf += sprintf(buf, "\n");
13955 + buf += sprintf(buf, "block count by state\n");
13956 + buf += sprintf(buf, "0:%d 1:%d 2:%d 3:%d 4:%d\n",
13957 + bs[0], bs[1], bs[2], bs[3], bs[4]);
13958 + buf += sprintf(buf, "5:%d 6:%d 7:%d 8:%d 9:%d\n",
13959 + bs[5], bs[6], bs[7], bs[8], bs[9]);
13961 + return buf;
13964 +static char *yaffs_dump_dev_part1(char *buf, struct yaffs_dev *dev)
13966 + buf += sprintf(buf, "max file size....... %lld\n",
13967 + (long long) yaffs_max_file_size(dev));
13968 + buf += sprintf(buf, "data_bytes_per_chunk. %d\n",
13969 + dev->data_bytes_per_chunk);
13970 + buf += sprintf(buf, "chunk_grp_bits....... %d\n", dev->chunk_grp_bits);
13971 + buf += sprintf(buf, "chunk_grp_size....... %d\n", dev->chunk_grp_size);
13972 + buf += sprintf(buf, "n_erased_blocks...... %d\n", dev->n_erased_blocks);
13973 + buf += sprintf(buf, "blocks_in_checkpt.... %d\n",
13974 + dev->blocks_in_checkpt);
13975 + buf += sprintf(buf, "\n");
13976 + buf += sprintf(buf, "n_tnodes............. %d\n", dev->n_tnodes);
13977 + buf += sprintf(buf, "n_obj................ %d\n", dev->n_obj);
13978 + buf += sprintf(buf, "n_free_chunks........ %d\n", dev->n_free_chunks);
13979 + buf += sprintf(buf, "\n");
13980 + buf += sprintf(buf, "n_page_writes........ %u\n", dev->n_page_writes);
13981 + buf += sprintf(buf, "n_page_reads......... %u\n", dev->n_page_reads);
13982 + buf += sprintf(buf, "n_erasures........... %u\n", dev->n_erasures);
13983 + buf += sprintf(buf, "n_gc_copies.......... %u\n", dev->n_gc_copies);
13984 + buf += sprintf(buf, "all_gcs.............. %u\n", dev->all_gcs);
13985 + buf += sprintf(buf, "passive_gc_count..... %u\n",
13986 + dev->passive_gc_count);
13987 + buf += sprintf(buf, "oldest_dirty_gc_count %u\n",
13988 + dev->oldest_dirty_gc_count);
13989 + buf += sprintf(buf, "n_gc_blocks.......... %u\n", dev->n_gc_blocks);
13990 + buf += sprintf(buf, "bg_gcs............... %u\n", dev->bg_gcs);
13991 + buf += sprintf(buf, "n_retried_writes..... %u\n",
13992 + dev->n_retried_writes);
13993 + buf += sprintf(buf, "n_retired_blocks..... %u\n",
13994 + dev->n_retired_blocks);
13995 + buf += sprintf(buf, "n_ecc_fixed.......... %u\n", dev->n_ecc_fixed);
13996 + buf += sprintf(buf, "n_ecc_unfixed........ %u\n", dev->n_ecc_unfixed);
13997 + buf += sprintf(buf, "n_tags_ecc_fixed..... %u\n",
13998 + dev->n_tags_ecc_fixed);
13999 + buf += sprintf(buf, "n_tags_ecc_unfixed... %u\n",
14000 + dev->n_tags_ecc_unfixed);
14001 + buf += sprintf(buf, "cache_hits........... %u\n", dev->cache_hits);
14002 + buf += sprintf(buf, "n_deleted_files...... %u\n", dev->n_deleted_files);
14003 + buf += sprintf(buf, "n_unlinked_files..... %u\n",
14004 + dev->n_unlinked_files);
14005 + buf += sprintf(buf, "refresh_count........ %u\n", dev->refresh_count);
14006 + buf += sprintf(buf, "n_bg_deletions....... %u\n", dev->n_bg_deletions);
14007 + buf += sprintf(buf, "tags_used............ %u\n", dev->tags_used);
14008 + buf += sprintf(buf, "summary_used......... %u\n", dev->summary_used);
14010 + return buf;
14013 +static int yaffs_proc_read(char *page,
14014 + char **start,
14015 + off_t offset, int count, int *eof, void *data)
14017 + struct list_head *item;
14018 + char *buf = page;
14019 + int step = offset;
14020 + int n = 0;
14022 + /* Get proc_file_read() to step 'offset' by one on each sucessive call.
14023 + * We use 'offset' (*ppos) to indicate where we are in dev_list.
14024 + * This also assumes the user has posted a read buffer large
14025 + * enough to hold the complete output; but that's life in /proc.
14026 + */
14028 + *(int *)start = 1;
14030 + /* Print header first */
14031 + if (step == 0)
14032 + buf +=
14033 + sprintf(buf,
14034 + "Multi-version YAFFS\n");
14035 + else if (step == 1)
14036 + buf += sprintf(buf, "\n");
14037 + else {
14038 + step -= 2;
14040 + mutex_lock(&yaffs_context_lock);
14042 + /* Locate and print the Nth entry. Order N-squared but N is small. */
14043 + list_for_each(item, &yaffs_context_list) {
14044 + struct yaffs_linux_context *dc =
14045 + list_entry(item, struct yaffs_linux_context,
14046 + context_list);
14047 + struct yaffs_dev *dev = dc->dev;
14049 + if (n < (step & ~1)) {
14050 + n += 2;
14051 + continue;
14053 + if ((step & 1) == 0) {
14054 + buf +=
14055 + sprintf(buf, "\nDevice %d \"%s\"\n", n,
14056 + dev->param.name);
14057 + buf = yaffs_dump_dev_part0(buf, dev);
14058 + } else {
14059 + buf = yaffs_dump_dev_part1(buf, dev);
14062 + break;
14064 + mutex_unlock(&yaffs_context_lock);
14067 + return buf - page < count ? buf - page : count;
14070 +/**
14071 + * Set the verbosity of the warnings and error messages.
14073 + * Note that the names can only be a..z or _ with the current code.
14074 + */
14076 +static struct {
14077 + char *mask_name;
14078 + unsigned mask_bitfield;
14079 +} mask_flags[] = {
14080 + {"allocate", YAFFS_TRACE_ALLOCATE},
14081 + {"always", YAFFS_TRACE_ALWAYS},
14082 + {"background", YAFFS_TRACE_BACKGROUND},
14083 + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
14084 + {"buffers", YAFFS_TRACE_BUFFERS},
14085 + {"bug", YAFFS_TRACE_BUG},
14086 + {"checkpt", YAFFS_TRACE_CHECKPOINT},
14087 + {"deletion", YAFFS_TRACE_DELETION},
14088 + {"erase", YAFFS_TRACE_ERASE},
14089 + {"error", YAFFS_TRACE_ERROR},
14090 + {"gc_detail", YAFFS_TRACE_GC_DETAIL},
14091 + {"gc", YAFFS_TRACE_GC},
14092 + {"lock", YAFFS_TRACE_LOCK},
14093 + {"mtd", YAFFS_TRACE_MTD},
14094 + {"nandaccess", YAFFS_TRACE_NANDACCESS},
14095 + {"os", YAFFS_TRACE_OS},
14096 + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
14097 + {"scan", YAFFS_TRACE_SCAN},
14098 + {"mount", YAFFS_TRACE_MOUNT},
14099 + {"tracing", YAFFS_TRACE_TRACING},
14100 + {"sync", YAFFS_TRACE_SYNC},
14101 + {"write", YAFFS_TRACE_WRITE},
14102 + {"verify", YAFFS_TRACE_VERIFY},
14103 + {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
14104 + {"verify_full", YAFFS_TRACE_VERIFY_FULL},
14105 + {"verify_all", YAFFS_TRACE_VERIFY_ALL},
14106 + {"all", 0xffffffff},
14107 + {"none", 0},
14108 + {NULL, 0},
14111 +#define MAX_MASK_NAME_LENGTH 40
14112 +static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
14113 + unsigned long count)
14115 + unsigned rg = 0, mask_bitfield;
14116 + char *end;
14117 + char *mask_name;
14118 + const char *x;
14119 + char substring[MAX_MASK_NAME_LENGTH + 1];
14120 + int i;
14121 + int done = 0;
14122 + int add, len = 0;
14123 + int pos = 0;
14125 + rg = yaffs_trace_mask;
14127 + while (!done && (pos < count)) {
14128 + done = 1;
14129 + while ((pos < count) && isspace(buf[pos]))
14130 + pos++;
14132 + switch (buf[pos]) {
14133 + case '+':
14134 + case '-':
14135 + case '=':
14136 + add = buf[pos];
14137 + pos++;
14138 + break;
14140 + default:
14141 + add = ' ';
14142 + break;
14144 + mask_name = NULL;
14146 + mask_bitfield = simple_strtoul(buf + pos, &end, 0);
14148 + if (end > buf + pos) {
14149 + mask_name = "numeral";
14150 + len = end - (buf + pos);
14151 + pos += len;
14152 + done = 0;
14153 + } else {
14154 + for (x = buf + pos, i = 0;
14155 + (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
14156 + i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
14157 + substring[i] = *x;
14158 + substring[i] = '\0';
14160 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
14161 + if (strcmp(substring, mask_flags[i].mask_name)
14162 + == 0) {
14163 + mask_name = mask_flags[i].mask_name;
14164 + mask_bitfield =
14165 + mask_flags[i].mask_bitfield;
14166 + done = 0;
14167 + break;
14172 + if (mask_name != NULL) {
14173 + done = 0;
14174 + switch (add) {
14175 + case '-':
14176 + rg &= ~mask_bitfield;
14177 + break;
14178 + case '+':
14179 + rg |= mask_bitfield;
14180 + break;
14181 + case '=':
14182 + rg = mask_bitfield;
14183 + break;
14184 + default:
14185 + rg |= mask_bitfield;
14186 + break;
14191 + yaffs_trace_mask = rg | YAFFS_TRACE_ALWAYS;
14193 + printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_trace_mask);
14195 + if (rg & YAFFS_TRACE_ALWAYS) {
14196 + for (i = 0; mask_flags[i].mask_name != NULL; i++) {
14197 + char flag;
14198 + flag = ((rg & mask_flags[i].mask_bitfield) ==
14199 + mask_flags[i].mask_bitfield) ? '+' : '-';
14200 + printk(KERN_DEBUG "%c%s\n", flag,
14201 + mask_flags[i].mask_name);
14205 + return count;
14208 +/* Debug strings are of the form:
14209 + * .bnnn print info on block n
14210 + * .cobjn,chunkn print nand chunk id for objn:chunkn
14211 + */
14213 +static int yaffs_proc_debug_write(struct file *file, const char *buf,
14214 + unsigned long count)
14217 + char str[100];
14218 + char *p0;
14219 + char *p1;
14220 + long p1_val;
14221 + long p0_val;
14222 + char cmd;
14223 + struct list_head *item;
14225 + memset(str, 0, sizeof(str));
14226 + memcpy(str, buf, min((size_t)count, sizeof(str) -1));
14228 + cmd = str[1];
14230 + p0 = str + 2;
14232 + p1 = p0;
14234 + while (*p1 && *p1 != ',') {
14235 + p1++;
14237 + *p1 = '\0';
14238 + p1++;
14240 + p0_val = simple_strtol(p0, NULL, 0);
14241 + p1_val = simple_strtol(p1, NULL, 0);
14244 + mutex_lock(&yaffs_context_lock);
14246 + /* Locate and print the Nth entry. Order N-squared but N is small. */
14247 + list_for_each(item, &yaffs_context_list) {
14248 + struct yaffs_linux_context *dc =
14249 + list_entry(item, struct yaffs_linux_context,
14250 + context_list);
14251 + struct yaffs_dev *dev = dc->dev;
14253 + if (cmd == 'b') {
14254 + struct yaffs_block_info *bi;
14256 + bi = yaffs_get_block_info(dev,p0_val);
14258 + if(bi) {
14259 + printk("Block %d: state %d, retire %d, use %d, seq %d\n",
14260 + (int)p0_val, bi->block_state,
14261 + bi->needs_retiring, bi->pages_in_use,
14262 + bi->seq_number);
14264 + } else if (cmd == 'c') {
14265 + struct yaffs_obj *obj;
14266 + int nand_chunk;
14268 + obj = yaffs_find_by_number(dev, p0_val);
14269 + if (!obj)
14270 + printk("No obj %d\n", (int)p0_val);
14271 + else {
14272 + if(p1_val == 0)
14273 + nand_chunk = obj->hdr_chunk;
14274 + else
14275 + nand_chunk =
14276 + yaffs_find_chunk_in_file(obj,
14277 + p1_val, NULL);
14278 + printk("Nand chunk for %d:%d is %d\n",
14279 + (int)p0_val, (int)p1_val, nand_chunk);
14284 + mutex_unlock(&yaffs_context_lock);
14286 + return count;
14290 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
14291 +static int yaffs_proc_write(struct file *file, const char *buf,
14292 + unsigned long count, void *ppos)
14293 +#else
14294 +static ssize_t yaffs_proc_write(struct file *file, const char __user *buf,
14295 + size_t count, loff_t *ppos)
14296 +#endif
14298 + if (buf[0] == '.')
14299 + return yaffs_proc_debug_write(file, buf, count);
14300 + return yaffs_proc_write_trace_options(file, buf, count);
14303 +/* Stuff to handle installation of file systems */
14304 +struct file_system_to_install {
14305 + struct file_system_type *fst;
14306 + int installed;
14309 +static struct file_system_to_install fs_to_install[] = {
14310 + {&yaffs_fs_type, 0},
14311 + {&yaffs2_fs_type, 0},
14312 + {NULL, 0}
14316 +#ifdef YAFFS_NEW_PROCFS
14317 +static int yaffs_proc_show(struct seq_file *m, void *v)
14319 + /* FIXME: Unify in a better way? */
14320 + char buffer[512];
14321 + char *start;
14322 + int len;
14324 + len = yaffs_proc_read(buffer, &start, 0, sizeof(buffer), NULL, NULL);
14325 + seq_puts(m, buffer);
14326 + return 0;
14329 +static int yaffs_proc_open(struct inode *inode, struct file *file)
14331 + return single_open(file, yaffs_proc_show, NULL);
14334 +static struct file_operations procfs_ops = {
14335 + .owner = THIS_MODULE,
14336 + .open = yaffs_proc_open,
14337 + .read = seq_read,
14338 + .write = yaffs_proc_write,
14341 +static int yaffs_procfs_init(void)
14343 + /* Install the proc_fs entries */
14344 + my_proc_entry = proc_create("yaffs",
14345 + S_IRUGO | S_IFREG,
14346 + YPROC_ROOT,
14347 + &procfs_ops);
14349 + if (my_proc_entry) {
14350 + return 0;
14351 + } else {
14352 + return -ENOMEM;
14356 +#else
14359 +static int yaffs_procfs_init(void)
14361 + /* Install the proc_fs entries */
14362 + my_proc_entry = create_proc_entry("yaffs",
14363 + S_IRUGO | S_IFREG, YPROC_ROOT);
14365 + if (my_proc_entry) {
14366 + my_proc_entry->write_proc = yaffs_proc_write;
14367 + my_proc_entry->read_proc = yaffs_proc_read;
14368 + my_proc_entry->data = NULL;
14369 + return 0;
14370 + } else {
14371 + return -ENOMEM;
14375 +#endif
14378 +static int __init init_yaffs_fs(void)
14380 + int error = 0;
14381 + struct file_system_to_install *fsinst;
14383 + mutex_init(&yaffs_context_lock);
14385 + error = yaffs_procfs_init();
14386 + if (error)
14387 + return error;
14389 + /* Now add the file system entries */
14391 + fsinst = fs_to_install;
14393 + while (fsinst->fst && !error) {
14394 + error = register_filesystem(fsinst->fst);
14395 + if (!error)
14396 + fsinst->installed = 1;
14397 + fsinst++;
14400 + /* Any errors? uninstall */
14401 + if (error) {
14402 + fsinst = fs_to_install;
14404 + while (fsinst->fst) {
14405 + if (fsinst->installed) {
14406 + unregister_filesystem(fsinst->fst);
14407 + fsinst->installed = 0;
14409 + fsinst++;
14413 + return error;
14416 +static void __exit exit_yaffs_fs(void)
14419 + struct file_system_to_install *fsinst;
14421 + remove_proc_entry("yaffs", YPROC_ROOT);
14423 + fsinst = fs_to_install;
14425 + while (fsinst->fst) {
14426 + if (fsinst->installed) {
14427 + unregister_filesystem(fsinst->fst);
14428 + fsinst->installed = 0;
14430 + fsinst++;
14434 +module_init(init_yaffs_fs)
14435 + module_exit(exit_yaffs_fs)
14437 + MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
14438 +MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2011");
14439 +MODULE_LICENSE("GPL");
14440 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_yaffs1.c linux-3.18.14/fs/yaffs2/yaffs_yaffs1.c
14441 --- linux-3.18.14.orig/fs/yaffs2/yaffs_yaffs1.c 1970-01-01 01:00:00.000000000 +0100
14442 +++ linux-3.18.14/fs/yaffs2/yaffs_yaffs1.c 2015-06-14 21:23:22.000000000 +0200
14443 @@ -0,0 +1,422 @@
14445 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
14447 + * Copyright (C) 2002-2011 Aleph One Ltd.
14448 + * for Toby Churchill Ltd and Brightstar Engineering
14450 + * Created by Charles Manning <charles@aleph1.co.uk>
14452 + * This program is free software; you can redistribute it and/or modify
14453 + * it under the terms of the GNU General Public License version 2 as
14454 + * published by the Free Software Foundation.
14455 + */
14457 +#include "yaffs_yaffs1.h"
14458 +#include "yportenv.h"
14459 +#include "yaffs_trace.h"
14460 +#include "yaffs_bitmap.h"
14461 +#include "yaffs_getblockinfo.h"
14462 +#include "yaffs_nand.h"
14463 +#include "yaffs_attribs.h"
14465 +int yaffs1_scan(struct yaffs_dev *dev)
14467 + struct yaffs_ext_tags tags;
14468 + int blk;
14469 + int result;
14470 + int chunk;
14471 + int c;
14472 + int deleted;
14473 + enum yaffs_block_state state;
14474 + LIST_HEAD(hard_list);
14475 + struct yaffs_block_info *bi;
14476 + u32 seq_number;
14477 + struct yaffs_obj_hdr *oh;
14478 + struct yaffs_obj *in;
14479 + struct yaffs_obj *parent;
14480 + int alloc_failed = 0;
14481 + struct yaffs_shadow_fixer *shadow_fixers = NULL;
14482 + u8 *chunk_data;
14484 + yaffs_trace(YAFFS_TRACE_SCAN,
14485 + "yaffs1_scan starts intstartblk %d intendblk %d...",
14486 + dev->internal_start_block, dev->internal_end_block);
14488 + chunk_data = yaffs_get_temp_buffer(dev);
14490 + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
14492 + /* Scan all the blocks to determine their state */
14493 + bi = dev->block_info;
14494 + for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
14495 + blk++) {
14496 + yaffs_clear_chunk_bits(dev, blk);
14497 + bi->pages_in_use = 0;
14498 + bi->soft_del_pages = 0;
14500 + yaffs_query_init_block_state(dev, blk, &state, &seq_number);
14502 + bi->block_state = state;
14503 + bi->seq_number = seq_number;
14505 + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
14506 + bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
14508 + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
14509 + "Block scanning block %d state %d seq %d",
14510 + blk, state, seq_number);
14512 + if (state == YAFFS_BLOCK_STATE_DEAD) {
14513 + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
14514 + "block %d is bad", blk);
14515 + } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
14516 + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
14517 + dev->n_erased_blocks++;
14518 + dev->n_free_chunks += dev->param.chunks_per_block;
14520 + bi++;
14523 + /* For each block.... */
14524 + for (blk = dev->internal_start_block;
14525 + !alloc_failed && blk <= dev->internal_end_block; blk++) {
14527 + cond_resched();
14529 + bi = yaffs_get_block_info(dev, blk);
14530 + state = bi->block_state;
14532 + deleted = 0;
14534 + /* For each chunk in each block that needs scanning.... */
14535 + for (c = 0;
14536 + !alloc_failed && c < dev->param.chunks_per_block &&
14537 + state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) {
14538 + /* Read the tags and decide what to do */
14539 + chunk = blk * dev->param.chunks_per_block + c;
14541 + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
14542 + &tags);
14544 + /* Let's have a good look at this chunk... */
14546 + if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED ||
14547 + tags.is_deleted) {
14548 + /* YAFFS1 only...
14549 + * A deleted chunk
14550 + */
14551 + deleted++;
14552 + dev->n_free_chunks++;
14553 + } else if (!tags.chunk_used) {
14554 + /* An unassigned chunk in the block
14555 + * This means that either the block is empty or
14556 + * this is the one being allocated from
14557 + */
14559 + if (c == 0) {
14560 + /* We're looking at the first chunk in
14561 + *the block so the block is unused */
14562 + state = YAFFS_BLOCK_STATE_EMPTY;
14563 + dev->n_erased_blocks++;
14564 + } else {
14565 + /* this is the block being allocated */
14566 + yaffs_trace(YAFFS_TRACE_SCAN,
14567 + " Allocating from %d %d",
14568 + blk, c);
14569 + state = YAFFS_BLOCK_STATE_ALLOCATING;
14570 + dev->alloc_block = blk;
14571 + dev->alloc_page = c;
14572 + dev->alloc_block_finder = blk;
14576 + dev->n_free_chunks +=
14577 + (dev->param.chunks_per_block - c);
14578 + } else if (tags.chunk_id > 0) {
14579 + /* chunk_id > 0 so it is a data chunk... */
14580 + unsigned int endpos;
14582 + yaffs_set_chunk_bit(dev, blk, c);
14583 + bi->pages_in_use++;
14585 + in = yaffs_find_or_create_by_number(dev,
14586 + tags.obj_id,
14587 + YAFFS_OBJECT_TYPE_FILE);
14588 + /* PutChunkIntoFile checks for a clash
14589 + * (two data chunks with the same chunk_id).
14590 + */
14592 + if (!in)
14593 + alloc_failed = 1;
14595 + if (in) {
14596 + if (!yaffs_put_chunk_in_file
14597 + (in, tags.chunk_id, chunk, 1))
14598 + alloc_failed = 1;
14601 + endpos =
14602 + (tags.chunk_id - 1) *
14603 + dev->data_bytes_per_chunk +
14604 + tags.n_bytes;
14605 + if (in &&
14606 + in->variant_type ==
14607 + YAFFS_OBJECT_TYPE_FILE &&
14608 + in->variant.file_variant.scanned_size <
14609 + endpos) {
14610 + in->variant.file_variant.scanned_size =
14611 + endpos;
14612 + if (!dev->param.use_header_file_size) {
14613 + in->variant.
14614 + file_variant.file_size =
14615 + in->variant.
14616 + file_variant.scanned_size;
14620 + } else {
14621 + /* chunk_id == 0, so it is an ObjectHeader.
14622 + * Make the object
14623 + */
14624 + yaffs_set_chunk_bit(dev, blk, c);
14625 + bi->pages_in_use++;
14627 + result = yaffs_rd_chunk_tags_nand(dev, chunk,
14628 + chunk_data,
14629 + NULL);
14631 + oh = (struct yaffs_obj_hdr *)chunk_data;
14633 + in = yaffs_find_by_number(dev, tags.obj_id);
14634 + if (in && in->variant_type != oh->type) {
14635 + /* This should not happen, but somehow
14636 + * Wev'e ended up with an obj_id that
14637 + * has been reused but not yet deleted,
14638 + * and worse still it has changed type.
14639 + * Delete the old object.
14640 + */
14642 + yaffs_del_obj(in);
14643 + in = NULL;
14646 + in = yaffs_find_or_create_by_number(dev,
14647 + tags.obj_id,
14648 + oh->type);
14650 + if (!in)
14651 + alloc_failed = 1;
14653 + if (in && oh->shadows_obj > 0) {
14655 + struct yaffs_shadow_fixer *fixer;
14656 + fixer =
14657 + kmalloc(sizeof
14658 + (struct yaffs_shadow_fixer),
14659 + GFP_NOFS);
14660 + if (fixer) {
14661 + fixer->next = shadow_fixers;
14662 + shadow_fixers = fixer;
14663 + fixer->obj_id = tags.obj_id;
14664 + fixer->shadowed_id =
14665 + oh->shadows_obj;
14666 + yaffs_trace(YAFFS_TRACE_SCAN,
14667 + " Shadow fixer: %d shadows %d",
14668 + fixer->obj_id,
14669 + fixer->shadowed_id);
14675 + if (in && in->valid) {
14676 + /* We have already filled this one.
14677 + * We have a duplicate and need to
14678 + * resolve it. */
14680 + unsigned existing_serial = in->serial;
14681 + unsigned new_serial =
14682 + tags.serial_number;
14684 + if (((existing_serial + 1) & 3) ==
14685 + new_serial) {
14686 + /* Use new one - destroy the
14687 + * exisiting one */
14688 + yaffs_chunk_del(dev,
14689 + in->hdr_chunk,
14690 + 1, __LINE__);
14691 + in->valid = 0;
14692 + } else {
14693 + /* Use existing - destroy
14694 + * this one. */
14695 + yaffs_chunk_del(dev, chunk, 1,
14696 + __LINE__);
14700 + if (in && !in->valid &&
14701 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
14702 + tags.obj_id ==
14703 + YAFFS_OBJECTID_LOSTNFOUND)) {
14704 + /* We only load some info, don't fiddle
14705 + * with directory structure */
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 + } else if (in && !in->valid) {
14715 + /* we need to load this info */
14717 + in->valid = 1;
14718 + in->variant_type = oh->type;
14720 + in->yst_mode = oh->yst_mode;
14721 + yaffs_load_attribs(in, oh);
14722 + in->hdr_chunk = chunk;
14723 + in->serial = tags.serial_number;
14725 + yaffs_set_obj_name_from_oh(in, oh);
14726 + in->dirty = 0;
14728 + /* directory stuff...
14729 + * hook up to parent
14730 + */
14732 + parent =
14733 + yaffs_find_or_create_by_number
14734 + (dev, oh->parent_obj_id,
14735 + YAFFS_OBJECT_TYPE_DIRECTORY);
14736 + if (!parent)
14737 + alloc_failed = 1;
14738 + if (parent && parent->variant_type ==
14739 + YAFFS_OBJECT_TYPE_UNKNOWN) {
14740 + /* Set up as a directory */
14741 + parent->variant_type =
14742 + YAFFS_OBJECT_TYPE_DIRECTORY;
14743 + INIT_LIST_HEAD(&parent->
14744 + variant.dir_variant.
14745 + children);
14746 + } else if (!parent ||
14747 + parent->variant_type !=
14748 + YAFFS_OBJECT_TYPE_DIRECTORY) {
14749 + /* Hoosterman, a problem....
14750 + * We're trying to use a
14751 + * non-directory as a directory
14752 + */
14754 + yaffs_trace(YAFFS_TRACE_ERROR,
14755 + "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
14756 + );
14757 + parent = dev->lost_n_found;
14760 + yaffs_add_obj_to_dir(parent, in);
14762 + switch (in->variant_type) {
14763 + case YAFFS_OBJECT_TYPE_UNKNOWN:
14764 + /* Todo got a problem */
14765 + break;
14766 + case YAFFS_OBJECT_TYPE_FILE:
14767 + if (dev->param.
14768 + use_header_file_size)
14769 + in->variant.
14770 + file_variant.file_size
14771 + = yaffs_oh_to_size(oh);
14772 + break;
14773 + case YAFFS_OBJECT_TYPE_HARDLINK:
14774 + in->variant.
14775 + hardlink_variant.equiv_id =
14776 + oh->equiv_id;
14777 + list_add(&in->hard_links,
14778 + &hard_list);
14779 + break;
14780 + case YAFFS_OBJECT_TYPE_DIRECTORY:
14781 + /* Do nothing */
14782 + break;
14783 + case YAFFS_OBJECT_TYPE_SPECIAL:
14784 + /* Do nothing */
14785 + break;
14786 + case YAFFS_OBJECT_TYPE_SYMLINK:
14787 + in->variant.symlink_variant.
14788 + alias =
14789 + yaffs_clone_str(oh->alias);
14790 + if (!in->variant.
14791 + symlink_variant.alias)
14792 + alloc_failed = 1;
14793 + break;
14799 + if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
14800 + /* If we got this far while scanning,
14801 + * then the block is fully allocated. */
14802 + state = YAFFS_BLOCK_STATE_FULL;
14805 + if (state == YAFFS_BLOCK_STATE_ALLOCATING) {
14806 + /* If the block was partially allocated then
14807 + * treat it as fully allocated. */
14808 + state = YAFFS_BLOCK_STATE_FULL;
14809 + dev->alloc_block = -1;
14812 + bi->block_state = state;
14814 + /* Now let's see if it was dirty */
14815 + if (bi->pages_in_use == 0 &&
14816 + !bi->has_shrink_hdr &&
14817 + bi->block_state == YAFFS_BLOCK_STATE_FULL)
14818 + yaffs_block_became_dirty(dev, blk);
14821 + /* Ok, we've done all the scanning.
14822 + * Fix up the hard link chains.
14823 + * We should now have scanned all the objects, now it's time to add
14824 + * these hardlinks.
14825 + */
14827 + yaffs_link_fixup(dev, &hard_list);
14829 + /*
14830 + * Fix up any shadowed objects.
14831 + * There should not be more than one of these.
14832 + */
14834 + struct yaffs_shadow_fixer *fixer;
14835 + struct yaffs_obj *obj;
14837 + while (shadow_fixers) {
14838 + fixer = shadow_fixers;
14839 + shadow_fixers = fixer->next;
14840 + /* Complete the rename transaction by deleting the
14841 + * shadowed object then setting the object header
14842 + to unshadowed.
14843 + */
14844 + obj = yaffs_find_by_number(dev, fixer->shadowed_id);
14845 + if (obj)
14846 + yaffs_del_obj(obj);
14848 + obj = yaffs_find_by_number(dev, fixer->obj_id);
14850 + if (obj)
14851 + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL);
14853 + kfree(fixer);
14857 + yaffs_release_temp_buffer(dev, chunk_data);
14859 + if (alloc_failed)
14860 + return YAFFS_FAIL;
14862 + yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends");
14864 + return YAFFS_OK;
14866 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_yaffs1.h linux-3.18.14/fs/yaffs2/yaffs_yaffs1.h
14867 --- linux-3.18.14.orig/fs/yaffs2/yaffs_yaffs1.h 1970-01-01 01:00:00.000000000 +0100
14868 +++ linux-3.18.14/fs/yaffs2/yaffs_yaffs1.h 2015-06-14 21:23:22.000000000 +0200
14869 @@ -0,0 +1,22 @@
14871 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
14873 + * Copyright (C) 2002-2011 Aleph One Ltd.
14874 + * for Toby Churchill Ltd and Brightstar Engineering
14876 + * Created by Charles Manning <charles@aleph1.co.uk>
14878 + * This program is free software; you can redistribute it and/or modify
14879 + * it under the terms of the GNU Lesser General Public License version 2.1 as
14880 + * published by the Free Software Foundation.
14882 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
14883 + */
14885 +#ifndef __YAFFS_YAFFS1_H__
14886 +#define __YAFFS_YAFFS1_H__
14888 +#include "yaffs_guts.h"
14889 +int yaffs1_scan(struct yaffs_dev *dev);
14891 +#endif
14892 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_yaffs2.c linux-3.18.14/fs/yaffs2/yaffs_yaffs2.c
14893 --- linux-3.18.14.orig/fs/yaffs2/yaffs_yaffs2.c 1970-01-01 01:00:00.000000000 +0100
14894 +++ linux-3.18.14/fs/yaffs2/yaffs_yaffs2.c 2015-06-14 21:23:22.000000000 +0200
14895 @@ -0,0 +1,1532 @@
14897 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
14899 + * Copyright (C) 2002-2011 Aleph One Ltd.
14900 + * for Toby Churchill Ltd and Brightstar Engineering
14902 + * Created by Charles Manning <charles@aleph1.co.uk>
14904 + * This program is free software; you can redistribute it and/or modify
14905 + * it under the terms of the GNU General Public License version 2 as
14906 + * published by the Free Software Foundation.
14907 + */
14909 +#include "yaffs_guts.h"
14910 +#include "yaffs_trace.h"
14911 +#include "yaffs_yaffs2.h"
14912 +#include "yaffs_checkptrw.h"
14913 +#include "yaffs_bitmap.h"
14914 +#include "yaffs_nand.h"
14915 +#include "yaffs_getblockinfo.h"
14916 +#include "yaffs_verify.h"
14917 +#include "yaffs_attribs.h"
14918 +#include "yaffs_summary.h"
14921 + * Checkpoints are really no benefit on very small partitions.
14923 + * To save space on small partitions don't bother with checkpoints unless
14924 + * the partition is at least this big.
14925 + */
14926 +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
14927 +#define YAFFS_SMALL_HOLE_THRESHOLD 4
14930 + * Oldest Dirty Sequence Number handling.
14931 + */
14933 +/* yaffs_calc_oldest_dirty_seq()
14934 + * yaffs2_find_oldest_dirty_seq()
14935 + * Calculate the oldest dirty sequence number if we don't know it.
14936 + */
14937 +void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
14939 + int i;
14940 + unsigned seq;
14941 + unsigned block_no = 0;
14942 + struct yaffs_block_info *b;
14944 + if (!dev->param.is_yaffs2)
14945 + return;
14947 + /* Find the oldest dirty sequence number. */
14948 + seq = dev->seq_number + 1;
14949 + b = dev->block_info;
14950 + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
14951 + if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
14952 + (b->pages_in_use - b->soft_del_pages) <
14953 + dev->param.chunks_per_block &&
14954 + b->seq_number < seq) {
14955 + seq = b->seq_number;
14956 + block_no = i;
14958 + b++;
14961 + if (block_no) {
14962 + dev->oldest_dirty_seq = seq;
14963 + dev->oldest_dirty_block = block_no;
14967 +void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
14969 + if (!dev->param.is_yaffs2)
14970 + return;
14972 + if (!dev->oldest_dirty_seq)
14973 + yaffs_calc_oldest_dirty_seq(dev);
14977 + * yaffs_clear_oldest_dirty_seq()
14978 + * Called when a block is erased or marked bad. (ie. when its seq_number
14979 + * becomes invalid). If the value matches the oldest then we clear
14980 + * dev->oldest_dirty_seq to force its recomputation.
14981 + */
14982 +void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
14983 + struct yaffs_block_info *bi)
14986 + if (!dev->param.is_yaffs2)
14987 + return;
14989 + if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
14990 + dev->oldest_dirty_seq = 0;
14991 + dev->oldest_dirty_block = 0;
14996 + * yaffs2_update_oldest_dirty_seq()
14997 + * Update the oldest dirty sequence number whenever we dirty a block.
14998 + * Only do this if the oldest_dirty_seq is actually being tracked.
14999 + */
15000 +void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
15001 + struct yaffs_block_info *bi)
15003 + if (!dev->param.is_yaffs2)
15004 + return;
15006 + if (dev->oldest_dirty_seq) {
15007 + if (dev->oldest_dirty_seq > bi->seq_number) {
15008 + dev->oldest_dirty_seq = bi->seq_number;
15009 + dev->oldest_dirty_block = block_no;
15014 +int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
15017 + if (!dev->param.is_yaffs2)
15018 + return 1; /* disqualification only applies to yaffs2. */
15020 + if (!bi->has_shrink_hdr)
15021 + return 1; /* can gc */
15023 + yaffs2_find_oldest_dirty_seq(dev);
15025 + /* Can't do gc of this block if there are any blocks older than this
15026 + * one that have discarded pages.
15027 + */
15028 + return (bi->seq_number <= dev->oldest_dirty_seq);
15032 + * yaffs2_find_refresh_block()
15033 + * periodically finds the oldest full block by sequence number for refreshing.
15034 + * Only for yaffs2.
15035 + */
15036 +u32 yaffs2_find_refresh_block(struct yaffs_dev *dev)
15038 + u32 b;
15039 + u32 oldest = 0;
15040 + u32 oldest_seq = 0;
15041 + struct yaffs_block_info *bi;
15043 + if (!dev->param.is_yaffs2)
15044 + return oldest;
15046 + /*
15047 + * If refresh period < 10 then refreshing is disabled.
15048 + */
15049 + if (dev->param.refresh_period < 10)
15050 + return oldest;
15052 + /*
15053 + * Fix broken values.
15054 + */
15055 + if (dev->refresh_skip > dev->param.refresh_period)
15056 + dev->refresh_skip = dev->param.refresh_period;
15058 + if (dev->refresh_skip > 0)
15059 + return oldest;
15061 + /*
15062 + * Refresh skip is now zero.
15063 + * We'll do a refresh this time around....
15064 + * Update the refresh skip and find the oldest block.
15065 + */
15066 + dev->refresh_skip = dev->param.refresh_period;
15067 + dev->refresh_count++;
15068 + bi = dev->block_info;
15069 + for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
15071 + if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
15073 + if (oldest < 1 || bi->seq_number < oldest_seq) {
15074 + oldest = b;
15075 + oldest_seq = bi->seq_number;
15078 + bi++;
15081 + if (oldest > 0) {
15082 + yaffs_trace(YAFFS_TRACE_GC,
15083 + "GC refresh count %d selected block %d with seq_number %d",
15084 + dev->refresh_count, oldest, oldest_seq);
15087 + return oldest;
15090 +int yaffs2_checkpt_required(struct yaffs_dev *dev)
15092 + int nblocks;
15094 + if (!dev->param.is_yaffs2)
15095 + return 0;
15097 + nblocks = dev->internal_end_block - dev->internal_start_block + 1;
15099 + return !dev->param.skip_checkpt_wr &&
15100 + !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
15103 +int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
15105 + int retval;
15106 + int n_bytes = 0;
15107 + int n_blocks;
15108 + int dev_blocks;
15110 + if (!dev->param.is_yaffs2)
15111 + return 0;
15113 + if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
15114 + /* Not a valid value so recalculate */
15115 + dev_blocks = dev->param.end_block - dev->param.start_block + 1;
15116 + n_bytes += sizeof(struct yaffs_checkpt_validity);
15117 + n_bytes += sizeof(struct yaffs_checkpt_dev);
15118 + n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
15119 + n_bytes += dev_blocks * dev->chunk_bit_stride;
15120 + n_bytes +=
15121 + (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) *
15122 + dev->n_obj;
15123 + n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes;
15124 + n_bytes += sizeof(struct yaffs_checkpt_validity);
15125 + n_bytes += sizeof(u32); /* checksum */
15127 + /* Round up and add 2 blocks to allow for some bad blocks,
15128 + * so add 3 */
15130 + n_blocks =
15131 + (n_bytes /
15132 + (dev->data_bytes_per_chunk *
15133 + dev->param.chunks_per_block)) + 3;
15135 + dev->checkpoint_blocks_required = n_blocks;
15138 + retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
15139 + if (retval < 0)
15140 + retval = 0;
15141 + return retval;
15144 +/*--------------------- Checkpointing --------------------*/
15146 +static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
15148 + struct yaffs_checkpt_validity cp;
15150 + memset(&cp, 0, sizeof(cp));
15152 + cp.struct_type = sizeof(cp);
15153 + cp.magic = YAFFS_MAGIC;
15154 + cp.version = YAFFS_CHECKPOINT_VERSION;
15155 + cp.head = (head) ? 1 : 0;
15157 + return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
15160 +static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
15162 + struct yaffs_checkpt_validity cp;
15163 + int ok;
15165 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
15167 + if (ok)
15168 + ok = (cp.struct_type == sizeof(cp)) &&
15169 + (cp.magic == YAFFS_MAGIC) &&
15170 + (cp.version == YAFFS_CHECKPOINT_VERSION) &&
15171 + (cp.head == ((head) ? 1 : 0));
15172 + return ok ? 1 : 0;
15175 +static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
15176 + struct yaffs_dev *dev)
15178 + cp->n_erased_blocks = dev->n_erased_blocks;
15179 + cp->alloc_block = dev->alloc_block;
15180 + cp->alloc_page = dev->alloc_page;
15181 + cp->n_free_chunks = dev->n_free_chunks;
15183 + cp->n_deleted_files = dev->n_deleted_files;
15184 + cp->n_unlinked_files = dev->n_unlinked_files;
15185 + cp->n_bg_deletions = dev->n_bg_deletions;
15186 + cp->seq_number = dev->seq_number;
15190 +static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
15191 + struct yaffs_checkpt_dev *cp)
15193 + dev->n_erased_blocks = cp->n_erased_blocks;
15194 + dev->alloc_block = cp->alloc_block;
15195 + dev->alloc_page = cp->alloc_page;
15196 + dev->n_free_chunks = cp->n_free_chunks;
15198 + dev->n_deleted_files = cp->n_deleted_files;
15199 + dev->n_unlinked_files = cp->n_unlinked_files;
15200 + dev->n_bg_deletions = cp->n_bg_deletions;
15201 + dev->seq_number = cp->seq_number;
15204 +static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
15206 + struct yaffs_checkpt_dev cp;
15207 + u32 n_bytes;
15208 + u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
15209 + int ok;
15211 + /* Write device runtime values */
15212 + yaffs2_dev_to_checkpt_dev(&cp, dev);
15213 + cp.struct_type = sizeof(cp);
15215 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
15216 + if (!ok)
15217 + return 0;
15219 + /* Write block info */
15220 + n_bytes = n_blocks * sizeof(struct yaffs_block_info);
15221 + ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
15222 + if (!ok)
15223 + return 0;
15225 + /* Write chunk bits */
15226 + n_bytes = n_blocks * dev->chunk_bit_stride;
15227 + ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
15229 + return ok ? 1 : 0;
15232 +static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
15234 + struct yaffs_checkpt_dev cp;
15235 + u32 n_bytes;
15236 + u32 n_blocks =
15237 + (dev->internal_end_block - dev->internal_start_block + 1);
15238 + int ok;
15240 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
15241 + if (!ok)
15242 + return 0;
15244 + if (cp.struct_type != sizeof(cp))
15245 + return 0;
15247 + yaffs_checkpt_dev_to_dev(dev, &cp);
15249 + n_bytes = n_blocks * sizeof(struct yaffs_block_info);
15251 + ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
15253 + if (!ok)
15254 + return 0;
15256 + n_bytes = n_blocks * dev->chunk_bit_stride;
15258 + ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
15260 + return ok ? 1 : 0;
15263 +static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
15264 + struct yaffs_obj *obj)
15266 + cp->obj_id = obj->obj_id;
15267 + cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
15268 + cp->hdr_chunk = obj->hdr_chunk;
15269 + cp->variant_type = obj->variant_type;
15270 + cp->deleted = obj->deleted;
15271 + cp->soft_del = obj->soft_del;
15272 + cp->unlinked = obj->unlinked;
15273 + cp->fake = obj->fake;
15274 + cp->rename_allowed = obj->rename_allowed;
15275 + cp->unlink_allowed = obj->unlink_allowed;
15276 + cp->serial = obj->serial;
15277 + cp->n_data_chunks = obj->n_data_chunks;
15279 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
15280 + cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
15281 + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
15282 + cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
15285 +static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
15286 + struct yaffs_checkpt_obj *cp)
15288 + struct yaffs_obj *parent;
15290 + if (obj->variant_type != cp->variant_type) {
15291 + yaffs_trace(YAFFS_TRACE_ERROR,
15292 + "Checkpoint read object %d type %d chunk %d does not match existing object type %d",
15293 + cp->obj_id, cp->variant_type, cp->hdr_chunk,
15294 + obj->variant_type);
15295 + return 0;
15298 + obj->obj_id = cp->obj_id;
15300 + if (cp->parent_id)
15301 + parent = yaffs_find_or_create_by_number(obj->my_dev,
15302 + cp->parent_id,
15303 + YAFFS_OBJECT_TYPE_DIRECTORY);
15304 + else
15305 + parent = NULL;
15307 + if (parent) {
15308 + if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
15309 + yaffs_trace(YAFFS_TRACE_ALWAYS,
15310 + "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory",
15311 + cp->obj_id, cp->parent_id,
15312 + cp->variant_type, cp->hdr_chunk,
15313 + parent->variant_type);
15314 + return 0;
15316 + yaffs_add_obj_to_dir(parent, obj);
15319 + obj->hdr_chunk = cp->hdr_chunk;
15320 + obj->variant_type = cp->variant_type;
15321 + obj->deleted = cp->deleted;
15322 + obj->soft_del = cp->soft_del;
15323 + obj->unlinked = cp->unlinked;
15324 + obj->fake = cp->fake;
15325 + obj->rename_allowed = cp->rename_allowed;
15326 + obj->unlink_allowed = cp->unlink_allowed;
15327 + obj->serial = cp->serial;
15328 + obj->n_data_chunks = cp->n_data_chunks;
15330 + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
15331 + obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
15332 + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
15333 + obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
15335 + if (obj->hdr_chunk > 0)
15336 + obj->lazy_loaded = 1;
15337 + return 1;
15340 +static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
15341 + struct yaffs_tnode *tn, u32 level,
15342 + int chunk_offset)
15344 + int i;
15345 + struct yaffs_dev *dev = in->my_dev;
15346 + int ok = 1;
15347 + u32 base_offset;
15349 + if (!tn)
15350 + return 1;
15352 + if (level > 0) {
15353 + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
15354 + if (!tn->internal[i])
15355 + continue;
15356 + ok = yaffs2_checkpt_tnode_worker(in,
15357 + tn->internal[i],
15358 + level - 1,
15359 + (chunk_offset <<
15360 + YAFFS_TNODES_INTERNAL_BITS) + i);
15362 + return ok;
15365 + /* Level 0 tnode */
15366 + base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
15367 + ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) ==
15368 + sizeof(base_offset));
15369 + if (ok)
15370 + ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) ==
15371 + dev->tnode_size);
15373 + return ok;
15376 +static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
15378 + u32 end_marker = ~0;
15379 + int ok = 1;
15381 + if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
15382 + return ok;
15384 + ok = yaffs2_checkpt_tnode_worker(obj,
15385 + obj->variant.file_variant.top,
15386 + obj->variant.file_variant.
15387 + top_level, 0);
15388 + if (ok)
15389 + ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker,
15390 + sizeof(end_marker)) == sizeof(end_marker));
15392 + return ok ? 1 : 0;
15395 +static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
15397 + u32 base_chunk;
15398 + int ok = 1;
15399 + struct yaffs_dev *dev = obj->my_dev;
15400 + struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
15401 + struct yaffs_tnode *tn;
15402 + int nread = 0;
15404 + ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
15405 + sizeof(base_chunk));
15407 + while (ok && (~base_chunk)) {
15408 + nread++;
15409 + /* Read level 0 tnode */
15411 + tn = yaffs_get_tnode(dev);
15412 + if (tn)
15413 + ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
15414 + dev->tnode_size);
15415 + else
15416 + ok = 0;
15418 + if (tn && ok)
15419 + ok = yaffs_add_find_tnode_0(dev,
15420 + file_stuct_ptr,
15421 + base_chunk, tn) ? 1 : 0;
15423 + if (ok)
15424 + ok = (yaffs2_checkpt_rd
15425 + (dev, &base_chunk,
15426 + sizeof(base_chunk)) == sizeof(base_chunk));
15429 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15430 + "Checkpoint read tnodes %d records, last %d. ok %d",
15431 + nread, base_chunk, ok);
15433 + return ok ? 1 : 0;
15436 +static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
15438 + struct yaffs_obj *obj;
15439 + struct yaffs_checkpt_obj cp;
15440 + int i;
15441 + int ok = 1;
15442 + struct list_head *lh;
15444 + /* Iterate through the objects in each hash entry,
15445 + * dumping them to the checkpointing stream.
15446 + */
15448 + for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
15449 + list_for_each(lh, &dev->obj_bucket[i].list) {
15450 + obj = list_entry(lh, struct yaffs_obj, hash_link);
15451 + if (!obj->defered_free) {
15452 + yaffs2_obj_checkpt_obj(&cp, obj);
15453 + cp.struct_type = sizeof(cp);
15455 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15456 + "Checkpoint write object %d parent %d type %d chunk %d obj addr %p",
15457 + cp.obj_id, cp.parent_id,
15458 + cp.variant_type, cp.hdr_chunk, obj);
15460 + ok = (yaffs2_checkpt_wr(dev, &cp,
15461 + sizeof(cp)) == sizeof(cp));
15463 + if (ok &&
15464 + obj->variant_type ==
15465 + YAFFS_OBJECT_TYPE_FILE)
15466 + ok = yaffs2_wr_checkpt_tnodes(obj);
15471 + /* Dump end of list */
15472 + memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj));
15473 + cp.struct_type = sizeof(cp);
15475 + if (ok)
15476 + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
15478 + return ok ? 1 : 0;
15481 +static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
15483 + struct yaffs_obj *obj;
15484 + struct yaffs_checkpt_obj cp;
15485 + int ok = 1;
15486 + int done = 0;
15487 + LIST_HEAD(hard_list);
15490 + while (ok && !done) {
15491 + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
15492 + if (cp.struct_type != sizeof(cp)) {
15493 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15494 + "struct size %d instead of %d ok %d",
15495 + cp.struct_type, (int)sizeof(cp), ok);
15496 + ok = 0;
15499 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15500 + "Checkpoint read object %d parent %d type %d chunk %d ",
15501 + cp.obj_id, cp.parent_id, cp.variant_type,
15502 + cp.hdr_chunk);
15504 + if (ok && cp.obj_id == ~0) {
15505 + done = 1;
15506 + } else if (ok) {
15507 + obj =
15508 + yaffs_find_or_create_by_number(dev, cp.obj_id,
15509 + cp.variant_type);
15510 + if (obj) {
15511 + ok = yaffs2_checkpt_obj_to_obj(obj, &cp);
15512 + if (!ok)
15513 + break;
15514 + if (obj->variant_type ==
15515 + YAFFS_OBJECT_TYPE_FILE) {
15516 + ok = yaffs2_rd_checkpt_tnodes(obj);
15517 + } else if (obj->variant_type ==
15518 + YAFFS_OBJECT_TYPE_HARDLINK) {
15519 + list_add(&obj->hard_links, &hard_list);
15521 + } else {
15522 + ok = 0;
15527 + if (ok)
15528 + yaffs_link_fixup(dev, &hard_list);
15530 + return ok ? 1 : 0;
15533 +static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
15535 + u32 checkpt_sum;
15536 + int ok;
15538 + yaffs2_get_checkpt_sum(dev, &checkpt_sum);
15540 + ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
15541 + sizeof(checkpt_sum));
15543 + if (!ok)
15544 + return 0;
15546 + return 1;
15549 +static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
15551 + u32 checkpt_sum0;
15552 + u32 checkpt_sum1;
15553 + int ok;
15555 + yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
15557 + ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
15558 + sizeof(checkpt_sum1));
15560 + if (!ok)
15561 + return 0;
15563 + if (checkpt_sum0 != checkpt_sum1)
15564 + return 0;
15566 + return 1;
15569 +static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
15571 + int ok = 1;
15573 + if (!yaffs2_checkpt_required(dev)) {
15574 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15575 + "skipping checkpoint write");
15576 + ok = 0;
15579 + if (ok)
15580 + ok = yaffs2_checkpt_open(dev, 1);
15582 + if (ok) {
15583 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15584 + "write checkpoint validity");
15585 + ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
15587 + if (ok) {
15588 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15589 + "write checkpoint device");
15590 + ok = yaffs2_wr_checkpt_dev(dev);
15592 + if (ok) {
15593 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15594 + "write checkpoint objects");
15595 + ok = yaffs2_wr_checkpt_objs(dev);
15597 + if (ok) {
15598 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15599 + "write checkpoint validity");
15600 + ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
15603 + if (ok)
15604 + ok = yaffs2_wr_checkpt_sum(dev);
15606 + if (!yaffs_checkpt_close(dev))
15607 + ok = 0;
15609 + if (ok)
15610 + dev->is_checkpointed = 1;
15611 + else
15612 + dev->is_checkpointed = 0;
15614 + return dev->is_checkpointed;
15617 +static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
15619 + int ok = 1;
15621 + if (!dev->param.is_yaffs2)
15622 + ok = 0;
15624 + if (ok && dev->param.skip_checkpt_rd) {
15625 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15626 + "skipping checkpoint read");
15627 + ok = 0;
15630 + if (ok)
15631 + ok = yaffs2_checkpt_open(dev, 0); /* open for read */
15633 + if (ok) {
15634 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15635 + "read checkpoint validity");
15636 + ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
15638 + if (ok) {
15639 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15640 + "read checkpoint device");
15641 + ok = yaffs2_rd_checkpt_dev(dev);
15643 + if (ok) {
15644 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15645 + "read checkpoint objects");
15646 + ok = yaffs2_rd_checkpt_objs(dev);
15648 + if (ok) {
15649 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15650 + "read checkpoint validity");
15651 + ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
15654 + if (ok) {
15655 + ok = yaffs2_rd_checkpt_sum(dev);
15656 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15657 + "read checkpoint checksum %d", ok);
15660 + if (!yaffs_checkpt_close(dev))
15661 + ok = 0;
15663 + if (ok)
15664 + dev->is_checkpointed = 1;
15665 + else
15666 + dev->is_checkpointed = 0;
15668 + return ok ? 1 : 0;
15671 +void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
15673 + if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
15674 + dev->is_checkpointed = 0;
15675 + yaffs2_checkpt_invalidate_stream(dev);
15677 + if (dev->param.sb_dirty_fn)
15678 + dev->param.sb_dirty_fn(dev);
15681 +int yaffs_checkpoint_save(struct yaffs_dev *dev)
15683 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15684 + "save entry: is_checkpointed %d",
15685 + dev->is_checkpointed);
15687 + yaffs_verify_objects(dev);
15688 + yaffs_verify_blocks(dev);
15689 + yaffs_verify_free_chunks(dev);
15691 + if (!dev->is_checkpointed) {
15692 + yaffs2_checkpt_invalidate(dev);
15693 + yaffs2_wr_checkpt_data(dev);
15696 + yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT,
15697 + "save exit: is_checkpointed %d",
15698 + dev->is_checkpointed);
15700 + return dev->is_checkpointed;
15703 +int yaffs2_checkpt_restore(struct yaffs_dev *dev)
15705 + int retval;
15707 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15708 + "restore entry: is_checkpointed %d",
15709 + dev->is_checkpointed);
15711 + retval = yaffs2_rd_checkpt_data(dev);
15713 + if (dev->is_checkpointed) {
15714 + yaffs_verify_objects(dev);
15715 + yaffs_verify_blocks(dev);
15716 + yaffs_verify_free_chunks(dev);
15719 + yaffs_trace(YAFFS_TRACE_CHECKPOINT,
15720 + "restore exit: is_checkpointed %d",
15721 + dev->is_checkpointed);
15723 + return retval;
15726 +int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
15728 + /* if new_size > old_file_size.
15729 + * We're going to be writing a hole.
15730 + * If the hole is small then write zeros otherwise write a start
15731 + * of hole marker.
15732 + */
15733 + loff_t old_file_size;
15734 + loff_t increase;
15735 + int small_hole;
15736 + int result = YAFFS_OK;
15737 + struct yaffs_dev *dev = NULL;
15738 + u8 *local_buffer = NULL;
15739 + int small_increase_ok = 0;
15741 + if (!obj)
15742 + return YAFFS_FAIL;
15744 + if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
15745 + return YAFFS_FAIL;
15747 + dev = obj->my_dev;
15749 + /* Bail out if not yaffs2 mode */
15750 + if (!dev->param.is_yaffs2)
15751 + return YAFFS_OK;
15753 + old_file_size = obj->variant.file_variant.file_size;
15755 + if (new_size <= old_file_size)
15756 + return YAFFS_OK;
15758 + increase = new_size - old_file_size;
15760 + if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
15761 + yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
15762 + small_hole = 1;
15763 + else
15764 + small_hole = 0;
15766 + if (small_hole)
15767 + local_buffer = yaffs_get_temp_buffer(dev);
15769 + if (local_buffer) {
15770 + /* fill hole with zero bytes */
15771 + loff_t pos = old_file_size;
15772 + int this_write;
15773 + int written;
15774 + memset(local_buffer, 0, dev->data_bytes_per_chunk);
15775 + small_increase_ok = 1;
15777 + while (increase > 0 && small_increase_ok) {
15778 + this_write = increase;
15779 + if (this_write > dev->data_bytes_per_chunk)
15780 + this_write = dev->data_bytes_per_chunk;
15781 + written =
15782 + yaffs_do_file_wr(obj, local_buffer, pos, this_write,
15783 + 0);
15784 + if (written == this_write) {
15785 + pos += this_write;
15786 + increase -= this_write;
15787 + } else {
15788 + small_increase_ok = 0;
15792 + yaffs_release_temp_buffer(dev, local_buffer);
15794 + /* If out of space then reverse any chunks we've added */
15795 + if (!small_increase_ok)
15796 + yaffs_resize_file_down(obj, old_file_size);
15799 + if (!small_increase_ok &&
15800 + obj->parent &&
15801 + obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
15802 + obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
15803 + /* Write a hole start header with the old file size */
15804 + yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
15807 + return result;
15810 +struct yaffs_block_index {
15811 + int seq;
15812 + int block;
15815 +static int yaffs2_ybicmp(const void *a, const void *b)
15817 + int aseq = ((struct yaffs_block_index *)a)->seq;
15818 + int bseq = ((struct yaffs_block_index *)b)->seq;
15819 + int ablock = ((struct yaffs_block_index *)a)->block;
15820 + int bblock = ((struct yaffs_block_index *)b)->block;
15822 + if (aseq == bseq)
15823 + return ablock - bblock;
15825 + return aseq - bseq;
15828 +static inline int yaffs2_scan_chunk(struct yaffs_dev *dev,
15829 + struct yaffs_block_info *bi,
15830 + int blk, int chunk_in_block,
15831 + int *found_chunks,
15832 + u8 *chunk_data,
15833 + struct list_head *hard_list,
15834 + int summary_available)
15836 + struct yaffs_obj_hdr *oh;
15837 + struct yaffs_obj *in;
15838 + struct yaffs_obj *parent;
15839 + int equiv_id;
15840 + loff_t file_size;
15841 + int is_shrink;
15842 + int is_unlinked;
15843 + struct yaffs_ext_tags tags;
15844 + int result;
15845 + int alloc_failed = 0;
15846 + int chunk = blk * dev->param.chunks_per_block + chunk_in_block;
15847 + struct yaffs_file_var *file_var;
15848 + struct yaffs_hardlink_var *hl_var;
15849 + struct yaffs_symlink_var *sl_var;
15851 + if (summary_available) {
15852 + result = yaffs_summary_fetch(dev, &tags, chunk_in_block);
15853 + tags.seq_number = bi->seq_number;
15856 + if (!summary_available || tags.obj_id == 0) {
15857 + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags);
15858 + dev->tags_used++;
15859 + } else {
15860 + dev->summary_used++;
15863 + /* Let's have a good look at this chunk... */
15865 + if (!tags.chunk_used) {
15866 + /* An unassigned chunk in the block.
15867 + * If there are used chunks after this one, then
15868 + * it is a chunk that was skipped due to failing
15869 + * the erased check. Just skip it so that it can
15870 + * be deleted.
15871 + * But, more typically, We get here when this is
15872 + * an unallocated chunk and his means that
15873 + * either the block is empty or this is the one
15874 + * being allocated from
15875 + */
15877 + if (*found_chunks) {
15878 + /* This is a chunk that was skipped due
15879 + * to failing the erased check */
15880 + } else if (chunk_in_block == 0) {
15881 + /* We're looking at the first chunk in
15882 + * the block so the block is unused */
15883 + bi->block_state = YAFFS_BLOCK_STATE_EMPTY;
15884 + dev->n_erased_blocks++;
15885 + } else {
15886 + if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
15887 + bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) {
15888 + if (dev->seq_number == bi->seq_number) {
15889 + /* Allocating from this block*/
15890 + yaffs_trace(YAFFS_TRACE_SCAN,
15891 + " Allocating from %d %d",
15892 + blk, chunk_in_block);
15894 + bi->block_state =
15895 + YAFFS_BLOCK_STATE_ALLOCATING;
15896 + dev->alloc_block = blk;
15897 + dev->alloc_page = chunk_in_block;
15898 + dev->alloc_block_finder = blk;
15899 + } else {
15900 + /* This is a partially written block
15901 + * that is not the current
15902 + * allocation block.
15903 + */
15904 + yaffs_trace(YAFFS_TRACE_SCAN,
15905 + "Partially written block %d detected. gc will fix this.",
15906 + blk);
15911 + dev->n_free_chunks++;
15913 + } else if (tags.ecc_result ==
15914 + YAFFS_ECC_RESULT_UNFIXED) {
15915 + yaffs_trace(YAFFS_TRACE_SCAN,
15916 + " Unfixed ECC in chunk(%d:%d), chunk ignored",
15917 + blk, chunk_in_block);
15918 + dev->n_free_chunks++;
15919 + } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
15920 + tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
15921 + tags.obj_id == YAFFS_OBJECTID_SUMMARY ||
15922 + (tags.chunk_id > 0 &&
15923 + tags.n_bytes > dev->data_bytes_per_chunk) ||
15924 + tags.seq_number != bi->seq_number) {
15925 + yaffs_trace(YAFFS_TRACE_SCAN,
15926 + "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored",
15927 + blk, chunk_in_block, tags.obj_id,
15928 + tags.chunk_id, tags.n_bytes);
15929 + dev->n_free_chunks++;
15930 + } else if (tags.chunk_id > 0) {
15931 + /* chunk_id > 0 so it is a data chunk... */
15932 + loff_t endpos;
15933 + loff_t chunk_base = (tags.chunk_id - 1) *
15934 + dev->data_bytes_per_chunk;
15936 + *found_chunks = 1;
15938 + yaffs_set_chunk_bit(dev, blk, chunk_in_block);
15939 + bi->pages_in_use++;
15941 + in = yaffs_find_or_create_by_number(dev,
15942 + tags.obj_id,
15943 + YAFFS_OBJECT_TYPE_FILE);
15944 + if (!in)
15945 + /* Out of memory */
15946 + alloc_failed = 1;
15948 + if (in &&
15949 + in->variant_type == YAFFS_OBJECT_TYPE_FILE &&
15950 + chunk_base < in->variant.file_variant.shrink_size) {
15951 + /* This has not been invalidated by
15952 + * a resize */
15953 + if (!yaffs_put_chunk_in_file(in, tags.chunk_id,
15954 + chunk, -1))
15955 + alloc_failed = 1;
15957 + /* File size is calculated by looking at
15958 + * the data chunks if we have not
15959 + * seen an object header yet.
15960 + * Stop this practice once we find an
15961 + * object header.
15962 + */
15963 + endpos = chunk_base + tags.n_bytes;
15965 + if (!in->valid &&
15966 + in->variant.file_variant.scanned_size < endpos) {
15967 + in->variant.file_variant.
15968 + scanned_size = endpos;
15969 + in->variant.file_variant.
15970 + file_size = endpos;
15972 + } else if (in) {
15973 + /* This chunk has been invalidated by a
15974 + * resize, or a past file deletion
15975 + * so delete the chunk*/
15976 + yaffs_chunk_del(dev, chunk, 1, __LINE__);
15978 + } else {
15979 + /* chunk_id == 0, so it is an ObjectHeader.
15980 + * Thus, we read in the object header and make
15981 + * the object
15982 + */
15983 + *found_chunks = 1;
15985 + yaffs_set_chunk_bit(dev, blk, chunk_in_block);
15986 + bi->pages_in_use++;
15988 + oh = NULL;
15989 + in = NULL;
15991 + if (tags.extra_available) {
15992 + in = yaffs_find_or_create_by_number(dev,
15993 + tags.obj_id,
15994 + tags.extra_obj_type);
15995 + if (!in)
15996 + alloc_failed = 1;
15999 + if (!in ||
16000 + (!in->valid && dev->param.disable_lazy_load) ||
16001 + tags.extra_shadows ||
16002 + (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT ||
16003 + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
16005 + /* If we don't have valid info then we
16006 + * need to read the chunk
16007 + * TODO In future we can probably defer
16008 + * reading the chunk and living with
16009 + * invalid data until needed.
16010 + */
16012 + result = yaffs_rd_chunk_tags_nand(dev,
16013 + chunk,
16014 + chunk_data,
16015 + NULL);
16017 + oh = (struct yaffs_obj_hdr *)chunk_data;
16019 + if (dev->param.inband_tags) {
16020 + /* Fix up the header if they got
16021 + * corrupted by inband tags */
16022 + oh->shadows_obj =
16023 + oh->inband_shadowed_obj_id;
16024 + oh->is_shrink =
16025 + oh->inband_is_shrink;
16028 + if (!in) {
16029 + in = yaffs_find_or_create_by_number(dev,
16030 + tags.obj_id, oh->type);
16031 + if (!in)
16032 + alloc_failed = 1;
16036 + if (!in) {
16037 + /* TODO Hoosterman we have a problem! */
16038 + yaffs_trace(YAFFS_TRACE_ERROR,
16039 + "yaffs tragedy: Could not make object for object %d at chunk %d during scan",
16040 + tags.obj_id, chunk);
16041 + return YAFFS_FAIL;
16044 + if (in->valid) {
16045 + /* We have already filled this one.
16046 + * We have a duplicate that will be
16047 + * discarded, but we first have to suck
16048 + * out resize info if it is a file.
16049 + */
16050 + if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
16051 + ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) ||
16052 + (tags.extra_available &&
16053 + tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
16054 + )) {
16055 + loff_t this_size = (oh) ?
16056 + yaffs_oh_to_size(oh) :
16057 + tags.extra_file_size;
16058 + u32 parent_obj_id = (oh) ?
16059 + oh->parent_obj_id :
16060 + tags.extra_parent_id;
16062 + is_shrink = (oh) ?
16063 + oh->is_shrink :
16064 + tags.extra_is_shrink;
16066 + /* If it is deleted (unlinked
16067 + * at start also means deleted)
16068 + * we treat the file size as
16069 + * being zeroed at this point.
16070 + */
16071 + if (parent_obj_id == YAFFS_OBJECTID_DELETED ||
16072 + parent_obj_id == YAFFS_OBJECTID_UNLINKED) {
16073 + this_size = 0;
16074 + is_shrink = 1;
16077 + if (is_shrink &&
16078 + in->variant.file_variant.shrink_size >
16079 + this_size)
16080 + in->variant.file_variant.shrink_size =
16081 + this_size;
16083 + if (is_shrink)
16084 + bi->has_shrink_hdr = 1;
16086 + /* Use existing - destroy this one. */
16087 + yaffs_chunk_del(dev, chunk, 1, __LINE__);
16090 + if (!in->valid && in->variant_type !=
16091 + (oh ? oh->type : tags.extra_obj_type)) {
16092 + yaffs_trace(YAFFS_TRACE_ERROR,
16093 + "yaffs tragedy: Bad type, %d != %d, for object %d at chunk %d during scan",
16094 + oh ? oh->type : tags.extra_obj_type,
16095 + in->variant_type, tags.obj_id,
16096 + chunk);
16097 + in = yaffs_retype_obj(in, oh ? oh->type : tags.extra_obj_type);
16100 + if (!in->valid &&
16101 + (tags.obj_id == YAFFS_OBJECTID_ROOT ||
16102 + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) {
16103 + /* We only load some info, don't fiddle
16104 + * with directory structure */
16105 + in->valid = 1;
16107 + if (oh) {
16108 + in->yst_mode = oh->yst_mode;
16109 + yaffs_load_attribs(in, oh);
16110 + in->lazy_loaded = 0;
16111 + } else {
16112 + in->lazy_loaded = 1;
16114 + in->hdr_chunk = chunk;
16116 + } else if (!in->valid) {
16117 + /* we need to load this info */
16118 + in->valid = 1;
16119 + in->hdr_chunk = chunk;
16120 + if (oh) {
16121 + in->variant_type = oh->type;
16122 + in->yst_mode = oh->yst_mode;
16123 + yaffs_load_attribs(in, oh);
16125 + if (oh->shadows_obj > 0)
16126 + yaffs_handle_shadowed_obj(dev,
16127 + oh->shadows_obj, 1);
16129 + yaffs_set_obj_name_from_oh(in, oh);
16130 + parent = yaffs_find_or_create_by_number(dev,
16131 + oh->parent_obj_id,
16132 + YAFFS_OBJECT_TYPE_DIRECTORY);
16133 + file_size = yaffs_oh_to_size(oh);
16134 + is_shrink = oh->is_shrink;
16135 + equiv_id = oh->equiv_id;
16136 + } else {
16137 + in->variant_type = tags.extra_obj_type;
16138 + parent = yaffs_find_or_create_by_number(dev,
16139 + tags.extra_parent_id,
16140 + YAFFS_OBJECT_TYPE_DIRECTORY);
16141 + file_size = tags.extra_file_size;
16142 + is_shrink = tags.extra_is_shrink;
16143 + equiv_id = tags.extra_equiv_id;
16144 + in->lazy_loaded = 1;
16146 + in->dirty = 0;
16148 + if (!parent)
16149 + alloc_failed = 1;
16151 + /* directory stuff...
16152 + * hook up to parent
16153 + */
16155 + if (parent &&
16156 + parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) {
16157 + /* Set up as a directory */
16158 + parent->variant_type =
16159 + YAFFS_OBJECT_TYPE_DIRECTORY;
16160 + INIT_LIST_HEAD(&parent->
16161 + variant.dir_variant.children);
16162 + } else if (!parent ||
16163 + parent->variant_type !=
16164 + YAFFS_OBJECT_TYPE_DIRECTORY) {
16165 + /* Hoosterman, another problem....
16166 + * Trying to use a non-directory as a directory
16167 + */
16169 + yaffs_trace(YAFFS_TRACE_ERROR,
16170 + "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
16171 + );
16172 + parent = dev->lost_n_found;
16174 + yaffs_add_obj_to_dir(parent, in);
16176 + is_unlinked = (parent == dev->del_dir) ||
16177 + (parent == dev->unlinked_dir);
16179 + if (is_shrink)
16180 + /* Mark the block */
16181 + bi->has_shrink_hdr = 1;
16183 + /* Note re hardlinks.
16184 + * Since we might scan a hardlink before its equivalent
16185 + * object is scanned we put them all in a list.
16186 + * After scanning is complete, we should have all the
16187 + * objects, so we run through this list and fix up all
16188 + * the chains.
16189 + */
16191 + switch (in->variant_type) {
16192 + case YAFFS_OBJECT_TYPE_UNKNOWN:
16193 + /* Todo got a problem */
16194 + break;
16195 + case YAFFS_OBJECT_TYPE_FILE:
16196 + file_var = &in->variant.file_variant;
16197 + if (file_var->scanned_size < file_size) {
16198 + /* This covers the case where the file
16199 + * size is greater than the data held.
16200 + * This will happen if the file is
16201 + * resized to be larger than its
16202 + * current data extents.
16203 + */
16204 + file_var->file_size = file_size;
16205 + file_var->scanned_size = file_size;
16208 + if (file_var->shrink_size > file_size)
16209 + file_var->shrink_size = file_size;
16211 + break;
16212 + case YAFFS_OBJECT_TYPE_HARDLINK:
16213 + hl_var = &in->variant.hardlink_variant;
16214 + if (!is_unlinked) {
16215 + hl_var->equiv_id = equiv_id;
16216 + list_add(&in->hard_links, hard_list);
16218 + break;
16219 + case YAFFS_OBJECT_TYPE_DIRECTORY:
16220 + /* Do nothing */
16221 + break;
16222 + case YAFFS_OBJECT_TYPE_SPECIAL:
16223 + /* Do nothing */
16224 + break;
16225 + case YAFFS_OBJECT_TYPE_SYMLINK:
16226 + sl_var = &in->variant.symlink_variant;
16227 + if (oh) {
16228 + sl_var->alias =
16229 + yaffs_clone_str(oh->alias);
16230 + if (!sl_var->alias)
16231 + alloc_failed = 1;
16233 + break;
16237 + return alloc_failed ? YAFFS_FAIL : YAFFS_OK;
16240 +int yaffs2_scan_backwards(struct yaffs_dev *dev)
16242 + int blk;
16243 + int block_iter;
16244 + int start_iter;
16245 + int end_iter;
16246 + int n_to_scan = 0;
16247 + enum yaffs_block_state state;
16248 + int c;
16249 + LIST_HEAD(hard_list);
16250 + struct yaffs_block_info *bi;
16251 + u32 seq_number;
16252 + int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
16253 + u8 *chunk_data;
16254 + int found_chunks;
16255 + int alloc_failed = 0;
16256 + struct yaffs_block_index *block_index = NULL;
16257 + int alt_block_index = 0;
16258 + int summary_available;
16260 + yaffs_trace(YAFFS_TRACE_SCAN,
16261 + "yaffs2_scan_backwards starts intstartblk %d intendblk %d...",
16262 + dev->internal_start_block, dev->internal_end_block);
16264 + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
16266 + block_index =
16267 + kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS);
16269 + if (!block_index) {
16270 + block_index =
16271 + vmalloc(n_blocks * sizeof(struct yaffs_block_index));
16272 + alt_block_index = 1;
16275 + if (!block_index) {
16276 + yaffs_trace(YAFFS_TRACE_SCAN,
16277 + "yaffs2_scan_backwards() could not allocate block index!"
16278 + );
16279 + return YAFFS_FAIL;
16282 + dev->blocks_in_checkpt = 0;
16284 + chunk_data = yaffs_get_temp_buffer(dev);
16286 + /* Scan all the blocks to determine their state */
16287 + bi = dev->block_info;
16288 + for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
16289 + blk++) {
16290 + yaffs_clear_chunk_bits(dev, blk);
16291 + bi->pages_in_use = 0;
16292 + bi->soft_del_pages = 0;
16294 + yaffs_query_init_block_state(dev, blk, &state, &seq_number);
16296 + bi->block_state = state;
16297 + bi->seq_number = seq_number;
16299 + if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
16300 + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT;
16301 + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
16302 + bi->block_state = YAFFS_BLOCK_STATE_DEAD;
16304 + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG,
16305 + "Block scanning block %d state %d seq %d",
16306 + blk, bi->block_state, seq_number);
16308 + if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) {
16309 + dev->blocks_in_checkpt++;
16311 + } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) {
16312 + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
16313 + "block %d is bad", blk);
16314 + } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) {
16315 + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty ");
16316 + dev->n_erased_blocks++;
16317 + dev->n_free_chunks += dev->param.chunks_per_block;
16318 + } else if (bi->block_state ==
16319 + YAFFS_BLOCK_STATE_NEEDS_SCAN) {
16320 + /* Determine the highest sequence number */
16321 + if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
16322 + seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
16323 + block_index[n_to_scan].seq = seq_number;
16324 + block_index[n_to_scan].block = blk;
16325 + n_to_scan++;
16326 + if (seq_number >= dev->seq_number)
16327 + dev->seq_number = seq_number;
16328 + } else {
16329 + /* TODO: Nasty sequence number! */
16330 + yaffs_trace(YAFFS_TRACE_SCAN,
16331 + "Block scanning block %d has bad sequence number %d",
16332 + blk, seq_number);
16335 + bi++;
16338 + yaffs_trace(YAFFS_TRACE_ALWAYS, "%d blocks to be sorted...", n_to_scan);
16340 + cond_resched();
16342 + /* Sort the blocks by sequence number */
16343 + sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
16344 + yaffs2_ybicmp, NULL);
16346 + cond_resched();
16348 + yaffs_trace(YAFFS_TRACE_SCAN, "...done");
16350 + /* Now scan the blocks looking at the data. */
16351 + start_iter = 0;
16352 + end_iter = n_to_scan - 1;
16353 + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan);
16355 + /* For each block.... backwards */
16356 + for (block_iter = end_iter;
16357 + !alloc_failed && block_iter >= start_iter;
16358 + block_iter--) {
16359 + /* Cooperative multitasking! This loop can run for so
16360 + long that watchdog timers expire. */
16361 + cond_resched();
16363 + /* get the block to scan in the correct order */
16364 + blk = block_index[block_iter].block;
16365 + bi = yaffs_get_block_info(dev, blk);
16367 + summary_available = yaffs_summary_read(dev, dev->sum_tags, blk);
16369 + /* For each chunk in each block that needs scanning.... */
16370 + found_chunks = 0;
16371 + if (summary_available)
16372 + c = dev->chunks_per_summary - 1;
16373 + else
16374 + c = dev->param.chunks_per_block - 1;
16376 + for (/* c is already initialised */;
16377 + !alloc_failed && c >= 0 &&
16378 + (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN ||
16379 + bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING);
16380 + c--) {
16381 + /* Scan backwards...
16382 + * Read the tags and decide what to do
16383 + */
16384 + if (yaffs2_scan_chunk(dev, bi, blk, c,
16385 + &found_chunks, chunk_data,
16386 + &hard_list, summary_available) ==
16387 + YAFFS_FAIL)
16388 + alloc_failed = 1;
16391 + if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) {
16392 + /* If we got this far while scanning, then the block
16393 + * is fully allocated. */
16394 + bi->block_state = YAFFS_BLOCK_STATE_FULL;
16397 + /* Now let's see if it was dirty */
16398 + if (bi->pages_in_use == 0 &&
16399 + !bi->has_shrink_hdr &&
16400 + bi->block_state == YAFFS_BLOCK_STATE_FULL) {
16401 + yaffs_block_became_dirty(dev, blk);
16405 + yaffs_skip_rest_of_block(dev);
16407 + if (alt_block_index)
16408 + vfree(block_index);
16409 + else
16410 + kfree(block_index);
16412 + /* Ok, we've done all the scanning.
16413 + * Fix up the hard link chains.
16414 + * We have scanned all the objects, now it's time to add these
16415 + * hardlinks.
16416 + */
16417 + yaffs_link_fixup(dev, &hard_list);
16419 + yaffs_release_temp_buffer(dev, chunk_data);
16421 + if (alloc_failed)
16422 + return YAFFS_FAIL;
16424 + yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends");
16426 + return YAFFS_OK;
16428 diff -Nur linux-3.18.14.orig/fs/yaffs2/yaffs_yaffs2.h linux-3.18.14/fs/yaffs2/yaffs_yaffs2.h
16429 --- linux-3.18.14.orig/fs/yaffs2/yaffs_yaffs2.h 1970-01-01 01:00:00.000000000 +0100
16430 +++ linux-3.18.14/fs/yaffs2/yaffs_yaffs2.h 2015-06-14 21:23:22.000000000 +0200
16431 @@ -0,0 +1,39 @@
16433 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16435 + * Copyright (C) 2002-2011 Aleph One Ltd.
16436 + * for Toby Churchill Ltd and Brightstar Engineering
16438 + * Created by Charles Manning <charles@aleph1.co.uk>
16440 + * This program is free software; you can redistribute it and/or modify
16441 + * it under the terms of the GNU Lesser General Public License version 2.1 as
16442 + * published by the Free Software Foundation.
16444 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
16445 + */
16447 +#ifndef __YAFFS_YAFFS2_H__
16448 +#define __YAFFS_YAFFS2_H__
16450 +#include "yaffs_guts.h"
16452 +void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev);
16453 +void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev);
16454 +void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
16455 + struct yaffs_block_info *bi);
16456 +void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
16457 + struct yaffs_block_info *bi);
16458 +int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi);
16459 +u32 yaffs2_find_refresh_block(struct yaffs_dev *dev);
16460 +int yaffs2_checkpt_required(struct yaffs_dev *dev);
16461 +int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev);
16463 +void yaffs2_checkpt_invalidate(struct yaffs_dev *dev);
16464 +int yaffs2_checkpt_save(struct yaffs_dev *dev);
16465 +int yaffs2_checkpt_restore(struct yaffs_dev *dev);
16467 +int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size);
16468 +int yaffs2_scan_backwards(struct yaffs_dev *dev);
16470 +#endif
16471 diff -Nur linux-3.18.14.orig/fs/yaffs2/yportenv.h linux-3.18.14/fs/yaffs2/yportenv.h
16472 --- linux-3.18.14.orig/fs/yaffs2/yportenv.h 1970-01-01 01:00:00.000000000 +0100
16473 +++ linux-3.18.14/fs/yaffs2/yportenv.h 2015-06-14 21:23:22.000000000 +0200
16474 @@ -0,0 +1,85 @@
16476 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
16478 + * Copyright (C) 2002-2011 Aleph One Ltd.
16479 + * for Toby Churchill Ltd and Brightstar Engineering
16481 + * Created by Charles Manning <charles@aleph1.co.uk>
16483 + * This program is free software; you can redistribute it and/or modify
16484 + * it under the terms of the GNU Lesser General Public License version 2.1 as
16485 + * published by the Free Software Foundation.
16487 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
16488 + */
16490 +#ifndef __YPORTENV_H__
16491 +#define __YPORTENV_H__
16494 + * Define the MTD version in terms of Linux Kernel versions
16495 + * This allows yaffs to be used independantly of the kernel
16496 + * as well as with it.
16497 + */
16499 +#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
16501 +#ifdef YAFFS_OUT_OF_TREE
16502 +#include "moduleconfig.h"
16503 +#endif
16505 +#include <linux/version.h>
16506 +#define MTD_VERSION_CODE LINUX_VERSION_CODE
16508 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
16509 +#include <linux/config.h>
16510 +#endif
16511 +#include <linux/version.h>
16512 +#include <linux/kernel.h>
16513 +#include <linux/mm.h>
16514 +#include <linux/sched.h>
16515 +#include <linux/string.h>
16516 +#include <linux/slab.h>
16517 +#include <linux/vmalloc.h>
16518 +#include <linux/xattr.h>
16519 +#include <linux/list.h>
16520 +#include <linux/types.h>
16521 +#include <linux/fs.h>
16522 +#include <linux/stat.h>
16523 +#include <linux/sort.h>
16524 +#include <linux/bitops.h>
16526 +/* These type wrappings are used to support Unicode names in WinCE. */
16527 +#define YCHAR char
16528 +#define YUCHAR unsigned char
16529 +#define _Y(x) x
16531 +#define YAFFS_LOSTNFOUND_NAME "lost+found"
16532 +#define YAFFS_LOSTNFOUND_PREFIX "obj"
16535 +#define YAFFS_ROOT_MODE 0755
16536 +#define YAFFS_LOSTNFOUND_MODE 0700
16538 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
16539 +#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
16540 +#define Y_TIME_CONVERT(x) (x).tv_sec
16541 +#else
16542 +#define Y_CURRENT_TIME CURRENT_TIME
16543 +#define Y_TIME_CONVERT(x) (x)
16544 +#endif
16546 +#define compile_time_assertion(assertion) \
16547 + ({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
16550 +#define yaffs_printf(msk, fmt, ...) \
16551 + printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__)
16553 +#define yaffs_trace(msk, fmt, ...) do { \
16554 + if (yaffs_trace_mask & (msk)) \
16555 + printk(KERN_DEBUG "yaffs: " fmt "\n", ##__VA_ARGS__); \
16556 +} while (0)
16559 +#endif