add generic 2.6.23 patches and config
[openwrt/svn-archive/archive.git] / target / linux / generic-2.6 / patches-2.6.23 / 510-Yaffs.patch
1 Index: linux-2.6.23-rc6/fs/Kconfig
2 ===================================================================
3 --- linux-2.6.23-rc6.orig/fs/Kconfig 2007-09-21 16:24:06.000000000 +0800
4 +++ linux-2.6.23-rc6/fs/Kconfig 2007-09-21 16:24:08.000000000 +0800
5 @@ -419,6 +419,7 @@
6
7 source "fs/xfs/Kconfig"
8 source "fs/gfs2/Kconfig"
9 +source "fs/yaffs2/Kconfig"
10
11 config OCFS2_FS
12 tristate "OCFS2 file system support"
13 Index: linux-2.6.23-rc6/fs/Makefile
14 ===================================================================
15 --- linux-2.6.23-rc6.orig/fs/Makefile 2007-09-21 16:24:06.000000000 +0800
16 +++ linux-2.6.23-rc6/fs/Makefile 2007-09-21 16:24:08.000000000 +0800
17 @@ -120,3 +120,4 @@
18 obj-$(CONFIG_DEBUG_FS) += debugfs/
19 obj-$(CONFIG_OCFS2_FS) += ocfs2/
20 obj-$(CONFIG_GFS2_FS) += gfs2/
21 +obj-$(CONFIG_YAFFS_FS) += yaffs2/
22 Index: linux-2.6.23-rc6/fs/yaffs2/Kconfig
23 ===================================================================
24 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
25 +++ linux-2.6.23-rc6/fs/yaffs2/Kconfig 2007-09-21 16:24:08.000000000 +0800
26 @@ -0,0 +1,175 @@
27 +#
28 +# YAFFS file system configurations
29 +#
30 +
31 +config YAFFS_FS
32 + tristate "YAFFS2 file system support"
33 + default n
34 + depends on MTD
35 + select YAFFS_YAFFS1
36 + select YAFFS_YAFFS2
37 + help
38 + YAFFS2, or Yet Another Flash Filing System, is a filing system
39 + optimised for NAND Flash chips.
40 +
41 + To compile the YAFFS2 file system support as a module, choose M
42 + here: the module will be called yaffs2.
43 +
44 + If unsure, say N.
45 +
46 + Further information on YAFFS2 is available at
47 + <http://www.aleph1.co.uk/yaffs/>.
48 +
49 +config YAFFS_YAFFS1
50 + bool "512 byte / page devices"
51 + depends on YAFFS_FS
52 + default y
53 + help
54 + Enable YAFFS1 support -- yaffs for 512 byte / page devices
55 +
56 + Not needed for 2K-page devices.
57 +
58 + If unsure, say Y.
59 +
60 +config YAFFS_9BYTE_TAGS
61 + bool "Use older-style on-NAND data format with pageStatus byte"
62 + depends on YAFFS_YAFFS1
63 + default n
64 + help
65 +
66 + Older-style on-NAND data format has a "pageStatus" byte to record
67 + chunk/page state. This byte is zero when the page is discarded.
68 + Choose this option if you have existing on-NAND data using this
69 + format that you need to continue to support. New data written
70 + also uses the older-style format. Note: Use of this option
71 + generally requires that MTD's oob layout be adjusted to use the
72 + older-style format. See notes on tags formats and MTD versions.
73 +
74 + If unsure, say N.
75 +
76 +config YAFFS_DOES_ECC
77 + bool "Lets Yaffs do its own ECC"
78 + depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
79 + default n
80 + help
81 + This enables Yaffs to use its own ECC functions instead of using
82 + the ones from the generic MTD-NAND driver.
83 +
84 + If unsure, say N.
85 +
86 +config YAFFS_ECC_WRONG_ORDER
87 + bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
88 + depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
89 + default n
90 + help
91 + This makes yaffs_ecc.c use the same ecc byte order as Steven
92 + Hill's nand_ecc.c. If not set, then you get the same ecc byte
93 + order as SmartMedia.
94 +
95 + If unsure, say N.
96 +
97 +config YAFFS_YAFFS2
98 + bool "2048 byte (or larger) / page devices"
99 + depends on YAFFS_FS
100 + default y
101 + help
102 + Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
103 +
104 + If unsure, say Y.
105 +
106 +config YAFFS_AUTO_YAFFS2
107 + bool "Autoselect yaffs2 format"
108 + depends on YAFFS_YAFFS2
109 + default y
110 + help
111 + Without this, you need to explicitely use yaffs2 as the file
112 + system type. With this, you can say "yaffs" and yaffs or yaffs2
113 + will be used depending on the device page size (yaffs on
114 + 512-byte page devices, yaffs2 on 2K page devices).
115 +
116 + If unsure, say Y.
117 +
118 +config YAFFS_DISABLE_LAZY_LOAD
119 + bool "Disable lazy loading"
120 + depends on YAFFS_YAFFS2
121 + default n
122 + help
123 + "Lazy loading" defers loading file details until they are
124 + required. This saves mount time, but makes the first look-up
125 + a bit longer.
126 +
127 + Lazy loading will only happen if enabled by this option being 'n'
128 + and if the appropriate tags are available, else yaffs2 will
129 + automatically fall back to immediate loading and do the right
130 + thing.
131 +
132 + Lazy laoding will be required by checkpointing.
133 +
134 + Setting this to 'y' will disable lazy loading.
135 +
136 + If unsure, say N.
137 +
138 +config YAFFS_CHECKPOINT_RESERVED_BLOCKS
139 + int "Reserved blocks for checkpointing"
140 + depends on YAFFS_YAFFS2
141 + default 10
142 + help
143 + Give the number of Blocks to reserve for checkpointing.
144 + Checkpointing saves the state at unmount so that mounting is
145 + much faster as a scan of all the flash to regenerate this state
146 + is not needed. These Blocks are reserved per partition, so if
147 + you have very small partitions the default (10) may be a mess
148 + for you. You can set this value to 0, but that does not mean
149 + checkpointing is disabled at all. There only won't be any
150 + specially reserved blocks for checkpointing, so if there is
151 + enough free space on the filesystem, it will be used for
152 + checkpointing.
153 +
154 + If unsure, leave at default (10), but don't wonder if there are
155 + always 2MB used on your large page device partition (10 x 2k
156 + pagesize). When using small partitions or when being very small
157 + on space, you probably want to set this to zero.
158 +
159 +config YAFFS_DISABLE_WIDE_TNODES
160 + bool "Turn off wide tnodes"
161 + depends on YAFFS_FS
162 + default n
163 + help
164 + Wide tnodes are only used for NAND arrays >=32MB for 512-byte
165 + page devices and >=128MB for 2k page devices. They use slightly
166 + more RAM but are faster since they eliminate chunk group
167 + searching.
168 +
169 + Setting this to 'y' will force tnode width to 16 bits and save
170 + memory but make large arrays slower.
171 +
172 + If unsure, say N.
173 +
174 +config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
175 + bool "Force chunk erase check"
176 + depends on YAFFS_FS
177 + default n
178 + help
179 + Normally YAFFS only checks chunks before writing until an erased
180 + chunk is found. This helps to detect any partially written
181 + chunks that might have happened due to power loss.
182 +
183 + Enabling this forces on the test that chunks are erased in flash
184 + before writing to them. This takes more time but is potentially
185 + a bit more secure.
186 +
187 + Suggest setting Y during development and ironing out driver
188 + issues etc. Suggest setting to N if you want faster writing.
189 +
190 + If unsure, say Y.
191 +
192 +config YAFFS_SHORT_NAMES_IN_RAM
193 + bool "Cache short names in RAM"
194 + depends on YAFFS_FS
195 + default y
196 + help
197 + If this config is set, then short names are stored with the
198 + yaffs_Object. This costs an extra 16 bytes of RAM per object,
199 + but makes look-ups faster.
200 +
201 + If unsure, say Y.
202 Index: linux-2.6.23-rc6/fs/yaffs2/Makefile
203 ===================================================================
204 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
205 +++ linux-2.6.23-rc6/fs/yaffs2/Makefile 2007-09-21 16:24:08.000000000 +0800
206 @@ -0,0 +1,11 @@
207 +#
208 +# Makefile for the linux YAFFS filesystem routines.
209 +#
210 +
211 +obj-$(CONFIG_YAFFS_FS) += yaffs.o
212 +
213 +yaffs-y := yaffs_ecc.o yaffs_fs.o yaffs_guts.o yaffs_checkptrw.o
214 +yaffs-y += yaffs_packedtags2.o yaffs_nand.o yaffs_qsort.o
215 +yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
216 +yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o
217 +yaffs-y += yaffs_mtdif.o yaffs_mtdif2.o
218 Index: linux-2.6.23-rc6/fs/yaffs2/devextras.h
219 ===================================================================
220 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
221 +++ linux-2.6.23-rc6/fs/yaffs2/devextras.h 2007-09-21 16:24:08.000000000 +0800
222 @@ -0,0 +1,264 @@
223 +/*
224 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
225 + *
226 + * Copyright (C) 2002-2007 Aleph One Ltd.
227 + * for Toby Churchill Ltd and Brightstar Engineering
228 + *
229 + * Created by Charles Manning <charles@aleph1.co.uk>
230 + *
231 + * This program is free software; you can redistribute it and/or modify
232 + * it under the terms of the GNU Lesser General Public License version 2.1 as
233 + * published by the Free Software Foundation.
234 + *
235 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
236 + */
237 +
238 +/*
239 + * This file is just holds extra declarations used during development.
240 + * Most of these are from kernel includes placed here so we can use them in
241 + * applications.
242 + *
243 + */
244 +
245 +#ifndef __EXTRAS_H__
246 +#define __EXTRAS_H__
247 +
248 +#if defined WIN32
249 +#define __inline__ __inline
250 +#define new newHack
251 +#endif
252 +
253 +#if !(defined __KERNEL__) || (defined WIN32)
254 +
255 +/* User space defines */
256 +
257 +typedef unsigned char __u8;
258 +typedef unsigned short __u16;
259 +typedef unsigned __u32;
260 +
261 +/*
262 + * Simple doubly linked list implementation.
263 + *
264 + * Some of the internal functions ("__xxx") are useful when
265 + * manipulating whole lists rather than single entries, as
266 + * sometimes we already know the next/prev entries and we can
267 + * generate better code by using them directly rather than
268 + * using the generic single-entry routines.
269 + */
270 +
271 +#define prefetch(x) 1
272 +
273 +struct list_head {
274 + struct list_head *next, *prev;
275 +};
276 +
277 +#define LIST_HEAD_INIT(name) { &(name), &(name) }
278 +
279 +#define LIST_HEAD(name) \
280 + struct list_head name = LIST_HEAD_INIT(name)
281 +
282 +#define INIT_LIST_HEAD(ptr) do { \
283 + (ptr)->next = (ptr); (ptr)->prev = (ptr); \
284 +} while (0)
285 +
286 +/*
287 + * Insert a new entry between two known consecutive entries.
288 + *
289 + * This is only for internal list manipulation where we know
290 + * the prev/next entries already!
291 + */
292 +static __inline__ void __list_add(struct list_head *new,
293 + struct list_head *prev,
294 + struct list_head *next)
295 +{
296 + next->prev = new;
297 + new->next = next;
298 + new->prev = prev;
299 + prev->next = new;
300 +}
301 +
302 +/**
303 + * list_add - add a new entry
304 + * @new: new entry to be added
305 + * @head: list head to add it after
306 + *
307 + * Insert a new entry after the specified head.
308 + * This is good for implementing stacks.
309 + */
310 +static __inline__ void list_add(struct list_head *new, struct list_head *head)
311 +{
312 + __list_add(new, head, head->next);
313 +}
314 +
315 +/**
316 + * list_add_tail - add a new entry
317 + * @new: new entry to be added
318 + * @head: list head to add it before
319 + *
320 + * Insert a new entry before the specified head.
321 + * This is useful for implementing queues.
322 + */
323 +static __inline__ void list_add_tail(struct list_head *new,
324 + struct list_head *head)
325 +{
326 + __list_add(new, head->prev, head);
327 +}
328 +
329 +/*
330 + * Delete a list entry by making the prev/next entries
331 + * point to each other.
332 + *
333 + * This is only for internal list manipulation where we know
334 + * the prev/next entries already!
335 + */
336 +static __inline__ void __list_del(struct list_head *prev,
337 + struct list_head *next)
338 +{
339 + next->prev = prev;
340 + prev->next = next;
341 +}
342 +
343 +/**
344 + * list_del - deletes entry from list.
345 + * @entry: the element to delete from the list.
346 + * Note: list_empty on entry does not return true after this, the entry is
347 + * in an undefined state.
348 + */
349 +static __inline__ void list_del(struct list_head *entry)
350 +{
351 + __list_del(entry->prev, entry->next);
352 +}
353 +
354 +/**
355 + * list_del_init - deletes entry from list and reinitialize it.
356 + * @entry: the element to delete from the list.
357 + */
358 +static __inline__ void list_del_init(struct list_head *entry)
359 +{
360 + __list_del(entry->prev, entry->next);
361 + INIT_LIST_HEAD(entry);
362 +}
363 +
364 +/**
365 + * list_empty - tests whether a list is empty
366 + * @head: the list to test.
367 + */
368 +static __inline__ int list_empty(struct list_head *head)
369 +{
370 + return head->next == head;
371 +}
372 +
373 +/**
374 + * list_splice - join two lists
375 + * @list: the new list to add.
376 + * @head: the place to add it in the first list.
377 + */
378 +static __inline__ void list_splice(struct list_head *list,
379 + struct list_head *head)
380 +{
381 + struct list_head *first = list->next;
382 +
383 + if (first != list) {
384 + struct list_head *last = list->prev;
385 + struct list_head *at = head->next;
386 +
387 + first->prev = head;
388 + head->next = first;
389 +
390 + last->next = at;
391 + at->prev = last;
392 + }
393 +}
394 +
395 +/**
396 + * list_entry - get the struct for this entry
397 + * @ptr: the &struct list_head pointer.
398 + * @type: the type of the struct this is embedded in.
399 + * @member: the name of the list_struct within the struct.
400 + */
401 +#define list_entry(ptr, type, member) \
402 + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
403 +
404 +/**
405 + * list_for_each - iterate over a list
406 + * @pos: the &struct list_head to use as a loop counter.
407 + * @head: the head for your list.
408 + */
409 +#define list_for_each(pos, head) \
410 + for (pos = (head)->next, prefetch(pos->next); pos != (head); \
411 + pos = pos->next, prefetch(pos->next))
412 +
413 +/**
414 + * list_for_each_safe - iterate over a list safe against removal
415 + * of list entry
416 + * @pos: the &struct list_head to use as a loop counter.
417 + * @n: another &struct list_head to use as temporary storage
418 + * @head: the head for your list.
419 + */
420 +#define list_for_each_safe(pos, n, head) \
421 + for (pos = (head)->next, n = pos->next; pos != (head); \
422 + pos = n, n = pos->next)
423 +
424 +/*
425 + * File types
426 + */
427 +#define DT_UNKNOWN 0
428 +#define DT_FIFO 1
429 +#define DT_CHR 2
430 +#define DT_DIR 4
431 +#define DT_BLK 6
432 +#define DT_REG 8
433 +#define DT_LNK 10
434 +#define DT_SOCK 12
435 +#define DT_WHT 14
436 +
437 +#ifndef WIN32
438 +#include <sys/stat.h>
439 +#endif
440 +
441 +/*
442 + * Attribute flags. These should be or-ed together to figure out what
443 + * has been changed!
444 + */
445 +#define ATTR_MODE 1
446 +#define ATTR_UID 2
447 +#define ATTR_GID 4
448 +#define ATTR_SIZE 8
449 +#define ATTR_ATIME 16
450 +#define ATTR_MTIME 32
451 +#define ATTR_CTIME 64
452 +#define ATTR_ATIME_SET 128
453 +#define ATTR_MTIME_SET 256
454 +#define ATTR_FORCE 512 /* Not a change, but a change it */
455 +#define ATTR_ATTR_FLAG 1024
456 +
457 +struct iattr {
458 + unsigned int ia_valid;
459 + unsigned ia_mode;
460 + unsigned ia_uid;
461 + unsigned ia_gid;
462 + unsigned ia_size;
463 + unsigned ia_atime;
464 + unsigned ia_mtime;
465 + unsigned ia_ctime;
466 + unsigned int ia_attr_flags;
467 +};
468 +
469 +#define KERN_DEBUG
470 +
471 +#else
472 +
473 +#ifndef WIN32
474 +#include <linux/types.h>
475 +#include <linux/list.h>
476 +#include <linux/fs.h>
477 +#include <linux/stat.h>
478 +#endif
479 +
480 +#endif
481 +
482 +#if defined WIN32
483 +#undef new
484 +#endif
485 +
486 +#endif
487 Index: linux-2.6.23-rc6/fs/yaffs2/moduleconfig.h
488 ===================================================================
489 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
490 +++ linux-2.6.23-rc6/fs/yaffs2/moduleconfig.h 2007-09-21 16:24:08.000000000 +0800
491 @@ -0,0 +1,65 @@
492 +/*
493 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
494 + *
495 + * Copyright (C) 2002-2007 Aleph One Ltd.
496 + * for Toby Churchill Ltd and Brightstar Engineering
497 + *
498 + * Created by Martin Fouts <Martin.Fouts@palmsource.com>
499 + *
500 + * This program is free software; you can redistribute it and/or modify
501 + * it under the terms of the GNU Lesser General Public License version 2.1 as
502 + * published by the Free Software Foundation.
503 + *
504 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
505 + */
506 +
507 +#ifndef __YAFFS_CONFIG_H__
508 +#define __YAFFS_CONFIG_H__
509 +
510 +#ifdef YAFFS_OUT_OF_TREE
511 +
512 +/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */
513 +#define CONFIG_YAFFS_FS
514 +#define CONFIG_YAFFS_YAFFS1
515 +#define CONFIG_YAFFS_YAFFS2
516 +
517 +/* These options are independent of each other. Select those that matter. */
518 +
519 +/* Default: Not selected */
520 +/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
521 +//#define CONFIG_YAFFS_DOES_ECC
522 +
523 +/* Default: Not selected */
524 +/* Meaning: ECC byte order is 'wrong'. Only meaningful if */
525 +/* CONFIG_YAFFS_DOES_ECC is set */
526 +//#define CONFIG_YAFFS_ECC_WRONG_ORDER
527 +
528 +/* Default: Selected */
529 +/* Meaning: Disables testing whether chunks are erased before writing to them*/
530 +#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
531 +
532 +/* Default: Selected */
533 +/* Meaning: Cache short names, taking more RAM, but faster look-ups */
534 +#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
535 +
536 +/* Default: 10 */
537 +/* Meaning: set the count of blocks to reserve for checkpointing */
538 +#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
539 +
540 +/*
541 +Older-style on-NAND data format has a "pageStatus" byte to record
542 +chunk/page state. This byte is zeroed when the page is discarded.
543 +Choose this option if you have existing on-NAND data in this format
544 +that you need to continue to support. New data written also uses the
545 +older-style format.
546 +Note: Use of this option generally requires that MTD's oob layout be
547 +adjusted to use the older-style format. See notes on tags formats and
548 +MTD versions.
549 +*/
550 +/* Default: Not selected */
551 +/* Meaning: Use older-style on-NAND data format with pageStatus byte */
552 +#define CONFIG_YAFFS_9BYTE_TAGS
553 +
554 +#endif /* YAFFS_OUT_OF_TREE */
555 +
556 +#endif /* __YAFFS_CONFIG_H__ */
557 Index: linux-2.6.23-rc6/fs/yaffs2/yaffs_checkptrw.c
558 ===================================================================
559 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
560 +++ linux-2.6.23-rc6/fs/yaffs2/yaffs_checkptrw.c 2007-09-21 16:24:08.000000000 +0800
561 @@ -0,0 +1,404 @@
562 +/*
563 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
564 + *
565 + * Copyright (C) 2002-2007 Aleph One Ltd.
566 + * for Toby Churchill Ltd and Brightstar Engineering
567 + *
568 + * Created by Charles Manning <charles@aleph1.co.uk>
569 + *
570 + * This program is free software; you can redistribute it and/or modify
571 + * it under the terms of the GNU General Public License version 2 as
572 + * published by the Free Software Foundation.
573 + */
574 +
575 +const char *yaffs_checkptrw_c_version =
576 + "$Id: yaffs_checkptrw.c,v 1.14 2007-05-15 20:07:40 charles Exp $";
577 +
578 +
579 +#include "yaffs_checkptrw.h"
580 +
581 +
582 +static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
583 +{
584 +
585 + int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
586 +
587 + T(YAFFS_TRACE_CHECKPOINT,
588 + (TSTR("checkpt blocks available = %d" TENDSTR),
589 + blocksAvailable));
590 +
591 +
592 + return (blocksAvailable <= 0) ? 0 : 1;
593 +}
594 +
595 +
596 +static int yaffs_CheckpointErase(yaffs_Device *dev)
597 +{
598 +
599 + int i;
600 +
601 +
602 + if(!dev->eraseBlockInNAND)
603 + return 0;
604 + T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
605 + dev->internalStartBlock,dev->internalEndBlock));
606 +
607 + for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
608 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
609 + if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){
610 + T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
611 + if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){
612 + bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
613 + dev->nErasedBlocks++;
614 + dev->nFreeChunks += dev->nChunksPerBlock;
615 + }
616 + else {
617 + dev->markNANDBlockBad(dev,i);
618 + bi->blockState = YAFFS_BLOCK_STATE_DEAD;
619 + }
620 + }
621 + }
622 +
623 + dev->blocksInCheckpoint = 0;
624 +
625 + return 1;
626 +}
627 +
628 +
629 +static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
630 +{
631 + int i;
632 + int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
633 + T(YAFFS_TRACE_CHECKPOINT,
634 + (TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
635 + dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock));
636 +
637 + if(dev->checkpointNextBlock >= 0 &&
638 + dev->checkpointNextBlock <= dev->internalEndBlock &&
639 + blocksAvailable > 0){
640 +
641 + for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
642 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
643 + if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){
644 + dev->checkpointNextBlock = i + 1;
645 + dev->checkpointCurrentBlock = i;
646 + T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i));
647 + return;
648 + }
649 + }
650 + }
651 + T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
652 +
653 + dev->checkpointNextBlock = -1;
654 + dev->checkpointCurrentBlock = -1;
655 +}
656 +
657 +static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
658 +{
659 + int i;
660 + yaffs_ExtendedTags tags;
661 +
662 + T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start: blocks %d next %d" TENDSTR),
663 + dev->blocksInCheckpoint, dev->checkpointNextBlock));
664 +
665 + if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
666 + for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
667 + int chunk = i * dev->nChunksPerBlock;
668 + int realignedChunk = chunk - dev->chunkOffset;
669 +
670 + dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags);
671 + T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
672 + i, tags.objectId,tags.sequenceNumber,tags.eccResult));
673 +
674 + if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
675 + /* Right kind of block */
676 + dev->checkpointNextBlock = tags.objectId;
677 + dev->checkpointCurrentBlock = i;
678 + dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
679 + dev->blocksInCheckpoint++;
680 + T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
681 + return;
682 + }
683 + }
684 +
685 + T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
686 +
687 + dev->checkpointNextBlock = -1;
688 + dev->checkpointCurrentBlock = -1;
689 +}
690 +
691 +
692 +int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
693 +{
694 +
695 + /* Got the functions we need? */
696 + if (!dev->writeChunkWithTagsToNAND ||
697 + !dev->readChunkWithTagsFromNAND ||
698 + !dev->eraseBlockInNAND ||
699 + !dev->markNANDBlockBad)
700 + return 0;
701 +
702 + if(forWriting && !yaffs_CheckpointSpaceOk(dev))
703 + return 0;
704 +
705 + if(!dev->checkpointBuffer)
706 + dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
707 + if(!dev->checkpointBuffer)
708 + return 0;
709 +
710 +
711 + dev->checkpointPageSequence = 0;
712 +
713 + dev->checkpointOpenForWrite = forWriting;
714 +
715 + dev->checkpointByteCount = 0;
716 + dev->checkpointSum = 0;
717 + dev->checkpointXor = 0;
718 + dev->checkpointCurrentBlock = -1;
719 + dev->checkpointCurrentChunk = -1;
720 + dev->checkpointNextBlock = dev->internalStartBlock;
721 +
722 + /* Erase all the blocks in the checkpoint area */
723 + if(forWriting){
724 + memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
725 + dev->checkpointByteOffset = 0;
726 + return yaffs_CheckpointErase(dev);
727 +
728 +
729 + } else {
730 + int i;
731 + /* Set to a value that will kick off a read */
732 + dev->checkpointByteOffset = dev->nDataBytesPerChunk;
733 + /* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
734 + * going to be way more than we need */
735 + dev->blocksInCheckpoint = 0;
736 + dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
737 + dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
738 + for(i = 0; i < dev->checkpointMaxBlocks; i++)
739 + dev->checkpointBlockList[i] = -1;
740 + }
741 +
742 + return 1;
743 +}
744 +
745 +int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
746 +{
747 + __u32 compositeSum;
748 + compositeSum = (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
749 + *sum = compositeSum;
750 + return 1;
751 +}
752 +
753 +static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
754 +{
755 +
756 + int chunk;
757 + int realignedChunk;
758 +
759 + yaffs_ExtendedTags tags;
760 +
761 + if(dev->checkpointCurrentBlock < 0){
762 + yaffs_CheckpointFindNextErasedBlock(dev);
763 + dev->checkpointCurrentChunk = 0;
764 + }
765 +
766 + if(dev->checkpointCurrentBlock < 0)
767 + return 0;
768 +
769 + tags.chunkDeleted = 0;
770 + tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
771 + tags.chunkId = dev->checkpointPageSequence + 1;
772 + tags.sequenceNumber = YAFFS_SEQUENCE_CHECKPOINT_DATA;
773 + tags.byteCount = dev->nDataBytesPerChunk;
774 + if(dev->checkpointCurrentChunk == 0){
775 + /* First chunk we write for the block? Set block state to
776 + checkpoint */
777 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock);
778 + bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
779 + dev->blocksInCheckpoint++;
780 + }
781 +
782 + chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
783 +
784 +
785 + T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
786 + chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId));
787 +
788 + realignedChunk = chunk - dev->chunkOffset;
789 +
790 + dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags);
791 + dev->checkpointByteOffset = 0;
792 + dev->checkpointPageSequence++;
793 + dev->checkpointCurrentChunk++;
794 + if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
795 + dev->checkpointCurrentChunk = 0;
796 + dev->checkpointCurrentBlock = -1;
797 + }
798 + memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
799 +
800 + return 1;
801 +}
802 +
803 +
804 +int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
805 +{
806 + int i=0;
807 + int ok = 1;
808 +
809 +
810 + __u8 * dataBytes = (__u8 *)data;
811 +
812 +
813 +
814 + if(!dev->checkpointBuffer)
815 + return 0;
816 +
817 + if(!dev->checkpointOpenForWrite)
818 + return -1;
819 +
820 + while(i < nBytes && ok) {
821 +
822 +
823 +
824 + dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
825 + dev->checkpointSum += *dataBytes;
826 + dev->checkpointXor ^= *dataBytes;
827 +
828 + dev->checkpointByteOffset++;
829 + i++;
830 + dataBytes++;
831 + dev->checkpointByteCount++;
832 +
833 +
834 + if(dev->checkpointByteOffset < 0 ||
835 + dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
836 + ok = yaffs_CheckpointFlushBuffer(dev);
837 +
838 + }
839 +
840 + return i;
841 +}
842 +
843 +int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
844 +{
845 + int i=0;
846 + int ok = 1;
847 + yaffs_ExtendedTags tags;
848 +
849 +
850 + int chunk;
851 + int realignedChunk;
852 +
853 + __u8 *dataBytes = (__u8 *)data;
854 +
855 + if(!dev->checkpointBuffer)
856 + return 0;
857 +
858 + if(dev->checkpointOpenForWrite)
859 + return -1;
860 +
861 + while(i < nBytes && ok) {
862 +
863 +
864 + if(dev->checkpointByteOffset < 0 ||
865 + dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
866 +
867 + if(dev->checkpointCurrentBlock < 0){
868 + yaffs_CheckpointFindNextCheckpointBlock(dev);
869 + dev->checkpointCurrentChunk = 0;
870 + }
871 +
872 + if(dev->checkpointCurrentBlock < 0)
873 + ok = 0;
874 + else {
875 +
876 + chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
877 + dev->checkpointCurrentChunk;
878 +
879 + realignedChunk = chunk - dev->chunkOffset;
880 +
881 + /* read in the next chunk */
882 + /* printf("read checkpoint page %d\n",dev->checkpointPage); */
883 + dev->readChunkWithTagsFromNAND(dev, realignedChunk,
884 + dev->checkpointBuffer,
885 + &tags);
886 +
887 + if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
888 + tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
889 + ok = 0;
890 +
891 + dev->checkpointByteOffset = 0;
892 + dev->checkpointPageSequence++;
893 + dev->checkpointCurrentChunk++;
894 +
895 + if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
896 + dev->checkpointCurrentBlock = -1;
897 + }
898 + }
899 +
900 + if(ok){
901 + *dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
902 + dev->checkpointSum += *dataBytes;
903 + dev->checkpointXor ^= *dataBytes;
904 + dev->checkpointByteOffset++;
905 + i++;
906 + dataBytes++;
907 + dev->checkpointByteCount++;
908 + }
909 + }
910 +
911 + return i;
912 +}
913 +
914 +int yaffs_CheckpointClose(yaffs_Device *dev)
915 +{
916 +
917 + if(dev->checkpointOpenForWrite){
918 + if(dev->checkpointByteOffset != 0)
919 + yaffs_CheckpointFlushBuffer(dev);
920 + } else {
921 + int i;
922 + for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
923 + yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]);
924 + if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
925 + bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
926 + else {
927 + // Todo this looks odd...
928 + }
929 + }
930 + YFREE(dev->checkpointBlockList);
931 + dev->checkpointBlockList = NULL;
932 + }
933 +
934 + dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
935 + dev->nErasedBlocks -= dev->blocksInCheckpoint;
936 +
937 +
938 + T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
939 + dev->checkpointByteCount));
940 +
941 + if(dev->checkpointBuffer){
942 + /* free the buffer */
943 + YFREE(dev->checkpointBuffer);
944 + dev->checkpointBuffer = NULL;
945 + return 1;
946 + }
947 + else
948 + return 0;
949 +
950 +}
951 +
952 +int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
953 +{
954 + /* Erase the first checksum block */
955 +
956 + T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
957 +
958 + if(!yaffs_CheckpointSpaceOk(dev))
959 + return 0;
960 +
961 + return yaffs_CheckpointErase(dev);
962 +}
963 +
964 +
965 +
966 Index: linux-2.6.23-rc6/fs/yaffs2/yaffs_checkptrw.h
967 ===================================================================
968 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
969 +++ linux-2.6.23-rc6/fs/yaffs2/yaffs_checkptrw.h 2007-09-21 16:24:08.000000000 +0800
970 @@ -0,0 +1,35 @@
971 +/*
972 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
973 + *
974 + * Copyright (C) 2002-2007 Aleph One Ltd.
975 + * for Toby Churchill Ltd and Brightstar Engineering
976 + *
977 + * Created by Charles Manning <charles@aleph1.co.uk>
978 + *
979 + * This program is free software; you can redistribute it and/or modify
980 + * it under the terms of the GNU Lesser General Public License version 2.1 as
981 + * published by the Free Software Foundation.
982 + *
983 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
984 + */
985 +
986 +#ifndef __YAFFS_CHECKPTRW_H__
987 +#define __YAFFS_CHECKPTRW_H__
988 +
989 +#include "yaffs_guts.h"
990 +
991 +int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
992 +
993 +int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes);
994 +
995 +int yaffs_CheckpointRead(yaffs_Device *dev,void *data, int nBytes);
996 +
997 +int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
998 +
999 +int yaffs_CheckpointClose(yaffs_Device *dev);
1000 +
1001 +int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
1002 +
1003 +
1004 +#endif
1005 +
1006 Index: linux-2.6.23-rc6/fs/yaffs2/yaffs_ecc.c
1007 ===================================================================
1008 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1009 +++ linux-2.6.23-rc6/fs/yaffs2/yaffs_ecc.c 2007-09-21 16:24:08.000000000 +0800
1010 @@ -0,0 +1,331 @@
1011 +/*
1012 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1013 + *
1014 + * Copyright (C) 2002-2007 Aleph One Ltd.
1015 + * for Toby Churchill Ltd and Brightstar Engineering
1016 + *
1017 + * Created by Charles Manning <charles@aleph1.co.uk>
1018 + *
1019 + * This program is free software; you can redistribute it and/or modify
1020 + * it under the terms of the GNU General Public License version 2 as
1021 + * published by the Free Software Foundation.
1022 + */
1023 +
1024 +/*
1025 + * This code implements the ECC algorithm used in SmartMedia.
1026 + *
1027 + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
1028 + * The two unused bit are set to 1.
1029 + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
1030 + * blocks are used on a 512-byte NAND page.
1031 + *
1032 + */
1033 +
1034 +/* Table generated by gen-ecc.c
1035 + * Using a table means we do not have to calculate p1..p4 and p1'..p4'
1036 + * for each byte of data. These are instead provided in a table in bits7..2.
1037 + * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
1038 + * this bytes influence on the line parity.
1039 + */
1040 +
1041 +const char *yaffs_ecc_c_version =
1042 + "$Id: yaffs_ecc.c,v 1.9 2007-02-14 01:09:06 wookey Exp $";
1043 +
1044 +#include "yportenv.h"
1045 +
1046 +#include "yaffs_ecc.h"
1047 +
1048 +static const unsigned char column_parity_table[] = {
1049 + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
1050 + 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
1051 + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
1052 + 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
1053 + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
1054 + 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
1055 + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
1056 + 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
1057 + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
1058 + 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
1059 + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
1060 + 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
1061 + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
1062 + 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
1063 + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
1064 + 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
1065 + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
1066 + 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
1067 + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
1068 + 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
1069 + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
1070 + 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
1071 + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
1072 + 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
1073 + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
1074 + 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
1075 + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
1076 + 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
1077 + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
1078 + 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
1079 + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
1080 + 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
1081 +};
1082 +
1083 +/* Count the bits in an unsigned char or a U32 */
1084 +
1085 +static int yaffs_CountBits(unsigned char x)
1086 +{
1087 + int r = 0;
1088 + while (x) {
1089 + if (x & 1)
1090 + r++;
1091 + x >>= 1;
1092 + }
1093 + return r;
1094 +}
1095 +
1096 +static int yaffs_CountBits32(unsigned x)
1097 +{
1098 + int r = 0;
1099 + while (x) {
1100 + if (x & 1)
1101 + r++;
1102 + x >>= 1;
1103 + }
1104 + return r;
1105 +}
1106 +
1107 +/* Calculate the ECC for a 256-byte block of data */
1108 +void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
1109 +{
1110 + unsigned int i;
1111 +
1112 + unsigned char col_parity = 0;
1113 + unsigned char line_parity = 0;
1114 + unsigned char line_parity_prime = 0;
1115 + unsigned char t;
1116 + unsigned char b;
1117 +
1118 + for (i = 0; i < 256; i++) {
1119 + b = column_parity_table[*data++];
1120 + col_parity ^= b;
1121 +
1122 + if (b & 0x01) // odd number of bits in the byte
1123 + {
1124 + line_parity ^= i;
1125 + line_parity_prime ^= ~i;
1126 + }
1127 +
1128 + }
1129 +
1130 + ecc[2] = (~col_parity) | 0x03;
1131 +
1132 + t = 0;
1133 + if (line_parity & 0x80)
1134 + t |= 0x80;
1135 + if (line_parity_prime & 0x80)
1136 + t |= 0x40;
1137 + if (line_parity & 0x40)
1138 + t |= 0x20;
1139 + if (line_parity_prime & 0x40)
1140 + t |= 0x10;
1141 + if (line_parity & 0x20)
1142 + t |= 0x08;
1143 + if (line_parity_prime & 0x20)
1144 + t |= 0x04;
1145 + if (line_parity & 0x10)
1146 + t |= 0x02;
1147 + if (line_parity_prime & 0x10)
1148 + t |= 0x01;
1149 + ecc[1] = ~t;
1150 +
1151 + t = 0;
1152 + if (line_parity & 0x08)
1153 + t |= 0x80;
1154 + if (line_parity_prime & 0x08)
1155 + t |= 0x40;
1156 + if (line_parity & 0x04)
1157 + t |= 0x20;
1158 + if (line_parity_prime & 0x04)
1159 + t |= 0x10;
1160 + if (line_parity & 0x02)
1161 + t |= 0x08;
1162 + if (line_parity_prime & 0x02)
1163 + t |= 0x04;
1164 + if (line_parity & 0x01)
1165 + t |= 0x02;
1166 + if (line_parity_prime & 0x01)
1167 + t |= 0x01;
1168 + ecc[0] = ~t;
1169 +
1170 +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
1171 + // Swap the bytes into the wrong order
1172 + t = ecc[0];
1173 + ecc[0] = ecc[1];
1174 + ecc[1] = t;
1175 +#endif
1176 +}
1177 +
1178 +
1179 +/* Correct the ECC on a 256 byte block of data */
1180 +
1181 +int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
1182 + const unsigned char *test_ecc)
1183 +{
1184 + unsigned char d0, d1, d2; /* deltas */
1185 +
1186 + d0 = read_ecc[0] ^ test_ecc[0];
1187 + d1 = read_ecc[1] ^ test_ecc[1];
1188 + d2 = read_ecc[2] ^ test_ecc[2];
1189 +
1190 + if ((d0 | d1 | d2) == 0)
1191 + return 0; /* no error */
1192 +
1193 + if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
1194 + ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
1195 + ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
1196 + /* Single bit (recoverable) error in data */
1197 +
1198 + unsigned byte;
1199 + unsigned bit;
1200 +
1201 +#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
1202 + // swap the bytes to correct for the wrong order
1203 + unsigned char t;
1204 +
1205 + t = d0;
1206 + d0 = d1;
1207 + d1 = t;
1208 +#endif
1209 +
1210 + bit = byte = 0;
1211 +
1212 + if (d1 & 0x80)
1213 + byte |= 0x80;
1214 + if (d1 & 0x20)
1215 + byte |= 0x40;
1216 + if (d1 & 0x08)
1217 + byte |= 0x20;
1218 + if (d1 & 0x02)
1219 + byte |= 0x10;
1220 + if (d0 & 0x80)
1221 + byte |= 0x08;
1222 + if (d0 & 0x20)
1223 + byte |= 0x04;
1224 + if (d0 & 0x08)
1225 + byte |= 0x02;
1226 + if (d0 & 0x02)
1227 + byte |= 0x01;
1228 +
1229 + if (d2 & 0x80)
1230 + bit |= 0x04;
1231 + if (d2 & 0x20)
1232 + bit |= 0x02;
1233 + if (d2 & 0x08)
1234 + bit |= 0x01;
1235 +
1236 + data[byte] ^= (1 << bit);
1237 +
1238 + return 1; /* Corrected the error */
1239 + }
1240 +
1241 + if ((yaffs_CountBits(d0) +
1242 + yaffs_CountBits(d1) +
1243 + yaffs_CountBits(d2)) == 1) {
1244 + /* Reccoverable error in ecc */
1245 +
1246 + read_ecc[0] = test_ecc[0];
1247 + read_ecc[1] = test_ecc[1];
1248 + read_ecc[2] = test_ecc[2];
1249 +
1250 + return 1; /* Corrected the error */
1251 + }
1252 +
1253 + /* Unrecoverable error */
1254 +
1255 + return -1;
1256 +
1257 +}
1258 +
1259 +
1260 +/*
1261 + * ECCxxxOther does ECC calcs on arbitrary n bytes of data
1262 + */
1263 +void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
1264 + yaffs_ECCOther * eccOther)
1265 +{
1266 + unsigned int i;
1267 +
1268 + unsigned char col_parity = 0;
1269 + unsigned line_parity = 0;
1270 + unsigned line_parity_prime = 0;
1271 + unsigned char b;
1272 +
1273 + for (i = 0; i < nBytes; i++) {
1274 + b = column_parity_table[*data++];
1275 + col_parity ^= b;
1276 +
1277 + if (b & 0x01) {
1278 + /* odd number of bits in the byte */
1279 + line_parity ^= i;
1280 + line_parity_prime ^= ~i;
1281 + }
1282 +
1283 + }
1284 +
1285 + eccOther->colParity = (col_parity >> 2) & 0x3f;
1286 + eccOther->lineParity = line_parity;
1287 + eccOther->lineParityPrime = line_parity_prime;
1288 +}
1289 +
1290 +int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
1291 + yaffs_ECCOther * read_ecc,
1292 + const yaffs_ECCOther * test_ecc)
1293 +{
1294 + unsigned char cDelta; /* column parity delta */
1295 + unsigned lDelta; /* line parity delta */
1296 + unsigned lDeltaPrime; /* line parity delta */
1297 + unsigned bit;
1298 +
1299 + cDelta = read_ecc->colParity ^ test_ecc->colParity;
1300 + lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
1301 + lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
1302 +
1303 + if ((cDelta | lDelta | lDeltaPrime) == 0)
1304 + return 0; /* no error */
1305 +
1306 + if (lDelta == ~lDeltaPrime &&
1307 + (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15))
1308 + {
1309 + /* Single bit (recoverable) error in data */
1310 +
1311 + bit = 0;
1312 +
1313 + if (cDelta & 0x20)
1314 + bit |= 0x04;
1315 + if (cDelta & 0x08)
1316 + bit |= 0x02;
1317 + if (cDelta & 0x02)
1318 + bit |= 0x01;
1319 +
1320 + if(lDelta >= nBytes)
1321 + return -1;
1322 +
1323 + data[lDelta] ^= (1 << bit);
1324 +
1325 + return 1; /* corrected */
1326 + }
1327 +
1328 + if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
1329 + yaffs_CountBits(cDelta)) == 1) {
1330 + /* Reccoverable error in ecc */
1331 +
1332 + *read_ecc = *test_ecc;
1333 + return 1; /* corrected */
1334 + }
1335 +
1336 + /* Unrecoverable error */
1337 +
1338 + return -1;
1339 +
1340 +}
1341 +
1342 Index: linux-2.6.23-rc6/fs/yaffs2/yaffs_ecc.h
1343 ===================================================================
1344 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1345 +++ linux-2.6.23-rc6/fs/yaffs2/yaffs_ecc.h 2007-09-21 16:24:08.000000000 +0800
1346 @@ -0,0 +1,44 @@
1347 +/*
1348 + * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
1349 + *
1350 + * Copyright (C) 2002-2007 Aleph One Ltd.
1351 + * for Toby Churchill Ltd and Brightstar Engineering
1352 + *
1353 + * Created by Charles Manning <charles@aleph1.co.uk>
1354 + *
1355 + * This program is free software; you can redistribute it and/or modify
1356 + * it under the terms of the GNU Lesser General Public License version 2.1 as
1357 + * published by the Free Software Foundation.
1358 + *
1359 + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
1360 + */
1361 +
1362 + /*
1363 + * This code implements the ECC algorithm used in SmartMedia.
1364 + *
1365 + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
1366 + * The two unused bit are set to 1.
1367 + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
1368 + * blocks are used on a 512-byte NAND page.
1369 + *
1370 + */
1371 +
1372 +#ifndef __YAFFS_ECC_H__
1373 +#define __YAFFS_ECC_H__
1374 +
1375 +typedef struct {
1376 + unsigned char colParity;
1377 + unsigned lineParity;
1378 + unsigned lineParityPrime;
1379 +} yaffs_ECCOther;
1380 +
1381 +void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
1382 +int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
1383 + const unsigned char *test_ecc);
1384 +
1385 +void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
1386 + yaffs_ECCOther * ecc);
1387 +int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
1388 + yaffs_ECCOther * read_ecc,
1389 + const yaffs_ECCOther * test_ecc);
1390 +#endif
1391 Index: linux-2.6.23-rc6/fs/yaffs2/yaffs_fs.c
1392 ===================================================================
1393 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
1394 +++ linux-2.6.23-rc6/fs/yaffs2/yaffs_fs.c 2007-09-21 16:24:08.000000000 +0800
1395 @@ -0,0 +1,2278 @@
1396 +/*
1397 + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
1398 + *
1399 + * Copyright (C) 2002-2007 Aleph One Ltd.
1400 + * for Toby Churchill Ltd and Brightstar Engineering
1401 + *
1402 + * Created by Charles Manning <charles@aleph1.co.uk>
1403 + * Acknowledgements:
1404 + * Luc van OostenRyck for numerous patches.
1405 + * Nick Bane for numerous patches.
1406 + * Nick Bane for 2.5/2.6 integration.
1407 + * Andras Toth for mknod rdev issue.
1408 + * Michael Fischer for finding the problem with inode inconsistency.
1409 + * Some code bodily lifted from JFFS
1410 + *
1411 + * This program is free software; you can redistribute it and/or modify
1412 + * it under the terms of the GNU General Public License version 2 as
1413 + * published by the Free Software Foundation.
1414 + */
1415 +
1416 +/*
1417 + *
1418 + * This is the file system front-end to YAFFS that hooks it up to
1419 + * the VFS.
1420 + *
1421 + * Special notes:
1422 + * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
1423 + * this superblock
1424 + * >> 2.6: sb->s_fs_info points to the yaffs_Device associated with this
1425 + * superblock
1426 + * >> inode->u.generic_ip points to the associated yaffs_Object.
1427 + */
1428 +
1429 +const char *yaffs_fs_c_version =
1430 + "$Id: yaffs_fs.c,v 1.60 2007-05-15 20:07:40 charles Exp $";
1431 +extern const char *yaffs_guts_c_version;
1432 +
1433 +#include <linux/version.h>
1434 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
1435 +#include <linux/config.h>
1436 +#endif
1437 +#include <linux/kernel.h>
1438 +#include <linux/module.h>
1439 +#include <linux/slab.h>
1440 +#include <linux/init.h>
1441 +#include <linux/list.h>
1442 +#include <linux/fs.h>
1443 +#include <linux/proc_fs.h>
1444 +#include <linux/smp_lock.h>
1445 +#include <linux/pagemap.h>
1446 +#include <linux/mtd/mtd.h>
1447 +#include <linux/interrupt.h>
1448 +#include <linux/string.h>
1449 +#include <linux/ctype.h>
1450 +
1451 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1452 +
1453 +#include <linux/statfs.h> /* Added NCB 15-8-2003 */
1454 +#include <asm/statfs.h>
1455 +#define UnlockPage(p) unlock_page(p)
1456 +#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
1457 +
1458 +/* FIXME: use sb->s_id instead ? */
1459 +#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
1460 +
1461 +#else
1462 +
1463 +#include <linux/locks.h>
1464 +#define BDEVNAME_SIZE 0
1465 +#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
1466 +
1467 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
1468 +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
1469 +#define __user
1470 +#endif
1471 +
1472 +#endif
1473 +
1474 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1475 +#define WRITE_SIZE_STR "writesize"
1476 +#define WRITE_SIZE(mtd) (mtd)->writesize
1477 +#else
1478 +#define WRITE_SIZE_STR "oobblock"
1479 +#define WRITE_SIZE(mtd) (mtd)->oobblock
1480 +#endif
1481 +
1482 +#include <asm/uaccess.h>
1483 +
1484 +#include "yportenv.h"
1485 +#include "yaffs_guts.h"
1486 +
1487 +#include <linux/mtd/mtd.h>
1488 +#include "yaffs_mtdif.h"
1489 +#include "yaffs_mtdif1.h"
1490 +#include "yaffs_mtdif2.h"
1491 +
1492 +unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
1493 +unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
1494 +
1495 +/* Module Parameters */
1496 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1497 +module_param(yaffs_traceMask,uint,0644);
1498 +module_param(yaffs_wr_attempts,uint,0644);
1499 +#else
1500 +MODULE_PARM(yaffs_traceMask,"i");
1501 +MODULE_PARM(yaffs_wr_attempts,"i");
1502 +#endif
1503 +
1504 +/*#define T(x) printk x */
1505 +
1506 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
1507 +#define yaffs_InodeToObjectLV(iptr) (iptr)->i_private
1508 +#else
1509 +#define yaffs_InodeToObjectLV(iptr) (iptr)->u.generic_ip
1510 +#endif
1511 +
1512 +#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
1513 +#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
1514 +
1515 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1516 +#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
1517 +#else
1518 +#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
1519 +#endif
1520 +
1521 +static void yaffs_put_super(struct super_block *sb);
1522 +
1523 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
1524 + loff_t * pos);
1525 +
1526 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1527 +static int yaffs_file_flush(struct file *file, fl_owner_t id);
1528 +#else
1529 +static int yaffs_file_flush(struct file *file);
1530 +#endif
1531 +
1532 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
1533 + int datasync);
1534 +
1535 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
1536 +
1537 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1538 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1539 + struct nameidata *n);
1540 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1541 + struct nameidata *n);
1542 +#else
1543 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
1544 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
1545 +#endif
1546 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
1547 + struct dentry *dentry);
1548 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
1549 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
1550 + const char *symname);
1551 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
1552 +
1553 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1554 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1555 + dev_t dev);
1556 +#else
1557 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1558 + int dev);
1559 +#endif
1560 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
1561 + struct inode *new_dir, struct dentry *new_dentry);
1562 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
1563 +
1564 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1565 +static int yaffs_sync_fs(struct super_block *sb, int wait);
1566 +static void yaffs_write_super(struct super_block *sb);
1567 +#else
1568 +static int yaffs_sync_fs(struct super_block *sb);
1569 +static int yaffs_write_super(struct super_block *sb);
1570 +#endif
1571 +
1572 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1573 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
1574 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1575 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
1576 +#else
1577 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
1578 +#endif
1579 +static void yaffs_read_inode(struct inode *inode);
1580 +
1581 +static void yaffs_put_inode(struct inode *inode);
1582 +static void yaffs_delete_inode(struct inode *);
1583 +static void yaffs_clear_inode(struct inode *);
1584 +
1585 +static int yaffs_readpage(struct file *file, struct page *page);
1586 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1587 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
1588 +#else
1589 +static int yaffs_writepage(struct page *page);
1590 +#endif
1591 +static int yaffs_prepare_write(struct file *f, struct page *pg,
1592 + unsigned offset, unsigned to);
1593 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
1594 + unsigned to);
1595 +
1596 +static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
1597 + int buflen);
1598 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
1599 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1600 +#else
1601 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
1602 +#endif
1603 +
1604 +static struct address_space_operations yaffs_file_address_operations = {
1605 + .readpage = yaffs_readpage,
1606 + .writepage = yaffs_writepage,
1607 + .prepare_write = yaffs_prepare_write,
1608 + .commit_write = yaffs_commit_write,
1609 +};
1610 +
1611 +static struct file_operations yaffs_file_operations = {
1612 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
1613 + .read = do_sync_read,
1614 + .write = do_sync_write,
1615 + .aio_read = generic_file_aio_read,
1616 + .aio_write = generic_file_aio_write,
1617 +#else
1618 + .read = generic_file_read,
1619 + .write = generic_file_write,
1620 +#endif
1621 + .mmap = generic_file_mmap,
1622 + .flush = yaffs_file_flush,
1623 + .fsync = yaffs_sync_object,
1624 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1625 + .sendfile = generic_file_sendfile,
1626 +#endif
1627 +
1628 +};
1629 +
1630 +static struct inode_operations yaffs_file_inode_operations = {
1631 + .setattr = yaffs_setattr,
1632 +};
1633 +
1634 +static struct inode_operations yaffs_symlink_inode_operations = {
1635 + .readlink = yaffs_readlink,
1636 + .follow_link = yaffs_follow_link,
1637 + .setattr = yaffs_setattr,
1638 +};
1639 +
1640 +static struct inode_operations yaffs_dir_inode_operations = {
1641 + .create = yaffs_create,
1642 + .lookup = yaffs_lookup,
1643 + .link = yaffs_link,
1644 + .unlink = yaffs_unlink,
1645 + .symlink = yaffs_symlink,
1646 + .mkdir = yaffs_mkdir,
1647 + .rmdir = yaffs_unlink,
1648 + .mknod = yaffs_mknod,
1649 + .rename = yaffs_rename,
1650 + .setattr = yaffs_setattr,
1651 +};
1652 +
1653 +static struct file_operations yaffs_dir_operations = {
1654 + .read = generic_read_dir,
1655 + .readdir = yaffs_readdir,
1656 + .fsync = yaffs_sync_object,
1657 +};
1658 +
1659 +static struct super_operations yaffs_super_ops = {
1660 + .statfs = yaffs_statfs,
1661 + .read_inode = yaffs_read_inode,
1662 + .put_inode = yaffs_put_inode,
1663 + .put_super = yaffs_put_super,
1664 + .delete_inode = yaffs_delete_inode,
1665 + .clear_inode = yaffs_clear_inode,
1666 + .sync_fs = yaffs_sync_fs,
1667 + .write_super = yaffs_write_super,
1668 +};
1669 +
1670 +static void yaffs_GrossLock(yaffs_Device * dev)
1671 +{
1672 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs locking\n"));
1673 +
1674 + down(&dev->grossLock);
1675 +}
1676 +
1677 +static void yaffs_GrossUnlock(yaffs_Device * dev)
1678 +{
1679 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs unlocking\n"));
1680 + up(&dev->grossLock);
1681 +
1682 +}
1683 +
1684 +static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
1685 + int buflen)
1686 +{
1687 + unsigned char *alias;
1688 + int ret;
1689 +
1690 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1691 +
1692 + yaffs_GrossLock(dev);
1693 +
1694 + alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
1695 +
1696 + yaffs_GrossUnlock(dev);
1697 +
1698 + if (!alias)
1699 + return -ENOMEM;
1700 +
1701 + ret = vfs_readlink(dentry, buffer, buflen, alias);
1702 + kfree(alias);
1703 + return ret;
1704 +}
1705 +
1706 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
1707 +static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
1708 +#else
1709 +static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
1710 +#endif
1711 +{
1712 + unsigned char *alias;
1713 + int ret;
1714 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1715 +
1716 + yaffs_GrossLock(dev);
1717 +
1718 + alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
1719 +
1720 + yaffs_GrossUnlock(dev);
1721 +
1722 + if (!alias)
1723 + {
1724 + ret = -ENOMEM;
1725 + goto out;
1726 + }
1727 +
1728 + ret = vfs_follow_link(nd, alias);
1729 + kfree(alias);
1730 +out:
1731 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
1732 + return ERR_PTR (ret);
1733 +#else
1734 + return ret;
1735 +#endif
1736 +}
1737 +
1738 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
1739 + yaffs_Object * obj);
1740 +
1741 +/*
1742 + * Lookup is used to find objects in the fs
1743 + */
1744 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1745 +
1746 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
1747 + struct nameidata *n)
1748 +#else
1749 +static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
1750 +#endif
1751 +{
1752 + yaffs_Object *obj;
1753 + struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
1754 +
1755 + yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
1756 +
1757 + yaffs_GrossLock(dev);
1758 +
1759 + T(YAFFS_TRACE_OS,
1760 + (KERN_DEBUG "yaffs_lookup for %d:%s\n",
1761 + yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
1762 +
1763 + obj =
1764 + yaffs_FindObjectByName(yaffs_InodeToObject(dir),
1765 + dentry->d_name.name);
1766 +
1767 + obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
1768 +
1769 + /* Can't hold gross lock when calling yaffs_get_inode() */
1770 + yaffs_GrossUnlock(dev);
1771 +
1772 + if (obj) {
1773 + T(YAFFS_TRACE_OS,
1774 + (KERN_DEBUG "yaffs_lookup found %d\n", obj->objectId));
1775 +
1776 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
1777 +
1778 + if (inode) {
1779 + T(YAFFS_TRACE_OS,
1780 + (KERN_DEBUG "yaffs_loookup dentry \n"));
1781 +/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
1782 + * d_add even if NULL inode */
1783 +#if 0
1784 + /*dget(dentry); // try to solve directory bug */
1785 + d_add(dentry, inode);
1786 +
1787 + /* return dentry; */
1788 + return NULL;
1789 +#endif
1790 + }
1791 +
1792 + } else {
1793 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_lookup not found\n"));
1794 +
1795 + }
1796 +
1797 +/* added NCB for 2.5/6 compatability - forces add even if inode is
1798 + * NULL which creates dentry hash */
1799 + d_add(dentry, inode);
1800 +
1801 + return NULL;
1802 + /* return (ERR_PTR(-EIO)); */
1803 +
1804 +}
1805 +
1806 +/* For now put inode is just for debugging
1807 + * Put inode is called when the inode **structure** is put.
1808 + */
1809 +static void yaffs_put_inode(struct inode *inode)
1810 +{
1811 + T(YAFFS_TRACE_OS,
1812 + ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
1813 + atomic_read(&inode->i_count)));
1814 +
1815 +}
1816 +
1817 +/* clear is called to tell the fs to release any per-inode data it holds */
1818 +static void yaffs_clear_inode(struct inode *inode)
1819 +{
1820 + yaffs_Object *obj;
1821 + yaffs_Device *dev;
1822 +
1823 + obj = yaffs_InodeToObject(inode);
1824 +
1825 + T(YAFFS_TRACE_OS,
1826 + ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
1827 + atomic_read(&inode->i_count),
1828 + obj ? "object exists" : "null object"));
1829 +
1830 + if (obj) {
1831 + dev = obj->myDev;
1832 + yaffs_GrossLock(dev);
1833 +
1834 + /* Clear the association between the inode and
1835 + * the yaffs_Object.
1836 + */
1837 + obj->myInode = NULL;
1838 + yaffs_InodeToObjectLV(inode) = NULL;
1839 +
1840 + /* If the object freeing was deferred, then the real
1841 + * free happens now.
1842 + * This should fix the inode inconsistency problem.
1843 + */
1844 +
1845 + yaffs_HandleDeferedFree(obj);
1846 +
1847 + yaffs_GrossUnlock(dev);
1848 + }
1849 +
1850 +}
1851 +
1852 +/* delete is called when the link count is zero and the inode
1853 + * is put (ie. nobody wants to know about it anymore, time to
1854 + * delete the file).
1855 + * NB Must call clear_inode()
1856 + */
1857 +static void yaffs_delete_inode(struct inode *inode)
1858 +{
1859 + yaffs_Object *obj = yaffs_InodeToObject(inode);
1860 + yaffs_Device *dev;
1861 +
1862 + T(YAFFS_TRACE_OS,
1863 + ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
1864 + atomic_read(&inode->i_count),
1865 + obj ? "object exists" : "null object"));
1866 +
1867 + if (obj) {
1868 + dev = obj->myDev;
1869 + yaffs_GrossLock(dev);
1870 + yaffs_DeleteFile(obj);
1871 + yaffs_GrossUnlock(dev);
1872 + }
1873 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
1874 + truncate_inode_pages (&inode->i_data, 0);
1875 +#endif
1876 + clear_inode(inode);
1877 +}
1878 +
1879 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1880 +static int yaffs_file_flush(struct file *file, fl_owner_t id)
1881 +#else
1882 +static int yaffs_file_flush(struct file *file)
1883 +#endif
1884 +{
1885 + yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
1886 +
1887 + yaffs_Device *dev = obj->myDev;
1888 +
1889 + T(YAFFS_TRACE_OS,
1890 + (KERN_DEBUG "yaffs_file_flush object %d (%s)\n", obj->objectId,
1891 + obj->dirty ? "dirty" : "clean"));
1892 +
1893 + yaffs_GrossLock(dev);
1894 +
1895 + yaffs_FlushFile(obj, 1);
1896 +
1897 + yaffs_GrossUnlock(dev);
1898 +
1899 + return 0;
1900 +}
1901 +
1902 +static int yaffs_readpage_nolock(struct file *f, struct page *pg)
1903 +{
1904 + /* Lifted from jffs2 */
1905 +
1906 + yaffs_Object *obj;
1907 + unsigned char *pg_buf;
1908 + int ret;
1909 +
1910 + yaffs_Device *dev;
1911 +
1912 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_readpage at %08x, size %08x\n",
1913 + (unsigned)(pg->index << PAGE_CACHE_SHIFT),
1914 + (unsigned)PAGE_CACHE_SIZE));
1915 +
1916 + obj = yaffs_DentryToObject(f->f_dentry);
1917 +
1918 + dev = obj->myDev;
1919 +
1920 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1921 + BUG_ON(!PageLocked(pg));
1922 +#else
1923 + if (!PageLocked(pg))
1924 + PAGE_BUG(pg);
1925 +#endif
1926 +
1927 + pg_buf = kmap(pg);
1928 + /* FIXME: Can kmap fail? */
1929 +
1930 + yaffs_GrossLock(dev);
1931 +
1932 + ret =
1933 + yaffs_ReadDataFromFile(obj, pg_buf, pg->index << PAGE_CACHE_SHIFT,
1934 + PAGE_CACHE_SIZE);
1935 +
1936 + yaffs_GrossUnlock(dev);
1937 +
1938 + if (ret >= 0)
1939 + ret = 0;
1940 +
1941 + if (ret) {
1942 + ClearPageUptodate(pg);
1943 + SetPageError(pg);
1944 + } else {
1945 + SetPageUptodate(pg);
1946 + ClearPageError(pg);
1947 + }
1948 +
1949 + flush_dcache_page(pg);
1950 + kunmap(pg);
1951 +
1952 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_readpage done\n"));
1953 + return ret;
1954 +}
1955 +
1956 +static int yaffs_readpage_unlock(struct file *f, struct page *pg)
1957 +{
1958 + int ret = yaffs_readpage_nolock(f, pg);
1959 + UnlockPage(pg);
1960 + return ret;
1961 +}
1962 +
1963 +static int yaffs_readpage(struct file *f, struct page *pg)
1964 +{
1965 + return yaffs_readpage_unlock(f, pg);
1966 +}
1967 +
1968 +/* writepage inspired by/stolen from smbfs */
1969 +
1970 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1971 +static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
1972 +#else
1973 +static int yaffs_writepage(struct page *page)
1974 +#endif
1975 +{
1976 + struct address_space *mapping = page->mapping;
1977 + loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
1978 + struct inode *inode;
1979 + unsigned long end_index;
1980 + char *buffer;
1981 + yaffs_Object *obj;
1982 + int nWritten = 0;
1983 + unsigned nBytes;
1984 +
1985 + if (!mapping)
1986 + BUG();
1987 + inode = mapping->host;
1988 + if (!inode)
1989 + BUG();
1990 +
1991 + if (offset > inode->i_size) {
1992 + T(YAFFS_TRACE_OS,
1993 + (KERN_DEBUG
1994 + "yaffs_writepage at %08x, inode size = %08x!!!\n",
1995 + (unsigned)(page->index << PAGE_CACHE_SHIFT),
1996 + (unsigned)inode->i_size));
1997 + T(YAFFS_TRACE_OS,
1998 + (KERN_DEBUG " -> don't care!!\n"));
1999 + unlock_page(page);
2000 + return 0;
2001 + }
2002 +
2003 + end_index = inode->i_size >> PAGE_CACHE_SHIFT;
2004 +
2005 + /* easy case */
2006 + if (page->index < end_index) {
2007 + nBytes = PAGE_CACHE_SIZE;
2008 + } else {
2009 + nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
2010 + }
2011 +
2012 + get_page(page);
2013 +
2014 + buffer = kmap(page);
2015 +
2016 + obj = yaffs_InodeToObject(inode);
2017 + yaffs_GrossLock(obj->myDev);
2018 +
2019 + T(YAFFS_TRACE_OS,
2020 + (KERN_DEBUG "yaffs_writepage at %08x, size %08x\n",
2021 + (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
2022 + T(YAFFS_TRACE_OS,
2023 + (KERN_DEBUG "writepag0: obj = %05x, ino = %05x\n",
2024 + (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
2025 +
2026 + nWritten =
2027 + yaffs_WriteDataToFile(obj, buffer, page->index << PAGE_CACHE_SHIFT,
2028 + nBytes, 0);
2029 +
2030 + T(YAFFS_TRACE_OS,
2031 + (KERN_DEBUG "writepag1: obj = %05x, ino = %05x\n",
2032 + (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
2033 +
2034 + yaffs_GrossUnlock(obj->myDev);
2035 +
2036 + kunmap(page);
2037 + SetPageUptodate(page);
2038 + UnlockPage(page);
2039 + put_page(page);
2040 +
2041 + return (nWritten == nBytes) ? 0 : -ENOSPC;
2042 +}
2043 +
2044 +static int yaffs_prepare_write(struct file *f, struct page *pg,
2045 + unsigned offset, unsigned to)
2046 +{
2047 +
2048 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_prepair_write\n"));
2049 + if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
2050 + return yaffs_readpage_nolock(f, pg);
2051 +
2052 + return 0;
2053 +
2054 +}
2055 +
2056 +static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
2057 + unsigned to)
2058 +{
2059 +
2060 + void *addr = page_address(pg) + offset;
2061 + loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
2062 + int nBytes = to - offset;
2063 + int nWritten;
2064 +
2065 + unsigned spos = pos;
2066 + unsigned saddr = (unsigned)addr;
2067 +
2068 + T(YAFFS_TRACE_OS,
2069 + (KERN_DEBUG "yaffs_commit_write addr %x pos %x nBytes %d\n", saddr,
2070 + spos, nBytes));
2071 +
2072 + nWritten = yaffs_file_write(f, addr, nBytes, &pos);
2073 +
2074 + if (nWritten != nBytes) {
2075 + T(YAFFS_TRACE_OS,
2076 + (KERN_DEBUG
2077 + "yaffs_commit_write not same size nWritten %d nBytes %d\n",
2078 + nWritten, nBytes));
2079 + SetPageError(pg);
2080 + ClearPageUptodate(pg);
2081 + } else {
2082 + SetPageUptodate(pg);
2083 + }
2084 +
2085 + T(YAFFS_TRACE_OS,
2086 + (KERN_DEBUG "yaffs_commit_write returning %d\n",
2087 + nWritten == nBytes ? 0 : nWritten));
2088 +
2089 + return nWritten == nBytes ? 0 : nWritten;
2090 +
2091 +}
2092 +
2093 +static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
2094 +{
2095 + if (inode && obj) {
2096 +
2097 +
2098 + /* Check mode against the variant type and attempt to repair if broken. */
2099 + __u32 mode = obj->yst_mode;
2100 + switch( obj->variantType ){
2101 + case YAFFS_OBJECT_TYPE_FILE :
2102 + if( ! S_ISREG(mode) ){
2103 + obj->yst_mode &= ~S_IFMT;
2104 + obj->yst_mode |= S_IFREG;
2105 + }
2106 +
2107 + break;
2108 + case YAFFS_OBJECT_TYPE_SYMLINK :
2109 + if( ! S_ISLNK(mode) ){
2110 + obj->yst_mode &= ~S_IFMT;
2111 + obj->yst_mode |= S_IFLNK;
2112 + }
2113 +
2114 + break;
2115 + case YAFFS_OBJECT_TYPE_DIRECTORY :
2116 + if( ! S_ISDIR(mode) ){
2117 + obj->yst_mode &= ~S_IFMT;
2118 + obj->yst_mode |= S_IFDIR;
2119 + }
2120 +
2121 + break;
2122 + case YAFFS_OBJECT_TYPE_UNKNOWN :
2123 + case YAFFS_OBJECT_TYPE_HARDLINK :
2124 + case YAFFS_OBJECT_TYPE_SPECIAL :
2125 + default:
2126 + /* TODO? */
2127 + break;
2128 + }
2129 +
2130 + inode->i_ino = obj->objectId;
2131 + inode->i_mode = obj->yst_mode;
2132 + inode->i_uid = obj->yst_uid;
2133 + inode->i_gid = obj->yst_gid;
2134 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
2135 + inode->i_blksize = inode->i_sb->s_blocksize;
2136 +#endif
2137 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2138 +
2139 + inode->i_rdev = old_decode_dev(obj->yst_rdev);
2140 + inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
2141 + inode->i_atime.tv_nsec = 0;
2142 + inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
2143 + inode->i_mtime.tv_nsec = 0;
2144 + inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
2145 + inode->i_ctime.tv_nsec = 0;
2146 +#else
2147 + inode->i_rdev = obj->yst_rdev;
2148 + inode->i_atime = obj->yst_atime;
2149 + inode->i_mtime = obj->yst_mtime;
2150 + inode->i_ctime = obj->yst_ctime;
2151 +#endif
2152 + inode->i_size = yaffs_GetObjectFileLength(obj);
2153 + inode->i_blocks = (inode->i_size + 511) >> 9;
2154 +
2155 + inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2156 +
2157 + T(YAFFS_TRACE_OS,
2158 + (KERN_DEBUG
2159 + "yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
2160 + inode->i_mode, inode->i_uid, inode->i_gid,
2161 + (int)inode->i_size, atomic_read(&inode->i_count)));
2162 +
2163 + switch (obj->yst_mode & S_IFMT) {
2164 + default: /* fifo, device or socket */
2165 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2166 + init_special_inode(inode, obj->yst_mode,
2167 + old_decode_dev(obj->yst_rdev));
2168 +#else
2169 + init_special_inode(inode, obj->yst_mode,
2170 + (dev_t) (obj->yst_rdev));
2171 +#endif
2172 + break;
2173 + case S_IFREG: /* file */
2174 + inode->i_op = &yaffs_file_inode_operations;
2175 + inode->i_fop = &yaffs_file_operations;
2176 + inode->i_mapping->a_ops =
2177 + &yaffs_file_address_operations;
2178 + break;
2179 + case S_IFDIR: /* directory */
2180 + inode->i_op = &yaffs_dir_inode_operations;
2181 + inode->i_fop = &yaffs_dir_operations;
2182 + break;
2183 + case S_IFLNK: /* symlink */
2184 + inode->i_op = &yaffs_symlink_inode_operations;
2185 + break;
2186 + }
2187 +
2188 + yaffs_InodeToObjectLV(inode) = obj;
2189 +
2190 + obj->myInode = inode;
2191 +
2192 + } else {
2193 + T(YAFFS_TRACE_OS,
2194 + (KERN_DEBUG "yaffs_FileInode invalid parameters\n"));
2195 + }
2196 +
2197 +}
2198 +
2199 +struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
2200 + yaffs_Object * obj)
2201 +{
2202 + struct inode *inode;
2203 +
2204 + if (!sb) {
2205 + T(YAFFS_TRACE_OS,
2206 + (KERN_DEBUG "yaffs_get_inode for NULL super_block!!\n"));
2207 + return NULL;
2208 +
2209 + }
2210 +
2211 + if (!obj) {
2212 + T(YAFFS_TRACE_OS,
2213 + (KERN_DEBUG "yaffs_get_inode for NULL object!!\n"));
2214 + return NULL;
2215 +
2216 + }
2217 +
2218 + T(YAFFS_TRACE_OS,
2219 + (KERN_DEBUG "yaffs_get_inode for object %d\n", obj->objectId));
2220 +
2221 + inode = iget(sb, obj->objectId);
2222 +
2223 + /* NB Side effect: iget calls back to yaffs_read_inode(). */
2224 + /* iget also increments the inode's i_count */
2225 + /* NB You can't be holding grossLock or deadlock will happen! */
2226 +
2227 + return inode;
2228 +}
2229 +
2230 +static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
2231 + loff_t * pos)
2232 +{
2233 + yaffs_Object *obj;
2234 + int nWritten, ipos;
2235 + struct inode *inode;
2236 + yaffs_Device *dev;
2237 +
2238 + obj = yaffs_DentryToObject(f->f_dentry);
2239 +
2240 + dev = obj->myDev;
2241 +
2242 + yaffs_GrossLock(dev);
2243 +
2244 + inode = f->f_dentry->d_inode;
2245 +
2246 + if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) {
2247 + ipos = inode->i_size;
2248 + } else {
2249 + ipos = *pos;
2250 + }
2251 +
2252 + if (!obj) {
2253 + T(YAFFS_TRACE_OS,
2254 + (KERN_DEBUG "yaffs_file_write: hey obj is null!\n"));
2255 + } else {
2256 + T(YAFFS_TRACE_OS,
2257 + (KERN_DEBUG
2258 + "yaffs_file_write about to write writing %d bytes"
2259 + "to object %d at %d\n",
2260 + n, obj->objectId, ipos));
2261 + }
2262 +
2263 + nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
2264 +
2265 + T(YAFFS_TRACE_OS,
2266 + (KERN_DEBUG "yaffs_file_write writing %d bytes, %d written at %d\n",
2267 + n, nWritten, ipos));
2268 + if (nWritten > 0) {
2269 + ipos += nWritten;
2270 + *pos = ipos;
2271 + if (ipos > inode->i_size) {
2272 + inode->i_size = ipos;
2273 + inode->i_blocks = (ipos + 511) >> 9;
2274 +
2275 + T(YAFFS_TRACE_OS,
2276 + (KERN_DEBUG
2277 + "yaffs_file_write size updated to %d bytes, "
2278 + "%d blocks\n",
2279 + ipos, (int)(inode->i_blocks)));
2280 + }
2281 +
2282 + }
2283 + yaffs_GrossUnlock(dev);
2284 + return nWritten == 0 ? -ENOSPC : nWritten;
2285 +}
2286 +
2287 +static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
2288 +{
2289 + yaffs_Object *obj;
2290 + yaffs_Device *dev;
2291 + struct inode *inode = f->f_dentry->d_inode;
2292 + unsigned long offset, curoffs;
2293 + struct list_head *i;
2294 + yaffs_Object *l;
2295 +
2296 + char name[YAFFS_MAX_NAME_LENGTH + 1];
2297 +
2298 + obj = yaffs_DentryToObject(f->f_dentry);
2299 + dev = obj->myDev;
2300 +
2301 + yaffs_GrossLock(dev);
2302 +
2303 + offset = f->f_pos;
2304 +
2305 + T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
2306 +
2307 + if (offset == 0) {
2308 + T(YAFFS_TRACE_OS,
2309 + (KERN_DEBUG "yaffs_readdir: entry . ino %d \n",
2310 + (int)inode->i_ino));
2311 + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR)
2312 + < 0) {
2313 + goto out;
2314 + }
2315 + offset++;
2316 + f->f_pos++;
2317 + }
2318 + if (offset == 1) {
2319 + T(YAFFS_TRACE_OS,
2320 + (KERN_DEBUG "yaffs_readdir: entry .. ino %d \n",
2321 + (int)f->f_dentry->d_parent->d_inode->i_ino));
2322 + if (filldir
2323 + (dirent, "..", 2, offset,
2324 + f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
2325 + goto out;
2326 + }
2327 + offset++;
2328 + f->f_pos++;
2329 + }
2330 +
2331 + curoffs = 1;
2332 +
2333 + /* If the directory has changed since the open or last call to
2334 + readdir, rewind to after the 2 canned entries. */
2335 +
2336 + if (f->f_version != inode->i_version) {
2337 + offset = 2;
2338 + f->f_pos = offset;
2339 + f->f_version = inode->i_version;
2340 + }
2341 +
2342 + list_for_each(i, &obj->variant.directoryVariant.children) {
2343 + curoffs++;
2344 + if (curoffs >= offset) {
2345 + l = list_entry(i, yaffs_Object, siblings);
2346 +
2347 + yaffs_GetObjectName(l, name,
2348 + YAFFS_MAX_NAME_LENGTH + 1);
2349 + T(YAFFS_TRACE_OS,
2350 + (KERN_DEBUG "yaffs_readdir: %s inode %d\n", name,
2351 + yaffs_GetObjectInode(l)));
2352 +
2353 + if (filldir(dirent,
2354 + name,
2355 + strlen(name),
2356 + offset,
2357 + yaffs_GetObjectInode(l),
2358 + yaffs_GetObjectType(l))
2359 + < 0) {
2360 + goto up_and_out;
2361 + }
2362 +
2363 + offset++;
2364 + f->f_pos++;
2365 + }
2366 + }
2367 +
2368 + up_and_out:
2369 + out:
2370 +
2371 + yaffs_GrossUnlock(dev);
2372 +
2373 + return 0;
2374 +}
2375 +
2376 +/*
2377 + * File creation. Allocate an inode, and we're done..
2378 + */
2379 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2380 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2381 + dev_t rdev)
2382 +#else
2383 +static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
2384 + int rdev)
2385 +#endif
2386 +{
2387 + struct inode *inode;
2388 +
2389 + yaffs_Object *obj = NULL;
2390 + yaffs_Device *dev;
2391 +
2392 + yaffs_Object *parent = yaffs_InodeToObject(dir);
2393 +
2394 + int error = -ENOSPC;
2395 + uid_t uid = current->fsuid;
2396 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
2397 +
2398 + if((dir->i_mode & S_ISGID) && S_ISDIR(mode))
2399 + mode |= S_ISGID;
2400 +
2401 + if (parent) {
2402 + T(YAFFS_TRACE_OS,
2403 + (KERN_DEBUG "yaffs_mknod: parent object %d type %d\n",
2404 + parent->objectId, parent->variantType));
2405 + } else {
2406 + T(YAFFS_TRACE_OS,
2407 + (KERN_DEBUG "yaffs_mknod: could not get parent object\n"));
2408 + return -EPERM;
2409 + }
2410 +
2411 + T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
2412 + "mode %x dev %x\n",
2413 + dentry->d_name.name, mode, rdev));
2414 +
2415 + dev = parent->myDev;
2416 +
2417 + yaffs_GrossLock(dev);
2418 +
2419 + switch (mode & S_IFMT) {
2420 + default:
2421 + /* Special (socket, fifo, device...) */
2422 + T(YAFFS_TRACE_OS, (KERN_DEBUG
2423 + "yaffs_mknod: making special\n"));
2424 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2425 + obj =
2426 + yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2427 + gid, old_encode_dev(rdev));
2428 +#else
2429 + obj =
2430 + yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
2431 + gid, rdev);
2432 +#endif
2433 + break;
2434 + case S_IFREG: /* file */
2435 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mknod: making file\n"));
2436 + obj =
2437 + yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
2438 + gid);
2439 + break;
2440 + case S_IFDIR: /* directory */
2441 + T(YAFFS_TRACE_OS,
2442 + (KERN_DEBUG "yaffs_mknod: making directory\n"));
2443 + obj =
2444 + yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
2445 + uid, gid);
2446 + break;
2447 + case S_IFLNK: /* symlink */
2448 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mknod: making file\n"));
2449 + obj = NULL; /* Do we ever get here? */
2450 + break;
2451 + }
2452 +
2453 + /* Can not call yaffs_get_inode() with gross lock held */
2454 + yaffs_GrossUnlock(dev);
2455 +
2456 + if (obj) {
2457 + inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
2458 + d_instantiate(dentry, inode);
2459 + T(YAFFS_TRACE_OS,
2460 + (KERN_DEBUG "yaffs_mknod created object %d count = %d\n",
2461 + obj->objectId, atomic_read(&inode->i_count)));
2462 + error = 0;
2463 + } else {
2464 + T(YAFFS_TRACE_OS,
2465 + (KERN_DEBUG "yaffs_mknod failed making object\n"));
2466 + error = -ENOMEM;
2467 + }
2468 +
2469 + return error;
2470 +}
2471 +
2472 +static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
2473 +{
2474 + int retVal;
2475 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mkdir\n"));
2476 + retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
2477 +#if 0
2478 + /* attempt to fix dir bug - didn't work */
2479 + if (!retVal) {
2480 + dget(dentry);
2481 + }
2482 +#endif
2483 + return retVal;
2484 +}
2485 +
2486 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2487 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
2488 + struct nameidata *n)
2489 +#else
2490 +static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
2491 +#endif
2492 +{
2493 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_create\n"));
2494 + return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
2495 +}
2496 +
2497 +static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
2498 +{
2499 + int retVal;
2500 +
2501 + yaffs_Device *dev;
2502 +
2503 + T(YAFFS_TRACE_OS,
2504 + (KERN_DEBUG "yaffs_unlink %d:%s\n", (int)(dir->i_ino),
2505 + dentry->d_name.name));
2506 +
2507 + dev = yaffs_InodeToObject(dir)->myDev;
2508 +
2509 + yaffs_GrossLock(dev);
2510 +
2511 + retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
2512 +
2513 + if (retVal == YAFFS_OK) {
2514 + dentry->d_inode->i_nlink--;
2515 + dir->i_version++;
2516 + yaffs_GrossUnlock(dev);
2517 + mark_inode_dirty(dentry->d_inode);
2518 + return 0;
2519 + }
2520 + yaffs_GrossUnlock(dev);
2521 + return -ENOTEMPTY;
2522 +}
2523 +
2524 +/*
2525 + * Create a link...
2526 + */
2527 +static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
2528 + struct dentry *dentry)
2529 +{
2530 + struct inode *inode = old_dentry->d_inode;
2531 + yaffs_Object *obj = NULL;
2532 + yaffs_Object *link = NULL;
2533 + yaffs_Device *dev;
2534 +
2535 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_link\n"));
2536 +
2537 + obj = yaffs_InodeToObject(inode);
2538 + dev = obj->myDev;
2539 +
2540 + yaffs_GrossLock(dev);
2541 +
2542 + if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
2543 + {
2544 + link =
2545 + yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
2546 + obj);
2547 + }
2548 +
2549 + if (link) {
2550 + old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
2551 + d_instantiate(dentry, old_dentry->d_inode);
2552 + atomic_inc(&old_dentry->d_inode->i_count);
2553 + T(YAFFS_TRACE_OS,
2554 + (KERN_DEBUG "yaffs_link link count %d i_count %d\n",
2555 + old_dentry->d_inode->i_nlink,
2556 + atomic_read(&old_dentry->d_inode->i_count)));
2557 +
2558 + }
2559 +
2560 + yaffs_GrossUnlock(dev);
2561 +
2562 + if (link) {
2563 +
2564 + return 0;
2565 + }
2566 +
2567 + return -EPERM;
2568 +}
2569 +
2570 +static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
2571 + const char *symname)
2572 +{
2573 + yaffs_Object *obj;
2574 + yaffs_Device *dev;
2575 + uid_t uid = current->fsuid;
2576 + gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
2577 +
2578 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_symlink\n"));
2579 +
2580 + dev = yaffs_InodeToObject(dir)->myDev;
2581 + yaffs_GrossLock(dev);
2582 + obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
2583 + S_IFLNK | S_IRWXUGO, uid, gid, symname);
2584 + yaffs_GrossUnlock(dev);
2585 +
2586 + if (obj) {
2587 +
2588 + struct inode *inode;
2589 +
2590 + inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
2591 + d_instantiate(dentry, inode);
2592 + T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink created OK\n"));
2593 + return 0;
2594 + } else {
2595 + T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink not created\n"));
2596 +
2597 + }
2598 +
2599 + return -ENOMEM;
2600 +}
2601 +
2602 +static int yaffs_sync_object(struct file *file, struct dentry *dentry,
2603 + int datasync)
2604 +{
2605 +
2606 + yaffs_Object *obj;
2607 + yaffs_Device *dev;
2608 +
2609 + obj = yaffs_DentryToObject(dentry);
2610 +
2611 + dev = obj->myDev;
2612 +
2613 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_object\n"));
2614 + yaffs_GrossLock(dev);
2615 + yaffs_FlushFile(obj, 1);
2616 + yaffs_GrossUnlock(dev);
2617 + return 0;
2618 +}
2619 +
2620 +/*
2621 + * The VFS layer already does all the dentry stuff for rename.
2622 + *
2623 + * NB: POSIX says you can rename an object over an old object of the same name
2624 + */
2625 +static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
2626 + struct inode *new_dir, struct dentry *new_dentry)
2627 +{
2628 + yaffs_Device *dev;
2629 + int retVal = YAFFS_FAIL;
2630 + yaffs_Object *target;
2631 +
2632 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_rename\n"));
2633 + dev = yaffs_InodeToObject(old_dir)->myDev;
2634 +
2635 + yaffs_GrossLock(dev);
2636 +
2637 + /* Check if the target is an existing directory that is not empty. */
2638 + target =
2639 + yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
2640 + new_dentry->d_name.name);
2641 +
2642 +
2643 +
2644 + if (target &&
2645 + target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
2646 + !list_empty(&target->variant.directoryVariant.children)) {
2647 +
2648 + T(YAFFS_TRACE_OS, (KERN_DEBUG "target is non-empty dir\n"));
2649 +
2650 + retVal = YAFFS_FAIL;
2651 + } else {
2652 +
2653 + /* Now does unlinking internally using shadowing mechanism */
2654 + T(YAFFS_TRACE_OS, (KERN_DEBUG "calling yaffs_RenameObject\n"));
2655 +
2656 + retVal =
2657 + yaffs_RenameObject(yaffs_InodeToObject(old_dir),
2658 + old_dentry->d_name.name,
2659 + yaffs_InodeToObject(new_dir),
2660 + new_dentry->d_name.name);
2661 +
2662 + }
2663 + yaffs_GrossUnlock(dev);
2664 +
2665 + if (retVal == YAFFS_OK) {
2666 + if(target) {
2667 + new_dentry->d_inode->i_nlink--;
2668 + mark_inode_dirty(new_dentry->d_inode);
2669 + }
2670 +
2671 + return 0;
2672 + } else {
2673 + return -ENOTEMPTY;
2674 + }
2675 +
2676 +}
2677 +
2678 +static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
2679 +{
2680 + struct inode *inode = dentry->d_inode;
2681 + int error;
2682 + yaffs_Device *dev;
2683 +
2684 + T(YAFFS_TRACE_OS,
2685 + (KERN_DEBUG "yaffs_setattr of object %d\n",
2686 + yaffs_InodeToObject(inode)->objectId));
2687 +
2688 + if ((error = inode_change_ok(inode, attr)) == 0) {
2689 +
2690 + dev = yaffs_InodeToObject(inode)->myDev;
2691 + yaffs_GrossLock(dev);
2692 + if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
2693 + YAFFS_OK) {
2694 + error = 0;
2695 + } else {
2696 + error = -EPERM;
2697 + }
2698 + yaffs_GrossUnlock(dev);
2699 + if (!error)
2700 + error = inode_setattr(inode, attr);
2701 + }
2702 + return error;
2703 +}
2704 +
2705 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
2706 +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
2707 +{
2708 + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
2709 + struct super_block *sb = dentry->d_sb;
2710 +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
2711 +static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
2712 +{
2713 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
2714 +#else
2715 +static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
2716 +{
2717 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
2718 +#endif
2719 +
2720 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_statfs\n"));
2721 +
2722 + yaffs_GrossLock(dev);
2723 +
2724 + buf->f_type = YAFFS_MAGIC;
2725 + buf->f_bsize = sb->s_blocksize;
2726 + buf->f_namelen = 255;
2727 + if (sb->s_blocksize > dev->nDataBytesPerChunk) {
2728 +
2729 + buf->f_blocks =
2730 + (dev->endBlock - dev->startBlock +
2731 + 1) * dev->nChunksPerBlock / (sb->s_blocksize /
2732 + dev->nDataBytesPerChunk);
2733 + buf->f_bfree =
2734 + yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize /
2735 + dev->nDataBytesPerChunk);
2736 + } else {
2737 +
2738 + buf->f_blocks =
2739 + (dev->endBlock - dev->startBlock +
2740 + 1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk /
2741 + sb->s_blocksize);
2742 + buf->f_bfree =
2743 + yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk /
2744 + sb->s_blocksize);
2745 + }
2746 + buf->f_files = 0;
2747 + buf->f_ffree = 0;
2748 + buf->f_bavail = buf->f_bfree;
2749 +
2750 + yaffs_GrossUnlock(dev);
2751 + return 0;
2752 +}
2753 +
2754 +
2755 +/**
2756 +static int yaffs_do_sync_fs(struct super_block *sb)
2757 +{
2758 +
2759 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
2760 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_do_sync_fs\n"));
2761 +
2762 + if(sb->s_dirt) {
2763 + yaffs_GrossLock(dev);
2764 +
2765 + if(dev)
2766 + yaffs_CheckpointSave(dev);
2767 +
2768 + yaffs_GrossUnlock(dev);
2769 +
2770 + sb->s_dirt = 0;
2771 + }
2772 + return 0;
2773 +}
2774 +**/
2775 +
2776 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
2777 +static void yaffs_write_super(struct super_block *sb)
2778 +#else
2779 +static int yaffs_write_super(struct super_block *sb)
2780 +#endif
2781 +{
2782 +
2783 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_super\n"));
2784 +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
2785 + return 0; /* yaffs_do_sync_fs(sb);*/
2786 +#endif
2787 +}
2788 +
2789 +
2790 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
2791 +static int yaffs_sync_fs(struct super_block *sb, int wait)
2792 +#else
2793 +static int yaffs_sync_fs(struct super_block *sb)
2794 +#endif
2795 +{
2796 +
2797 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n"));
2798 +
2799 + return 0; /* yaffs_do_sync_fs(sb);*/
2800 +
2801 +}
2802 +
2803 +
2804 +static void yaffs_read_inode(struct inode *inode)
2805 +{
2806 + /* NB This is called as a side effect of other functions, but
2807 + * we had to release the lock to prevent deadlocks, so
2808 + * need to lock again.
2809 + */
2810 +
2811 + yaffs_Object *obj;
2812 + yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
2813 +
2814 + T(YAFFS_TRACE_OS,
2815 + (KERN_DEBUG "yaffs_read_inode for %d\n", (int)inode->i_ino));
2816 +
2817 + yaffs_GrossLock(dev);
2818 +
2819 + obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
2820 +
2821 + yaffs_FillInodeFromObject(inode, obj);
2822 +
2823 + yaffs_GrossUnlock(dev);
2824 +}
2825 +
2826 +static LIST_HEAD(yaffs_dev_list);
2827 +
2828 +static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
2829 +{
2830 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
2831 +
2832 + if( *flags & MS_RDONLY ) {
2833 + struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
2834 +
2835 + T(YAFFS_TRACE_OS,
2836 + (KERN_DEBUG "yaffs_remount_fs: %s: RO\n", dev->name ));
2837 +
2838 + yaffs_GrossLock(dev);
2839 +
2840 + yaffs_FlushEntireDeviceCache(dev);
2841 +
2842 + yaffs_CheckpointSave(dev);
2843 +
2844 + if (mtd->sync)
2845 + mtd->sync(mtd);
2846 +
2847 + yaffs_GrossUnlock(dev);
2848 + }
2849 + else {
2850 + T(YAFFS_TRACE_OS,
2851 + (KERN_DEBUG "yaffs_remount_fs: %s: RW\n", dev->name ));
2852 + }
2853 +
2854 + return 0;
2855 +}
2856 +
2857 +static void yaffs_put_super(struct super_block *sb)
2858 +{
2859 + yaffs_Device *dev = yaffs_SuperToDevice(sb);
2860 +
2861 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_put_super\n"));
2862 +
2863 + yaffs_GrossLock(dev);
2864 +
2865 + yaffs_FlushEntireDeviceCache(dev);
2866 +
2867 + yaffs_CheckpointSave(dev);
2868 +
2869 + if (dev->putSuperFunc) {
2870 + dev->putSuperFunc(sb);
2871 + }
2872 +
2873 + yaffs_Deinitialise(dev);
2874 +
2875 + yaffs_GrossUnlock(dev);
2876 +
2877 + /* we assume this is protected by lock_kernel() in mount/umount */
2878 + list_del(&dev->devList);
2879 +
2880 + if(dev->spareBuffer){
2881 + YFREE(dev->spareBuffer);
2882 + dev->spareBuffer = NULL;
2883 + }
2884 +
2885 + kfree(dev);
2886 +}
2887 +
2888 +
2889 +static void yaffs_MTDPutSuper(struct super_block *sb)
2890 +{
2891 +
2892 + struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
2893 +
2894 + if (mtd->sync) {
2895 + mtd->sync(mtd);
2896 + }
2897 +
2898 + put_mtd_device(mtd);
2899 +}
2900 +
2901 +
2902 +static void yaffs_MarkSuperBlockDirty(void *vsb)
2903 +{
2904 + struct super_block *sb = (struct super_block *)vsb;
2905 +
2906 + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_MarkSuperBlockDirty() sb = %p\n",sb));
2907 +// if(sb)
2908 +// sb->s_dirt = 1;
2909 +}
2910 +
2911 +typedef struct {
2912 + int inband_tags;
2913 + int skip_checkpoint_read;
2914 + int skip_checkpoint_write;
2915 + int no_cache;
2916 +} yaffs_options;
2917 +
2918 +#define MAX_OPT_LEN 20
2919 +static int yaffs_parse_options(yaffs_options *options, const char *options_str)
2920 +{
2921 + char cur_opt[MAX_OPT_LEN+1];
2922 + int p;
2923 + int error = 0;
2924 +
2925 + /* Parse through the options which is a comma seperated list */
2926 +
2927 + while(options_str && *options_str && !error){
2928 + memset(cur_opt,0,MAX_OPT_LEN+1);
2929 + p = 0;
2930 +
2931 + while(*options_str && *options_str != ','){
2932 + if(p < MAX_OPT_LEN){
2933 + cur_opt[p] = *options_str;
2934 + p++;
2935 + }
2936 + options_str++;
2937 + }
2938 +
2939 + if(!strcmp(cur_opt,"inband-tags"))
2940 + options->inband_tags = 1;
2941 + else if(!strcmp(cur_opt,"no-cache"))
2942 + options->no_cache = 1;
2943 + else if(!strcmp(cur_opt,"no-checkpoint-read"))
2944 + options->skip_checkpoint_read = 1;
2945 + else if(!strcmp(cur_opt,"no-checkpoint-write"))
2946 + options->skip_checkpoint_write = 1;
2947 + else if(!strcmp(cur_opt,"no-checkpoint")){
2948 + options->skip_checkpoint_read = 1;
2949 + options->skip_checkpoint_write = 1;
2950 + } else {
2951 + printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",cur_opt);
2952 + error = 1;
2953 + }
2954 +
2955 + }
2956 +
2957 + return error;
2958 +}
2959 +
2960 +static struct super_block *yaffs_internal_read_super(int yaffsVersion,
2961 + struct super_block *sb,
2962 + void *data, int silent)
2963 +{
2964 + int nBlocks;
2965 + struct inode *inode = NULL;
2966 + struct dentry *root;
2967 + yaffs_Device *dev = 0;
2968 + char devname_buf[BDEVNAME_SIZE + 1];
2969 + struct mtd_info *mtd;
2970 + int err;
2971 + char *data_str = (char *)data;
2972 +
2973 + yaffs_options options;
2974 +
2975 + sb->s_magic = YAFFS_MAGIC;
2976 + sb->s_op = &yaffs_super_ops;
2977 +
2978 + if (!sb)
2979 + printk(KERN_INFO "yaffs: sb is NULL\n");
2980 + else if (!sb->s_dev)
2981 + printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
2982 + else if (!yaffs_devname(sb, devname_buf))
2983 + printk(KERN_INFO "yaffs: devname is NULL\n");
2984 + else
2985 + printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
2986 + sb->s_dev,
2987 + yaffs_devname(sb, devname_buf));
2988 +
2989 + if(!data_str)
2990 + data_str = "";
2991 +
2992 + printk(KERN_INFO "yaffs: passed flags \"%s\"\n",data_str);
2993 +
2994 + memset(&options,0,sizeof(options));
2995 +
2996 + if(yaffs_parse_options(&options,data_str)){
2997 + /* Option parsing failed */
2998 + return NULL;
2999 + }
3000 +
3001 +
3002 + sb->s_blocksize = PAGE_CACHE_SIZE;
3003 + sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
3004 + T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
3005 + T(YAFFS_TRACE_OS,
3006 + ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
3007 +
3008 +#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
3009 + T(YAFFS_TRACE_OS,
3010 + ("yaffs: Write verification disabled. All guarantees "
3011 + "null and void\n"));
3012 +#endif
3013 +
3014 + T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
3015 + "\"%s\"\n",
3016 + MAJOR(sb->s_dev), MINOR(sb->s_dev),
3017 + yaffs_devname(sb, devname_buf)));
3018 +
3019 + /* Check it's an mtd device..... */
3020 + if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) {
3021 + return NULL; /* This isn't an mtd device */
3022 + }
3023 + /* Get the device */
3024 + mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
3025 + if (!mtd) {
3026 + T(YAFFS_TRACE_ALWAYS,
3027 + ("yaffs: MTD device #%u doesn't appear to exist\n",
3028 + MINOR(sb->s_dev)));
3029 + return NULL;
3030 + }
3031 + /* Check it's NAND */
3032 + if (mtd->type != MTD_NANDFLASH) {
3033 + T(YAFFS_TRACE_ALWAYS,
3034 + ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
3035 + return NULL;
3036 + }
3037 +
3038 + T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
3039 + T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
3040 + T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
3041 + T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
3042 + T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
3043 + T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
3044 + T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
3045 + T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
3046 + T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
3047 + T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
3048 + T(YAFFS_TRACE_OS, (" size %d\n", mtd->size));
3049 +
3050 +#ifdef CONFIG_YAFFS_AUTO_YAFFS2
3051 +
3052 + if (yaffsVersion == 1 &&
3053 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
3054 + mtd->writesize >= 2048) {
3055 +#else
3056 + mtd->oobblock >= 2048) {
3057 +#endif
3058 + T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
3059 + yaffsVersion = 2;
3060 + }
3061 +
3062 + /* Added NCB 26/5/2006 for completeness */
3063 + if (yaffsVersion == 2 &&
3064 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
3065 + mtd->writesize == 512) {
3066 +#else
3067 + mtd->oobblock == 512) {
3068 +#endif
3069 + T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
3070 + yaffsVersion = 1;
3071 + }
3072 +
3073 +#endif
3074 +
3075 + if (yaffsVersion == 2) {
3076 + /* Check for version 2 style functions */
3077 + if (!mtd->erase ||
3078 + !mtd->block_isbad ||
3079 + !mtd->block_markbad ||
3080 + !mtd->read ||
3081 + !mtd->write ||
3082 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
3083 + !mtd->read_oob || !mtd->write_oob) {
3084 +#else
3085 + !mtd->write_ecc ||
3086 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3087 +#endif
3088 + T(YAFFS_TRACE_ALWAYS,
3089 + ("yaffs: MTD device does not support required "
3090 + "functions\n"));;
3091 + return NULL;
3092 + }
3093 +
3094 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
3095 + if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
3096 +#else
3097 + if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
3098 +#endif
3099 + mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) {
3100 + T(YAFFS_TRACE_ALWAYS,
3101 + ("yaffs: MTD device does not have the "
3102 + "right page sizes\n"));
3103 + return NULL;
3104 + }
3105 + } else {
3106 + /* Check for V1 style functions */
3107 + if (!mtd->erase ||
3108 + !mtd->read ||
3109 + !mtd->write ||
3110 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
3111 + !mtd->read_oob || !mtd->write_oob) {
3112 +#else
3113 + !mtd->write_ecc ||
3114 + !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
3115 +#endif
3116 + T(YAFFS_TRACE_ALWAYS,
3117 + ("yaffs: MTD device does not support required "
3118 + "functions\n"));;
3119 + return NULL;
3120 + }
3121 +
3122 + if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
3123 + mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
3124 + T(YAFFS_TRACE_ALWAYS,
3125 + ("yaffs: MTD device does not support have the "
3126 + "right page sizes\n"));
3127 + return NULL;
3128 + }
3129 + }
3130 +
3131 + /* OK, so if we got here, we have an MTD that's NAND and looks
3132 + * like it has the right capabilities
3133 + * Set the yaffs_Device up for mtd
3134 + */
3135 +
3136 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
3137 + sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3138 +#else
3139 + sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
3140 +#endif
3141 + if (!dev) {
3142 + /* Deep shit could not allocate device structure */
3143 + T(YAFFS_TRACE_ALWAYS,
3144 + ("yaffs_read_super: Failed trying to allocate "
3145 + "yaffs_Device. \n"));
3146 + return NULL;
3147 + }
3148 +
3149 + memset(dev, 0, sizeof(yaffs_Device));
3150 + dev->genericDevice = mtd;
3151 + dev->name = mtd->name;
3152 +
3153 + /* Set up the memory size parameters.... */
3154 +
3155 + nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
3156 + dev->startBlock = 0;
3157 + dev->endBlock = nBlocks - 1;
3158 + dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
3159 + dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
3160 + dev->nReservedBlocks = 5;
3161 + dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
3162 +
3163 + /* ... and the functions. */
3164 + if (yaffsVersion == 2) {
3165 + dev->writeChunkWithTagsToNAND =
3166 + nandmtd2_WriteChunkWithTagsToNAND;
3167 + dev->readChunkWithTagsFromNAND =
3168 + nandmtd2_ReadChunkWithTagsFromNAND;
3169 + dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
3170 + dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
3171 + dev->spareBuffer = YMALLOC(mtd->oobsize);
3172 + dev->isYaffs2 = 1;
3173 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
3174 + dev->nDataBytesPerChunk = mtd->writesize;
3175 + dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
3176 +#else
3177 + dev->nDataBytesPerChunk = mtd->oobblock;
3178 + dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
3179 +#endif
3180 + nBlocks = mtd->size / mtd->erasesize;
3181 +
3182 + dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS;
3183 + dev->startBlock = 0;
3184 + dev->endBlock = nBlocks - 1;
3185 + } else {
3186 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
3187 + /* use the MTD interface in yaffs_mtdif1.c */
3188 + dev->writeChunkWithTagsToNAND =
3189 + nandmtd1_WriteChunkWithTagsToNAND;
3190 + dev->readChunkWithTagsFromNAND =
3191 + nandmtd1_ReadChunkWithTagsFromNAND;
3192 + dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
3193 + dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
3194 +#else
3195 + dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
3196 + dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
3197 +#endif
3198 + dev->isYaffs2 = 0;
3199 + }
3200 + /* ... and common functions */
3201 + dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
3202 + dev->initialiseNAND = nandmtd_InitialiseNAND;
3203 +
3204 + dev->putSuperFunc = yaffs_MTDPutSuper;
3205 +
3206 + dev->superBlock = (void *)sb;
3207 + dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
3208 +
3209 +
3210 +#ifndef CONFIG_YAFFS_DOES_ECC
3211 + dev->useNANDECC = 1;
3212 +#endif
3213 +
3214 +#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
3215 + dev->wideTnodesDisabled = 1;
3216 +#endif
3217 +
3218 + dev->skipCheckpointRead = options.skip_checkpoint_read;
3219 + dev->skipCheckpointWrite = options.skip_checkpoint_write;
3220 +
3221 + /* we assume this is protected by lock_kernel() in mount/umount */
3222 + list_add_tail(&dev->devList, &yaffs_dev_list);
3223 +
3224 + init_MUTEX(&dev->grossLock);
3225 +
3226 + yaffs_GrossLock(dev);
3227 +
3228 + err = yaffs_GutsInitialise(dev);
3229 +
3230 + T(YAFFS_TRACE_OS,
3231 + ("yaffs_read_super: guts initialised %s\n",
3232 + (err == YAFFS_OK) ? "OK" : "FAILED"));
3233 +
3234 + /* Release lock before yaffs_get_inode() */
3235 + yaffs_GrossUnlock(dev);
3236 +
3237 + /* Create root inode */
3238 + if (err == YAFFS_OK)
3239 + inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
3240 + yaffs_Root(dev));
3241 +
3242 + if (!inode)
3243 + return NULL;
3244 +
3245 + inode->i_op = &yaffs_dir_inode_operations;
3246 + inode->i_fop = &yaffs_dir_operations;
3247 +
3248 + T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
3249 +
3250 + root = d_alloc_root(inode);
3251 +
3252 + T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
3253 +
3254 + if (!root) {
3255 + iput(inode);
3256 + return NULL;
3257 + }
3258 + sb->s_root = root;
3259 +
3260 + T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
3261 + return sb;
3262 +}
3263 +
3264 +
3265 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
3266 +static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
3267 + int silent)
3268 +{
3269 + return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
3270 +}
3271 +
3272 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
3273 +static int yaffs_read_super(struct file_system_type *fs,
3274 + int flags, const char *dev_name,
3275 + void *data, struct vfsmount *mnt)
3276 +{
3277 +
3278 + return get_sb_bdev(fs, flags, dev_name, data,
3279 + yaffs_internal_read_super_mtd, mnt);
3280 +}
3281 +#else
3282 +static struct super_block *yaffs_read_super(struct file_system_type *fs,
3283 + int flags, const char *dev_name,
3284 + void *data)
3285 +{
3286 +
3287 + return get_sb_bdev(fs, flags, dev_name, data,
3288 + yaffs_internal_read_super_mtd);
3289 +}
3290 +#endif
3291 +
3292 +static struct file_system_type yaffs_fs_type = {
3293 + .owner = THIS_MODULE,
3294 + .name = "yaffs",
3295 + .get_sb = yaffs_read_super,
3296 + .kill_sb = kill_block_super,
3297 + .fs_flags = FS_REQUIRES_DEV,
3298 +};
3299 +#else
3300 +static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
3301 + int silent)
3302 +{
3303 + return yaffs_internal_read_super(1, sb, data, silent);
3304 +}
3305 +
3306 +static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
3307 + FS_REQUIRES_DEV);
3308 +#endif
3309 +
3310 +
3311 +#ifdef CONFIG_YAFFS_YAFFS2
3312 +
3313 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
3314 +static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
3315 + int silent)
3316 +{
3317 + return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
3318 +}
3319 +
3320 +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
3321 +static int yaffs2_read_super(struct file_system_type *fs,
3322 + int flags, const char *dev_name, void *data,
3323 + struct vfsmount *mnt)
3324 +{
3325 + return get_sb_bdev(fs, flags, dev_name, data,
3326 + yaffs2_internal_read_super_mtd, mnt);
3327 +}
3328 +#else
3329 +static struct super_block *yaffs2_read_super(struct file_system_type *fs,
3330 + int flags, const char *dev_name,
3331 + void *data)
3332 +{
3333 +
3334 + return get_sb_bdev(fs, flags, dev_name, data,
3335 + yaffs2_internal_read_super_mtd);
3336 +}
3337 +#endif
3338 +
3339 +static struct file_system_type yaffs2_fs_type = {
3340 + .owner = THIS_MODULE,
3341 + .name = "yaffs2",
3342 + .get_sb = yaffs2_read_super,
3343 + .kill_sb = kill_block_super,
3344 + .fs_flags = FS_REQUIRES_DEV,
3345 +};
3346 +#else
3347 +static struct super_block *yaffs2_read_super(struct super_block *sb,
3348 + void *data, int silent)
3349 +{
3350 + return yaffs_internal_read_super(2, sb, data, silent);
3351 +}
3352 +
3353 +static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
3354 + FS_REQUIRES_DEV);
3355 +#endif
3356 +
3357 +#endif /* CONFIG_YAFFS_YAFFS2 */
3358 +
3359 +static struct proc_dir_entry *my_proc_entry;
3360 +
3361 +static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
3362 +{
3363 + buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
3364 + buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
3365 + buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
3366 + buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
3367 + buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
3368 + buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
3369 + buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
3370 + buf += sprintf(buf, "nCheckptResBlocks.. %d\n", dev->nCheckpointReservedBlocks);
3371 + buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
3372 + buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
3373 + buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
3374 + buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
3375 + buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
3376 + buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
3377 + buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
3378 + buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
3379 + buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
3380 + buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
3381 + buf +=
3382 + sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
3383 + buf +=
3384 + sprintf(buf, "passiveGCs......... %d\n",
3385 + dev->passiveGarbageCollections);
3386 + buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
3387 + buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
3388 + buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
3389 + buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
3390 + buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
3391 + buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
3392 + buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
3393 + buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
3394 + buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
3395 + buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
3396 + buf +=
3397 + sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
3398 + buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
3399 + buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
3400 +
3401 + return buf;
3402 +}
3403 +
3404 +static int yaffs_proc_read(char *page,
3405 + char **start,
3406 + off_t offset, int count, int *eof, void *data)
3407 +{
3408 + struct list_head *item;
3409 + char *buf = page;
3410 + int step = offset;
3411 + int n = 0;
3412 +
3413 + /* Get proc_file_read() to step 'offset' by one on each sucessive call.
3414 + * We use 'offset' (*ppos) to indicate where we are in devList.
3415 + * This also assumes the user has posted a read buffer large
3416 + * enough to hold the complete output; but that's life in /proc.
3417 + */
3418 +
3419 + *(int *)start = 1;
3420 +
3421 + /* Print header first */
3422 + if (step == 0) {
3423 + buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
3424 + "\n%s\n%s\n", yaffs_fs_c_version,
3425 + yaffs_guts_c_version);
3426 + }
3427 +
3428 + /* hold lock_kernel while traversing yaffs_dev_list */
3429 + lock_kernel();
3430 +
3431 + /* Locate and print the Nth entry. Order N-squared but N is small. */
3432 + list_for_each(item, &yaffs_dev_list) {
3433 + yaffs_Device *dev = list_entry(item, yaffs_Device, devList);
3434 + if (n < step) {
3435 + n++;
3436 + continue;
3437 + }
3438 + buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
3439 + buf = yaffs_dump_dev(buf, dev);
3440 + break;
3441 + }
3442 + unlock_kernel();
3443 +
3444 + return buf - page < count ? buf - page : count;
3445 +}
3446 +
3447 +/**
3448 + * Set the verbosity of the warnings and error messages.
3449 + *
3450 + * Note that the names can only be a..z or _ with the current code.
3451 + */
3452 +
3453 +static struct {
3454 + char *mask_name;
3455 + unsigned mask_bitfield;
3456 +} mask_flags[] = {
3457 + {"allocate", YAFFS_TRACE_ALLOCATE},
3458 + {"always", YAFFS_TRACE_ALWAYS},
3459 + {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
3460 + {"buffers", YAFFS_TRACE_BUFFERS},
3461 + {"bug", YAFFS_TRACE_BUG},
3462 + {"checkpt", YAFFS_TRACE_CHECKPOINT},
3463 + {"deletion", YAFFS_TRACE_DELETION},
3464 + {"erase", YAFFS_TRACE_ERASE},
3465 + {"error", YAFFS_TRACE_ERROR},
3466 + {"gc_detail", YAFFS_TRACE_GC_DETAIL},
3467 + {"gc", YAFFS_TRACE_GC},
3468 + {"mtd", YAFFS_TRACE_MTD},
3469 + {"nandaccess", YAFFS_TRACE_NANDACCESS},
3470 + {"os", YAFFS_TRACE_OS},
3471 + {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
3472 + {"scan", YAFFS_TRACE_SCAN},
3473 + {"tracing", YAFFS_TRACE_TRACING},
3474 +
3475 + {"verify", YAFFS_TRACE_VERIFY},
3476 + {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
3477 + {"verify_full", YAFFS_TRACE_VERIFY_FULL},
3478 + {"verify_all", YAFFS_TRACE_VERIFY_ALL},
3479 +
3480 + {"write", YAFFS_TRACE_WRITE},
3481 + {"all", 0xffffffff},
3482 + {"none", 0},
3483 + {NULL, 0},
3484 +};
3485 +
3486 +#define MAX_MASK_NAME_LENGTH 40
3487 +static int yaffs_proc_write(struct file *file, const char *buf,
3488 + unsigned long count, void *data)
3489 +{
3490 + unsigned rg = 0, mask_bitfield;
3491 + char *end;
3492 + char *mask_name;
3493 + char *x;
3494 + char substring[MAX_MASK_NAME_LENGTH+1];
3495 + int i;
3496 + int done = 0;
3497 + int add, len = 0;
3498 + int pos = 0;
3499 +
3500 + rg = yaffs_traceMask;
3501 +
3502 + while (!done && (pos < count)) {
3503 + done = 1;
3504 + while ((pos < count) && isspace(buf[pos])) {
3505 + pos++;
3506 + }
3507 +
3508 + switch (buf[pos]) {
3509 + case '+':
3510 + case '-':
3511 + case '=':
3512 + add = buf[pos];
3513 + pos++;
3514 + break;
3515 +
3516 + default:
3517 + add = ' ';
3518 + break;
3519 + }
3520 + mask_name = NULL;
3521 +
3522 + mask_bitfield = simple_strtoul(buf + pos, &end, 0);
3523 + if (end > buf + pos) {
3524 + mask_name = "numeral";
3525 + len = end - (buf + pos);
3526 + done = 0;
3527 + } else {
3528 + for(x = buf + pos, i = 0;
3529 + (*x == '_' || (*x >='a' && *x <= 'z')) &&
3530 + i <MAX_MASK_NAME_LENGTH; x++, i++, pos++)
3531 + substring[i] = *x;
3532 + substring[i] = '\0';
3533 +