summaryrefslogtreecommitdiff
path: root/target/linux/generic/files/fs/yaffs2/yaffs_guts.h
blob: 05785367cb2e30a00daba4f928165d14ddaf0c33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
/*
 * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
 *
 * Copyright (C) 2002-2011 Aleph One Ltd.
 *   for Toby Churchill Ltd and Brightstar Engineering
 *
 * Created by Charles Manning <charles@aleph1.co.uk>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 2.1 as
 * published by the Free Software Foundation.
 *
 * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
 */

#ifndef __YAFFS_GUTS_H__
#define __YAFFS_GUTS_H__

#include "yportenv.h"

#define YAFFS_OK	1
#define YAFFS_FAIL  0

/* Give us a  Y=0x59,
 * Give us an A=0x41,
 * Give us an FF=0xff
 * Give us an S=0x53
 * And what have we got...
 */
#define YAFFS_MAGIC			0x5941ff53

/*
 * Tnodes form a tree with the tnodes in "levels"
 * Levels greater than 0 hold 8 slots which point to other tnodes.
 * Those at level 0 hold 16 slots which point to chunks in NAND.
 *
 * A maximum level of 8 thust supports files of size up to:
 *
 * 2^(3*MAX_LEVEL+4)
 *
 * Thus a max level of 8 supports files with up to 2^^28 chunks which gives
 * a maximum file size of around 512Gbytees with 2k chunks.
 */
#define YAFFS_NTNODES_LEVEL0		16
#define YAFFS_TNODES_LEVEL0_BITS	4
#define YAFFS_TNODES_LEVEL0_MASK	0xf

#define YAFFS_NTNODES_INTERNAL		(YAFFS_NTNODES_LEVEL0 / 2)
#define YAFFS_TNODES_INTERNAL_BITS	(YAFFS_TNODES_LEVEL0_BITS - 1)
#define YAFFS_TNODES_INTERNAL_MASK	0x7
#define YAFFS_TNODES_MAX_LEVEL		8
#define YAFFS_TNODES_MAX_BITS		(YAFFS_TNODES_LEVEL0_BITS + \
					YAFFS_TNODES_INTERNAL_BITS * \
					YAFFS_TNODES_MAX_LEVEL)
#define YAFFS_MAX_CHUNK_ID		((1 << YAFFS_TNODES_MAX_BITS) - 1)

#define YAFFS_MAX_FILE_SIZE_32		0x7fffffff

/* Constants for YAFFS1 mode */
#define YAFFS_BYTES_PER_SPARE		16
#define YAFFS_BYTES_PER_CHUNK		512
#define YAFFS_CHUNK_SIZE_SHIFT		9
#define YAFFS_CHUNKS_PER_BLOCK		32
#define YAFFS_BYTES_PER_BLOCK	(YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)

#define YAFFS_MIN_YAFFS2_CHUNK_SIZE	1024
#define YAFFS_MIN_YAFFS2_SPARE_SIZE	32



#define YAFFS_ALLOCATION_NOBJECTS	100
#define YAFFS_ALLOCATION_NTNODES	100
#define YAFFS_ALLOCATION_NLINKS		100

#define YAFFS_NOBJECT_BUCKETS		256

#define YAFFS_OBJECT_SPACE		0x40000
#define YAFFS_MAX_OBJECT_ID		(YAFFS_OBJECT_SPACE - 1)

/* Binary data version stamps */
#define YAFFS_SUMMARY_VERSION		1
#define YAFFS_CHECKPOINT_VERSION	7

#ifdef CONFIG_YAFFS_UNICODE
#define YAFFS_MAX_NAME_LENGTH		127
#define YAFFS_MAX_ALIAS_LENGTH		79
#else
#define YAFFS_MAX_NAME_LENGTH		255
#define YAFFS_MAX_ALIAS_LENGTH		159
#endif

#define YAFFS_SHORT_NAME_LENGTH		15

/* Some special object ids for pseudo objects */
#define YAFFS_OBJECTID_ROOT		1
#define YAFFS_OBJECTID_LOSTNFOUND	2
#define YAFFS_OBJECTID_UNLINKED		3
#define YAFFS_OBJECTID_DELETED		4

/* Fake object Id for summary data */
#define YAFFS_OBJECTID_SUMMARY		0x10

/* Pseudo object ids for checkpointing */
#define YAFFS_OBJECTID_CHECKPOINT_DATA	0x20
#define YAFFS_SEQUENCE_CHECKPOINT_DATA	0x21

#define YAFFS_MAX_SHORT_OP_CACHES	20

#define YAFFS_N_TEMP_BUFFERS		6

/* We limit the number attempts at sucessfully saving a chunk of data.
 * Small-page devices have 32 pages per block; large-page devices have 64.
 * Default to something in the order of 5 to 10 blocks worth of chunks.
 */
#define YAFFS_WR_ATTEMPTS		(5*64)

/* Sequence numbers are used in YAFFS2 to determine block allocation order.
 * The range is limited slightly to help distinguish bad numbers from good.
 * This also allows us to perhaps in the future use special numbers for
 * special purposes.
 * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years,
 * and is a larger number than the lifetime of a 2GB device.
 */
#define YAFFS_LOWEST_SEQUENCE_NUMBER	0x00001000
#define YAFFS_HIGHEST_SEQUENCE_NUMBER	0xefffff00

/* Special sequence number for bad block that failed to be marked bad */
#define YAFFS_SEQUENCE_BAD_BLOCK	0xffff0000

/* ChunkCache is used for short read/write operations.*/
struct yaffs_cache {
	struct yaffs_obj *object;
	int chunk_id;
	int last_use;
	int dirty;
	int n_bytes;		/* Only valid if the cache is dirty */
	int locked;		/* Can't push out or flush while locked. */
	u8 *data;
};

/* yaffs1 tags structures in RAM
 * NB This uses bitfield. Bitfields should not straddle a u32 boundary
 * otherwise the structure size will get blown out.
 */

struct yaffs_tags {
	unsigned chunk_id:20;
	unsigned serial_number:2;
	unsigned n_bytes_lsb:10;
	unsigned obj_id:18;
	unsigned ecc:12;
	unsigned n_bytes_msb:2;
};

union yaffs_tags_union {
	struct yaffs_tags as_tags;
	u8 as_bytes[8];
};


/* Stuff used for extended tags in YAFFS2 */

enum yaffs_ecc_result {
	YAFFS_ECC_RESULT_UNKNOWN,
	YAFFS_ECC_RESULT_NO_ERROR,
	YAFFS_ECC_RESULT_FIXED,
	YAFFS_ECC_RESULT_UNFIXED
};

enum yaffs_obj_type {
	YAFFS_OBJECT_TYPE_UNKNOWN,
	YAFFS_OBJECT_TYPE_FILE,
	YAFFS_OBJECT_TYPE_SYMLINK,
	YAFFS_OBJECT_TYPE_DIRECTORY,
	YAFFS_OBJECT_TYPE_HARDLINK,
	YAFFS_OBJECT_TYPE_SPECIAL
};

#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL

struct yaffs_ext_tags {
	unsigned chunk_used;	/*  Status of the chunk: used or unused */
	unsigned obj_id;	/* If 0 this is not used */
	unsigned chunk_id;	/* If 0 this is a header, else a data chunk */
	unsigned n_bytes;	/* Only valid for data chunks */

	/* The following stuff only has meaning when we read */
	enum yaffs_ecc_result ecc_result;
	unsigned block_bad;

	/* YAFFS 1 stuff */
	unsigned is_deleted;	/* The chunk is marked deleted */
	unsigned serial_number;	/* Yaffs1 2-bit serial number */

	/* YAFFS2 stuff */
	unsigned seq_number;	/* The sequence number of this block */

	/* Extra info if this is an object header (YAFFS2 only) */

	unsigned extra_available;	/* Extra info available if not zero */
	unsigned extra_parent_id;	/* The parent object */
	unsigned extra_is_shrink;	/* Is it a shrink header? */
	unsigned extra_shadows;	/* Does this shadow another object? */

	enum yaffs_obj_type extra_obj_type;	/* What object type? */

	loff_t extra_file_size;		/* Length if it is a file */
	unsigned extra_equiv_id;	/* Equivalent object for a hard link */
};

/* Spare structure for YAFFS1 */
struct yaffs_spare {
	u8 tb0;
	u8 tb1;
	u8 tb2;
	u8 tb3;
	u8 page_status;		/* set to 0 to delete the chunk */
	u8 block_status;
	u8 tb4;
	u8 tb5;
	u8 ecc1[3];
	u8 tb6;
	u8 tb7;
	u8 ecc2[3];
};

/*Special structure for passing through to mtd */
struct yaffs_nand_spare {
	struct yaffs_spare spare;
	int eccres1;
	int eccres2;
};

/* Block data in RAM */

enum yaffs_block_state {
	YAFFS_BLOCK_STATE_UNKNOWN = 0,

	YAFFS_BLOCK_STATE_SCANNING,
	/* Being scanned */

	YAFFS_BLOCK_STATE_NEEDS_SCAN,
	/* The block might have something on it (ie it is allocating or full,
	 * perhaps empty) but it needs to be scanned to determine its true
	 * state.
	 * This state is only valid during scanning.
	 * NB We tolerate empty because the pre-scanner might be incapable of
	 * deciding
	 * However, if this state is returned on a YAFFS2 device,
	 * then we expect a sequence number
	 */

	YAFFS_BLOCK_STATE_EMPTY,
	/* This block is empty */

	YAFFS_BLOCK_STATE_ALLOCATING,
	/* This block is partially allocated.
	 * At least one page holds valid data.
	 * This is the one currently being used for page
	 * allocation. Should never be more than one of these.
	 * If a block is only partially allocated at mount it is treated as
	 * full.
	 */

	YAFFS_BLOCK_STATE_FULL,
	/* All the pages in this block have been allocated.
	 * If a block was only partially allocated when mounted we treat
	 * it as fully allocated.
	 */

	YAFFS_BLOCK_STATE_DIRTY,
	/* The block was full and now all chunks have been deleted.
	 * Erase me, reuse me.
	 */

	YAFFS_BLOCK_STATE_CHECKPOINT,
	/* This block is assigned to holding checkpoint data. */

	YAFFS_BLOCK_STATE_COLLECTING,
	/* This block is being garbage collected */

	YAFFS_BLOCK_STATE_DEAD
	    /* This block has failed and is not in use */
};

#define	YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)

struct yaffs_block_info {

	int soft_del_pages:10;	/* number of soft deleted pages */
	int pages_in_use:10;	/* number of pages in use */
	unsigned block_state:4;	/* One of the above block states. */
				/* NB use unsigned because enum is sometimes
				 * an int */
	u32 needs_retiring:1;	/* Data has failed on this block, */
				/*need to get valid data off and retire*/
	u32 skip_erased_check:1;/* Skip the erased check on this block */
	u32 gc_prioritise:1;	/* An ECC check or blank check has failed.
				   Block should be prioritised for GC */
	u32 chunk_error_strikes:3;	/* How many times we've had ecc etc
				failures on this block and tried to reuse it */
	u32 has_summary:1;	/* The block has a summary */

	u32 has_shrink_hdr:1;	/* This block has at least one shrink header */
	u32 seq_number;		/* block sequence number for yaffs2 */

};

/* -------------------------- Object structure -------------------------------*/
/* This is the object structure as stored on NAND */

struct yaffs_obj_hdr {
	enum yaffs_obj_type type;

	/* Apply to everything  */
	int parent_obj_id;
	u16 sum_no_longer_used;	/* checksum of name. No longer used */
	YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];

	/* The following apply to all object types except for hard links */
	u32 yst_mode;		/* protection */

	u32 yst_uid;
	u32 yst_gid;
	u32 yst_atime;
	u32 yst_mtime;
	u32 yst_ctime;

	/* File size  applies to files only */
	u32 file_size_low;

	/* Equivalent object id applies to hard links only. */
	int equiv_id;

	/* Alias is for symlinks only. */
	YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];

	u32 yst_rdev;	/* stuff for block and char devices (major/min) */

	u32 win_ctime[2];
	u32 win_atime[2];
	u32 win_mtime[2];

	u32 inband_shadowed_obj_id;
	u32 inband_is_shrink;

	u32 file_size_high;
	u32 reserved[1];
	int shadows_obj;	/* This object header shadows the
				specified object if > 0 */

	/* is_shrink applies to object headers written when wemake a hole. */
	u32 is_shrink;

};

/*--------------------------- Tnode -------------------------- */

struct yaffs_tnode {
	struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];
};

/*------------------------  Object -----------------------------*/
/* An object can be one of:
 * - a directory (no data, has children links
 * - a regular file (data.... not prunes :->).
 * - a symlink [symbolic link] (the alias).
 * - a hard link
 */

struct yaffs_file_var {
	loff_t file_size;
	loff_t scanned_size;
	loff_t shrink_size;
	int top_level;
	struct yaffs_tnode *top;
};

struct yaffs_dir_var {
	struct list_head children;	/* list of child links */
	struct list_head dirty;	/* Entry for list of dirty directories */
};

struct yaffs_symlink_var {
	YCHAR *alias;
};

struct yaffs_hardlink_var {
	struct yaffs_obj *equiv_obj;
	u32 equiv_id;
};

union yaffs_obj_var {
	struct yaffs_file_var file_variant;
	struct yaffs_dir_var dir_variant;
	struct yaffs_symlink_var symlink_variant;
	struct yaffs_hardlink_var hardlink_variant;
};

struct yaffs_obj {
	u8 deleted:1;		/* This should only apply to unlinked files. */
	u8 soft_del:1;		/* it has also been soft deleted */
	u8 unlinked:1;		/* An unlinked file.*/
	u8 fake:1;		/* A fake object has no presence on NAND. */
	u8 rename_allowed:1;	/* Some objects cannot be renamed. */
	u8 unlink_allowed:1;
	u8 dirty:1;		/* the object needs to be written to flash */
	u8 valid:1;		/* When the file system is being loaded up, this
				 * object might be created before the data
				 * is available
				 * ie. file data chunks encountered before
				* the header.
				 */
	u8 lazy_loaded:1;	/* This object has been lazy loaded and
				 * is missing some detail */

	u8 defered_free:1;	/* Object is removed from NAND, but is
				 * still in the inode cache.
				 * Free of object is defered.
				 * until the inode is released.
				 */
	u8 being_created:1;	/* This object is still being created
				 * so skip some verification checks. */
	u8 is_shadowed:1;	/* This object is shadowed on the way
				 * to being renamed. */

	u8 xattr_known:1;	/* We know if this has object has xattribs
				 * or not. */
	u8 has_xattr:1;		/* This object has xattribs.
				 * Only valid if xattr_known. */

	u8 serial;		/* serial number of chunk in NAND.*/
	u16 sum;		/* sum of the name to speed searching */

	struct yaffs_dev *my_dev;	/* The device I'm on */

	struct list_head hash_link;	/* list of objects in hash bucket */

	struct list_head hard_links;	/* hard linked object chain*/

	/* directory structure stuff */
	/* also used for linking up the free list */
	struct yaffs_obj *parent;
	struct list_head siblings;

	/* Where's my object header in NAND? */
	int hdr_chunk;

	int n_data_chunks;	/* Number of data chunks for this file. */

	u32 obj_id;		/* the object id value */

	u32 yst_mode;

	YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1];

#ifdef CONFIG_YAFFS_WINCE
	u32 win_ctime[2];
	u32 win_mtime[2];
	u32 win_atime[2];
#else
	u32 yst_uid;
	u32 yst_gid;
	u32 yst_atime;
	u32 yst_mtime;
	u32 yst_ctime;
#endif

	u32 yst_rdev;

	void *my_inode;

	enum yaffs_obj_type variant_type;

	union yaffs_obj_var variant;

};

struct yaffs_obj_bucket {
	struct list_head list;
	int count;
};

/* yaffs_checkpt_obj holds the definition of an object as dumped
 * by checkpointing.
 */

struct yaffs_checkpt_obj {
	int struct_type;
	u32 obj_id;
	u32 parent_id;
	int hdr_chunk;
	enum yaffs_obj_type variant_type:3;
	u8 deleted:1;
	u8 soft_del:1;
	u8 unlinked:1;
	u8 fake:1;
	u8 rename_allowed:1;
	u8 unlink_allowed:1;
	u8 serial;
	int n_data_chunks;
	loff_t size_or_equiv_obj;
};

/*--------------------- Temporary buffers ----------------
 *
 * These are chunk-sized working buffers. Each device has a few.
 */

struct yaffs_buffer {
	u8 *buffer;
	int in_use;
};

/*----------------- Device ---------------------------------*/

struct yaffs_param {
	const YCHAR *name;

	/*
	 * Entry parameters set up way early. Yaffs sets up the rest.
	 * The structure should be zeroed out before use so that unused
	 * and default values are zero.
	 */

	int inband_tags;	/* Use unband tags */
	u32 total_bytes_per_chunk;	/* Should be >= 512, does not need to
					 be a power of 2 */
	int chunks_per_block;	/* does not need to be a power of 2 */
	int spare_bytes_per_chunk;	/* spare area size */
	int start_block;	/* Start block we're allowed to use */
	int end_block;		/* End block we're allowed to use */
	int n_reserved_blocks;	/* Tuneable so that we can reduce
				 * reserved blocks on NOR and RAM. */

	int n_caches;		/* If <= 0, then short op caching is disabled,
				 * else the number of short op caches.
				 */
	int cache_bypass_aligned; /* If non-zero then bypass the cache for
				   * aligned writes.
				   */

	int use_nand_ecc;	/* Flag to decide whether or not to use
				 * NAND driver ECC on data (yaffs1) */
	int tags_9bytes;	/* Use 9 byte tags */
	int no_tags_ecc;	/* Flag to decide whether or not to do ECC
				 * on packed tags (yaffs2) */

	int is_yaffs2;		/* Use yaffs2 mode on this device */

	int empty_lost_n_found;	/* Auto-empty lost+found directory on mount */

	int refresh_period;	/* How often to check for a block refresh */

	/* Checkpoint control. Can be set before or after initialisation */
	u8 skip_checkpt_rd;
	u8 skip_checkpt_wr;

	int enable_xattr;	/* Enable xattribs */

	int max_objects;	/*
				 * Set to limit the number of objects created.
				 * 0 = no limit.
				*/

	/* The remove_obj_fn function must be supplied by OS flavours that
	 * need it.
	 * yaffs direct uses it to implement the faster readdir.
	 * Linux uses it to protect the directory during unlocking.
	 */
	void (*remove_obj_fn) (struct yaffs_obj *obj);

	/* Callback to mark the superblock dirty */
	void (*sb_dirty_fn) (struct yaffs_dev *dev);

	/*  Callback to control garbage collection. */
	unsigned (*gc_control_fn) (struct yaffs_dev *dev);

	/* Debug control flags. Don't use unless you know what you're doing */
	int use_header_file_size;	/* Flag to determine if we should use
					 * file sizes from the header */
	int disable_lazy_load;	/* Disable lazy loading on this device */
	int wide_tnodes_disabled;	/* Set to disable wide tnodes */
	int disable_soft_del;	/* yaffs 1 only: Set to disable the use of
				 * softdeletion. */

	int defered_dir_update;	/* Set to defer directory updates */

#ifdef CONFIG_YAFFS_AUTO_UNICODE
	int auto_unicode;
#endif
	int always_check_erased;	/* Force chunk erased check always on */

	int disable_summary;
	int disable_bad_block_marking;

};

struct yaffs_driver {
	int (*drv_write_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
				   const u8 *data, int data_len,
				   const u8 *oob, int oob_len);
	int (*drv_read_chunk_fn) (struct yaffs_dev *dev, int nand_chunk,
				   u8 *data, int data_len,
				   u8 *oob, int oob_len,
				   enum yaffs_ecc_result *ecc_result);
	int (*drv_erase_fn) (struct yaffs_dev *dev, int block_no);
	int (*drv_mark_bad_fn) (struct yaffs_dev *dev, int block_no);
	int (*drv_check_bad_fn) (struct yaffs_dev *dev, int block_no);
	int (*drv_initialise_fn) (struct yaffs_dev *dev);
	int (*drv_deinitialise_fn) (struct yaffs_dev *dev);
};

struct yaffs_tags_handler {
	int (*write_chunk_tags_fn) (struct yaffs_dev *dev,
				    int nand_chunk, const u8 *data,
				    const struct yaffs_ext_tags *tags);
	int (*read_chunk_tags_fn) (struct yaffs_dev *dev,
				   int nand_chunk, u8 *data,
				   struct yaffs_ext_tags *tags);

	int (*query_block_fn) (struct yaffs_dev *dev, int block_no,
			       enum yaffs_block_state *state,
			       u32 *seq_number);
	int (*mark_bad_fn) (struct yaffs_dev *dev, int block_no);
};

struct yaffs_dev {
	struct yaffs_param param;
	struct yaffs_driver drv;
	struct yaffs_tags_handler tagger;

	/* Context storage. Holds extra OS specific data for this device */

	void *os_context;
	void *driver_context;

	struct list_head dev_list;

	int ll_init;
	/* Runtime parameters. Set up by YAFFS. */
	int data_bytes_per_chunk;

	/* Non-wide tnode stuff */
	u16 chunk_grp_bits;	/* Number of bits that need to be resolved if
				 * the tnodes are not wide enough.
				 */
	u16 chunk_grp_size;	/* == 2^^chunk_grp_bits */

	/* Stuff to support wide tnodes */
	u32 tnode_width;
	u32 tnode_mask;
	u32 tnode_size;

	/* Stuff for figuring out file offset to chunk conversions */
	u32 chunk_shift;	/* Shift value */
	u32 chunk_div;		/* Divisor after shifting: 1 for 2^n sizes */
	u32 chunk_mask;		/* Mask to use for power-of-2 case */

	int is_mounted;
	int read_only;
	int is_checkpointed;

	/* Stuff to support block offsetting to support start block zero */
	int internal_start_block;
	int internal_end_block;
	int block_offset;
	int chunk_offset;

	/* Runtime checkpointing stuff */
	int checkpt_page_seq;	/* running sequence number of checkpt pages */
	int checkpt_byte_count;
	int checkpt_byte_offs;
	u8 *checkpt_buffer;
	int checkpt_open_write;
	int blocks_in_checkpt;
	int checkpt_cur_chunk;
	int checkpt_cur_block;
	int checkpt_next_block;
	int *checkpt_block_list;
	int checkpt_max_blocks;
	u32 checkpt_sum;
	u32 checkpt_xor;

	int checkpoint_blocks_required;	/* Number of blocks needed to store
					 * current checkpoint set */

	/* Block Info */
	struct yaffs_block_info *block_info;
	u8 *chunk_bits;		/* bitmap of chunks in use */
	unsigned block_info_alt:1;	/* allocated using alternative alloc */
	unsigned chunk_bits_alt:1;	/* allocated using alternative alloc */
	int chunk_bit_stride;	/* Number of bytes of chunk_bits per block.
				 * Must be consistent with chunks_per_block.
				 */

	int n_erased_blocks;
	int alloc_block;	/* Current block being allocated off */
	u32 alloc_page;
	int alloc_block_finder;	/* Used to search for next allocation block */

	/* Object and Tnode memory management */
	void *allocator;
	int n_obj;
	int n_tnodes;

	int n_hardlinks;

	struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS];
	u32 bucket_finder;

	int n_free_chunks;

	/* Garbage collection control */
	u32 *gc_cleanup_list;	/* objects to delete at the end of a GC. */
	u32 n_clean_ups;

	unsigned has_pending_prioritised_gc;	/* We think this device might
						have pending prioritised gcs */
	unsigned gc_disable;
	unsigned gc_block_finder;
	unsigned gc_dirtiest;
	unsigned gc_pages_in_use;
	unsigned gc_not_done;
	unsigned gc_block;
	unsigned gc_chunk;
	unsigned gc_skip;
	struct yaffs_summary_tags *gc_sum_tags;

	/* Special directories */
	struct yaffs_obj *root_dir;
	struct yaffs_obj *lost_n_found;

	int buffered_block;	/* Which block is buffered here? */
	int doing_buffered_block_rewrite;

	struct yaffs_cache *cache;
	int cache_last_use;

	/* Stuff for background deletion and unlinked files. */
	struct yaffs_obj *unlinked_dir;	/* Directory where unlinked and deleted
					 files live. */
	struct yaffs_obj *del_dir;	/* Directory where deleted objects are
					sent to disappear. */
	struct yaffs_obj *unlinked_deletion;	/* Current file being
							background deleted. */
	int n_deleted_files;	/* Count of files awaiting deletion; */
	int n_unlinked_files;	/* Count of unlinked files. */
	int n_bg_deletions;	/* Count of background deletions. */

	/* Temporary buffer management */
	struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS];
	int max_temp;
	int temp_in_use;
	int unmanaged_buffer_allocs;
	int unmanaged_buffer_deallocs;

	/* yaffs2 runtime stuff */
	unsigned seq_number;	/* Sequence number of currently
					allocating block */
	unsigned oldest_dirty_seq;
	unsigned oldest_dirty_block;

	/* Block refreshing */
	int refresh_skip;	/* A skip down counter.
				 * Refresh happens when this gets to zero. */

	/* Dirty directory handling */
	struct list_head dirty_dirs;	/* List of dirty directories */

	/* Summary */
	int chunks_per_summary;
	struct yaffs_summary_tags *sum_tags;

	/* Statistics */
	u32 n_page_writes;
	u32 n_page_reads;
	u32 n_erasures;
	u32 n_bad_markings;
	u32 n_erase_failures;
	u32 n_gc_copies;
	u32 all_gcs;
	u32 passive_gc_count;
	u32 oldest_dirty_gc_count;
	u32 n_gc_blocks;
	u32 bg_gcs;
	u32 n_retried_writes;
	u32 n_retired_blocks;
	u32 n_ecc_fixed;
	u32 n_ecc_unfixed;
	u32 n_tags_ecc_fixed;
	u32 n_tags_ecc_unfixed;
	u32 n_deletions;
	u32 n_unmarked_deletions;
	u32 refresh_count;
	u32 cache_hits;
	u32 tags_used;
	u32 summary_used;

};

/* The CheckpointDevice structure holds the device information that changes
 *at runtime and must be preserved over unmount/mount cycles.
 */
struct yaffs_checkpt_dev {
	int struct_type;
	int n_erased_blocks;
	int alloc_block;	/* Current block being allocated off */
	u32 alloc_page;
	int n_free_chunks;

	int n_deleted_files;	/* Count of files awaiting deletion; */
	int n_unlinked_files;	/* Count of unlinked files. */
	int n_bg_deletions;	/* Count of background deletions. */

	/* yaffs2 runtime stuff */
	unsigned seq_number;	/* Sequence number of currently
				 * allocating block */

};

struct yaffs_checkpt_validity {
	int struct_type;
	u32 magic;
	u32 version;
	u32 head;
};

struct yaffs_shadow_fixer {
	int obj_id;
	int shadowed_id;
	struct yaffs_shadow_fixer *next;
};

/* Structure for doing xattr modifications */
struct yaffs_xattr_mod {
	int set;		/* If 0 then this is a deletion */
	const YCHAR *name;
	const void *data;
	int size;
	int flags;
	int result;
};

/*----------------------- YAFFS Functions -----------------------*/

int yaffs_guts_initialise(struct yaffs_dev *dev);
void yaffs_deinitialise(struct yaffs_dev *dev);

int yaffs_get_n_free_chunks(struct yaffs_dev *dev);

int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name,
		     struct yaffs_obj *new_dir, const YCHAR * new_name);

int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name);
int yaffs_del_obj(struct yaffs_obj *obj);

int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size);
loff_t yaffs_get_obj_length(struct yaffs_obj *obj);
int yaffs_get_obj_inode(struct yaffs_obj *obj);
unsigned yaffs_get_obj_type(struct yaffs_obj *obj);
int yaffs_get_obj_link_count(struct yaffs_obj *obj);

/* File operations */
int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset,
		  int n_bytes);
int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset,
		  int n_bytes, int write_trhrough);
int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size);

struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent,
				    const YCHAR *name, u32 mode, u32 uid,
				    u32 gid);

int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync);

/* Flushing and checkpointing */
void yaffs_flush_whole_cache(struct yaffs_dev *dev);

int yaffs_checkpoint_save(struct yaffs_dev *dev);
int yaffs_checkpoint_restore(struct yaffs_dev *dev);

/* Directory operations */
struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name,
				   u32 mode, u32 uid, u32 gid);
struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir,
				     const YCHAR *name);
struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number);

/* Link operations */
struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name,
				 struct yaffs_obj *equiv_obj);

struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj);

/* Symlink operations */
struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent,
				       const YCHAR *name, u32 mode, u32 uid,
				       u32 gid, const YCHAR *alias);
YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj);

/* Special inodes (fifos, sockets and devices) */
struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent,
				       const YCHAR *name, u32 mode, u32 uid,
				       u32 gid, u32 rdev);

int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name,
		      const void *value, int size, int flags);
int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value,
		      int size);
int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size);
int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name);

/* Special directories */
struct yaffs_obj *yaffs_root(struct yaffs_dev *dev);
struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev);

void yaffs_handle_defered_free(struct yaffs_obj *obj);

void yaffs_update_dirty_dirs(struct yaffs_dev *dev);

int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency);

/* Debug dump  */
int yaffs_dump_obj(struct yaffs_obj *obj);

void yaffs_guts_test(struct yaffs_dev *dev);
int yaffs_guts_ll_init(struct yaffs_dev *dev);


/* A few useful functions to be used within the core files*/
void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash,
		     int lyn);
int yaffs_check_ff(u8 *buffer, int n_bytes);
void yaffs_handle_chunk_error(struct yaffs_dev *dev,
			      struct yaffs_block_info *bi);

u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev);
void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer);

struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev,
						 int number,
						 enum yaffs_obj_type type);
int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
			    int nand_chunk, int in_scan);
void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name);
void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj,
				const struct yaffs_obj_hdr *oh);
void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj);
YCHAR *yaffs_clone_str(const YCHAR *str);
void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list);
void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no);
int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name,
		    int force, int is_shrink, int shadows,
		    struct yaffs_xattr_mod *xop);
void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id,
			       int backward_scanning);
int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks);
struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev);
struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev,
					   struct yaffs_file_var *file_struct,
					   u32 chunk_id,
					   struct yaffs_tnode *passed_tn);

int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset,
		     int n_bytes, int write_trhrough);
void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size);
void yaffs_skip_rest_of_block(struct yaffs_dev *dev);

int yaffs_count_free_chunks(struct yaffs_dev *dev);

struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev,
				       struct yaffs_file_var *file_struct,
				       u32 chunk_id);

u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn,
			 unsigned pos);

int yaffs_is_non_empty_dir(struct yaffs_obj *obj);

int yaffs_format_dev(struct yaffs_dev *dev);

void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr,
				int *chunk_out, u32 *offset_out);
/*
 * Marshalling functions to get loff_t file sizes into aand out of
 * object headers.
 */
void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize);
loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh);
loff_t yaffs_max_file_size(struct yaffs_dev *dev);

/*
 * Debug function to count number of blocks in each state
 * NB Needs to be called with correct number of integers
 */

void yaffs_count_blocks_by_state(struct yaffs_dev *dev, int bs[10]);

int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk,
				    struct yaffs_ext_tags *tags);

#endif