2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
7 * Created by Charles Manning <charles@aleph1.co.uk>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
15 #include "yaffs_guts.h"
16 #include "yaffs_trace.h"
17 #include "yaffs_yaffs2.h"
18 #include "yaffs_checkptrw.h"
19 #include "yaffs_bitmap.h"
20 #include "yaffs_qsort.h"
21 #include "yaffs_nand.h"
22 #include "yaffs_getblockinfo.h"
23 #include "yaffs_verify.h"
26 * Checkpoints are really no benefit on very small partitions.
28 * To save space on small partitions don't bother with checkpoints unless
29 * the partition is at least this big.
31 #define YAFFS_CHECKPOINT_MIN_BLOCKS 60
33 #define YAFFS_SMALL_HOLE_THRESHOLD 4
37 * Oldest Dirty Sequence Number handling.
40 /* yaffs_calc_oldest_dirty_seq()
41 * yaffs2_find_oldest_dirty_seq()
42 * Calculate the oldest dirty sequence number if we don't know it.
44 void yaffs_calc_oldest_dirty_seq(yaffs_dev_t
*dev
)
48 unsigned block_no
= 0;
49 yaffs_block_info_t
*b
;
51 if(!dev
->param
.is_yaffs2
)
54 /* Find the oldest dirty sequence number. */
55 seq
= dev
->seq_number
+ 1;
57 for (i
= dev
->internal_start_block
; i
<= dev
->internal_end_block
; i
++) {
58 if (b
->block_state
== YAFFS_BLOCK_STATE_FULL
&&
59 (b
->pages_in_use
- b
->soft_del_pages
) < dev
->param
.chunks_per_block
&&
60 b
->seq_number
< seq
) {
68 dev
->oldest_dirty_seq
= seq
;
69 dev
->oldest_dirty_block
= block_no
;
75 void yaffs2_find_oldest_dirty_seq(yaffs_dev_t
*dev
)
77 if(!dev
->param
.is_yaffs2
)
80 if(!dev
->oldest_dirty_seq
)
81 yaffs_calc_oldest_dirty_seq(dev
);
85 * yaffs_clear_oldest_dirty_seq()
86 * Called when a block is erased or marked bad. (ie. when its seq_number
87 * becomes invalid). If the value matches the oldest then we clear
88 * dev->oldest_dirty_seq to force its recomputation.
90 void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t
*dev
, yaffs_block_info_t
*bi
)
93 if(!dev
->param
.is_yaffs2
)
96 if(!bi
|| bi
->seq_number
== dev
->oldest_dirty_seq
){
97 dev
->oldest_dirty_seq
= 0;
98 dev
->oldest_dirty_block
= 0;
103 * yaffs2_update_oldest_dirty_seq()
104 * Update the oldest dirty sequence number whenever we dirty a block.
105 * Only do this if the oldest_dirty_seq is actually being tracked.
107 void yaffs2_update_oldest_dirty_seq(yaffs_dev_t
*dev
, unsigned block_no
, yaffs_block_info_t
*bi
)
109 if(!dev
->param
.is_yaffs2
)
112 if(dev
->oldest_dirty_seq
){
113 if(dev
->oldest_dirty_seq
> bi
->seq_number
){
114 dev
->oldest_dirty_seq
= bi
->seq_number
;
115 dev
->oldest_dirty_block
= block_no
;
120 int yaffs_block_ok_for_gc(yaffs_dev_t
*dev
,
121 yaffs_block_info_t
*bi
)
124 if (!dev
->param
.is_yaffs2
)
125 return 1; /* disqualification only applies to yaffs2. */
127 if (!bi
->has_shrink_hdr
)
128 return 1; /* can gc */
130 yaffs2_find_oldest_dirty_seq(dev
);
132 /* Can't do gc of this block if there are any blocks older than this one that have
135 return (bi
->seq_number
<= dev
->oldest_dirty_seq
);
139 * yaffs2_find_refresh_block()
140 * periodically finds the oldest full block by sequence number for refreshing.
143 __u32
yaffs2_find_refresh_block(yaffs_dev_t
*dev
)
148 __u32 oldestSequence
= 0;
150 yaffs_block_info_t
*bi
;
152 if(!dev
->param
.is_yaffs2
)
156 * If refresh period < 10 then refreshing is disabled.
158 if(dev
->param
.refresh_period
< 10)
164 if(dev
->refresh_skip
> dev
->param
.refresh_period
)
165 dev
->refresh_skip
= dev
->param
.refresh_period
;
167 if(dev
->refresh_skip
> 0)
171 * Refresh skip is now zero.
172 * We'll do a refresh this time around....
173 * Update the refresh skip and find the oldest block.
175 dev
->refresh_skip
= dev
->param
.refresh_period
;
176 dev
->refresh_count
++;
177 bi
= dev
->block_info
;
178 for (b
= dev
->internal_start_block
; b
<=dev
->internal_end_block
; b
++){
180 if (bi
->block_state
== YAFFS_BLOCK_STATE_FULL
){
183 bi
->seq_number
< oldestSequence
){
185 oldestSequence
= bi
->seq_number
;
193 (TSTR("GC refresh count %d selected block %d with seq_number %d" TENDSTR
),
194 dev
->refresh_count
, oldest
, oldestSequence
));
200 int yaffs2_checkpt_required(yaffs_dev_t
*dev
)
204 if(!dev
->param
.is_yaffs2
)
207 nblocks
= dev
->internal_end_block
- dev
->internal_start_block
+ 1 ;
209 return !dev
->param
.skip_checkpt_wr
&&
211 (nblocks
>= YAFFS_CHECKPOINT_MIN_BLOCKS
);
214 int yaffs_calc_checkpt_blocks_required(yaffs_dev_t
*dev
)
218 if(!dev
->param
.is_yaffs2
)
221 if (!dev
->checkpoint_blocks_required
&&
222 yaffs2_checkpt_required(dev
)){
223 /* Not a valid value so recalculate */
226 int devBlocks
= (dev
->param
.end_block
- dev
->param
.start_block
+ 1);
228 n_bytes
+= sizeof(yaffs_checkpt_validty_t
);
229 n_bytes
+= sizeof(yaffs_checkpt_dev_t
);
230 n_bytes
+= devBlocks
* sizeof(yaffs_block_info_t
);
231 n_bytes
+= devBlocks
* dev
->chunk_bit_stride
;
232 n_bytes
+= (sizeof(yaffs_checkpt_obj_t
) + sizeof(__u32
)) * (dev
->n_obj
);
233 n_bytes
+= (dev
->tnode_size
+ sizeof(__u32
)) * (dev
->n_tnodes
);
234 n_bytes
+= sizeof(yaffs_checkpt_validty_t
);
235 n_bytes
+= sizeof(__u32
); /* checksum*/
237 /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
239 nBlocks
= (n_bytes
/(dev
->data_bytes_per_chunk
* dev
->param
.chunks_per_block
)) + 3;
241 dev
->checkpoint_blocks_required
= nBlocks
;
244 retval
= dev
->checkpoint_blocks_required
- dev
->blocks_in_checkpt
;
250 /*--------------------- Checkpointing --------------------*/
253 static int yaffs2_wr_checkpt_validity_marker(yaffs_dev_t
*dev
, int head
)
255 yaffs_checkpt_validty_t cp
;
257 memset(&cp
, 0, sizeof(cp
));
259 cp
.struct_type
= sizeof(cp
);
260 cp
.magic
= YAFFS_MAGIC
;
261 cp
.version
= YAFFS_CHECKPOINT_VERSION
;
262 cp
.head
= (head
) ? 1 : 0;
264 return (yaffs2_checkpt_wr(dev
, &cp
, sizeof(cp
)) == sizeof(cp
)) ?
268 static int yaffs2_rd_checkpt_validty_marker(yaffs_dev_t
*dev
, int head
)
270 yaffs_checkpt_validty_t cp
;
273 ok
= (yaffs2_checkpt_rd(dev
, &cp
, sizeof(cp
)) == sizeof(cp
));
276 ok
= (cp
.struct_type
== sizeof(cp
)) &&
277 (cp
.magic
== YAFFS_MAGIC
) &&
278 (cp
.version
== YAFFS_CHECKPOINT_VERSION
) &&
279 (cp
.head
== ((head
) ? 1 : 0));
283 static void yaffs2_dev_to_checkpt_dev(yaffs_checkpt_dev_t
*cp
,
286 cp
->n_erased_blocks
= dev
->n_erased_blocks
;
287 cp
->alloc_block
= dev
->alloc_block
;
288 cp
->alloc_page
= dev
->alloc_page
;
289 cp
->n_free_chunks
= dev
->n_free_chunks
;
291 cp
->n_deleted_files
= dev
->n_deleted_files
;
292 cp
->n_unlinked_files
= dev
->n_unlinked_files
;
293 cp
->n_bg_deletions
= dev
->n_bg_deletions
;
294 cp
->seq_number
= dev
->seq_number
;
298 static void yaffs_checkpt_dev_to_dev(yaffs_dev_t
*dev
,
299 yaffs_checkpt_dev_t
*cp
)
301 dev
->n_erased_blocks
= cp
->n_erased_blocks
;
302 dev
->alloc_block
= cp
->alloc_block
;
303 dev
->alloc_page
= cp
->alloc_page
;
304 dev
->n_free_chunks
= cp
->n_free_chunks
;
306 dev
->n_deleted_files
= cp
->n_deleted_files
;
307 dev
->n_unlinked_files
= cp
->n_unlinked_files
;
308 dev
->n_bg_deletions
= cp
->n_bg_deletions
;
309 dev
->seq_number
= cp
->seq_number
;
313 static int yaffs2_wr_checkpt_dev(yaffs_dev_t
*dev
)
315 yaffs_checkpt_dev_t cp
;
317 __u32 nBlocks
= (dev
->internal_end_block
- dev
->internal_start_block
+ 1);
321 /* Write device runtime values*/
322 yaffs2_dev_to_checkpt_dev(&cp
, dev
);
323 cp
.struct_type
= sizeof(cp
);
325 ok
= (yaffs2_checkpt_wr(dev
, &cp
, sizeof(cp
)) == sizeof(cp
));
327 /* Write block info */
329 n_bytes
= nBlocks
* sizeof(yaffs_block_info_t
);
330 ok
= (yaffs2_checkpt_wr(dev
, dev
->block_info
, n_bytes
) == n_bytes
);
333 /* Write chunk bits */
335 n_bytes
= nBlocks
* dev
->chunk_bit_stride
;
336 ok
= (yaffs2_checkpt_wr(dev
, dev
->chunk_bits
, n_bytes
) == n_bytes
);
342 static int yaffs2_rd_checkpt_dev(yaffs_dev_t
*dev
)
344 yaffs_checkpt_dev_t cp
;
346 __u32 nBlocks
= (dev
->internal_end_block
- dev
->internal_start_block
+ 1);
350 ok
= (yaffs2_checkpt_rd(dev
, &cp
, sizeof(cp
)) == sizeof(cp
));
354 if (cp
.struct_type
!= sizeof(cp
))
358 yaffs_checkpt_dev_to_dev(dev
, &cp
);
360 n_bytes
= nBlocks
* sizeof(yaffs_block_info_t
);
362 ok
= (yaffs2_checkpt_rd(dev
, dev
->block_info
, n_bytes
) == n_bytes
);
366 n_bytes
= nBlocks
* dev
->chunk_bit_stride
;
368 ok
= (yaffs2_checkpt_rd(dev
, dev
->chunk_bits
, n_bytes
) == n_bytes
);
373 static void yaffs2_obj_checkpt_obj(yaffs_checkpt_obj_t
*cp
,
377 cp
->obj_id
= obj
->obj_id
;
378 cp
->parent_id
= (obj
->parent
) ? obj
->parent
->obj_id
: 0;
379 cp
->hdr_chunk
= obj
->hdr_chunk
;
380 cp
->variant_type
= obj
->variant_type
;
381 cp
->deleted
= obj
->deleted
;
382 cp
->soft_del
= obj
->soft_del
;
383 cp
->unlinked
= obj
->unlinked
;
384 cp
->fake
= obj
->fake
;
385 cp
->rename_allowed
= obj
->rename_allowed
;
386 cp
->unlink_allowed
= obj
->unlink_allowed
;
387 cp
->serial
= obj
->serial
;
388 cp
->n_data_chunks
= obj
->n_data_chunks
;
390 if (obj
->variant_type
== YAFFS_OBJECT_TYPE_FILE
)
391 cp
->size_or_equiv_obj
= obj
->variant
.file_variant
.file_size
;
392 else if (obj
->variant_type
== YAFFS_OBJECT_TYPE_HARDLINK
)
393 cp
->size_or_equiv_obj
= obj
->variant
.hardlink_variant
.equiv_id
;
396 static int taffs2_checkpt_obj_to_obj(yaffs_obj_t
*obj
, yaffs_checkpt_obj_t
*cp
)
401 if (obj
->variant_type
!= cp
->variant_type
) {
402 T(YAFFS_TRACE_ERROR
, (TSTR("Checkpoint read object %d type %d "
403 TCONT("chunk %d does not match existing object type %d")
404 TENDSTR
), cp
->obj_id
, cp
->variant_type
, cp
->hdr_chunk
,
409 obj
->obj_id
= cp
->obj_id
;
412 parent
= yaffs_find_or_create_by_number(
415 YAFFS_OBJECT_TYPE_DIRECTORY
);
420 if (parent
->variant_type
!= YAFFS_OBJECT_TYPE_DIRECTORY
) {
421 T(YAFFS_TRACE_ALWAYS
, (TSTR("Checkpoint read object %d parent %d type %d"
422 TCONT(" chunk %d Parent type, %d, not directory")
424 cp
->obj_id
, cp
->parent_id
, cp
->variant_type
,
425 cp
->hdr_chunk
, parent
->variant_type
));
428 yaffs_add_obj_to_dir(parent
, obj
);
431 obj
->hdr_chunk
= cp
->hdr_chunk
;
432 obj
->variant_type
= cp
->variant_type
;
433 obj
->deleted
= cp
->deleted
;
434 obj
->soft_del
= cp
->soft_del
;
435 obj
->unlinked
= cp
->unlinked
;
436 obj
->fake
= cp
->fake
;
437 obj
->rename_allowed
= cp
->rename_allowed
;
438 obj
->unlink_allowed
= cp
->unlink_allowed
;
439 obj
->serial
= cp
->serial
;
440 obj
->n_data_chunks
= cp
->n_data_chunks
;
442 if (obj
->variant_type
== YAFFS_OBJECT_TYPE_FILE
)
443 obj
->variant
.file_variant
.file_size
= cp
->size_or_equiv_obj
;
444 else if (obj
->variant_type
== YAFFS_OBJECT_TYPE_HARDLINK
)
445 obj
->variant
.hardlink_variant
.equiv_id
= cp
->size_or_equiv_obj
;
447 if (obj
->hdr_chunk
> 0)
448 obj
->lazy_loaded
= 1;
454 static int yaffs2_checkpt_tnode_worker(yaffs_obj_t
*in
, yaffs_tnode_t
*tn
,
455 __u32 level
, int chunk_offset
)
458 yaffs_dev_t
*dev
= in
->my_dev
;
464 for (i
= 0; i
< YAFFS_NTNODES_INTERNAL
&& ok
; i
++) {
465 if (tn
->internal
[i
]) {
466 ok
= yaffs2_checkpt_tnode_worker(in
,
469 (chunk_offset
<<YAFFS_TNODES_INTERNAL_BITS
) + i
);
472 } else if (level
== 0) {
473 __u32 baseOffset
= chunk_offset
<< YAFFS_TNODES_LEVEL0_BITS
;
474 ok
= (yaffs2_checkpt_wr(dev
, &baseOffset
, sizeof(baseOffset
)) == sizeof(baseOffset
));
476 ok
= (yaffs2_checkpt_wr(dev
, tn
, dev
->tnode_size
) == dev
->tnode_size
);
484 static int yaffs2_wr_checkpt_tnodes(yaffs_obj_t
*obj
)
486 __u32 endMarker
= ~0;
489 if (obj
->variant_type
== YAFFS_OBJECT_TYPE_FILE
) {
490 ok
= yaffs2_checkpt_tnode_worker(obj
,
491 obj
->variant
.file_variant
.top
,
492 obj
->variant
.file_variant
.top_level
,
495 ok
= (yaffs2_checkpt_wr(obj
->my_dev
, &endMarker
, sizeof(endMarker
)) ==
502 static int yaffs2_rd_checkpt_tnodes(yaffs_obj_t
*obj
)
506 yaffs_dev_t
*dev
= obj
->my_dev
;
507 yaffs_file_s
*fileStructPtr
= &obj
->variant
.file_variant
;
511 ok
= (yaffs2_checkpt_rd(dev
, &baseChunk
, sizeof(baseChunk
)) == sizeof(baseChunk
));
513 while (ok
&& (~baseChunk
)) {
515 /* Read level 0 tnode */
518 tn
= yaffs_get_tnode(dev
);
520 ok
= (yaffs2_checkpt_rd(dev
, tn
, dev
->tnode_size
) == dev
->tnode_size
);
525 ok
= yaffs_add_find_tnode_0(dev
,
531 ok
= (yaffs2_checkpt_rd(dev
, &baseChunk
, sizeof(baseChunk
)) == sizeof(baseChunk
));
535 T(YAFFS_TRACE_CHECKPOINT
, (
536 TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR
),
537 nread
, baseChunk
, ok
));
543 static int yaffs2_wr_checkpt_objs(yaffs_dev_t
*dev
)
546 yaffs_checkpt_obj_t cp
;
549 struct ylist_head
*lh
;
552 /* Iterate through the objects in each hash entry,
553 * dumping them to the checkpointing stream.
556 for (i
= 0; ok
&& i
< YAFFS_NOBJECT_BUCKETS
; i
++) {
557 ylist_for_each(lh
, &dev
->obj_bucket
[i
].list
) {
559 obj
= ylist_entry(lh
, yaffs_obj_t
, hash_link
);
560 if (!obj
->defered_free
) {
561 yaffs2_obj_checkpt_obj(&cp
, obj
);
562 cp
.struct_type
= sizeof(cp
);
564 T(YAFFS_TRACE_CHECKPOINT
, (
565 TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %p" TENDSTR
),
566 cp
.obj_id
, cp
.parent_id
, cp
.variant_type
, cp
.hdr_chunk
, obj
));
568 ok
= (yaffs2_checkpt_wr(dev
, &cp
, sizeof(cp
)) == sizeof(cp
));
570 if (ok
&& obj
->variant_type
== YAFFS_OBJECT_TYPE_FILE
)
571 ok
= yaffs2_wr_checkpt_tnodes(obj
);
577 /* Dump end of list */
578 memset(&cp
, 0xFF, sizeof(yaffs_checkpt_obj_t
));
579 cp
.struct_type
= sizeof(cp
);
582 ok
= (yaffs2_checkpt_wr(dev
, &cp
, sizeof(cp
)) == sizeof(cp
));
587 static int yaffs2_rd_checkpt_objs(yaffs_dev_t
*dev
)
590 yaffs_checkpt_obj_t cp
;
593 yaffs_obj_t
*hard_list
= NULL
;
595 while (ok
&& !done
) {
596 ok
= (yaffs2_checkpt_rd(dev
, &cp
, sizeof(cp
)) == sizeof(cp
));
597 if (cp
.struct_type
!= sizeof(cp
)) {
598 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("struct size %d instead of %d ok %d"TENDSTR
),
599 cp
.struct_type
, (int)sizeof(cp
), ok
));
603 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR
),
604 cp
.obj_id
, cp
.parent_id
, cp
.variant_type
, cp
.hdr_chunk
));
606 if (ok
&& cp
.obj_id
== ~0)
609 obj
= yaffs_find_or_create_by_number(dev
, cp
.obj_id
, cp
.variant_type
);
611 ok
= taffs2_checkpt_obj_to_obj(obj
, &cp
);
614 if (obj
->variant_type
== YAFFS_OBJECT_TYPE_FILE
) {
615 ok
= yaffs2_rd_checkpt_tnodes(obj
);
616 } else if (obj
->variant_type
== YAFFS_OBJECT_TYPE_HARDLINK
) {
617 obj
->hard_links
.next
=
618 (struct ylist_head
*) hard_list
;
627 yaffs_link_fixup(dev
, hard_list
);
632 static int yaffs2_wr_checkpt_sum(yaffs_dev_t
*dev
)
637 yaffs2_get_checkpt_sum(dev
, &checkpt_sum
);
639 ok
= (yaffs2_checkpt_wr(dev
, &checkpt_sum
, sizeof(checkpt_sum
)) == sizeof(checkpt_sum
));
647 static int yaffs2_rd_checkpt_sum(yaffs_dev_t
*dev
)
653 yaffs2_get_checkpt_sum(dev
, &checkpt_sum0
);
655 ok
= (yaffs2_checkpt_rd(dev
, &checkpt_sum1
, sizeof(checkpt_sum1
)) == sizeof(checkpt_sum1
));
660 if (checkpt_sum0
!= checkpt_sum1
)
667 static int yaffs2_wr_checkpt_data(yaffs_dev_t
*dev
)
671 if (!yaffs2_checkpt_required(dev
)) {
672 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("skipping checkpoint write" TENDSTR
)));
677 ok
= yaffs2_checkpt_open(dev
, 1);
680 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("write checkpoint validity" TENDSTR
)));
681 ok
= yaffs2_wr_checkpt_validity_marker(dev
, 1);
684 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("write checkpoint device" TENDSTR
)));
685 ok
= yaffs2_wr_checkpt_dev(dev
);
688 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("write checkpoint objects" TENDSTR
)));
689 ok
= yaffs2_wr_checkpt_objs(dev
);
692 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("write checkpoint validity" TENDSTR
)));
693 ok
= yaffs2_wr_checkpt_validity_marker(dev
, 0);
697 ok
= yaffs2_wr_checkpt_sum(dev
);
699 if (!yaffs_checkpt_close(dev
))
703 dev
->is_checkpointed
= 1;
705 dev
->is_checkpointed
= 0;
707 return dev
->is_checkpointed
;
710 static int yaffs2_rd_checkpt_data(yaffs_dev_t
*dev
)
714 if(!dev
->param
.is_yaffs2
)
717 if (ok
&& dev
->param
.skip_checkpt_rd
) {
718 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("skipping checkpoint read" TENDSTR
)));
723 ok
= yaffs2_checkpt_open(dev
, 0); /* open for read */
726 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("read checkpoint validity" TENDSTR
)));
727 ok
= yaffs2_rd_checkpt_validty_marker(dev
, 1);
730 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("read checkpoint device" TENDSTR
)));
731 ok
= yaffs2_rd_checkpt_dev(dev
);
734 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("read checkpoint objects" TENDSTR
)));
735 ok
= yaffs2_rd_checkpt_objs(dev
);
738 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("read checkpoint validity" TENDSTR
)));
739 ok
= yaffs2_rd_checkpt_validty_marker(dev
, 0);
743 ok
= yaffs2_rd_checkpt_sum(dev
);
744 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("read checkpoint checksum %d" TENDSTR
), ok
));
747 if (!yaffs_checkpt_close(dev
))
751 dev
->is_checkpointed
= 1;
753 dev
->is_checkpointed
= 0;
759 void yaffs2_checkpt_invalidate(yaffs_dev_t
*dev
)
761 if (dev
->is_checkpointed
||
762 dev
->blocks_in_checkpt
> 0) {
763 dev
->is_checkpointed
= 0;
764 yaffs2_checkpt_invalidate_stream(dev
);
766 if (dev
->param
.sb_dirty_fn
)
767 dev
->param
.sb_dirty_fn(dev
);
771 int yaffs_checkpoint_save(yaffs_dev_t
*dev
)
774 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("save entry: is_checkpointed %d"TENDSTR
), dev
->is_checkpointed
));
776 yaffs_verify_objects(dev
);
777 yaffs_verify_blocks(dev
);
778 yaffs_verify_free_chunks(dev
);
780 if (!dev
->is_checkpointed
) {
781 yaffs2_checkpt_invalidate(dev
);
782 yaffs2_wr_checkpt_data(dev
);
785 T(YAFFS_TRACE_ALWAYS
, (TSTR("save exit: is_checkpointed %d"TENDSTR
), dev
->is_checkpointed
));
787 return dev
->is_checkpointed
;
790 int yaffs2_checkpt_restore(yaffs_dev_t
*dev
)
793 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("restore entry: is_checkpointed %d"TENDSTR
), dev
->is_checkpointed
));
795 retval
= yaffs2_rd_checkpt_data(dev
);
797 if (dev
->is_checkpointed
) {
798 yaffs_verify_objects(dev
);
799 yaffs_verify_blocks(dev
);
800 yaffs_verify_free_chunks(dev
);
803 T(YAFFS_TRACE_CHECKPOINT
, (TSTR("restore exit: is_checkpointed %d"TENDSTR
), dev
->is_checkpointed
));
808 int yaffs2_handle_hole(yaffs_obj_t
*obj
, loff_t new_size
)
810 /* if newsSize > oldFileSize.
811 * We're going to be writing a hole.
812 * If the hole is small then write zeros otherwise write a start of hole marker.
819 int result
= YAFFS_OK
;
820 yaffs_dev_t
*dev
= NULL
;
822 __u8
*localBuffer
= NULL
;
824 int smallIncreaseOk
= 0;
829 if(obj
->variant_type
!= YAFFS_OBJECT_TYPE_FILE
)
834 /* Bail out if not yaffs2 mode */
835 if(!dev
->param
.is_yaffs2
)
838 oldFileSize
= obj
->variant
.file_variant
.file_size
;
840 if (new_size
<= oldFileSize
)
843 increase
= new_size
- oldFileSize
;
845 if(increase
< YAFFS_SMALL_HOLE_THRESHOLD
* dev
->data_bytes_per_chunk
&&
846 yaffs_check_alloc_available(dev
, YAFFS_SMALL_HOLE_THRESHOLD
+ 1))
852 localBuffer
= yaffs_get_temp_buffer(dev
, __LINE__
);
855 /* fill hole with zero bytes */
856 int pos
= oldFileSize
;
859 memset(localBuffer
,0,dev
->data_bytes_per_chunk
);
862 while(increase
> 0 && smallIncreaseOk
){
863 thisWrite
= increase
;
864 if(thisWrite
> dev
->data_bytes_per_chunk
)
865 thisWrite
= dev
->data_bytes_per_chunk
;
866 written
= yaffs_do_file_wr(obj
,localBuffer
,pos
,thisWrite
,0);
867 if(written
== thisWrite
){
869 increase
-= thisWrite
;
874 yaffs_release_temp_buffer(dev
,localBuffer
,__LINE__
);
876 /* If we were out of space then reverse any chunks we've added */
878 yaffs_resize_file_down(obj
, oldFileSize
);
881 if (!smallIncreaseOk
&&
883 obj
->parent
->obj_id
!= YAFFS_OBJECTID_UNLINKED
&&
884 obj
->parent
->obj_id
!= YAFFS_OBJECTID_DELETED
){
885 /* Write a hole start header with the old file size */
886 yaffs_update_oh(obj
, NULL
, 0, 1, 0, NULL
);
900 static int yaffs2_ybicmp(const void *a
, const void *b
)
902 register int aseq
= ((yaffs_BlockIndex
*)a
)->seq
;
903 register int bseq
= ((yaffs_BlockIndex
*)b
)->seq
;
904 register int ablock
= ((yaffs_BlockIndex
*)a
)->block
;
905 register int bblock
= ((yaffs_BlockIndex
*)b
)->block
;
907 return ablock
- bblock
;
912 int yaffs2_scan_backwards(yaffs_dev_t
*dev
)
919 int nBlocksToScan
= 0;
925 yaffs_block_state_t state
;
926 yaffs_obj_t
*hard_list
= NULL
;
927 yaffs_block_info_t
*bi
;
929 yaffs_obj_header
*oh
;
932 int nBlocks
= dev
->internal_end_block
- dev
->internal_start_block
+ 1;
938 int foundChunksInBlock
;
940 int alloc_failed
= 0;
943 yaffs_BlockIndex
*blockIndex
= NULL
;
944 int altBlockIndex
= 0;
948 ("yaffs2_scan_backwards starts intstartblk %d intendblk %d..."
949 TENDSTR
), dev
->internal_start_block
, dev
->internal_end_block
));
952 dev
->seq_number
= YAFFS_LOWEST_SEQUENCE_NUMBER
;
954 blockIndex
= YMALLOC(nBlocks
* sizeof(yaffs_BlockIndex
));
957 blockIndex
= YMALLOC_ALT(nBlocks
* sizeof(yaffs_BlockIndex
));
963 (TSTR("yaffs2_scan_backwards() could not allocate block index!" TENDSTR
)));
967 dev
->blocks_in_checkpt
= 0;
969 chunkData
= yaffs_get_temp_buffer(dev
, __LINE__
);
971 /* Scan all the blocks to determine their state */
972 bi
= dev
->block_info
;
973 for (blk
= dev
->internal_start_block
; blk
<= dev
->internal_end_block
; blk
++) {
974 yaffs_clear_chunk_bits(dev
, blk
);
975 bi
->pages_in_use
= 0;
976 bi
->soft_del_pages
= 0;
978 yaffs_query_init_block_state(dev
, blk
, &state
, &seq_number
);
980 bi
->block_state
= state
;
981 bi
->seq_number
= seq_number
;
983 if (bi
->seq_number
== YAFFS_SEQUENCE_CHECKPOINT_DATA
)
984 bi
->block_state
= state
= YAFFS_BLOCK_STATE_CHECKPOINT
;
985 if (bi
->seq_number
== YAFFS_SEQUENCE_BAD_BLOCK
)
986 bi
->block_state
= state
= YAFFS_BLOCK_STATE_DEAD
;
988 T(YAFFS_TRACE_SCAN_DEBUG
,
989 (TSTR("Block scanning block %d state %d seq %d" TENDSTR
), blk
,
993 if (state
== YAFFS_BLOCK_STATE_CHECKPOINT
) {
994 dev
->blocks_in_checkpt
++;
996 } else if (state
== YAFFS_BLOCK_STATE_DEAD
) {
997 T(YAFFS_TRACE_BAD_BLOCKS
,
998 (TSTR("block %d is bad" TENDSTR
), blk
));
999 } else if (state
== YAFFS_BLOCK_STATE_EMPTY
) {
1000 T(YAFFS_TRACE_SCAN_DEBUG
,
1001 (TSTR("Block empty " TENDSTR
)));
1002 dev
->n_erased_blocks
++;
1003 dev
->n_free_chunks
+= dev
->param
.chunks_per_block
;
1004 } else if (state
== YAFFS_BLOCK_STATE_NEEDS_SCANNING
) {
1006 /* Determine the highest sequence number */
1007 if (seq_number
>= YAFFS_LOWEST_SEQUENCE_NUMBER
&&
1008 seq_number
< YAFFS_HIGHEST_SEQUENCE_NUMBER
) {
1010 blockIndex
[nBlocksToScan
].seq
= seq_number
;
1011 blockIndex
[nBlocksToScan
].block
= blk
;
1015 if (seq_number
>= dev
->seq_number
)
1016 dev
->seq_number
= seq_number
;
1018 /* TODO: Nasty sequence number! */
1021 ("Block scanning block %d has bad sequence number %d"
1022 TENDSTR
), blk
, seq_number
));
1030 (TSTR("%d blocks to be sorted..." TENDSTR
), nBlocksToScan
));
1036 /* Sort the blocks by sequence number*/
1037 yaffs_qsort(blockIndex
, nBlocksToScan
, sizeof(yaffs_BlockIndex
), yaffs2_ybicmp
);
1041 T(YAFFS_TRACE_SCAN
, (TSTR("...done" TENDSTR
)));
1043 /* Now scan the blocks looking at the data. */
1045 endIterator
= nBlocksToScan
- 1;
1046 T(YAFFS_TRACE_SCAN_DEBUG
,
1047 (TSTR("%d blocks to be scanned" TENDSTR
), nBlocksToScan
));
1049 /* For each block.... backwards */
1050 for (blockIterator
= endIterator
; !alloc_failed
&& blockIterator
>= startIterator
;
1052 /* Cooperative multitasking! This loop can run for so
1053 long that watchdog timers expire. */
1056 /* get the block to scan in the correct order */
1057 blk
= blockIndex
[blockIterator
].block
;
1059 bi
= yaffs_get_block_info(dev
, blk
);
1062 state
= bi
->block_state
;
1066 /* For each chunk in each block that needs scanning.... */
1067 foundChunksInBlock
= 0;
1068 for (c
= dev
->param
.chunks_per_block
- 1;
1069 !alloc_failed
&& c
>= 0 &&
1070 (state
== YAFFS_BLOCK_STATE_NEEDS_SCANNING
||
1071 state
== YAFFS_BLOCK_STATE_ALLOCATING
); c
--) {
1072 /* Scan backwards...
1073 * Read the tags and decide what to do
1076 chunk
= blk
* dev
->param
.chunks_per_block
+ c
;
1078 result
= yaffs_rd_chunk_tags_nand(dev
, chunk
, NULL
,
1081 /* Let's have a good look at this chunk... */
1083 if (!tags
.chunk_used
) {
1084 /* An unassigned chunk in the block.
1085 * If there are used chunks after this one, then
1086 * it is a chunk that was skipped due to failing the erased
1087 * check. Just skip it so that it can be deleted.
1088 * But, more typically, We get here when this is an unallocated
1089 * chunk and his means that either the block is empty or
1090 * this is the one being allocated from
1093 if (foundChunksInBlock
) {
1094 /* This is a chunk that was skipped due to failing the erased check */
1095 } else if (c
== 0) {
1096 /* We're looking at the first chunk in the block so the block is unused */
1097 state
= YAFFS_BLOCK_STATE_EMPTY
;
1098 dev
->n_erased_blocks
++;
1100 if (state
== YAFFS_BLOCK_STATE_NEEDS_SCANNING
||
1101 state
== YAFFS_BLOCK_STATE_ALLOCATING
) {
1102 if (dev
->seq_number
== bi
->seq_number
) {
1103 /* this is the block being allocated from */
1107 (" Allocating from %d %d"
1110 state
= YAFFS_BLOCK_STATE_ALLOCATING
;
1111 dev
->alloc_block
= blk
;
1112 dev
->alloc_page
= c
;
1113 dev
->alloc_block_finder
= blk
;
1115 /* This is a partially written block that is not
1116 * the current allocation block.
1120 (TSTR("Partially written block %d detected" TENDSTR
),
1126 dev
->n_free_chunks
++;
1128 } else if (tags
.ecc_result
== YAFFS_ECC_RESULT_UNFIXED
) {
1130 (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR
),
1133 dev
->n_free_chunks
++;
1135 } else if (tags
.obj_id
> YAFFS_MAX_OBJECT_ID
||
1136 tags
.chunk_id
> YAFFS_MAX_CHUNK_ID
||
1137 (tags
.chunk_id
> 0 && tags
.n_bytes
> dev
->data_bytes_per_chunk
) ||
1138 tags
.seq_number
!= bi
->seq_number
) {
1140 (TSTR("Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored"TENDSTR
),
1141 blk
, c
,tags
.obj_id
, tags
.chunk_id
, tags
.n_bytes
));
1143 dev
->n_free_chunks
++;
1145 } else if (tags
.chunk_id
> 0) {
1146 /* chunk_id > 0 so it is a data chunk... */
1147 unsigned int endpos
;
1149 (tags
.chunk_id
- 1) * dev
->data_bytes_per_chunk
;
1151 foundChunksInBlock
= 1;
1154 yaffs_set_chunk_bit(dev
, blk
, c
);
1157 in
= yaffs_find_or_create_by_number(dev
,
1160 YAFFS_OBJECT_TYPE_FILE
);
1167 in
->variant_type
== YAFFS_OBJECT_TYPE_FILE
1168 && chunkBase
< in
->variant
.file_variant
.shrink_size
) {
1169 /* This has not been invalidated by a resize */
1170 if (!yaffs_put_chunk_in_file(in
, tags
.chunk_id
, chunk
, -1)) {
1174 /* File size is calculated by looking at the data chunks if we have not
1175 * seen an object header yet. Stop this practice once we find an object header.
1177 endpos
= chunkBase
+ tags
.n_bytes
;
1179 if (!in
->valid
&& /* have not got an object header yet */
1180 in
->variant
.file_variant
.scanned_size
< endpos
) {
1181 in
->variant
.file_variant
.scanned_size
= endpos
;
1182 in
->variant
.file_variant
.file_size
= endpos
;
1186 /* This chunk has been invalidated by a resize, or a past file deletion
1187 * so delete the chunk*/
1188 yaffs_chunk_del(dev
, chunk
, 1, __LINE__
);
1192 /* chunk_id == 0, so it is an ObjectHeader.
1193 * Thus, we read in the object header and make the object
1195 foundChunksInBlock
= 1;
1197 yaffs_set_chunk_bit(dev
, blk
, c
);
1203 if (tags
.extra_available
) {
1204 in
= yaffs_find_or_create_by_number(dev
,
1206 tags
.extra_obj_type
);
1212 (!in
->valid
&& dev
->param
.disable_lazy_load
) ||
1213 tags
.extra_shadows
||
1215 (tags
.obj_id
== YAFFS_OBJECTID_ROOT
||
1216 tags
.obj_id
== YAFFS_OBJECTID_LOSTNFOUND
))) {
1218 /* If we don't have valid info then we need to read the chunk
1219 * TODO In future we can probably defer reading the chunk and
1220 * living with invalid data until needed.
1223 result
= yaffs_rd_chunk_tags_nand(dev
,
1228 oh
= (yaffs_obj_header
*) chunkData
;
1230 if (dev
->param
.inband_tags
) {
1231 /* Fix up the header if they got corrupted by inband tags */
1232 oh
->shadows_obj
= oh
->inband_shadowed_obj_id
;
1233 oh
->is_shrink
= oh
->inband_is_shrink
;
1237 in
= yaffs_find_or_create_by_number(dev
, tags
.obj_id
, oh
->type
);
1245 /* TODO Hoosterman we have a problem! */
1246 T(YAFFS_TRACE_ERROR
,
1248 ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
1249 TENDSTR
), tags
.obj_id
, chunk
));
1254 /* We have already filled this one.
1255 * We have a duplicate that will be discarded, but
1256 * we first have to suck out resize info if it is a file.
1259 if ((in
->variant_type
== YAFFS_OBJECT_TYPE_FILE
) &&
1261 oh
->type
== YAFFS_OBJECT_TYPE_FILE
) ||
1262 (tags
.extra_available
&&
1263 tags
.extra_obj_type
== YAFFS_OBJECT_TYPE_FILE
))) {
1265 (oh
) ? oh
->file_size
: tags
.
1267 __u32 parent_obj_id
=
1269 parent_obj_id
: tags
.
1274 (oh
) ? oh
->is_shrink
: tags
.
1277 /* If it is deleted (unlinked at start also means deleted)
1278 * we treat the file size as being zeroed at this point.
1280 if (parent_obj_id
==
1281 YAFFS_OBJECTID_DELETED
1283 YAFFS_OBJECTID_UNLINKED
) {
1288 if (is_shrink
&& in
->variant
.file_variant
.shrink_size
> thisSize
)
1289 in
->variant
.file_variant
.shrink_size
= thisSize
;
1292 bi
->has_shrink_hdr
= 1;
1295 /* Use existing - destroy this one. */
1296 yaffs_chunk_del(dev
, chunk
, 1, __LINE__
);
1300 if (!in
->valid
&& in
->variant_type
!=
1301 (oh
? oh
->type
: tags
.extra_obj_type
))
1302 T(YAFFS_TRACE_ERROR
, (
1303 TSTR("yaffs tragedy: Bad object type, "
1304 TCONT("%d != %d, for object %d at chunk ")
1305 TCONT("%d during scan")
1307 oh
->type
: tags
.extra_obj_type
,
1308 in
->variant_type
, tags
.obj_id
,
1312 (tags
.obj_id
== YAFFS_OBJECTID_ROOT
||
1314 YAFFS_OBJECTID_LOSTNFOUND
)) {
1315 /* We only load some info, don't fiddle with directory structure */
1320 in
->yst_mode
= oh
->yst_mode
;
1321 #ifdef CONFIG_YAFFS_WINCE
1322 in
->win_atime
[0] = oh
->win_atime
[0];
1323 in
->win_ctime
[0] = oh
->win_ctime
[0];
1324 in
->win_mtime
[0] = oh
->win_mtime
[0];
1325 in
->win_atime
[1] = oh
->win_atime
[1];
1326 in
->win_ctime
[1] = oh
->win_ctime
[1];
1327 in
->win_mtime
[1] = oh
->win_mtime
[1];
1329 in
->yst_uid
= oh
->yst_uid
;
1330 in
->yst_gid
= oh
->yst_gid
;
1331 in
->yst_atime
= oh
->yst_atime
;
1332 in
->yst_mtime
= oh
->yst_mtime
;
1333 in
->yst_ctime
= oh
->yst_ctime
;
1334 in
->yst_rdev
= oh
->yst_rdev
;
1336 in
->lazy_loaded
= 0;
1340 in
->lazy_loaded
= 1;
1342 in
->hdr_chunk
= chunk
;
1344 } else if (!in
->valid
) {
1345 /* we need to load this info */
1348 in
->hdr_chunk
= chunk
;
1351 in
->variant_type
= oh
->type
;
1353 in
->yst_mode
= oh
->yst_mode
;
1354 #ifdef CONFIG_YAFFS_WINCE
1355 in
->win_atime
[0] = oh
->win_atime
[0];
1356 in
->win_ctime
[0] = oh
->win_ctime
[0];
1357 in
->win_mtime
[0] = oh
->win_mtime
[0];
1358 in
->win_atime
[1] = oh
->win_atime
[1];
1359 in
->win_ctime
[1] = oh
->win_ctime
[1];
1360 in
->win_mtime
[1] = oh
->win_mtime
[1];
1362 in
->yst_uid
= oh
->yst_uid
;
1363 in
->yst_gid
= oh
->yst_gid
;
1364 in
->yst_atime
= oh
->yst_atime
;
1365 in
->yst_mtime
= oh
->yst_mtime
;
1366 in
->yst_ctime
= oh
->yst_ctime
;
1367 in
->yst_rdev
= oh
->yst_rdev
;
1370 if (oh
->shadows_obj
> 0)
1371 yaffs_handle_shadowed_obj(dev
,
1378 yaffs_set_obj_name_from_oh(in
, oh
);
1380 yaffs_find_or_create_by_number
1381 (dev
, oh
->parent_obj_id
,
1382 YAFFS_OBJECT_TYPE_DIRECTORY
);
1384 file_size
= oh
->file_size
;
1385 is_shrink
= oh
->is_shrink
;
1386 equiv_id
= oh
->equiv_id
;
1389 in
->variant_type
= tags
.extra_obj_type
;
1391 yaffs_find_or_create_by_number
1392 (dev
, tags
.extra_parent_id
,
1393 YAFFS_OBJECT_TYPE_DIRECTORY
);
1394 file_size
= tags
.extra_length
;
1395 is_shrink
= tags
.extra_is_shrink
;
1396 equiv_id
= tags
.extra_equiv_id
;
1397 in
->lazy_loaded
= 1;
1405 /* directory stuff...
1409 if (parent
&& parent
->variant_type
==
1410 YAFFS_OBJECT_TYPE_UNKNOWN
) {
1411 /* Set up as a directory */
1412 parent
->variant_type
=
1413 YAFFS_OBJECT_TYPE_DIRECTORY
;
1414 YINIT_LIST_HEAD(&parent
->variant
.
1417 } else if (!parent
|| parent
->variant_type
!=
1418 YAFFS_OBJECT_TYPE_DIRECTORY
) {
1419 /* Hoosterman, another problem....
1420 * We're trying to use a non-directory as a directory
1423 T(YAFFS_TRACE_ERROR
,
1425 ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
1427 parent
= dev
->lost_n_found
;
1430 yaffs_add_obj_to_dir(parent
, in
);
1432 itsUnlinked
= (parent
== dev
->del_dir
) ||
1433 (parent
== dev
->unlinked_dir
);
1436 /* Mark the block as having a shrinkHeader */
1437 bi
->has_shrink_hdr
= 1;
1440 /* Note re hardlinks.
1441 * Since we might scan a hardlink before its equivalent object is scanned
1442 * we put them all in a list.
1443 * After scanning is complete, we should have all the objects, so we run
1444 * through this list and fix up all the chains.
1447 switch (in
->variant_type
) {
1448 case YAFFS_OBJECT_TYPE_UNKNOWN
:
1449 /* Todo got a problem */
1451 case YAFFS_OBJECT_TYPE_FILE
:
1453 if (in
->variant
.file_variant
.
1454 scanned_size
< file_size
) {
1455 /* This covers the case where the file size is greater
1456 * than where the data is
1457 * This will happen if the file is resized to be larger
1458 * than its current data extents.
1460 in
->variant
.file_variant
.file_size
= file_size
;
1461 in
->variant
.file_variant
.scanned_size
= file_size
;
1464 if (in
->variant
.file_variant
.shrink_size
> file_size
)
1465 in
->variant
.file_variant
.shrink_size
= file_size
;
1469 case YAFFS_OBJECT_TYPE_HARDLINK
:
1471 in
->variant
.hardlink_variant
.equiv_id
=
1473 in
->hard_links
.next
=
1474 (struct ylist_head
*) hard_list
;
1478 case YAFFS_OBJECT_TYPE_DIRECTORY
:
1481 case YAFFS_OBJECT_TYPE_SPECIAL
:
1484 case YAFFS_OBJECT_TYPE_SYMLINK
:
1486 in
->variant
.symlink_variant
.alias
=
1487 yaffs_clone_str(oh
->alias
);
1488 if (!in
->variant
.symlink_variant
.alias
)
1498 } /* End of scanning for each chunk */
1500 if (state
== YAFFS_BLOCK_STATE_NEEDS_SCANNING
) {
1501 /* If we got this far while scanning, then the block is fully allocated. */
1502 state
= YAFFS_BLOCK_STATE_FULL
;
1506 bi
->block_state
= state
;
1508 /* Now let's see if it was dirty */
1509 if (bi
->pages_in_use
== 0 &&
1510 !bi
->has_shrink_hdr
&&
1511 bi
->block_state
== YAFFS_BLOCK_STATE_FULL
) {
1512 yaffs_block_became_dirty(dev
, blk
);
1517 yaffs_skip_rest_of_block(dev
);
1520 YFREE_ALT(blockIndex
);
1524 /* Ok, we've done all the scanning.
1525 * Fix up the hard link chains.
1526 * We should now have scanned all the objects, now it's time to add these
1529 yaffs_link_fixup(dev
, hard_list
);
1532 yaffs_release_temp_buffer(dev
, chunkData
, __LINE__
);
1537 T(YAFFS_TRACE_SCAN
, (TSTR("yaffs2_scan_backwards ends" TENDSTR
)));