Root/target/linux/generic/files/fs/yaffs2/yaffs_yaffs2.c

1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2010 Aleph One Ltd.
5 * for Toby Churchill Ltd and Brightstar Engineering
6 *
7 * Created by Charles Manning <charles@aleph1.co.uk>
8 *
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.
12 */
13
14
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"
24
25/*
26 * Checkpoints are really no benefit on very small partitions.
27 *
28 * To save space on small partitions don't bother with checkpoints unless
29 * the partition is at least this big.
30 */
31#define YAFFS_CHECKPOINT_MIN_BLOCKS 60
32
33#define YAFFS_SMALL_HOLE_THRESHOLD 4
34
35
36/*
37 * Oldest Dirty Sequence Number handling.
38 */
39 
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.
43 */
44void yaffs_calc_oldest_dirty_seq(yaffs_dev_t *dev)
45{
46    int i;
47    unsigned seq;
48    unsigned block_no = 0;
49    yaffs_block_info_t *b;
50
51    if(!dev->param.is_yaffs2)
52        return;
53
54    /* Find the oldest dirty sequence number. */
55    seq = dev->seq_number + 1;
56    b = dev->block_info;
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) {
61            seq = b->seq_number;
62            block_no = i;
63        }
64        b++;
65    }
66
67    if(block_no){
68        dev->oldest_dirty_seq = seq;
69        dev->oldest_dirty_block = block_no;
70    }
71
72}
73
74
75void yaffs2_find_oldest_dirty_seq(yaffs_dev_t *dev)
76{
77    if(!dev->param.is_yaffs2)
78        return;
79
80    if(!dev->oldest_dirty_seq)
81        yaffs_calc_oldest_dirty_seq(dev);
82}
83
84/*
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.
89 */
90void yaffs2_clear_oldest_dirty_seq(yaffs_dev_t *dev, yaffs_block_info_t *bi)
91{
92
93    if(!dev->param.is_yaffs2)
94        return;
95
96    if(!bi || bi->seq_number == dev->oldest_dirty_seq){
97        dev->oldest_dirty_seq = 0;
98        dev->oldest_dirty_block = 0;
99    }
100}
101
102/*
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.
106 */
107void yaffs2_update_oldest_dirty_seq(yaffs_dev_t *dev, unsigned block_no, yaffs_block_info_t *bi)
108{
109    if(!dev->param.is_yaffs2)
110        return;
111
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;
116        }
117    }
118}
119
120int yaffs_block_ok_for_gc(yaffs_dev_t *dev,
121                    yaffs_block_info_t *bi)
122{
123
124    if (!dev->param.is_yaffs2)
125        return 1; /* disqualification only applies to yaffs2. */
126
127    if (!bi->has_shrink_hdr)
128        return 1; /* can gc */
129
130    yaffs2_find_oldest_dirty_seq(dev);
131
132    /* Can't do gc of this block if there are any blocks older than this one that have
133     * discarded pages.
134     */
135    return (bi->seq_number <= dev->oldest_dirty_seq);
136}
137
138/*
139 * yaffs2_find_refresh_block()
140 * periodically finds the oldest full block by sequence number for refreshing.
141 * Only for yaffs2.
142 */
143__u32 yaffs2_find_refresh_block(yaffs_dev_t *dev)
144{
145    __u32 b ;
146
147    __u32 oldest = 0;
148    __u32 oldestSequence = 0;
149
150    yaffs_block_info_t *bi;
151
152    if(!dev->param.is_yaffs2)
153        return oldest;
154
155    /*
156     * If refresh period < 10 then refreshing is disabled.
157     */
158    if(dev->param.refresh_period < 10)
159            return oldest;
160
161        /*
162         * Fix broken values.
163         */
164        if(dev->refresh_skip > dev->param.refresh_period)
165                dev->refresh_skip = dev->param.refresh_period;
166
167    if(dev->refresh_skip > 0)
168            return oldest;
169
170    /*
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.
174     */
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++){
179
180        if (bi->block_state == YAFFS_BLOCK_STATE_FULL){
181
182            if(oldest < 1 ||
183                                bi->seq_number < oldestSequence){
184                                oldest = b;
185                                oldestSequence = bi->seq_number;
186                        }
187        }
188        bi++;
189    }
190
191    if (oldest > 0) {
192        T(YAFFS_TRACE_GC,
193          (TSTR("GC refresh count %d selected block %d with seq_number %d" TENDSTR),
194           dev->refresh_count, oldest, oldestSequence));
195    }
196
197    return oldest;
198}
199
200int yaffs2_checkpt_required(yaffs_dev_t *dev)
201{
202    int nblocks;
203    
204    if(!dev->param.is_yaffs2)
205        return 0;
206    
207    nblocks = dev->internal_end_block - dev->internal_start_block + 1 ;
208
209    return !dev->param.skip_checkpt_wr &&
210        !dev->read_only &&
211        (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
212}
213
214int yaffs_calc_checkpt_blocks_required(yaffs_dev_t *dev)
215{
216    int retval;
217
218    if(!dev->param.is_yaffs2)
219        return 0;
220
221    if (!dev->checkpoint_blocks_required &&
222        yaffs2_checkpt_required(dev)){
223        /* Not a valid value so recalculate */
224        int n_bytes = 0;
225        int nBlocks;
226        int devBlocks = (dev->param.end_block - dev->param.start_block + 1);
227
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*/
236
237        /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
238
239        nBlocks = (n_bytes/(dev->data_bytes_per_chunk * dev->param.chunks_per_block)) + 3;
240
241        dev->checkpoint_blocks_required = nBlocks;
242    }
243
244    retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
245    if(retval < 0)
246        retval = 0;
247    return retval;
248}
249
250/*--------------------- Checkpointing --------------------*/
251
252
253static int yaffs2_wr_checkpt_validity_marker(yaffs_dev_t *dev, int head)
254{
255    yaffs_checkpt_validty_t cp;
256
257    memset(&cp, 0, sizeof(cp));
258
259    cp.struct_type = sizeof(cp);
260    cp.magic = YAFFS_MAGIC;
261    cp.version = YAFFS_CHECKPOINT_VERSION;
262    cp.head = (head) ? 1 : 0;
263
264    return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
265        1 : 0;
266}
267
268static int yaffs2_rd_checkpt_validty_marker(yaffs_dev_t *dev, int head)
269{
270    yaffs_checkpt_validty_t cp;
271    int ok;
272
273    ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
274
275    if (ok)
276        ok = (cp.struct_type == sizeof(cp)) &&
277             (cp.magic == YAFFS_MAGIC) &&
278             (cp.version == YAFFS_CHECKPOINT_VERSION) &&
279             (cp.head == ((head) ? 1 : 0));
280    return ok ? 1 : 0;
281}
282
283static void yaffs2_dev_to_checkpt_dev(yaffs_checkpt_dev_t *cp,
284                       yaffs_dev_t *dev)
285{
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;
290
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;
295
296}
297
298static void yaffs_checkpt_dev_to_dev(yaffs_dev_t *dev,
299                       yaffs_checkpt_dev_t *cp)
300{
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;
305
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;
310}
311
312
313static int yaffs2_wr_checkpt_dev(yaffs_dev_t *dev)
314{
315    yaffs_checkpt_dev_t cp;
316    __u32 n_bytes;
317    __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1);
318
319    int ok;
320
321    /* Write device runtime values*/
322    yaffs2_dev_to_checkpt_dev(&cp, dev);
323    cp.struct_type = sizeof(cp);
324
325    ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
326
327    /* Write block info */
328    if (ok) {
329        n_bytes = nBlocks * sizeof(yaffs_block_info_t);
330        ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes);
331    }
332
333    /* Write chunk bits */
334    if (ok) {
335        n_bytes = nBlocks * dev->chunk_bit_stride;
336        ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes);
337    }
338    return ok ? 1 : 0;
339
340}
341
342static int yaffs2_rd_checkpt_dev(yaffs_dev_t *dev)
343{
344    yaffs_checkpt_dev_t cp;
345    __u32 n_bytes;
346    __u32 nBlocks = (dev->internal_end_block - dev->internal_start_block + 1);
347
348    int ok;
349
350    ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
351    if (!ok)
352        return 0;
353
354    if (cp.struct_type != sizeof(cp))
355        return 0;
356
357
358    yaffs_checkpt_dev_to_dev(dev, &cp);
359
360    n_bytes = nBlocks * sizeof(yaffs_block_info_t);
361
362    ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
363
364    if (!ok)
365        return 0;
366    n_bytes = nBlocks * dev->chunk_bit_stride;
367
368    ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
369
370    return ok ? 1 : 0;
371}
372
373static void yaffs2_obj_checkpt_obj(yaffs_checkpt_obj_t *cp,
374                       yaffs_obj_t *obj)
375{
376
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;
389
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;
394}
395
396static int taffs2_checkpt_obj_to_obj(yaffs_obj_t *obj, yaffs_checkpt_obj_t *cp)
397{
398
399    yaffs_obj_t *parent;
400
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,
405            obj->variant_type));
406        return 0;
407    }
408
409    obj->obj_id = cp->obj_id;
410
411    if (cp->parent_id)
412        parent = yaffs_find_or_create_by_number(
413                    obj->my_dev,
414                    cp->parent_id,
415                    YAFFS_OBJECT_TYPE_DIRECTORY);
416    else
417        parent = NULL;
418
419    if (parent) {
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")
423                TENDSTR),
424                cp->obj_id, cp->parent_id, cp->variant_type,
425                cp->hdr_chunk, parent->variant_type));
426            return 0;
427        }
428        yaffs_add_obj_to_dir(parent, obj);
429    }
430
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;
441
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;
446
447    if (obj->hdr_chunk > 0)
448        obj->lazy_loaded = 1;
449    return 1;
450}
451
452
453
454static int yaffs2_checkpt_tnode_worker(yaffs_obj_t *in, yaffs_tnode_t *tn,
455                    __u32 level, int chunk_offset)
456{
457    int i;
458    yaffs_dev_t *dev = in->my_dev;
459    int ok = 1;
460
461    if (tn) {
462        if (level > 0) {
463
464            for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
465                if (tn->internal[i]) {
466                    ok = yaffs2_checkpt_tnode_worker(in,
467                            tn->internal[i],
468                            level - 1,
469                            (chunk_offset<<YAFFS_TNODES_INTERNAL_BITS) + i);
470                }
471            }
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));
475            if (ok)
476                ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == dev->tnode_size);
477        }
478    }
479
480    return ok;
481
482}
483
484static int yaffs2_wr_checkpt_tnodes(yaffs_obj_t *obj)
485{
486    __u32 endMarker = ~0;
487    int ok = 1;
488
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,
493                        0);
494        if (ok)
495            ok = (yaffs2_checkpt_wr(obj->my_dev, &endMarker, sizeof(endMarker)) ==
496                sizeof(endMarker));
497    }
498
499    return ok ? 1 : 0;
500}
501
502static int yaffs2_rd_checkpt_tnodes(yaffs_obj_t *obj)
503{
504    __u32 baseChunk;
505    int ok = 1;
506    yaffs_dev_t *dev = obj->my_dev;
507    yaffs_file_s *fileStructPtr = &obj->variant.file_variant;
508    yaffs_tnode_t *tn;
509    int nread = 0;
510
511    ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
512
513    while (ok && (~baseChunk)) {
514        nread++;
515        /* Read level 0 tnode */
516
517
518        tn = yaffs_get_tnode(dev);
519        if (tn){
520            ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == dev->tnode_size);
521        } else
522            ok = 0;
523
524        if (tn && ok)
525            ok = yaffs_add_find_tnode_0(dev,
526                            fileStructPtr,
527                            baseChunk,
528                            tn) ? 1 : 0;
529
530        if (ok)
531            ok = (yaffs2_checkpt_rd(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
532
533    }
534
535    T(YAFFS_TRACE_CHECKPOINT, (
536        TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
537        nread, baseChunk, ok));
538
539    return ok ? 1 : 0;
540}
541
542
543static int yaffs2_wr_checkpt_objs(yaffs_dev_t *dev)
544{
545    yaffs_obj_t *obj;
546    yaffs_checkpt_obj_t cp;
547    int i;
548    int ok = 1;
549    struct ylist_head *lh;
550
551
552    /* Iterate through the objects in each hash entry,
553     * dumping them to the checkpointing stream.
554     */
555
556    for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
557        ylist_for_each(lh, &dev->obj_bucket[i].list) {
558            if (lh) {
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);
563
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));
567
568                    ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
569
570                    if (ok && obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
571                        ok = yaffs2_wr_checkpt_tnodes(obj);
572                }
573            }
574        }
575    }
576
577    /* Dump end of list */
578    memset(&cp, 0xFF, sizeof(yaffs_checkpt_obj_t));
579    cp.struct_type = sizeof(cp);
580
581    if (ok)
582        ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
583
584    return ok ? 1 : 0;
585}
586
587static int yaffs2_rd_checkpt_objs(yaffs_dev_t *dev)
588{
589    yaffs_obj_t *obj;
590    yaffs_checkpt_obj_t cp;
591    int ok = 1;
592    int done = 0;
593    yaffs_obj_t *hard_list = NULL;
594
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));
600            ok = 0;
601        }
602
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));
605
606        if (ok && cp.obj_id == ~0)
607            done = 1;
608        else if (ok) {
609            obj = yaffs_find_or_create_by_number(dev, cp.obj_id, cp.variant_type);
610            if (obj) {
611                ok = taffs2_checkpt_obj_to_obj(obj, &cp);
612                if (!ok)
613                    break;
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;
619                    hard_list = obj;
620                }
621            } else
622                ok = 0;
623        }
624    }
625
626    if (ok)
627        yaffs_link_fixup(dev, hard_list);
628
629    return ok ? 1 : 0;
630}
631
632static int yaffs2_wr_checkpt_sum(yaffs_dev_t *dev)
633{
634    __u32 checkpt_sum;
635    int ok;
636
637    yaffs2_get_checkpt_sum(dev, &checkpt_sum);
638
639    ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == sizeof(checkpt_sum));
640
641    if (!ok)
642        return 0;
643
644    return 1;
645}
646
647static int yaffs2_rd_checkpt_sum(yaffs_dev_t *dev)
648{
649    __u32 checkpt_sum0;
650    __u32 checkpt_sum1;
651    int ok;
652
653    yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
654
655    ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == sizeof(checkpt_sum1));
656
657    if (!ok)
658        return 0;
659
660    if (checkpt_sum0 != checkpt_sum1)
661        return 0;
662
663    return 1;
664}
665
666
667static int yaffs2_wr_checkpt_data(yaffs_dev_t *dev)
668{
669    int ok = 1;
670
671    if (!yaffs2_checkpt_required(dev)) {
672        T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
673        ok = 0;
674    }
675
676    if (ok)
677        ok = yaffs2_checkpt_open(dev, 1);
678
679    if (ok) {
680        T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
681        ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
682    }
683    if (ok) {
684        T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
685        ok = yaffs2_wr_checkpt_dev(dev);
686    }
687    if (ok) {
688        T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
689        ok = yaffs2_wr_checkpt_objs(dev);
690    }
691    if (ok) {
692        T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
693        ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
694    }
695
696    if (ok)
697        ok = yaffs2_wr_checkpt_sum(dev);
698
699    if (!yaffs_checkpt_close(dev))
700        ok = 0;
701
702    if (ok)
703        dev->is_checkpointed = 1;
704    else
705        dev->is_checkpointed = 0;
706
707    return dev->is_checkpointed;
708}
709
710static int yaffs2_rd_checkpt_data(yaffs_dev_t *dev)
711{
712    int ok = 1;
713    
714    if(!dev->param.is_yaffs2)
715        ok = 0;
716
717    if (ok && dev->param.skip_checkpt_rd) {
718        T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
719        ok = 0;
720    }
721
722    if (ok)
723        ok = yaffs2_checkpt_open(dev, 0); /* open for read */
724
725    if (ok) {
726        T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
727        ok = yaffs2_rd_checkpt_validty_marker(dev, 1);
728    }
729    if (ok) {
730        T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
731        ok = yaffs2_rd_checkpt_dev(dev);
732    }
733    if (ok) {
734        T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
735        ok = yaffs2_rd_checkpt_objs(dev);
736    }
737    if (ok) {
738        T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
739        ok = yaffs2_rd_checkpt_validty_marker(dev, 0);
740    }
741
742    if (ok) {
743        ok = yaffs2_rd_checkpt_sum(dev);
744        T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
745    }
746
747    if (!yaffs_checkpt_close(dev))
748        ok = 0;
749
750    if (ok)
751        dev->is_checkpointed = 1;
752    else
753        dev->is_checkpointed = 0;
754
755    return ok ? 1 : 0;
756
757}
758
759void yaffs2_checkpt_invalidate(yaffs_dev_t *dev)
760{
761    if (dev->is_checkpointed ||
762            dev->blocks_in_checkpt > 0) {
763        dev->is_checkpointed = 0;
764        yaffs2_checkpt_invalidate_stream(dev);
765    }
766    if (dev->param.sb_dirty_fn)
767        dev->param.sb_dirty_fn(dev);
768}
769
770
771int yaffs_checkpoint_save(yaffs_dev_t *dev)
772{
773
774    T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
775
776    yaffs_verify_objects(dev);
777    yaffs_verify_blocks(dev);
778    yaffs_verify_free_chunks(dev);
779
780    if (!dev->is_checkpointed) {
781        yaffs2_checkpt_invalidate(dev);
782        yaffs2_wr_checkpt_data(dev);
783    }
784
785    T(YAFFS_TRACE_ALWAYS, (TSTR("save exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
786
787    return dev->is_checkpointed;
788}
789
790int yaffs2_checkpt_restore(yaffs_dev_t *dev)
791{
792    int retval;
793    T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
794
795    retval = yaffs2_rd_checkpt_data(dev);
796
797    if (dev->is_checkpointed) {
798        yaffs_verify_objects(dev);
799        yaffs_verify_blocks(dev);
800        yaffs_verify_free_chunks(dev);
801    }
802
803    T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: is_checkpointed %d"TENDSTR), dev->is_checkpointed));
804
805    return retval;
806}
807
808int yaffs2_handle_hole(yaffs_obj_t *obj, loff_t new_size)
809{
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.
813     */
814        
815
816    loff_t oldFileSize;
817    int increase;
818    int smallHole ;
819    int result = YAFFS_OK;
820    yaffs_dev_t *dev = NULL;
821
822    __u8 *localBuffer = NULL;
823    
824    int smallIncreaseOk = 0;
825    
826    if(!obj)
827        return YAFFS_FAIL;
828
829    if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
830        return YAFFS_FAIL;
831    
832    dev = obj->my_dev;
833    
834    /* Bail out if not yaffs2 mode */
835    if(!dev->param.is_yaffs2)
836        return YAFFS_OK;
837
838    oldFileSize = obj->variant.file_variant.file_size;
839
840    if (new_size <= oldFileSize)
841        return YAFFS_OK;
842
843    increase = new_size - oldFileSize;
844
845    if(increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
846        yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
847        smallHole = 1;
848    else
849        smallHole = 0;
850
851    if(smallHole)
852        localBuffer= yaffs_get_temp_buffer(dev, __LINE__);
853    
854    if(localBuffer){
855        /* fill hole with zero bytes */
856        int pos = oldFileSize;
857        int thisWrite;
858        int written;
859        memset(localBuffer,0,dev->data_bytes_per_chunk);
860        smallIncreaseOk = 1;
861
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){
868                pos += thisWrite;
869                increase -= thisWrite;
870            } else
871                smallIncreaseOk = 0;
872        }
873
874        yaffs_release_temp_buffer(dev,localBuffer,__LINE__);
875
876        /* If we were out of space then reverse any chunks we've added */
877        if(!smallIncreaseOk)
878            yaffs_resize_file_down(obj, oldFileSize);
879    }
880    
881    if (!smallIncreaseOk &&
882        obj->parent &&
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);
887    }
888
889    return result;
890
891}
892
893
894typedef struct {
895    int seq;
896    int block;
897} yaffs_BlockIndex;
898
899
900static int yaffs2_ybicmp(const void *a, const void *b)
901{
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;
906    if (aseq == bseq)
907        return ablock - bblock;
908    else
909        return aseq - bseq;
910}
911
912int yaffs2_scan_backwards(yaffs_dev_t *dev)
913{
914    yaffs_ext_tags tags;
915    int blk;
916    int blockIterator;
917    int startIterator;
918    int endIterator;
919    int nBlocksToScan = 0;
920
921    int chunk;
922    int result;
923    int c;
924    int deleted;
925    yaffs_block_state_t state;
926    yaffs_obj_t *hard_list = NULL;
927    yaffs_block_info_t *bi;
928    __u32 seq_number;
929    yaffs_obj_header *oh;
930    yaffs_obj_t *in;
931    yaffs_obj_t *parent;
932    int nBlocks = dev->internal_end_block - dev->internal_start_block + 1;
933    int itsUnlinked;
934    __u8 *chunkData;
935
936    int file_size;
937    int is_shrink;
938    int foundChunksInBlock;
939    int equiv_id;
940    int alloc_failed = 0;
941
942
943    yaffs_BlockIndex *blockIndex = NULL;
944    int altBlockIndex = 0;
945
946    T(YAFFS_TRACE_SCAN,
947      (TSTR
948       ("yaffs2_scan_backwards starts intstartblk %d intendblk %d..."
949        TENDSTR), dev->internal_start_block, dev->internal_end_block));
950
951
952    dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
953
954    blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
955
956    if (!blockIndex) {
957        blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
958        altBlockIndex = 1;
959    }
960
961    if (!blockIndex) {
962        T(YAFFS_TRACE_SCAN,
963          (TSTR("yaffs2_scan_backwards() could not allocate block index!" TENDSTR)));
964        return YAFFS_FAIL;
965    }
966
967    dev->blocks_in_checkpt = 0;
968
969    chunkData = yaffs_get_temp_buffer(dev, __LINE__);
970
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;
977
978        yaffs_query_init_block_state(dev, blk, &state, &seq_number);
979
980        bi->block_state = state;
981        bi->seq_number = seq_number;
982
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;
987
988        T(YAFFS_TRACE_SCAN_DEBUG,
989          (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
990           state, seq_number));
991
992
993        if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
994            dev->blocks_in_checkpt++;
995
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) {
1005
1006            /* Determine the highest sequence number */
1007            if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
1008                seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
1009
1010                blockIndex[nBlocksToScan].seq = seq_number;
1011                blockIndex[nBlocksToScan].block = blk;
1012
1013                nBlocksToScan++;
1014
1015                if (seq_number >= dev->seq_number)
1016                    dev->seq_number = seq_number;
1017            } else {
1018                /* TODO: Nasty sequence number! */
1019                T(YAFFS_TRACE_SCAN,
1020                  (TSTR
1021                   ("Block scanning block %d has bad sequence number %d"
1022                    TENDSTR), blk, seq_number));
1023
1024            }
1025        }
1026        bi++;
1027    }
1028
1029    T(YAFFS_TRACE_SCAN,
1030    (TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
1031
1032
1033
1034    YYIELD();
1035
1036    /* Sort the blocks by sequence number*/
1037    yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), yaffs2_ybicmp);
1038
1039    YYIELD();
1040
1041    T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
1042
1043    /* Now scan the blocks looking at the data. */
1044    startIterator = 0;
1045    endIterator = nBlocksToScan - 1;
1046    T(YAFFS_TRACE_SCAN_DEBUG,
1047      (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
1048
1049    /* For each block.... backwards */
1050    for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
1051            blockIterator--) {
1052        /* Cooperative multitasking! This loop can run for so
1053           long that watchdog timers expire. */
1054        YYIELD();
1055
1056        /* get the block to scan in the correct order */
1057        blk = blockIndex[blockIterator].block;
1058
1059        bi = yaffs_get_block_info(dev, blk);
1060
1061
1062        state = bi->block_state;
1063
1064        deleted = 0;
1065
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
1074             */
1075
1076            chunk = blk * dev->param.chunks_per_block + c;
1077
1078            result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
1079                            &tags);
1080
1081            /* Let's have a good look at this chunk... */
1082
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
1091                 */
1092
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++;
1099                } else {
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 */
1104
1105                            T(YAFFS_TRACE_SCAN,
1106                              (TSTR
1107                               (" Allocating from %d %d"
1108                                TENDSTR), blk, c));
1109
1110                            state = YAFFS_BLOCK_STATE_ALLOCATING;
1111                            dev->alloc_block = blk;
1112                            dev->alloc_page = c;
1113                            dev->alloc_block_finder = blk;
1114                        } else {
1115                            /* This is a partially written block that is not
1116                             * the current allocation block.
1117                             */
1118
1119                             T(YAFFS_TRACE_SCAN,
1120                             (TSTR("Partially written block %d detected" TENDSTR),
1121                             blk));
1122                        }
1123                    }
1124                }
1125
1126                dev->n_free_chunks++;
1127
1128            } else if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
1129                T(YAFFS_TRACE_SCAN,
1130                  (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
1131                  blk, c));
1132
1133                  dev->n_free_chunks++;
1134
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 ) {
1139                T(YAFFS_TRACE_SCAN,
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));
1142
1143                  dev->n_free_chunks++;
1144
1145            } else if (tags.chunk_id > 0) {
1146                /* chunk_id > 0 so it is a data chunk... */
1147                unsigned int endpos;
1148                __u32 chunkBase =
1149                    (tags.chunk_id - 1) * dev->data_bytes_per_chunk;
1150
1151                foundChunksInBlock = 1;
1152
1153
1154                yaffs_set_chunk_bit(dev, blk, c);
1155                bi->pages_in_use++;
1156
1157                in = yaffs_find_or_create_by_number(dev,
1158                                      tags.
1159                                      obj_id,
1160                                      YAFFS_OBJECT_TYPE_FILE);
1161                if (!in) {
1162                    /* Out of memory */
1163                    alloc_failed = 1;
1164                }
1165
1166                if (in &&
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)) {
1171                        alloc_failed = 1;
1172                    }
1173
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.
1176                     */
1177                    endpos = chunkBase + tags.n_bytes;
1178
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;
1183                    }
1184
1185                } else if (in) {
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__);
1189
1190                }
1191            } else {
1192                /* chunk_id == 0, so it is an ObjectHeader.
1193                 * Thus, we read in the object header and make the object
1194                 */
1195                foundChunksInBlock = 1;
1196
1197                yaffs_set_chunk_bit(dev, blk, c);
1198                bi->pages_in_use++;
1199
1200                oh = NULL;
1201                in = NULL;
1202
1203                if (tags.extra_available) {
1204                    in = yaffs_find_or_create_by_number(dev,
1205                        tags.obj_id,
1206                        tags.extra_obj_type);
1207                    if (!in)
1208                        alloc_failed = 1;
1209                }
1210
1211                if (!in ||
1212                    (!in->valid && dev->param.disable_lazy_load) ||
1213                    tags.extra_shadows ||
1214                    (!in->valid &&
1215                    (tags.obj_id == YAFFS_OBJECTID_ROOT ||
1216                     tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) {
1217
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.
1221                     */
1222
1223                    result = yaffs_rd_chunk_tags_nand(dev,
1224                                    chunk,
1225                                    chunkData,
1226                                    NULL);
1227
1228                    oh = (yaffs_obj_header *) chunkData;
1229
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;
1234                    }
1235
1236                    if (!in) {
1237                        in = yaffs_find_or_create_by_number(dev, tags.obj_id, oh->type);
1238                        if (!in)
1239                            alloc_failed = 1;
1240                    }
1241
1242                }
1243
1244                if (!in) {
1245                    /* TODO Hoosterman we have a problem! */
1246                    T(YAFFS_TRACE_ERROR,
1247                      (TSTR
1248                       ("yaffs tragedy: Could not make object for object %d at chunk %d during scan"
1249                        TENDSTR), tags.obj_id, chunk));
1250                    continue;
1251                }
1252
1253                if (in->valid) {
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.
1257                     */
1258
1259                    if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) &&
1260                         ((oh &&
1261                           oh->type == YAFFS_OBJECT_TYPE_FILE) ||
1262                          (tags.extra_available &&
1263                           tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE))) {
1264                        __u32 thisSize =
1265                            (oh) ? oh->file_size : tags.
1266                            extra_length;
1267                        __u32 parent_obj_id =
1268                            (oh) ? oh->
1269                            parent_obj_id : tags.
1270                            extra_parent_id;
1271
1272
1273                        is_shrink =
1274                            (oh) ? oh->is_shrink : tags.
1275                            extra_is_shrink;
1276
1277                        /* If it is deleted (unlinked at start also means deleted)
1278                         * we treat the file size as being zeroed at this point.
1279                         */
1280                        if (parent_obj_id ==
1281                            YAFFS_OBJECTID_DELETED
1282                            || parent_obj_id ==
1283                            YAFFS_OBJECTID_UNLINKED) {
1284                            thisSize = 0;
1285                            is_shrink = 1;
1286                        }
1287
1288                        if (is_shrink && in->variant.file_variant.shrink_size > thisSize)
1289                            in->variant.file_variant.shrink_size = thisSize;
1290
1291                        if (is_shrink)
1292                            bi->has_shrink_hdr = 1;
1293
1294                    }
1295                    /* Use existing - destroy this one. */
1296                    yaffs_chunk_del(dev, chunk, 1, __LINE__);
1297
1298                }
1299
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")
1306                        TENDSTR), oh ?
1307                        oh->type : tags.extra_obj_type,
1308                        in->variant_type, tags.obj_id,
1309                        chunk));
1310
1311                if (!in->valid &&
1312                    (tags.obj_id == YAFFS_OBJECTID_ROOT ||
1313                     tags.obj_id ==
1314                     YAFFS_OBJECTID_LOSTNFOUND)) {
1315                    /* We only load some info, don't fiddle with directory structure */
1316                    in->valid = 1;
1317
1318                    if (oh) {
1319
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];
1328#else
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;
1335
1336                        in->lazy_loaded = 0;
1337
1338#endif
1339                    } else
1340                        in->lazy_loaded = 1;
1341
1342                    in->hdr_chunk = chunk;
1343
1344                } else if (!in->valid) {
1345                    /* we need to load this info */
1346
1347                    in->valid = 1;
1348                    in->hdr_chunk = chunk;
1349
1350                    if (oh) {
1351                        in->variant_type = oh->type;
1352
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];
1361#else
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;
1368#endif
1369
1370                        if (oh->shadows_obj > 0)
1371                            yaffs_handle_shadowed_obj(dev,
1372                                       oh->
1373                                       shadows_obj,
1374                                       1);
1375                            
1376
1377
1378                        yaffs_set_obj_name_from_oh(in, oh);
1379                        parent =
1380                            yaffs_find_or_create_by_number
1381                            (dev, oh->parent_obj_id,
1382                             YAFFS_OBJECT_TYPE_DIRECTORY);
1383
1384                         file_size = oh->file_size;
1385                         is_shrink = oh->is_shrink;
1386                         equiv_id = oh->equiv_id;
1387
1388                    } else {
1389                        in->variant_type = tags.extra_obj_type;
1390                        parent =
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;
1398
1399                    }
1400                    in->dirty = 0;
1401
1402                    if (!parent)
1403                        alloc_failed = 1;
1404
1405                    /* directory stuff...
1406                     * hook up to parent
1407                     */
1408
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.
1415                            dir_variant.
1416                            children);
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
1421                         */
1422
1423                        T(YAFFS_TRACE_ERROR,
1424                          (TSTR
1425                           ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
1426                            TENDSTR)));
1427                        parent = dev->lost_n_found;
1428                    }
1429
1430                    yaffs_add_obj_to_dir(parent, in);
1431
1432                    itsUnlinked = (parent == dev->del_dir) ||
1433                              (parent == dev->unlinked_dir);
1434
1435                    if (is_shrink) {
1436                        /* Mark the block as having a shrinkHeader */
1437                        bi->has_shrink_hdr = 1;
1438                    }
1439
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.
1445                     */
1446
1447                    switch (in->variant_type) {
1448                    case YAFFS_OBJECT_TYPE_UNKNOWN:
1449                        /* Todo got a problem */
1450                        break;
1451                    case YAFFS_OBJECT_TYPE_FILE:
1452
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.
1459                             */
1460                            in->variant.file_variant.file_size = file_size;
1461                            in->variant.file_variant.scanned_size = file_size;
1462                        }
1463
1464                        if (in->variant.file_variant.shrink_size > file_size)
1465                            in->variant.file_variant.shrink_size = file_size;
1466                
1467
1468                        break;
1469                    case YAFFS_OBJECT_TYPE_HARDLINK:
1470                        if (!itsUnlinked) {
1471                            in->variant.hardlink_variant.equiv_id =
1472                                equiv_id;
1473                            in->hard_links.next =
1474                                (struct ylist_head *) hard_list;
1475                            hard_list = in;
1476                        }
1477                        break;
1478                    case YAFFS_OBJECT_TYPE_DIRECTORY:
1479                        /* Do nothing */
1480                        break;
1481                    case YAFFS_OBJECT_TYPE_SPECIAL:
1482                        /* Do nothing */
1483                        break;
1484                    case YAFFS_OBJECT_TYPE_SYMLINK:
1485                        if (oh) {
1486                            in->variant.symlink_variant.alias =
1487                                yaffs_clone_str(oh->alias);
1488                            if (!in->variant.symlink_variant.alias)
1489                                alloc_failed = 1;
1490                        }
1491                        break;
1492                    }
1493
1494                }
1495
1496            }
1497
1498        } /* End of scanning for each chunk */
1499
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;
1503        }
1504
1505
1506        bi->block_state = state;
1507
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);
1513        }
1514
1515    }
1516    
1517    yaffs_skip_rest_of_block(dev);
1518
1519    if (altBlockIndex)
1520        YFREE_ALT(blockIndex);
1521    else
1522        YFREE(blockIndex);
1523
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
1527     * hardlinks.
1528     */
1529    yaffs_link_fixup(dev, hard_list);
1530
1531
1532    yaffs_release_temp_buffer(dev, chunkData, __LINE__);
1533
1534    if (alloc_failed)
1535        return YAFFS_FAIL;
1536
1537    T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_scan_backwards ends" TENDSTR)));
1538
1539    return YAFFS_OK;
1540}
1541

Archive Download this file



interactive