yaffs Updated quick tests' README.
[yaffs2.git] / 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 #include "yaffs_guts.h"
15 #include "yaffs_trace.h"
16 #include "yaffs_yaffs2.h"
17 #include "yaffs_checkptrw.h"
18 #include "yaffs_bitmap.h"
19 #include "yaffs_nand.h"
20 #include "yaffs_getblockinfo.h"
21 #include "yaffs_verify.h"
22 #include "yaffs_attribs.h"
23
24 /*
25  * Checkpoints are really no benefit on very small partitions.
26  *
27  * To save space on small partitions don't bother with checkpoints unless
28  * the partition is at least this big.
29  */
30 #define YAFFS_CHECKPOINT_MIN_BLOCKS 60
31
32 #define YAFFS_SMALL_HOLE_THRESHOLD 4
33
34 /*
35  * Oldest Dirty Sequence Number handling.
36  */
37
38 /* yaffs_calc_oldest_dirty_seq()
39  * yaffs2_find_oldest_dirty_seq()
40  * Calculate the oldest dirty sequence number if we don't know it.
41  */
42 void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev)
43 {
44         int i;
45         unsigned seq;
46         unsigned block_no = 0;
47         struct yaffs_block_info *b;
48
49         if (!dev->param.is_yaffs2)
50                 return;
51
52         /* Find the oldest dirty sequence number. */
53         seq = dev->seq_number + 1;
54         b = dev->block_info;
55         for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) {
56                 if (b->block_state == YAFFS_BLOCK_STATE_FULL &&
57                     (b->pages_in_use - b->soft_del_pages) <
58                     dev->param.chunks_per_block && b->seq_number < seq) {
59                         seq = b->seq_number;
60                         block_no = i;
61                 }
62                 b++;
63         }
64
65         if (block_no) {
66                 dev->oldest_dirty_seq = seq;
67                 dev->oldest_dirty_block = block_no;
68         }
69
70 }
71
72 void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev)
73 {
74         if (!dev->param.is_yaffs2)
75                 return;
76
77         if (!dev->oldest_dirty_seq)
78                 yaffs_calc_oldest_dirty_seq(dev);
79 }
80
81 /*
82  * yaffs_clear_oldest_dirty_seq()
83  * Called when a block is erased or marked bad. (ie. when its seq_number
84  * becomes invalid). If the value matches the oldest then we clear 
85  * dev->oldest_dirty_seq to force its recomputation.
86  */
87 void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev,
88                                    struct yaffs_block_info *bi)
89 {
90
91         if (!dev->param.is_yaffs2)
92                 return;
93
94         if (!bi || bi->seq_number == dev->oldest_dirty_seq) {
95                 dev->oldest_dirty_seq = 0;
96                 dev->oldest_dirty_block = 0;
97         }
98 }
99
100 /*
101  * yaffs2_update_oldest_dirty_seq()
102  * Update the oldest dirty sequence number whenever we dirty a block.
103  * Only do this if the oldest_dirty_seq is actually being tracked.
104  */
105 void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no,
106                                     struct yaffs_block_info *bi)
107 {
108         if (!dev->param.is_yaffs2)
109                 return;
110
111         if (dev->oldest_dirty_seq) {
112                 if (dev->oldest_dirty_seq > bi->seq_number) {
113                         dev->oldest_dirty_seq = bi->seq_number;
114                         dev->oldest_dirty_block = block_no;
115                 }
116         }
117 }
118
119 int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi)
120 {
121
122         if (!dev->param.is_yaffs2)
123                 return 1;       /* disqualification only applies to yaffs2. */
124
125         if (!bi->has_shrink_hdr)
126                 return 1;       /* can gc */
127
128         yaffs2_find_oldest_dirty_seq(dev);
129
130         /* Can't do gc of this block if there are any blocks older than this one that have
131          * discarded pages.
132          */
133         return (bi->seq_number <= dev->oldest_dirty_seq);
134 }
135
136 /*
137  * yaffs2_find_refresh_block()
138  * periodically finds the oldest full block by sequence number for refreshing.
139  * Only for yaffs2.
140  */
141 u32 yaffs2_find_refresh_block(struct yaffs_dev * dev)
142 {
143         u32 b;
144
145         u32 oldest = 0;
146         u32 oldest_seq = 0;
147
148         struct yaffs_block_info *bi;
149
150         if (!dev->param.is_yaffs2)
151                 return oldest;
152
153         /*
154          * If refresh period < 10 then refreshing is disabled.
155          */
156         if (dev->param.refresh_period < 10)
157                 return oldest;
158
159         /*
160          * Fix broken values.
161          */
162         if (dev->refresh_skip > dev->param.refresh_period)
163                 dev->refresh_skip = dev->param.refresh_period;
164
165         if (dev->refresh_skip > 0)
166                 return oldest;
167
168         /*
169          * Refresh skip is now zero.
170          * We'll do a refresh this time around....
171          * Update the refresh skip and find the oldest block.
172          */
173         dev->refresh_skip = dev->param.refresh_period;
174         dev->refresh_count++;
175         bi = dev->block_info;
176         for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) {
177
178                 if (bi->block_state == YAFFS_BLOCK_STATE_FULL) {
179
180                         if (oldest < 1 || bi->seq_number < oldest_seq) {
181                                 oldest = b;
182                                 oldest_seq = bi->seq_number;
183                         }
184                 }
185                 bi++;
186         }
187
188         if (oldest > 0) {
189                 T(YAFFS_TRACE_GC,
190                   (TSTR
191                    ("GC refresh count %d selected block %d with seq_number %d"
192                     TENDSTR), dev->refresh_count, oldest, oldest_seq));
193         }
194
195         return oldest;
196 }
197
198 int yaffs2_checkpt_required(struct yaffs_dev *dev)
199 {
200         int nblocks;
201
202         if (!dev->param.is_yaffs2)
203                 return 0;
204
205         nblocks = dev->internal_end_block - dev->internal_start_block + 1;
206
207         return !dev->param.skip_checkpt_wr &&
208             !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS);
209 }
210
211 int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev)
212 {
213         int retval;
214
215         if (!dev->param.is_yaffs2)
216                 return 0;
217
218         if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) {
219                 /* Not a valid value so recalculate */
220                 int n_bytes = 0;
221                 int n_blocks;
222                 int dev_blocks =
223                     (dev->param.end_block - dev->param.start_block + 1);
224
225                 n_bytes += sizeof(struct yaffs_checkpt_validity);
226                 n_bytes += sizeof(struct yaffs_checkpt_dev);
227                 n_bytes += dev_blocks * sizeof(struct yaffs_block_info);
228                 n_bytes += dev_blocks * dev->chunk_bit_stride;
229                 n_bytes +=
230                     (sizeof(struct yaffs_checkpt_obj) +
231                      sizeof(u32)) * (dev->n_obj);
232                 n_bytes += (dev->tnode_size + sizeof(u32)) * (dev->n_tnodes);
233                 n_bytes += sizeof(struct yaffs_checkpt_validity);
234                 n_bytes += sizeof(u32); /* checksum */
235
236                 /* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
237
238                 n_blocks =
239                     (n_bytes /
240                      (dev->data_bytes_per_chunk *
241                       dev->param.chunks_per_block)) + 3;
242
243                 dev->checkpoint_blocks_required = n_blocks;
244         }
245
246         retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt;
247         if (retval < 0)
248                 retval = 0;
249         return retval;
250 }
251
252 /*--------------------- Checkpointing --------------------*/
253
254 static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head)
255 {
256         struct yaffs_checkpt_validity cp;
257
258         memset(&cp, 0, sizeof(cp));
259
260         cp.struct_type = sizeof(cp);
261         cp.magic = YAFFS_MAGIC;
262         cp.version = YAFFS_CHECKPOINT_VERSION;
263         cp.head = (head) ? 1 : 0;
264
265         return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0;
266 }
267
268 static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head)
269 {
270         struct yaffs_checkpt_validity 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
283 static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp,
284                                       struct yaffs_dev *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
298 static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev,
299                                      struct yaffs_checkpt_dev *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 static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev)
313 {
314         struct yaffs_checkpt_dev cp;
315         u32 n_bytes;
316         u32 n_blocks =
317             (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 = n_blocks * sizeof(struct yaffs_block_info);
330                 ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) ==
331                       n_bytes);
332         }
333
334         /* Write chunk bits */
335         if (ok) {
336                 n_bytes = n_blocks * dev->chunk_bit_stride;
337                 ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) ==
338                       n_bytes);
339         }
340         return ok ? 1 : 0;
341
342 }
343
344 static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev)
345 {
346         struct yaffs_checkpt_dev cp;
347         u32 n_bytes;
348         u32 n_blocks =
349             (dev->internal_end_block - dev->internal_start_block + 1);
350
351         int ok;
352
353         ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
354         if (!ok)
355                 return 0;
356
357         if (cp.struct_type != sizeof(cp))
358                 return 0;
359
360         yaffs_checkpt_dev_to_dev(dev, &cp);
361
362         n_bytes = n_blocks * sizeof(struct yaffs_block_info);
363
364         ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes);
365
366         if (!ok)
367                 return 0;
368         n_bytes = n_blocks * dev->chunk_bit_stride;
369
370         ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes);
371
372         return ok ? 1 : 0;
373 }
374
375 static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp,
376                                    struct yaffs_obj *obj)
377 {
378
379         cp->obj_id = obj->obj_id;
380         cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0;
381         cp->hdr_chunk = obj->hdr_chunk;
382         cp->variant_type = obj->variant_type;
383         cp->deleted = obj->deleted;
384         cp->soft_del = obj->soft_del;
385         cp->unlinked = obj->unlinked;
386         cp->fake = obj->fake;
387         cp->rename_allowed = obj->rename_allowed;
388         cp->unlink_allowed = obj->unlink_allowed;
389         cp->serial = obj->serial;
390         cp->n_data_chunks = obj->n_data_chunks;
391
392         if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
393                 cp->size_or_equiv_obj = obj->variant.file_variant.file_size;
394         else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
395                 cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id;
396 }
397
398 static int taffs2_checkpt_obj_to_obj(struct yaffs_obj *obj,
399                                      struct yaffs_checkpt_obj *cp)
400 {
401
402         struct yaffs_obj *parent;
403
404         if (obj->variant_type != cp->variant_type) {
405                 T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
406                                            TCONT
407                                            ("chunk %d does not match existing object type %d")
408                                            TENDSTR), cp->obj_id,
409                                       cp->variant_type, cp->hdr_chunk,
410                                       obj->variant_type));
411                 return 0;
412         }
413
414         obj->obj_id = cp->obj_id;
415
416         if (cp->parent_id)
417                 parent = yaffs_find_or_create_by_number(obj->my_dev,
418                                                         cp->parent_id,
419                                                         YAFFS_OBJECT_TYPE_DIRECTORY);
420         else
421                 parent = NULL;
422
423         if (parent) {
424                 if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) {
425                         T(YAFFS_TRACE_ALWAYS,
426                           (TSTR
427                            ("Checkpoint read object %d parent %d type %d"
428                             TCONT(" chunk %d Parent type, %d, not directory")
429                             TENDSTR), cp->obj_id, cp->parent_id,
430                            cp->variant_type, cp->hdr_chunk,
431                            parent->variant_type));
432                         return 0;
433                 }
434                 yaffs_add_obj_to_dir(parent, obj);
435         }
436
437         obj->hdr_chunk = cp->hdr_chunk;
438         obj->variant_type = cp->variant_type;
439         obj->deleted = cp->deleted;
440         obj->soft_del = cp->soft_del;
441         obj->unlinked = cp->unlinked;
442         obj->fake = cp->fake;
443         obj->rename_allowed = cp->rename_allowed;
444         obj->unlink_allowed = cp->unlink_allowed;
445         obj->serial = cp->serial;
446         obj->n_data_chunks = cp->n_data_chunks;
447
448         if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
449                 obj->variant.file_variant.file_size = cp->size_or_equiv_obj;
450         else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK)
451                 obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj;
452
453         if (obj->hdr_chunk > 0)
454                 obj->lazy_loaded = 1;
455         return 1;
456 }
457
458 static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in,
459                                        struct yaffs_tnode *tn, u32 level,
460                                        int chunk_offset)
461 {
462         int i;
463         struct yaffs_dev *dev = in->my_dev;
464         int ok = 1;
465
466         if (tn) {
467                 if (level > 0) {
468
469                         for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
470                                 if (tn->internal[i]) {
471                                         ok = yaffs2_checkpt_tnode_worker(in,
472                                                                          tn->
473                                                                          internal
474                                                                          [i],
475                                                                          level -
476                                                                          1,
477                                                                          (chunk_offset
478                                                                           <<
479                                                                           YAFFS_TNODES_INTERNAL_BITS)
480                                                                          + i);
481                                 }
482                         }
483                 } else if (level == 0) {
484                         u32 base_offset =
485                             chunk_offset << YAFFS_TNODES_LEVEL0_BITS;
486                         ok = (yaffs2_checkpt_wr
487                               (dev, &base_offset,
488                                sizeof(base_offset)) == sizeof(base_offset));
489                         if (ok)
490                                 ok = (yaffs2_checkpt_wr
491                                       (dev, tn,
492                                        dev->tnode_size) == dev->tnode_size);
493                 }
494         }
495
496         return ok;
497
498 }
499
500 static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj)
501 {
502         u32 end_marker = ~0;
503         int ok = 1;
504
505         if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
506                 ok = yaffs2_checkpt_tnode_worker(obj,
507                                                  obj->variant.file_variant.top,
508                                                  obj->variant.file_variant.
509                                                  top_level, 0);
510                 if (ok)
511                         ok = (yaffs2_checkpt_wr
512                               (obj->my_dev, &end_marker,
513                                sizeof(end_marker)) == sizeof(end_marker));
514         }
515
516         return ok ? 1 : 0;
517 }
518
519 static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj)
520 {
521         u32 base_chunk;
522         int ok = 1;
523         struct yaffs_dev *dev = obj->my_dev;
524         struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant;
525         struct yaffs_tnode *tn;
526         int nread = 0;
527
528         ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) ==
529               sizeof(base_chunk));
530
531         while (ok && (~base_chunk)) {
532                 nread++;
533                 /* Read level 0 tnode */
534
535                 tn = yaffs_get_tnode(dev);
536                 if (tn) {
537                         ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) ==
538                               dev->tnode_size);
539                 } else
540                         ok = 0;
541
542                 if (tn && ok)
543                         ok = yaffs_add_find_tnode_0(dev,
544                                                     file_stuct_ptr,
545                                                     base_chunk, tn) ? 1 : 0;
546
547                 if (ok)
548                         ok = (yaffs2_checkpt_rd
549                               (dev, &base_chunk,
550                                sizeof(base_chunk)) == sizeof(base_chunk));
551
552         }
553
554         T(YAFFS_TRACE_CHECKPOINT,
555           (TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
556            nread, base_chunk, ok));
557
558         return ok ? 1 : 0;
559 }
560
561 static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev)
562 {
563         struct yaffs_obj *obj;
564         struct yaffs_checkpt_obj cp;
565         int i;
566         int ok = 1;
567         struct list_head *lh;
568
569         /* Iterate through the objects in each hash entry,
570          * dumping them to the checkpointing stream.
571          */
572
573         for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) {
574                 list_for_each(lh, &dev->obj_bucket[i].list) {
575                         if (lh) {
576                                 obj =
577                                     list_entry(lh, struct yaffs_obj, hash_link);
578                                 if (!obj->defered_free) {
579                                         yaffs2_obj_checkpt_obj(&cp, obj);
580                                         cp.struct_type = sizeof(cp);
581
582                                         T(YAFFS_TRACE_CHECKPOINT,
583                                           (TSTR
584                                            ("Checkpoint write object %d parent %d type %d chunk %d obj addr %p"
585                                             TENDSTR), cp.obj_id, cp.parent_id,
586                                            cp.variant_type, cp.hdr_chunk, obj));
587
588                                         ok = (yaffs2_checkpt_wr
589                                               (dev, &cp,
590                                                sizeof(cp)) == sizeof(cp));
591
592                                         if (ok
593                                             && obj->variant_type ==
594                                             YAFFS_OBJECT_TYPE_FILE)
595                                                 ok = yaffs2_wr_checkpt_tnodes
596                                                     (obj);
597                                 }
598                         }
599                 }
600         }
601
602         /* Dump end of list */
603         memset(&cp, 0xFF, sizeof(struct yaffs_checkpt_obj));
604         cp.struct_type = sizeof(cp);
605
606         if (ok)
607                 ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp));
608
609         return ok ? 1 : 0;
610 }
611
612 static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev)
613 {
614         struct yaffs_obj *obj;
615         struct yaffs_checkpt_obj cp;
616         int ok = 1;
617         int done = 0;
618         struct yaffs_obj *hard_list = NULL;
619
620         while (ok && !done) {
621                 ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp));
622                 if (cp.struct_type != sizeof(cp)) {
623                         T(YAFFS_TRACE_CHECKPOINT,
624                           (TSTR("struct size %d instead of %d ok %d" TENDSTR),
625                            cp.struct_type, (int)sizeof(cp), ok));
626                         ok = 0;
627                 }
628
629                 T(YAFFS_TRACE_CHECKPOINT,
630                   (TSTR
631                    ("Checkpoint read object %d parent %d type %d chunk %d "
632                     TENDSTR), cp.obj_id, cp.parent_id, cp.variant_type,
633                    cp.hdr_chunk));
634
635                 if (ok && cp.obj_id == ~0)
636                         done = 1;
637                 else if (ok) {
638                         obj =
639                             yaffs_find_or_create_by_number(dev, cp.obj_id,
640                                                            cp.variant_type);
641                         if (obj) {
642                                 ok = taffs2_checkpt_obj_to_obj(obj, &cp);
643                                 if (!ok)
644                                         break;
645                                 if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) {
646                                         ok = yaffs2_rd_checkpt_tnodes(obj);
647                                 } else if (obj->variant_type ==
648                                            YAFFS_OBJECT_TYPE_HARDLINK) {
649                                         obj->hard_links.next =
650                                             (struct list_head *)hard_list;
651                                         hard_list = obj;
652                                 }
653                         } else
654                                 ok = 0;
655                 }
656         }
657
658         if (ok)
659                 yaffs_link_fixup(dev, hard_list);
660
661         return ok ? 1 : 0;
662 }
663
664 static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev)
665 {
666         u32 checkpt_sum;
667         int ok;
668
669         yaffs2_get_checkpt_sum(dev, &checkpt_sum);
670
671         ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) ==
672               sizeof(checkpt_sum));
673
674         if (!ok)
675                 return 0;
676
677         return 1;
678 }
679
680 static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev)
681 {
682         u32 checkpt_sum0;
683         u32 checkpt_sum1;
684         int ok;
685
686         yaffs2_get_checkpt_sum(dev, &checkpt_sum0);
687
688         ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) ==
689               sizeof(checkpt_sum1));
690
691         if (!ok)
692                 return 0;
693
694         if (checkpt_sum0 != checkpt_sum1)
695                 return 0;
696
697         return 1;
698 }
699
700 static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev)
701 {
702         int ok = 1;
703
704         if (!yaffs2_checkpt_required(dev)) {
705                 T(YAFFS_TRACE_CHECKPOINT,
706                   (TSTR("skipping checkpoint write" TENDSTR)));
707                 ok = 0;
708         }
709
710         if (ok)
711                 ok = yaffs2_checkpt_open(dev, 1);
712
713         if (ok) {
714                 T(YAFFS_TRACE_CHECKPOINT,
715                   (TSTR("write checkpoint validity" TENDSTR)));
716                 ok = yaffs2_wr_checkpt_validity_marker(dev, 1);
717         }
718         if (ok) {
719                 T(YAFFS_TRACE_CHECKPOINT,
720                   (TSTR("write checkpoint device" TENDSTR)));
721                 ok = yaffs2_wr_checkpt_dev(dev);
722         }
723         if (ok) {
724                 T(YAFFS_TRACE_CHECKPOINT,
725                   (TSTR("write checkpoint objects" TENDSTR)));
726                 ok = yaffs2_wr_checkpt_objs(dev);
727         }
728         if (ok) {
729                 T(YAFFS_TRACE_CHECKPOINT,
730                   (TSTR("write checkpoint validity" TENDSTR)));
731                 ok = yaffs2_wr_checkpt_validity_marker(dev, 0);
732         }
733
734         if (ok)
735                 ok = yaffs2_wr_checkpt_sum(dev);
736
737         if (!yaffs_checkpt_close(dev))
738                 ok = 0;
739
740         if (ok)
741                 dev->is_checkpointed = 1;
742         else
743                 dev->is_checkpointed = 0;
744
745         return dev->is_checkpointed;
746 }
747
748 static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev)
749 {
750         int ok = 1;
751
752         if (!dev->param.is_yaffs2)
753                 ok = 0;
754
755         if (ok && dev->param.skip_checkpt_rd) {
756                 T(YAFFS_TRACE_CHECKPOINT,
757                   (TSTR("skipping checkpoint read" TENDSTR)));
758                 ok = 0;
759         }
760
761         if (ok)
762                 ok = yaffs2_checkpt_open(dev, 0);       /* open for read */
763
764         if (ok) {
765                 T(YAFFS_TRACE_CHECKPOINT,
766                   (TSTR("read checkpoint validity" TENDSTR)));
767                 ok = yaffs2_rd_checkpt_validity_marker(dev, 1);
768         }
769         if (ok) {
770                 T(YAFFS_TRACE_CHECKPOINT,
771                   (TSTR("read checkpoint device" TENDSTR)));
772                 ok = yaffs2_rd_checkpt_dev(dev);
773         }
774         if (ok) {
775                 T(YAFFS_TRACE_CHECKPOINT,
776                   (TSTR("read checkpoint objects" TENDSTR)));
777                 ok = yaffs2_rd_checkpt_objs(dev);
778         }
779         if (ok) {
780                 T(YAFFS_TRACE_CHECKPOINT,
781                   (TSTR("read checkpoint validity" TENDSTR)));
782                 ok = yaffs2_rd_checkpt_validity_marker(dev, 0);
783         }
784
785         if (ok) {
786                 ok = yaffs2_rd_checkpt_sum(dev);
787                 T(YAFFS_TRACE_CHECKPOINT,
788                   (TSTR("read checkpoint checksum %d" TENDSTR), ok));
789         }
790
791         if (!yaffs_checkpt_close(dev))
792                 ok = 0;
793
794         if (ok)
795                 dev->is_checkpointed = 1;
796         else
797                 dev->is_checkpointed = 0;
798
799         return ok ? 1 : 0;
800
801 }
802
803 void yaffs2_checkpt_invalidate(struct yaffs_dev *dev)
804 {
805         if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) {
806                 dev->is_checkpointed = 0;
807                 yaffs2_checkpt_invalidate_stream(dev);
808         }
809         if (dev->param.sb_dirty_fn)
810                 dev->param.sb_dirty_fn(dev);
811 }
812
813 int yaffs_checkpoint_save(struct yaffs_dev *dev)
814 {
815
816         T(YAFFS_TRACE_CHECKPOINT,
817           (TSTR("save entry: is_checkpointed %d" TENDSTR),
818            dev->is_checkpointed));
819
820         yaffs_verify_objects(dev);
821         yaffs_verify_blocks(dev);
822         yaffs_verify_free_chunks(dev);
823
824         if (!dev->is_checkpointed) {
825                 yaffs2_checkpt_invalidate(dev);
826                 yaffs2_wr_checkpt_data(dev);
827         }
828
829         T(YAFFS_TRACE_ALWAYS,
830           (TSTR("save exit: is_checkpointed %d" TENDSTR),
831            dev->is_checkpointed));
832
833         return dev->is_checkpointed;
834 }
835
836 int yaffs2_checkpt_restore(struct yaffs_dev *dev)
837 {
838         int retval;
839         T(YAFFS_TRACE_CHECKPOINT,
840           (TSTR("restore entry: is_checkpointed %d" TENDSTR),
841            dev->is_checkpointed));
842
843         retval = yaffs2_rd_checkpt_data(dev);
844
845         if (dev->is_checkpointed) {
846                 yaffs_verify_objects(dev);
847                 yaffs_verify_blocks(dev);
848                 yaffs_verify_free_chunks(dev);
849         }
850
851         T(YAFFS_TRACE_CHECKPOINT,
852           (TSTR("restore exit: is_checkpointed %d" TENDSTR),
853            dev->is_checkpointed));
854
855         return retval;
856 }
857
858 int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size)
859 {
860         /* if new_size > old_file_size.
861          * We're going to be writing a hole.
862          * If the hole is small then write zeros otherwise write a start of hole marker.
863          */
864
865         loff_t old_file_size;
866         int increase;
867         int small_hole;
868         int result = YAFFS_OK;
869         struct yaffs_dev *dev = NULL;
870
871         u8 *local_buffer = NULL;
872
873         int small_increase_ok = 0;
874
875         if (!obj)
876                 return YAFFS_FAIL;
877
878         if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
879                 return YAFFS_FAIL;
880
881         dev = obj->my_dev;
882
883         /* Bail out if not yaffs2 mode */
884         if (!dev->param.is_yaffs2)
885                 return YAFFS_OK;
886
887         old_file_size = obj->variant.file_variant.file_size;
888
889         if (new_size <= old_file_size)
890                 return YAFFS_OK;
891
892         increase = new_size - old_file_size;
893
894         if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk &&
895             yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1))
896                 small_hole = 1;
897         else
898                 small_hole = 0;
899
900         if (small_hole)
901                 local_buffer = yaffs_get_temp_buffer(dev, __LINE__);
902
903         if (local_buffer) {
904                 /* fill hole with zero bytes */
905                 int pos = old_file_size;
906                 int this_write;
907                 int written;
908                 memset(local_buffer, 0, dev->data_bytes_per_chunk);
909                 small_increase_ok = 1;
910
911                 while (increase > 0 && small_increase_ok) {
912                         this_write = increase;
913                         if (this_write > dev->data_bytes_per_chunk)
914                                 this_write = dev->data_bytes_per_chunk;
915                         written =
916                             yaffs_do_file_wr(obj, local_buffer, pos, this_write,
917                                              0);
918                         if (written == this_write) {
919                                 pos += this_write;
920                                 increase -= this_write;
921                         } else
922                                 small_increase_ok = 0;
923                 }
924
925                 yaffs_release_temp_buffer(dev, local_buffer, __LINE__);
926
927                 /* If we were out of space then reverse any chunks we've added */
928                 if (!small_increase_ok)
929                         yaffs_resize_file_down(obj, old_file_size);
930         }
931
932         if (!small_increase_ok &&
933             obj->parent &&
934             obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED &&
935             obj->parent->obj_id != YAFFS_OBJECTID_DELETED) {
936                 /* Write a hole start header with the old file size */
937                 yaffs_update_oh(obj, NULL, 0, 1, 0, NULL);
938         }
939
940         return result;
941
942 }
943
944 struct yaffs_block_index {
945         int seq;
946         int block;
947 };
948
949 static int yaffs2_ybicmp(const void *a, const void *b)
950 {
951         int aseq = ((struct yaffs_block_index *)a)->seq;
952         int bseq = ((struct yaffs_block_index *)b)->seq;
953         int ablock = ((struct yaffs_block_index *)a)->block;
954         int bblock = ((struct yaffs_block_index *)b)->block;
955         if (aseq == bseq)
956                 return ablock - bblock;
957         else
958                 return aseq - bseq;
959 }
960
961 int yaffs2_scan_backwards(struct yaffs_dev *dev)
962 {
963         struct yaffs_ext_tags tags;
964         int blk;
965         int block_iter;
966         int start_iter;
967         int end_iter;
968         int n_to_scan = 0;
969
970         int chunk;
971         int result;
972         int c;
973         int deleted;
974         enum yaffs_block_state state;
975         struct yaffs_obj *hard_list = NULL;
976         struct yaffs_block_info *bi;
977         u32 seq_number;
978         struct yaffs_obj_hdr *oh;
979         struct yaffs_obj *in;
980         struct yaffs_obj *parent;
981         int n_blocks = dev->internal_end_block - dev->internal_start_block + 1;
982         int is_unlinked;
983         u8 *chunk_data;
984
985         int file_size;
986         int is_shrink;
987         int found_chunks;
988         int equiv_id;
989         int alloc_failed = 0;
990
991         struct yaffs_block_index *block_index = NULL;
992         int alt_block_index = 0;
993
994         T(YAFFS_TRACE_SCAN,
995           (TSTR
996            ("yaffs2_scan_backwards starts  intstartblk %d intendblk %d..."
997             TENDSTR), dev->internal_start_block, dev->internal_end_block));
998
999         dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER;
1000
1001         block_index = YMALLOC(n_blocks * sizeof(struct yaffs_block_index));
1002
1003         if (!block_index) {
1004                 block_index =
1005                     YMALLOC_ALT(n_blocks * sizeof(struct yaffs_block_index));
1006                 alt_block_index = 1;
1007         }
1008
1009         if (!block_index) {
1010                 T(YAFFS_TRACE_SCAN,
1011                   (TSTR
1012                    ("yaffs2_scan_backwards() could not allocate block index!"
1013                     TENDSTR)));
1014                 return YAFFS_FAIL;
1015         }
1016
1017         dev->blocks_in_checkpt = 0;
1018
1019         chunk_data = yaffs_get_temp_buffer(dev, __LINE__);
1020
1021         /* Scan all the blocks to determine their state */
1022         bi = dev->block_info;
1023         for (blk = dev->internal_start_block; blk <= dev->internal_end_block;
1024              blk++) {
1025                 yaffs_clear_chunk_bits(dev, blk);
1026                 bi->pages_in_use = 0;
1027                 bi->soft_del_pages = 0;
1028
1029                 yaffs_query_init_block_state(dev, blk, &state, &seq_number);
1030
1031                 bi->block_state = state;
1032                 bi->seq_number = seq_number;
1033
1034                 if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA)
1035                         bi->block_state = state = YAFFS_BLOCK_STATE_CHECKPOINT;
1036                 if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK)
1037                         bi->block_state = state = YAFFS_BLOCK_STATE_DEAD;
1038
1039                 T(YAFFS_TRACE_SCAN_DEBUG,
1040                   (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
1041                    state, seq_number));
1042
1043                 if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
1044                         dev->blocks_in_checkpt++;
1045
1046                 } else if (state == YAFFS_BLOCK_STATE_DEAD) {
1047                         T(YAFFS_TRACE_BAD_BLOCKS,
1048                           (TSTR("block %d is bad" TENDSTR), blk));
1049                 } else if (state == YAFFS_BLOCK_STATE_EMPTY) {
1050                         T(YAFFS_TRACE_SCAN_DEBUG,
1051                           (TSTR("Block empty " TENDSTR)));
1052                         dev->n_erased_blocks++;
1053                         dev->n_free_chunks += dev->param.chunks_per_block;
1054                 } else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
1055
1056                         /* Determine the highest sequence number */
1057                         if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
1058                             seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
1059
1060                                 block_index[n_to_scan].seq = seq_number;
1061                                 block_index[n_to_scan].block = blk;
1062
1063                                 n_to_scan++;
1064
1065                                 if (seq_number >= dev->seq_number)
1066                                         dev->seq_number = seq_number;
1067                         } else {
1068                                 /* TODO: Nasty sequence number! */
1069                                 T(YAFFS_TRACE_SCAN,
1070                                   (TSTR
1071                                    ("Block scanning block %d has bad sequence number %d"
1072                                     TENDSTR), blk, seq_number));
1073
1074                         }
1075                 }
1076                 bi++;
1077         }
1078
1079         T(YAFFS_TRACE_SCAN,
1080           (TSTR("%d blocks to be sorted..." TENDSTR), n_to_scan));
1081
1082         YYIELD();
1083
1084         /* Sort the blocks by sequence number */
1085         yaffs_sort(block_index, n_to_scan, sizeof(struct yaffs_block_index),
1086                    yaffs2_ybicmp);
1087
1088         YYIELD();
1089
1090         T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
1091
1092         /* Now scan the blocks looking at the data. */
1093         start_iter = 0;
1094         end_iter = n_to_scan - 1;
1095         T(YAFFS_TRACE_SCAN_DEBUG,
1096           (TSTR("%d blocks to be scanned" TENDSTR), n_to_scan));
1097
1098         /* For each block.... backwards */
1099         for (block_iter = end_iter; !alloc_failed && block_iter >= start_iter;
1100              block_iter--) {
1101                 /* Cooperative multitasking! This loop can run for so
1102                    long that watchdog timers expire. */
1103                 YYIELD();
1104
1105                 /* get the block to scan in the correct order */
1106                 blk = block_index[block_iter].block;
1107
1108                 bi = yaffs_get_block_info(dev, blk);
1109
1110                 state = bi->block_state;
1111
1112                 deleted = 0;
1113
1114                 /* For each chunk in each block that needs scanning.... */
1115                 found_chunks = 0;
1116                 for (c = dev->param.chunks_per_block - 1;
1117                      !alloc_failed && c >= 0 &&
1118                      (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
1119                       state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
1120                         /* Scan backwards...
1121                          * Read the tags and decide what to do
1122                          */
1123
1124                         chunk = blk * dev->param.chunks_per_block + c;
1125
1126                         result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL,
1127                                                           &tags);
1128
1129                         /* Let's have a good look at this chunk... */
1130
1131                         if (!tags.chunk_used) {
1132                                 /* An unassigned chunk in the block.
1133                                  * If there are used chunks after this one, then
1134                                  * it is a chunk that was skipped due to failing the erased
1135                                  * check. Just skip it so that it can be deleted.
1136                                  * But, more typically, We get here when this is an unallocated
1137                                  * chunk and his means that either the block is empty or
1138                                  * this is the one being allocated from
1139                                  */
1140
1141                                 if (found_chunks) {
1142                                         /* This is a chunk that was skipped due to failing the erased check */
1143                                 } else if (c == 0) {
1144                                         /* We're looking at the first chunk in the block so the block is unused */
1145                                         state = YAFFS_BLOCK_STATE_EMPTY;
1146                                         dev->n_erased_blocks++;
1147                                 } else {
1148                                         if (state ==
1149                                             YAFFS_BLOCK_STATE_NEEDS_SCANNING
1150                                             || state ==
1151                                             YAFFS_BLOCK_STATE_ALLOCATING) {
1152                                                 if (dev->seq_number ==
1153                                                     bi->seq_number) {
1154                                                         /* this is the block being allocated from */
1155
1156                                                         T(YAFFS_TRACE_SCAN,
1157                                                           (TSTR
1158                                                            (" Allocating from %d %d"
1159                                                             TENDSTR), blk, c));
1160
1161                                                         state =
1162                                                             YAFFS_BLOCK_STATE_ALLOCATING;
1163                                                         dev->alloc_block = blk;
1164                                                         dev->alloc_page = c;
1165                                                         dev->
1166                                                             alloc_block_finder =
1167                                                             blk;
1168                                                 } else {
1169                                                         /* This is a partially written block that is not
1170                                                          * the current allocation block.
1171                                                          */
1172
1173                                                         T(YAFFS_TRACE_SCAN,
1174                                                           (TSTR
1175                                                            ("Partially written block %d detected"
1176                                                             TENDSTR), blk));
1177                                                 }
1178                                         }
1179                                 }
1180
1181                                 dev->n_free_chunks++;
1182
1183                         } else if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED) {
1184                                 T(YAFFS_TRACE_SCAN,
1185                                   (TSTR
1186                                    (" Unfixed ECC in chunk(%d:%d), chunk ignored"
1187                                     TENDSTR), blk, c));
1188
1189                                 dev->n_free_chunks++;
1190
1191                         } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID ||
1192                                    tags.chunk_id > YAFFS_MAX_CHUNK_ID ||
1193                                    (tags.chunk_id > 0
1194                                     && tags.n_bytes > dev->data_bytes_per_chunk)
1195                                    || tags.seq_number != bi->seq_number) {
1196                                 T(YAFFS_TRACE_SCAN,
1197                                   (TSTR
1198                                    ("Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored"
1199                                     TENDSTR), blk, c, tags.obj_id,
1200                                    tags.chunk_id, tags.n_bytes));
1201
1202                                 dev->n_free_chunks++;
1203
1204                         } else if (tags.chunk_id > 0) {
1205                                 /* chunk_id > 0 so it is a data chunk... */
1206                                 unsigned int endpos;
1207                                 u32 chunk_base =
1208                                     (tags.chunk_id -
1209                                      1) * dev->data_bytes_per_chunk;
1210
1211                                 found_chunks = 1;
1212
1213                                 yaffs_set_chunk_bit(dev, blk, c);
1214                                 bi->pages_in_use++;
1215
1216                                 in = yaffs_find_or_create_by_number(dev,
1217                                                                     tags.obj_id,
1218                                                                     YAFFS_OBJECT_TYPE_FILE);
1219                                 if (!in) {
1220                                         /* Out of memory */
1221                                         alloc_failed = 1;
1222                                 }
1223
1224                                 if (in &&
1225                                     in->variant_type == YAFFS_OBJECT_TYPE_FILE
1226                                     && chunk_base <
1227                                     in->variant.file_variant.shrink_size) {
1228                                         /* This has not been invalidated by a resize */
1229                                         if (!yaffs_put_chunk_in_file
1230                                             (in, tags.chunk_id, chunk, -1)) {
1231                                                 alloc_failed = 1;
1232                                         }
1233
1234                                         /* File size is calculated by looking at the data chunks if we have not
1235                                          * seen an object header yet. Stop this practice once we find an object header.
1236                                          */
1237                                         endpos = chunk_base + tags.n_bytes;
1238
1239                                         if (!in->valid &&       /* have not got an object header yet */
1240                                             in->variant.file_variant.
1241                                             scanned_size < endpos) {
1242                                                 in->variant.file_variant.
1243                                                     scanned_size = endpos;
1244                                                 in->variant.file_variant.
1245                                                     file_size = endpos;
1246                                         }
1247
1248                                 } else if (in) {
1249                                         /* This chunk has been invalidated by a resize, or a past file deletion
1250                                          * so delete the chunk*/
1251                                         yaffs_chunk_del(dev, chunk, 1,
1252                                                         __LINE__);
1253
1254                                 }
1255                         } else {
1256                                 /* chunk_id == 0, so it is an ObjectHeader.
1257                                  * Thus, we read in the object header and make the object
1258                                  */
1259                                 found_chunks = 1;
1260
1261                                 yaffs_set_chunk_bit(dev, blk, c);
1262                                 bi->pages_in_use++;
1263
1264                                 oh = NULL;
1265                                 in = NULL;
1266
1267                                 if (tags.extra_available) {
1268                                         in = yaffs_find_or_create_by_number(dev,
1269                                                                             tags.
1270                                                                             obj_id,
1271                                                                             tags.
1272                                                                             extra_obj_type);
1273                                         if (!in)
1274                                                 alloc_failed = 1;
1275                                 }
1276
1277                                 if (!in ||
1278                                     (!in->valid && dev->param.disable_lazy_load)
1279                                     || tags.extra_shadows || (!in->valid
1280                                                               && (tags.obj_id ==
1281                                                                   YAFFS_OBJECTID_ROOT
1282                                                                   || tags.
1283                                                                   obj_id ==
1284                                                                   YAFFS_OBJECTID_LOSTNFOUND)))
1285                                 {
1286
1287                                         /* If we don't have  valid info then we need to read the chunk
1288                                          * TODO In future we can probably defer reading the chunk and
1289                                          * living with invalid data until needed.
1290                                          */
1291
1292                                         result = yaffs_rd_chunk_tags_nand(dev,
1293                                                                           chunk,
1294                                                                           chunk_data,
1295                                                                           NULL);
1296
1297                                         oh = (struct yaffs_obj_hdr *)chunk_data;
1298
1299                                         if (dev->param.inband_tags) {
1300                                                 /* Fix up the header if they got corrupted by inband tags */
1301                                                 oh->shadows_obj =
1302                                                     oh->inband_shadowed_obj_id;
1303                                                 oh->is_shrink =
1304                                                     oh->inband_is_shrink;
1305                                         }
1306
1307                                         if (!in) {
1308                                                 in = yaffs_find_or_create_by_number(dev, tags.obj_id, oh->type);
1309                                                 if (!in)
1310                                                         alloc_failed = 1;
1311                                         }
1312
1313                                 }
1314
1315                                 if (!in) {
1316                                         /* TODO Hoosterman we have a problem! */
1317                                         T(YAFFS_TRACE_ERROR,
1318                                           (TSTR
1319                                            ("yaffs tragedy: Could not make object for object  %d at chunk %d during scan"
1320                                             TENDSTR), tags.obj_id, chunk));
1321                                         continue;
1322                                 }
1323
1324                                 if (in->valid) {
1325                                         /* We have already filled this one.
1326                                          * We have a duplicate that will be discarded, but
1327                                          * we first have to suck out resize info if it is a file.
1328                                          */
1329
1330                                         if ((in->variant_type ==
1331                                              YAFFS_OBJECT_TYPE_FILE) && ((oh
1332                                                                           &&
1333                                                                           oh->
1334                                                                           type
1335                                                                           ==
1336                                                                           YAFFS_OBJECT_TYPE_FILE)
1337                                                                          ||
1338                                                                          (tags.
1339                                                                           extra_available
1340                                                                           &&
1341                                                                           tags.
1342                                                                           extra_obj_type
1343                                                                           ==
1344                                                                           YAFFS_OBJECT_TYPE_FILE)))
1345                                         {
1346                                                 u32 this_size =
1347                                                     (oh) ? oh->
1348                                                     file_size :
1349                                                     tags.extra_length;
1350                                                 u32 parent_obj_id =
1351                                                     (oh) ? oh->parent_obj_id :
1352                                                     tags.extra_parent_id;
1353
1354                                                 is_shrink =
1355                                                     (oh) ? oh->
1356                                                     is_shrink :
1357                                                     tags.extra_is_shrink;
1358
1359                                                 /* If it is deleted (unlinked at start also means deleted)
1360                                                  * we treat the file size as being zeroed at this point.
1361                                                  */
1362                                                 if (parent_obj_id ==
1363                                                     YAFFS_OBJECTID_DELETED
1364                                                     || parent_obj_id ==
1365                                                     YAFFS_OBJECTID_UNLINKED) {
1366                                                         this_size = 0;
1367                                                         is_shrink = 1;
1368                                                 }
1369
1370                                                 if (is_shrink
1371                                                     && in->variant.file_variant.
1372                                                     shrink_size > this_size)
1373                                                         in->variant.
1374                                                             file_variant.
1375                                                             shrink_size =
1376                                                             this_size;
1377
1378                                                 if (is_shrink)
1379                                                         bi->has_shrink_hdr = 1;
1380
1381                                         }
1382                                         /* Use existing - destroy this one. */
1383                                         yaffs_chunk_del(dev, chunk, 1,
1384                                                         __LINE__);
1385
1386                                 }
1387
1388                                 if (!in->valid && in->variant_type !=
1389                                     (oh ? oh->type : tags.extra_obj_type))
1390                                         T(YAFFS_TRACE_ERROR,
1391                                           (TSTR
1392                                            ("yaffs tragedy: Bad object type, "
1393                                             TCONT
1394                                             ("%d != %d, for object %d at chunk ")
1395                                             TCONT("%d during scan")
1396                                             TENDSTR), oh ?
1397                                            oh->type : tags.extra_obj_type,
1398                                            in->variant_type, tags.obj_id,
1399                                            chunk));
1400
1401                                 if (!in->valid &&
1402                                     (tags.obj_id == YAFFS_OBJECTID_ROOT ||
1403                                      tags.obj_id ==
1404                                      YAFFS_OBJECTID_LOSTNFOUND)) {
1405                                         /* We only load some info, don't fiddle with directory structure */
1406                                         in->valid = 1;
1407
1408                                         if (oh) {
1409
1410                                                 in->yst_mode = oh->yst_mode;
1411                                                 yaffs_load_attribs(in, oh);
1412                                                 in->lazy_loaded = 0;
1413                                         } else
1414                                                 in->lazy_loaded = 1;
1415
1416                                         in->hdr_chunk = chunk;
1417
1418                                 } else if (!in->valid) {
1419                                         /* we need to load this info */
1420
1421                                         in->valid = 1;
1422                                         in->hdr_chunk = chunk;
1423
1424                                         if (oh) {
1425                                                 in->variant_type = oh->type;
1426
1427                                                 in->yst_mode = oh->yst_mode;
1428                                                 yaffs_load_attribs(in, oh);
1429
1430                                                 if (oh->shadows_obj > 0)
1431                                                         yaffs_handle_shadowed_obj
1432                                                             (dev,
1433                                                              oh->shadows_obj,
1434                                                              1);
1435
1436                                                 yaffs_set_obj_name_from_oh(in,
1437                                                                            oh);
1438                                                 parent =
1439                                                     yaffs_find_or_create_by_number
1440                                                     (dev, oh->parent_obj_id,
1441                                                      YAFFS_OBJECT_TYPE_DIRECTORY);
1442
1443                                                 file_size = oh->file_size;
1444                                                 is_shrink = oh->is_shrink;
1445                                                 equiv_id = oh->equiv_id;
1446
1447                                         } else {
1448                                                 in->variant_type =
1449                                                     tags.extra_obj_type;
1450                                                 parent =
1451                                                     yaffs_find_or_create_by_number
1452                                                     (dev, tags.extra_parent_id,
1453                                                      YAFFS_OBJECT_TYPE_DIRECTORY);
1454                                                 file_size = tags.extra_length;
1455                                                 is_shrink =
1456                                                     tags.extra_is_shrink;
1457                                                 equiv_id = tags.extra_equiv_id;
1458                                                 in->lazy_loaded = 1;
1459
1460                                         }
1461                                         in->dirty = 0;
1462
1463                                         if (!parent)
1464                                                 alloc_failed = 1;
1465
1466                                         /* directory stuff...
1467                                          * hook up to parent
1468                                          */
1469
1470                                         if (parent && parent->variant_type ==
1471                                             YAFFS_OBJECT_TYPE_UNKNOWN) {
1472                                                 /* Set up as a directory */
1473                                                 parent->variant_type =
1474                                                     YAFFS_OBJECT_TYPE_DIRECTORY;
1475                                                 INIT_LIST_HEAD(&parent->
1476                                                                variant.dir_variant.children);
1477                                         } else if (!parent
1478                                                    || parent->variant_type !=
1479                                                    YAFFS_OBJECT_TYPE_DIRECTORY)
1480                                         {
1481                                                 /* Hoosterman, another problem....
1482                                                  * We're trying to use a non-directory as a directory
1483                                                  */
1484
1485                                                 T(YAFFS_TRACE_ERROR,
1486                                                   (TSTR
1487                                                    ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
1488                                                     TENDSTR)));
1489                                                 parent = dev->lost_n_found;
1490                                         }
1491
1492                                         yaffs_add_obj_to_dir(parent, in);
1493
1494                                         is_unlinked = (parent == dev->del_dir)
1495                                             || (parent == dev->unlinked_dir);
1496
1497                                         if (is_shrink) {
1498                                                 /* Mark the block as having a shrink header */
1499                                                 bi->has_shrink_hdr = 1;
1500                                         }
1501
1502                                         /* Note re hardlinks.
1503                                          * Since we might scan a hardlink before its equivalent object is scanned
1504                                          * we put them all in a list.
1505                                          * After scanning is complete, we should have all the objects, so we run
1506                                          * through this list and fix up all the chains.
1507                                          */
1508
1509                                         switch (in->variant_type) {
1510                                         case YAFFS_OBJECT_TYPE_UNKNOWN:
1511                                                 /* Todo got a problem */
1512                                                 break;
1513                                         case YAFFS_OBJECT_TYPE_FILE:
1514
1515                                                 if (in->variant.
1516                                                     file_variant.scanned_size <
1517                                                     file_size) {
1518                                                         /* This covers the case where the file size is greater
1519                                                          * than where the data is
1520                                                          * This will happen if the file is resized to be larger
1521                                                          * than its current data extents.
1522                                                          */
1523                                                         in->variant.
1524                                                             file_variant.
1525                                                             file_size =
1526                                                             file_size;
1527                                                         in->variant.
1528                                                             file_variant.
1529                                                             scanned_size =
1530                                                             file_size;
1531                                                 }
1532
1533                                                 if (in->variant.file_variant.
1534                                                     shrink_size > file_size)
1535                                                         in->variant.
1536                                                             file_variant.
1537                                                             shrink_size =
1538                                                             file_size;
1539
1540                                                 break;
1541                                         case YAFFS_OBJECT_TYPE_HARDLINK:
1542                                                 if (!is_unlinked) {
1543                                                         in->variant.
1544                                                             hardlink_variant.
1545                                                             equiv_id = equiv_id;
1546                                                         in->hard_links.next =
1547                                                             (struct list_head *)
1548                                                             hard_list;
1549                                                         hard_list = in;
1550                                                 }
1551                                                 break;
1552                                         case YAFFS_OBJECT_TYPE_DIRECTORY:
1553                                                 /* Do nothing */
1554                                                 break;
1555                                         case YAFFS_OBJECT_TYPE_SPECIAL:
1556                                                 /* Do nothing */
1557                                                 break;
1558                                         case YAFFS_OBJECT_TYPE_SYMLINK:
1559                                                 if (oh) {
1560                                                         in->variant.
1561                                                             symlink_variant.
1562                                                             alias =
1563                                                             yaffs_clone_str(oh->
1564                                                                             alias);
1565                                                         if (!in->variant.
1566                                                             symlink_variant.
1567                                                             alias)
1568                                                                 alloc_failed =
1569                                                                     1;
1570                                                 }
1571                                                 break;
1572                                         }
1573
1574                                 }
1575
1576                         }
1577
1578                 }               /* End of scanning for each chunk */
1579
1580                 if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
1581                         /* If we got this far while scanning, then the block is fully allocated. */
1582                         state = YAFFS_BLOCK_STATE_FULL;
1583                 }
1584
1585                 bi->block_state = state;
1586
1587                 /* Now let's see if it was dirty */
1588                 if (bi->pages_in_use == 0 &&
1589                     !bi->has_shrink_hdr &&
1590                     bi->block_state == YAFFS_BLOCK_STATE_FULL) {
1591                         yaffs_block_became_dirty(dev, blk);
1592                 }
1593
1594         }
1595
1596         yaffs_skip_rest_of_block(dev);
1597
1598         if (alt_block_index)
1599                 YFREE_ALT(block_index);
1600         else
1601                 YFREE(block_index);
1602
1603         /* Ok, we've done all the scanning.
1604          * Fix up the hard link chains.
1605          * We should now have scanned all the objects, now it's time to add these
1606          * hardlinks.
1607          */
1608         yaffs_link_fixup(dev, hard_list);
1609
1610         yaffs_release_temp_buffer(dev, chunk_data, __LINE__);
1611
1612         if (alloc_failed)
1613                 return YAFFS_FAIL;
1614
1615         T(YAFFS_TRACE_SCAN, (TSTR("yaffs2_scan_backwards ends" TENDSTR)));
1616
1617         return YAFFS_OK;
1618 }