]>
Commit | Line | Data |
---|---|---|
0e8cc8bd WJ |
1 | /* |
2 | * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. | |
3 | * | |
753ac610 | 4 | * Copyright (C) 2002-2011 Aleph One Ltd. |
0e8cc8bd WJ |
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" | |
753ac610 | 16 | #include "yaffs_trace.h" |
0e8cc8bd WJ |
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 | ||
753ac610 | 27 | /* Extra flags applied to chunk_id */ |
0e8cc8bd WJ |
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 | ||
753ac610 | 34 | #define ALL_EXTRA_FLAGS 0xf0000000 |
0e8cc8bd WJ |
35 | |
36 | /* Also, the top 4 bits of the object Id are set to the object type. */ | |
37 | #define EXTRA_OBJECT_TYPE_SHIFT (28) | |
753ac610 | 38 | #define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT) |
0e8cc8bd | 39 | |
753ac610 CM |
40 | static void yaffs_dump_packed_tags2_tags_only( |
41 | const struct yaffs_packed_tags2_tags_only *ptt) | |
0e8cc8bd | 42 | { |
753ac610 CM |
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); | |
0e8cc8bd WJ |
46 | } |
47 | ||
753ac610 | 48 | static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt) |
0e8cc8bd | 49 | { |
753ac610 | 50 | yaffs_dump_packed_tags2_tags_only(&pt->t); |
0e8cc8bd WJ |
51 | } |
52 | ||
753ac610 | 53 | static void yaffs_dump_tags2(const struct yaffs_ext_tags *t) |
0e8cc8bd | 54 | { |
753ac610 CM |
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); | |
0e8cc8bd | 60 | |
753ac610 | 61 | } |
0e8cc8bd | 62 | |
753ac610 CM |
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 | } | |
0e8cc8bd | 74 | |
753ac610 CM |
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; | |
0e8cc8bd WJ |
105 | } |
106 | ||
753ac610 CM |
107 | yaffs_dump_packed_tags2_tags_only(ptt); |
108 | yaffs_dump_tags2(t); | |
0e8cc8bd WJ |
109 | } |
110 | ||
753ac610 CM |
111 | void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, |
112 | const struct yaffs_ext_tags *t, int tags_ecc) | |
0e8cc8bd | 113 | { |
753ac610 | 114 | yaffs_pack_tags2_tags_only(&pt->t, t); |
0e8cc8bd | 115 | |
753ac610 CM |
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 | } | |
0e8cc8bd | 121 | |
753ac610 CM |
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 | } | |
0e8cc8bd | 159 | |
753ac610 CM |
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; | |
0e8cc8bd WJ |
189 | } |
190 | } | |
753ac610 | 191 | yaffs_unpack_tags2_tags_only(t, &pt->t); |
0e8cc8bd | 192 | |
753ac610 | 193 | t->ecc_result = ecc_result; |
0e8cc8bd | 194 | |
753ac610 CM |
195 | yaffs_dump_packed_tags2(pt); |
196 | yaffs_dump_tags2(t); | |
0e8cc8bd | 197 | } |