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