1 | /* |
2 | * JFFS2 -- Journalling Flash File System, Version 2. |
3 | * |
4 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, |
5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, |
6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, |
7 | * University of Szeged, Hungary |
8 | * 2006 KaiGai Kohei <kaigai@ak.jp.nec.com> |
9 | * |
10 | * For licensing information, see the file 'LICENCE' in this directory. |
11 | * |
12 | */ |
13 | |
14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
15 | |
16 | #include <linux/kernel.h> |
17 | #include <linux/slab.h> |
18 | #include <linux/mtd/mtd.h> |
19 | #include <linux/pagemap.h> |
20 | #include <linux/crc32.h> |
21 | #include <linux/compiler.h> |
22 | #include <linux/vmalloc.h> |
23 | #include "nodelist.h" |
24 | #include "debug.h" |
25 | |
26 | int jffs2_sum_init(struct jffs2_sb_info *c) |
27 | { |
28 | uint32_t sum_size = min_t(uint32_t, c->sector_size, MAX_SUMMARY_SIZE); |
29 | |
30 | c->summary = kzalloc(size: sizeof(struct jffs2_summary), GFP_KERNEL); |
31 | |
32 | if (!c->summary) { |
33 | JFFS2_WARNING("Can't allocate memory for summary information!\n" ); |
34 | return -ENOMEM; |
35 | } |
36 | |
37 | c->summary->sum_buf = kmalloc(size: sum_size, GFP_KERNEL); |
38 | |
39 | if (!c->summary->sum_buf) { |
40 | JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n" ); |
41 | kfree(objp: c->summary); |
42 | return -ENOMEM; |
43 | } |
44 | |
45 | dbg_summary("returned successfully\n" ); |
46 | |
47 | return 0; |
48 | } |
49 | |
50 | void jffs2_sum_exit(struct jffs2_sb_info *c) |
51 | { |
52 | dbg_summary("called\n" ); |
53 | |
54 | jffs2_sum_disable_collecting(s: c->summary); |
55 | |
56 | kfree(objp: c->summary->sum_buf); |
57 | c->summary->sum_buf = NULL; |
58 | |
59 | kfree(objp: c->summary); |
60 | c->summary = NULL; |
61 | } |
62 | |
63 | static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item) |
64 | { |
65 | if (!s->sum_list_head) |
66 | s->sum_list_head = (union jffs2_sum_mem *) item; |
67 | if (s->sum_list_tail) |
68 | s->sum_list_tail->u.next = (union jffs2_sum_mem *) item; |
69 | s->sum_list_tail = (union jffs2_sum_mem *) item; |
70 | |
71 | switch (je16_to_cpu(item->u.nodetype)) { |
72 | case JFFS2_NODETYPE_INODE: |
73 | s->sum_size += JFFS2_SUMMARY_INODE_SIZE; |
74 | s->sum_num++; |
75 | dbg_summary("inode (%u) added to summary\n" , |
76 | je32_to_cpu(item->i.inode)); |
77 | break; |
78 | case JFFS2_NODETYPE_DIRENT: |
79 | s->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize); |
80 | s->sum_num++; |
81 | dbg_summary("dirent (%u) added to summary\n" , |
82 | je32_to_cpu(item->d.ino)); |
83 | break; |
84 | #ifdef CONFIG_JFFS2_FS_XATTR |
85 | case JFFS2_NODETYPE_XATTR: |
86 | s->sum_size += JFFS2_SUMMARY_XATTR_SIZE; |
87 | s->sum_num++; |
88 | dbg_summary("xattr (xid=%u, version=%u) added to summary\n" , |
89 | je32_to_cpu(item->x.xid), je32_to_cpu(item->x.version)); |
90 | break; |
91 | case JFFS2_NODETYPE_XREF: |
92 | s->sum_size += JFFS2_SUMMARY_XREF_SIZE; |
93 | s->sum_num++; |
94 | dbg_summary("xref added to summary\n" ); |
95 | break; |
96 | #endif |
97 | default: |
98 | JFFS2_WARNING("UNKNOWN node type %u\n" , |
99 | je16_to_cpu(item->u.nodetype)); |
100 | return 1; |
101 | } |
102 | return 0; |
103 | } |
104 | |
105 | |
106 | /* The following 3 functions are called from scan.c to collect summary info for not closed jeb */ |
107 | |
108 | int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size) |
109 | { |
110 | dbg_summary("called with %u\n" , size); |
111 | s->sum_padded += size; |
112 | return 0; |
113 | } |
114 | |
115 | int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, |
116 | uint32_t ofs) |
117 | { |
118 | struct jffs2_sum_inode_mem *temp = kmalloc(size: sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL); |
119 | |
120 | if (!temp) |
121 | return -ENOMEM; |
122 | |
123 | temp->nodetype = ri->nodetype; |
124 | temp->inode = ri->ino; |
125 | temp->version = ri->version; |
126 | temp->offset = cpu_to_je32(ofs); /* relative offset from the beginning of the jeb */ |
127 | temp->totlen = ri->totlen; |
128 | temp->next = NULL; |
129 | |
130 | return jffs2_sum_add_mem(s, item: (union jffs2_sum_mem *)temp); |
131 | } |
132 | |
133 | int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, |
134 | uint32_t ofs) |
135 | { |
136 | struct jffs2_sum_dirent_mem *temp = |
137 | kmalloc(size: sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL); |
138 | |
139 | if (!temp) |
140 | return -ENOMEM; |
141 | |
142 | temp->nodetype = rd->nodetype; |
143 | temp->totlen = rd->totlen; |
144 | temp->offset = cpu_to_je32(ofs); /* relative from the beginning of the jeb */ |
145 | temp->pino = rd->pino; |
146 | temp->version = rd->version; |
147 | temp->ino = rd->ino; |
148 | temp->nsize = rd->nsize; |
149 | temp->type = rd->type; |
150 | temp->next = NULL; |
151 | |
152 | memcpy(temp->name, rd->name, rd->nsize); |
153 | |
154 | return jffs2_sum_add_mem(s, item: (union jffs2_sum_mem *)temp); |
155 | } |
156 | |
157 | #ifdef CONFIG_JFFS2_FS_XATTR |
158 | int jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs) |
159 | { |
160 | struct jffs2_sum_xattr_mem *temp; |
161 | |
162 | temp = kmalloc(size: sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL); |
163 | if (!temp) |
164 | return -ENOMEM; |
165 | |
166 | temp->nodetype = rx->nodetype; |
167 | temp->xid = rx->xid; |
168 | temp->version = rx->version; |
169 | temp->offset = cpu_to_je32(ofs); |
170 | temp->totlen = rx->totlen; |
171 | temp->next = NULL; |
172 | |
173 | return jffs2_sum_add_mem(s, item: (union jffs2_sum_mem *)temp); |
174 | } |
175 | |
176 | int jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs) |
177 | { |
178 | struct jffs2_sum_xref_mem *temp; |
179 | |
180 | temp = kmalloc(size: sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL); |
181 | if (!temp) |
182 | return -ENOMEM; |
183 | |
184 | temp->nodetype = rr->nodetype; |
185 | temp->offset = cpu_to_je32(ofs); |
186 | temp->next = NULL; |
187 | |
188 | return jffs2_sum_add_mem(s, item: (union jffs2_sum_mem *)temp); |
189 | } |
190 | #endif |
191 | /* Cleanup every collected summary information */ |
192 | |
193 | static void jffs2_sum_clean_collected(struct jffs2_summary *s) |
194 | { |
195 | union jffs2_sum_mem *temp; |
196 | |
197 | if (!s->sum_list_head) { |
198 | dbg_summary("already empty\n" ); |
199 | } |
200 | while (s->sum_list_head) { |
201 | temp = s->sum_list_head; |
202 | s->sum_list_head = s->sum_list_head->u.next; |
203 | kfree(objp: temp); |
204 | } |
205 | s->sum_list_tail = NULL; |
206 | s->sum_padded = 0; |
207 | s->sum_num = 0; |
208 | } |
209 | |
210 | void jffs2_sum_reset_collected(struct jffs2_summary *s) |
211 | { |
212 | dbg_summary("called\n" ); |
213 | jffs2_sum_clean_collected(s); |
214 | s->sum_size = 0; |
215 | } |
216 | |
217 | void jffs2_sum_disable_collecting(struct jffs2_summary *s) |
218 | { |
219 | dbg_summary("called\n" ); |
220 | jffs2_sum_clean_collected(s); |
221 | s->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; |
222 | } |
223 | |
224 | int jffs2_sum_is_disabled(struct jffs2_summary *s) |
225 | { |
226 | return (s->sum_size == JFFS2_SUMMARY_NOSUM_SIZE); |
227 | } |
228 | |
229 | /* Move the collected summary information into sb (called from scan.c) */ |
230 | |
231 | void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s) |
232 | { |
233 | dbg_summary("oldsize=0x%x oldnum=%u => newsize=0x%x newnum=%u\n" , |
234 | c->summary->sum_size, c->summary->sum_num, |
235 | s->sum_size, s->sum_num); |
236 | |
237 | c->summary->sum_size = s->sum_size; |
238 | c->summary->sum_num = s->sum_num; |
239 | c->summary->sum_padded = s->sum_padded; |
240 | c->summary->sum_list_head = s->sum_list_head; |
241 | c->summary->sum_list_tail = s->sum_list_tail; |
242 | |
243 | s->sum_list_head = s->sum_list_tail = NULL; |
244 | } |
245 | |
246 | /* Called from wbuf.c to collect writed node info */ |
247 | |
248 | int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, |
249 | unsigned long count, uint32_t ofs) |
250 | { |
251 | union jffs2_node_union *node; |
252 | struct jffs2_eraseblock *jeb; |
253 | |
254 | if (c->summary->sum_size == JFFS2_SUMMARY_NOSUM_SIZE) { |
255 | dbg_summary("Summary is disabled for this jeb! Skipping summary info!\n" ); |
256 | return 0; |
257 | } |
258 | |
259 | node = invecs[0].iov_base; |
260 | jeb = &c->blocks[ofs / c->sector_size]; |
261 | ofs -= jeb->offset; |
262 | |
263 | switch (je16_to_cpu(node->u.nodetype)) { |
264 | case JFFS2_NODETYPE_INODE: { |
265 | struct jffs2_sum_inode_mem *temp = |
266 | kmalloc(size: sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL); |
267 | |
268 | if (!temp) |
269 | goto no_mem; |
270 | |
271 | temp->nodetype = node->i.nodetype; |
272 | temp->inode = node->i.ino; |
273 | temp->version = node->i.version; |
274 | temp->offset = cpu_to_je32(ofs); |
275 | temp->totlen = node->i.totlen; |
276 | temp->next = NULL; |
277 | |
278 | return jffs2_sum_add_mem(s: c->summary, item: (union jffs2_sum_mem *)temp); |
279 | } |
280 | |
281 | case JFFS2_NODETYPE_DIRENT: { |
282 | struct jffs2_sum_dirent_mem *temp = |
283 | kmalloc(size: sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL); |
284 | |
285 | if (!temp) |
286 | goto no_mem; |
287 | |
288 | temp->nodetype = node->d.nodetype; |
289 | temp->totlen = node->d.totlen; |
290 | temp->offset = cpu_to_je32(ofs); |
291 | temp->pino = node->d.pino; |
292 | temp->version = node->d.version; |
293 | temp->ino = node->d.ino; |
294 | temp->nsize = node->d.nsize; |
295 | temp->type = node->d.type; |
296 | temp->next = NULL; |
297 | |
298 | switch (count) { |
299 | case 1: |
300 | memcpy(temp->name,node->d.name,node->d.nsize); |
301 | break; |
302 | |
303 | case 2: |
304 | memcpy(temp->name,invecs[1].iov_base,node->d.nsize); |
305 | break; |
306 | |
307 | default: |
308 | BUG(); /* impossible count value */ |
309 | break; |
310 | } |
311 | |
312 | return jffs2_sum_add_mem(s: c->summary, item: (union jffs2_sum_mem *)temp); |
313 | } |
314 | #ifdef CONFIG_JFFS2_FS_XATTR |
315 | case JFFS2_NODETYPE_XATTR: { |
316 | struct jffs2_sum_xattr_mem *temp; |
317 | temp = kmalloc(size: sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL); |
318 | if (!temp) |
319 | goto no_mem; |
320 | |
321 | temp->nodetype = node->x.nodetype; |
322 | temp->xid = node->x.xid; |
323 | temp->version = node->x.version; |
324 | temp->totlen = node->x.totlen; |
325 | temp->offset = cpu_to_je32(ofs); |
326 | temp->next = NULL; |
327 | |
328 | return jffs2_sum_add_mem(s: c->summary, item: (union jffs2_sum_mem *)temp); |
329 | } |
330 | case JFFS2_NODETYPE_XREF: { |
331 | struct jffs2_sum_xref_mem *temp; |
332 | temp = kmalloc(size: sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL); |
333 | if (!temp) |
334 | goto no_mem; |
335 | temp->nodetype = node->r.nodetype; |
336 | temp->offset = cpu_to_je32(ofs); |
337 | temp->next = NULL; |
338 | |
339 | return jffs2_sum_add_mem(s: c->summary, item: (union jffs2_sum_mem *)temp); |
340 | } |
341 | #endif |
342 | case JFFS2_NODETYPE_PADDING: |
343 | dbg_summary("node PADDING\n" ); |
344 | c->summary->sum_padded += je32_to_cpu(node->u.totlen); |
345 | break; |
346 | |
347 | case JFFS2_NODETYPE_CLEANMARKER: |
348 | dbg_summary("node CLEANMARKER\n" ); |
349 | break; |
350 | |
351 | case JFFS2_NODETYPE_SUMMARY: |
352 | dbg_summary("node SUMMARY\n" ); |
353 | break; |
354 | |
355 | default: |
356 | /* If you implement a new node type you should also implement |
357 | summary support for it or disable summary. |
358 | */ |
359 | BUG(); |
360 | break; |
361 | } |
362 | |
363 | return 0; |
364 | |
365 | no_mem: |
366 | JFFS2_WARNING("MEMORY ALLOCATION ERROR!" ); |
367 | return -ENOMEM; |
368 | } |
369 | |
370 | static struct jffs2_raw_node_ref *sum_link_node_ref(struct jffs2_sb_info *c, |
371 | struct jffs2_eraseblock *jeb, |
372 | uint32_t ofs, uint32_t len, |
373 | struct jffs2_inode_cache *ic) |
374 | { |
375 | /* If there was a gap, mark it dirty */ |
376 | if ((ofs & ~3) > c->sector_size - jeb->free_size) { |
377 | /* Ew. Summary doesn't actually tell us explicitly about dirty space */ |
378 | jffs2_scan_dirty_space(c, jeb, size: (ofs & ~3) - (c->sector_size - jeb->free_size)); |
379 | } |
380 | |
381 | return jffs2_link_node_ref(c, jeb, ofs: jeb->offset + ofs, len, ic); |
382 | } |
383 | |
384 | /* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */ |
385 | |
386 | static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
387 | struct jffs2_raw_summary *summary, uint32_t *pseudo_random) |
388 | { |
389 | struct jffs2_inode_cache *ic; |
390 | struct jffs2_full_dirent *fd; |
391 | void *sp; |
392 | int i, ino; |
393 | int err; |
394 | |
395 | sp = summary->sum; |
396 | |
397 | for (i=0; i<je32_to_cpu(summary->sum_num); i++) { |
398 | dbg_summary("processing summary index %d\n" , i); |
399 | |
400 | cond_resched(); |
401 | |
402 | /* Make sure there's a spare ref for dirty space */ |
403 | err = jffs2_prealloc_raw_node_refs(c, jeb, nr: 2); |
404 | if (err) |
405 | return err; |
406 | |
407 | switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { |
408 | case JFFS2_NODETYPE_INODE: { |
409 | struct jffs2_sum_inode_flash *spi; |
410 | spi = sp; |
411 | |
412 | ino = je32_to_cpu(spi->inode); |
413 | |
414 | dbg_summary("Inode at 0x%08x-0x%08x\n" , |
415 | jeb->offset + je32_to_cpu(spi->offset), |
416 | jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spi->totlen)); |
417 | |
418 | ic = jffs2_scan_make_ino_cache(c, ino); |
419 | if (!ic) { |
420 | JFFS2_NOTICE("scan_make_ino_cache failed\n" ); |
421 | return -ENOMEM; |
422 | } |
423 | |
424 | sum_link_node_ref(c, jeb, je32_to_cpu(spi->offset) | REF_UNCHECKED, |
425 | PAD(je32_to_cpu(spi->totlen)), ic); |
426 | |
427 | *pseudo_random += je32_to_cpu(spi->version); |
428 | |
429 | sp += JFFS2_SUMMARY_INODE_SIZE; |
430 | |
431 | break; |
432 | } |
433 | |
434 | case JFFS2_NODETYPE_DIRENT: { |
435 | struct jffs2_sum_dirent_flash *spd; |
436 | int checkedlen; |
437 | spd = sp; |
438 | |
439 | dbg_summary("Dirent at 0x%08x-0x%08x\n" , |
440 | jeb->offset + je32_to_cpu(spd->offset), |
441 | jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen)); |
442 | |
443 | |
444 | /* This should never happen, but https://dev.laptop.org/ticket/4184 */ |
445 | checkedlen = strnlen(p: spd->name, maxlen: spd->nsize); |
446 | if (!checkedlen) { |
447 | pr_err("Dirent at %08x has zero at start of name. Aborting mount.\n" , |
448 | jeb->offset + |
449 | je32_to_cpu(spd->offset)); |
450 | return -EIO; |
451 | } |
452 | if (checkedlen < spd->nsize) { |
453 | pr_err("Dirent at %08x has zeroes in name. Truncating to %d chars\n" , |
454 | jeb->offset + |
455 | je32_to_cpu(spd->offset), |
456 | checkedlen); |
457 | } |
458 | |
459 | |
460 | fd = jffs2_alloc_full_dirent(namesize: checkedlen+1); |
461 | if (!fd) |
462 | return -ENOMEM; |
463 | |
464 | memcpy(&fd->name, spd->name, checkedlen); |
465 | fd->name[checkedlen] = 0; |
466 | |
467 | ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); |
468 | if (!ic) { |
469 | jffs2_free_full_dirent(fd); |
470 | return -ENOMEM; |
471 | } |
472 | |
473 | fd->raw = sum_link_node_ref(c, jeb, je32_to_cpu(spd->offset) | REF_UNCHECKED, |
474 | PAD(je32_to_cpu(spd->totlen)), ic); |
475 | |
476 | fd->next = NULL; |
477 | fd->version = je32_to_cpu(spd->version); |
478 | fd->ino = je32_to_cpu(spd->ino); |
479 | fd->nhash = full_name_hash(NULL, fd->name, checkedlen); |
480 | fd->type = spd->type; |
481 | |
482 | jffs2_add_fd_to_list(c, new: fd, list: &ic->scan_dents); |
483 | |
484 | *pseudo_random += je32_to_cpu(spd->version); |
485 | |
486 | sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); |
487 | |
488 | break; |
489 | } |
490 | #ifdef CONFIG_JFFS2_FS_XATTR |
491 | case JFFS2_NODETYPE_XATTR: { |
492 | struct jffs2_xattr_datum *xd; |
493 | struct jffs2_sum_xattr_flash *spx; |
494 | |
495 | spx = (struct jffs2_sum_xattr_flash *)sp; |
496 | dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n" , |
497 | jeb->offset + je32_to_cpu(spx->offset), |
498 | jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen), |
499 | je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); |
500 | |
501 | xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid), |
502 | je32_to_cpu(spx->version)); |
503 | if (IS_ERR(ptr: xd)) |
504 | return PTR_ERR(ptr: xd); |
505 | if (xd->version > je32_to_cpu(spx->version)) { |
506 | /* node is not the newest one */ |
507 | struct jffs2_raw_node_ref *raw |
508 | = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED, |
509 | PAD(je32_to_cpu(spx->totlen)), NULL); |
510 | raw->next_in_ino = xd->node->next_in_ino; |
511 | xd->node->next_in_ino = raw; |
512 | } else { |
513 | xd->version = je32_to_cpu(spx->version); |
514 | sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED, |
515 | PAD(je32_to_cpu(spx->totlen)), ic: (void *)xd); |
516 | } |
517 | *pseudo_random += je32_to_cpu(spx->xid); |
518 | sp += JFFS2_SUMMARY_XATTR_SIZE; |
519 | |
520 | break; |
521 | } |
522 | case JFFS2_NODETYPE_XREF: { |
523 | struct jffs2_xattr_ref *ref; |
524 | struct jffs2_sum_xref_flash *spr; |
525 | |
526 | spr = (struct jffs2_sum_xref_flash *)sp; |
527 | dbg_summary("xref at %#08x-%#08x\n" , |
528 | jeb->offset + je32_to_cpu(spr->offset), |
529 | jeb->offset + je32_to_cpu(spr->offset) + |
530 | (uint32_t)PAD(sizeof(struct jffs2_raw_xref))); |
531 | |
532 | ref = jffs2_alloc_xattr_ref(); |
533 | if (!ref) { |
534 | JFFS2_NOTICE("allocation of xattr_datum failed\n" ); |
535 | return -ENOMEM; |
536 | } |
537 | ref->next = c->xref_temp; |
538 | c->xref_temp = ref; |
539 | |
540 | sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED, |
541 | PAD(sizeof(struct jffs2_raw_xref)), ic: (void *)ref); |
542 | |
543 | *pseudo_random += ref->node->flash_offset; |
544 | sp += JFFS2_SUMMARY_XREF_SIZE; |
545 | |
546 | break; |
547 | } |
548 | #endif |
549 | default : { |
550 | uint16_t nodetype = je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype); |
551 | JFFS2_WARNING("Unsupported node type %x found in summary! Exiting...\n" , nodetype); |
552 | if ((nodetype & JFFS2_COMPAT_MASK) == JFFS2_FEATURE_INCOMPAT) |
553 | return -EIO; |
554 | |
555 | /* For compatible node types, just fall back to the full scan */ |
556 | c->wasted_size -= jeb->wasted_size; |
557 | c->free_size += c->sector_size - jeb->free_size; |
558 | c->used_size -= jeb->used_size; |
559 | c->dirty_size -= jeb->dirty_size; |
560 | jeb->wasted_size = jeb->used_size = jeb->dirty_size = 0; |
561 | jeb->free_size = c->sector_size; |
562 | |
563 | jffs2_free_jeb_node_refs(c, jeb); |
564 | return -ENOTRECOVERABLE; |
565 | } |
566 | } |
567 | } |
568 | return 0; |
569 | } |
570 | |
571 | /* Process the summary node - called from jffs2_scan_eraseblock() */ |
572 | int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
573 | struct jffs2_raw_summary *summary, uint32_t sumsize, |
574 | uint32_t *pseudo_random) |
575 | { |
576 | struct jffs2_unknown_node crcnode; |
577 | int ret, ofs; |
578 | uint32_t crc; |
579 | |
580 | ofs = c->sector_size - sumsize; |
581 | |
582 | dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n" , |
583 | jeb->offset, jeb->offset + ofs, sumsize); |
584 | |
585 | /* OK, now check for node validity and CRC */ |
586 | crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
587 | crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY); |
588 | crcnode.totlen = summary->totlen; |
589 | crc = crc32(0, &crcnode, sizeof(crcnode)-4); |
590 | |
591 | if (je32_to_cpu(summary->hdr_crc) != crc) { |
592 | dbg_summary("Summary node header is corrupt (bad CRC or " |
593 | "no summary at all)\n" ); |
594 | goto crc_err; |
595 | } |
596 | |
597 | if (je32_to_cpu(summary->totlen) != sumsize) { |
598 | dbg_summary("Summary node is corrupt (wrong erasesize?)\n" ); |
599 | goto crc_err; |
600 | } |
601 | |
602 | crc = crc32(0, summary, sizeof(struct jffs2_raw_summary)-8); |
603 | |
604 | if (je32_to_cpu(summary->node_crc) != crc) { |
605 | dbg_summary("Summary node is corrupt (bad CRC)\n" ); |
606 | goto crc_err; |
607 | } |
608 | |
609 | crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_raw_summary)); |
610 | |
611 | if (je32_to_cpu(summary->sum_crc) != crc) { |
612 | dbg_summary("Summary node data is corrupt (bad CRC)\n" ); |
613 | goto crc_err; |
614 | } |
615 | |
616 | if ( je32_to_cpu(summary->cln_mkr) ) { |
617 | |
618 | dbg_summary("Summary : CLEANMARKER node \n" ); |
619 | |
620 | ret = jffs2_prealloc_raw_node_refs(c, jeb, nr: 1); |
621 | if (ret) |
622 | return ret; |
623 | |
624 | if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) { |
625 | dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n" , |
626 | je32_to_cpu(summary->cln_mkr), c->cleanmarker_size); |
627 | if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) |
628 | return ret; |
629 | } else if (jeb->first_node) { |
630 | dbg_summary("CLEANMARKER node not first node in block " |
631 | "(0x%08x)\n" , jeb->offset); |
632 | if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) |
633 | return ret; |
634 | } else { |
635 | jffs2_link_node_ref(c, jeb, ofs: jeb->offset | REF_NORMAL, |
636 | je32_to_cpu(summary->cln_mkr), NULL); |
637 | } |
638 | } |
639 | |
640 | ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random); |
641 | /* -ENOTRECOVERABLE isn't a fatal error -- it means we should do a full |
642 | scan of this eraseblock. So return zero */ |
643 | if (ret == -ENOTRECOVERABLE) |
644 | return 0; |
645 | if (ret) |
646 | return ret; /* real error */ |
647 | |
648 | /* for PARANOIA_CHECK */ |
649 | ret = jffs2_prealloc_raw_node_refs(c, jeb, nr: 2); |
650 | if (ret) |
651 | return ret; |
652 | |
653 | sum_link_node_ref(c, jeb, ofs: ofs | REF_NORMAL, len: sumsize, NULL); |
654 | |
655 | if (unlikely(jeb->free_size)) { |
656 | JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n" , |
657 | jeb->free_size, jeb->offset); |
658 | jeb->wasted_size += jeb->free_size; |
659 | c->wasted_size += jeb->free_size; |
660 | c->free_size -= jeb->free_size; |
661 | jeb->free_size = 0; |
662 | } |
663 | |
664 | return jffs2_scan_classify_jeb(c, jeb); |
665 | |
666 | crc_err: |
667 | JFFS2_WARNING("Summary node crc error, skipping summary information.\n" ); |
668 | |
669 | return 0; |
670 | } |
671 | |
672 | /* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */ |
673 | |
674 | static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
675 | uint32_t infosize, uint32_t datasize, int padsize) |
676 | { |
677 | struct jffs2_raw_summary isum; |
678 | union jffs2_sum_mem *temp; |
679 | struct jffs2_sum_marker *sm; |
680 | struct kvec vecs[2]; |
681 | uint32_t sum_ofs; |
682 | void *wpage; |
683 | int ret; |
684 | size_t retlen; |
685 | |
686 | if (padsize + datasize > MAX_SUMMARY_SIZE) { |
687 | /* It won't fit in the buffer. Abort summary for this jeb */ |
688 | jffs2_sum_disable_collecting(s: c->summary); |
689 | |
690 | JFFS2_WARNING("Summary too big (%d data, %d pad) in eraseblock at %08x\n" , |
691 | datasize, padsize, jeb->offset); |
692 | /* Non-fatal */ |
693 | return 0; |
694 | } |
695 | /* Is there enough space for summary? */ |
696 | if (padsize < 0) { |
697 | /* don't try to write out summary for this jeb */ |
698 | jffs2_sum_disable_collecting(s: c->summary); |
699 | |
700 | JFFS2_WARNING("Not enough space for summary, padsize = %d\n" , |
701 | padsize); |
702 | /* Non-fatal */ |
703 | return 0; |
704 | } |
705 | |
706 | memset(c->summary->sum_buf, 0xff, datasize); |
707 | memset(&isum, 0, sizeof(isum)); |
708 | |
709 | isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
710 | isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY); |
711 | isum.totlen = cpu_to_je32(infosize); |
712 | isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4)); |
713 | isum.padded = cpu_to_je32(c->summary->sum_padded); |
714 | isum.cln_mkr = cpu_to_je32(c->cleanmarker_size); |
715 | isum.sum_num = cpu_to_je32(c->summary->sum_num); |
716 | wpage = c->summary->sum_buf; |
717 | |
718 | while (c->summary->sum_num) { |
719 | temp = c->summary->sum_list_head; |
720 | |
721 | switch (je16_to_cpu(temp->u.nodetype)) { |
722 | case JFFS2_NODETYPE_INODE: { |
723 | struct jffs2_sum_inode_flash *sino_ptr = wpage; |
724 | |
725 | sino_ptr->nodetype = temp->i.nodetype; |
726 | sino_ptr->inode = temp->i.inode; |
727 | sino_ptr->version = temp->i.version; |
728 | sino_ptr->offset = temp->i.offset; |
729 | sino_ptr->totlen = temp->i.totlen; |
730 | |
731 | wpage += JFFS2_SUMMARY_INODE_SIZE; |
732 | |
733 | break; |
734 | } |
735 | |
736 | case JFFS2_NODETYPE_DIRENT: { |
737 | struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage; |
738 | |
739 | sdrnt_ptr->nodetype = temp->d.nodetype; |
740 | sdrnt_ptr->totlen = temp->d.totlen; |
741 | sdrnt_ptr->offset = temp->d.offset; |
742 | sdrnt_ptr->pino = temp->d.pino; |
743 | sdrnt_ptr->version = temp->d.version; |
744 | sdrnt_ptr->ino = temp->d.ino; |
745 | sdrnt_ptr->nsize = temp->d.nsize; |
746 | sdrnt_ptr->type = temp->d.type; |
747 | |
748 | memcpy(sdrnt_ptr->name, temp->d.name, |
749 | temp->d.nsize); |
750 | |
751 | wpage += JFFS2_SUMMARY_DIRENT_SIZE(temp->d.nsize); |
752 | |
753 | break; |
754 | } |
755 | #ifdef CONFIG_JFFS2_FS_XATTR |
756 | case JFFS2_NODETYPE_XATTR: { |
757 | struct jffs2_sum_xattr_flash *sxattr_ptr = wpage; |
758 | |
759 | temp = c->summary->sum_list_head; |
760 | sxattr_ptr->nodetype = temp->x.nodetype; |
761 | sxattr_ptr->xid = temp->x.xid; |
762 | sxattr_ptr->version = temp->x.version; |
763 | sxattr_ptr->offset = temp->x.offset; |
764 | sxattr_ptr->totlen = temp->x.totlen; |
765 | |
766 | wpage += JFFS2_SUMMARY_XATTR_SIZE; |
767 | break; |
768 | } |
769 | case JFFS2_NODETYPE_XREF: { |
770 | struct jffs2_sum_xref_flash *sxref_ptr = wpage; |
771 | |
772 | temp = c->summary->sum_list_head; |
773 | sxref_ptr->nodetype = temp->r.nodetype; |
774 | sxref_ptr->offset = temp->r.offset; |
775 | |
776 | wpage += JFFS2_SUMMARY_XREF_SIZE; |
777 | break; |
778 | } |
779 | #endif |
780 | default : { |
781 | if ((je16_to_cpu(temp->u.nodetype) & JFFS2_COMPAT_MASK) |
782 | == JFFS2_FEATURE_RWCOMPAT_COPY) { |
783 | dbg_summary("Writing unknown RWCOMPAT_COPY node type %x\n" , |
784 | je16_to_cpu(temp->u.nodetype)); |
785 | jffs2_sum_disable_collecting(s: c->summary); |
786 | /* The above call removes the list, nothing more to do */ |
787 | goto bail_rwcompat; |
788 | } else { |
789 | BUG(); /* unknown node in summary information */ |
790 | } |
791 | } |
792 | } |
793 | |
794 | c->summary->sum_list_head = temp->u.next; |
795 | kfree(objp: temp); |
796 | |
797 | c->summary->sum_num--; |
798 | } |
799 | bail_rwcompat: |
800 | |
801 | jffs2_sum_reset_collected(s: c->summary); |
802 | |
803 | wpage += padsize; |
804 | |
805 | sm = wpage; |
806 | sm->offset = cpu_to_je32(c->sector_size - jeb->free_size); |
807 | sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC); |
808 | |
809 | isum.sum_crc = cpu_to_je32(crc32(0, c->summary->sum_buf, datasize)); |
810 | isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8)); |
811 | |
812 | vecs[0].iov_base = &isum; |
813 | vecs[0].iov_len = sizeof(isum); |
814 | vecs[1].iov_base = c->summary->sum_buf; |
815 | vecs[1].iov_len = datasize; |
816 | |
817 | sum_ofs = jeb->offset + c->sector_size - jeb->free_size; |
818 | |
819 | dbg_summary("writing out data to flash to pos : 0x%08x\n" , sum_ofs); |
820 | |
821 | ret = jffs2_flash_writev(c, vecs, count: 2, to: sum_ofs, retlen: &retlen, ino: 0); |
822 | |
823 | if (ret || (retlen != infosize)) { |
824 | |
825 | JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n" , |
826 | infosize, sum_ofs, ret, retlen); |
827 | |
828 | if (retlen) { |
829 | /* Waste remaining space */ |
830 | spin_lock(lock: &c->erase_completion_lock); |
831 | jffs2_link_node_ref(c, jeb, ofs: sum_ofs | REF_OBSOLETE, len: infosize, NULL); |
832 | spin_unlock(lock: &c->erase_completion_lock); |
833 | } |
834 | |
835 | c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; |
836 | |
837 | return 0; |
838 | } |
839 | |
840 | spin_lock(lock: &c->erase_completion_lock); |
841 | jffs2_link_node_ref(c, jeb, ofs: sum_ofs | REF_NORMAL, len: infosize, NULL); |
842 | spin_unlock(lock: &c->erase_completion_lock); |
843 | |
844 | return 0; |
845 | } |
846 | |
847 | /* Write out summary information - called from jffs2_do_reserve_space */ |
848 | |
849 | int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) |
850 | __must_hold(&c->erase_completion_block) |
851 | { |
852 | int datasize, infosize, padsize; |
853 | struct jffs2_eraseblock *jeb; |
854 | int ret = 0; |
855 | |
856 | dbg_summary("called\n" ); |
857 | |
858 | spin_unlock(lock: &c->erase_completion_lock); |
859 | |
860 | jeb = c->nextblock; |
861 | jffs2_prealloc_raw_node_refs(c, jeb, nr: 1); |
862 | |
863 | if (!c->summary->sum_num || !c->summary->sum_list_head) { |
864 | JFFS2_WARNING("Empty summary info!!!\n" ); |
865 | BUG(); |
866 | } |
867 | |
868 | datasize = c->summary->sum_size + sizeof(struct jffs2_sum_marker); |
869 | infosize = sizeof(struct jffs2_raw_summary) + datasize; |
870 | padsize = jeb->free_size - infosize; |
871 | infosize += padsize; |
872 | datasize += padsize; |
873 | |
874 | ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize); |
875 | spin_lock(lock: &c->erase_completion_lock); |
876 | return ret; |
877 | } |
878 | |