yaffs2: Make checkpoint block scanning skip bad blocks.
[yaffs2.git] / yaffs_packedtags2.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2011 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_packedtags2.h"
15 #include "yportenv.h"
16 #include "yaffs_trace.h"
17
18 /* This code packs a set of extended tags into a binary structure for
19  * NAND storage
20  */
21
22 /* Some of the information is "extra" struff which can be packed in to
23  * speed scanning
24  * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
25  */
26
27 /* Extra flags applied to chunk_id */
28
29 #define EXTRA_HEADER_INFO_FLAG  0x80000000
30 #define EXTRA_SHRINK_FLAG       0x40000000
31 #define EXTRA_SHADOWS_FLAG      0x20000000
32 #define EXTRA_SPARE_FLAGS       0x10000000
33
34 #define ALL_EXTRA_FLAGS         0xf0000000
35
36 /* Also, the top 4 bits of the object Id are set to the object type. */
37 #define EXTRA_OBJECT_TYPE_SHIFT (28)
38 #define EXTRA_OBJECT_TYPE_MASK  ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT)
39
40 static void yaffs_dump_packed_tags2_tags_only(
41                                 const struct yaffs_packed_tags2_tags_only *ptt)
42 {
43         yaffs_trace(YAFFS_TRACE_MTD,
44                 "packed tags obj %d chunk %d byte %d seq %d",
45                 ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number);
46 }
47
48 static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt)
49 {
50         yaffs_dump_packed_tags2_tags_only(&pt->t);
51 }
52
53 static void yaffs_dump_tags2(const struct yaffs_ext_tags *t)
54 {
55         yaffs_trace(YAFFS_TRACE_MTD,
56                 "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d",
57                 t->ecc_result, t->block_bad, t->chunk_used, t->obj_id,
58                 t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number,
59                 t->seq_number);
60
61 }
62
63 static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t)
64 {
65         if (t->chunk_id != 0 || !t->extra_available)
66                 return 0;
67
68         /* Check if the file size is too long to store */
69         if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE &&
70             (t->extra_file_size >> 31) != 0)
71                 return 0;
72         return 1;
73 }
74
75 void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt,
76                                 const struct yaffs_ext_tags *t)
77 {
78         ptt->chunk_id = t->chunk_id;
79         ptt->seq_number = t->seq_number;
80         ptt->n_bytes = t->n_bytes;
81         ptt->obj_id = t->obj_id;
82
83         /* Only store extra tags for object headers.
84          * If it is a file then only store  if the file size is short\
85          * enough to fit.
86          */
87         if (yaffs_check_tags_extra_packable(t)) {
88                 /* Store the extra header info instead */
89                 /* We save the parent object in the chunk_id */
90                 ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id;
91                 if (t->extra_is_shrink)
92                         ptt->chunk_id |= EXTRA_SHRINK_FLAG;
93                 if (t->extra_shadows)
94                         ptt->chunk_id |= EXTRA_SHADOWS_FLAG;
95
96                 ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
97                 ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT);
98
99                 if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
100                         ptt->n_bytes = t->extra_equiv_id;
101                 else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE)
102                         ptt->n_bytes = (unsigned) t->extra_file_size;
103                 else
104                         ptt->n_bytes = 0;
105         }
106
107         yaffs_dump_packed_tags2_tags_only(ptt);
108         yaffs_dump_tags2(t);
109 }
110
111 void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt,
112                       const struct yaffs_ext_tags *t, int tags_ecc)
113 {
114         yaffs_pack_tags2_tags_only(&pt->t, t);
115
116         if (tags_ecc)
117                 yaffs_ecc_calc_other((unsigned char *)&pt->t,
118                                     sizeof(struct yaffs_packed_tags2_tags_only),
119                                     &pt->ecc);
120 }
121
122 void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t,
123                                   struct yaffs_packed_tags2_tags_only *ptt)
124 {
125         memset(t, 0, sizeof(struct yaffs_ext_tags));
126
127         if (ptt->seq_number == 0xffffffff)
128                 return;
129
130         t->block_bad = 0;
131         t->chunk_used = 1;
132         t->obj_id = ptt->obj_id;
133         t->chunk_id = ptt->chunk_id;
134         t->n_bytes = ptt->n_bytes;
135         t->is_deleted = 0;
136         t->serial_number = 0;
137         t->seq_number = ptt->seq_number;
138
139         /* Do extra header info stuff */
140         if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) {
141                 t->chunk_id = 0;
142                 t->n_bytes = 0;
143
144                 t->extra_available = 1;
145                 t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS));
146                 t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0;
147                 t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0;
148                 t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT;
149                 t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK;
150
151                 if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK)
152                         t->extra_equiv_id = ptt->n_bytes;
153                 else
154                         t->extra_file_size = ptt->n_bytes;
155         }
156         yaffs_dump_packed_tags2_tags_only(ptt);
157         yaffs_dump_tags2(t);
158 }
159
160 void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt,
161                         int tags_ecc)
162 {
163         enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
164
165         if (pt->t.seq_number != 0xffffffff && tags_ecc) {
166                 /* Chunk is in use and we need to do ECC */
167
168                 struct yaffs_ecc_other ecc;
169                 int result;
170                 yaffs_ecc_calc_other((unsigned char *)&pt->t,
171                                 sizeof(struct yaffs_packed_tags2_tags_only),
172                                 &ecc);
173                 result =
174                     yaffs_ecc_correct_other((unsigned char *)&pt->t,
175                                 sizeof(struct yaffs_packed_tags2_tags_only),
176                                 &pt->ecc, &ecc);
177                 switch (result) {
178                 case 0:
179                         ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
180                         break;
181                 case 1:
182                         ecc_result = YAFFS_ECC_RESULT_FIXED;
183                         break;
184                 case -1:
185                         ecc_result = YAFFS_ECC_RESULT_UNFIXED;
186                         break;
187                 default:
188                         ecc_result = YAFFS_ECC_RESULT_UNKNOWN;
189                 }
190         }
191         yaffs_unpack_tags2_tags_only(t, &pt->t);
192
193         t->ecc_result = ecc_result;
194
195         yaffs_dump_packed_tags2(pt);
196         yaffs_dump_tags2(t);
197 }