Branch data Line data Source code
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 : 0 : int jffs2_sum_init(struct jffs2_sb_info *c)
27 : : {
28 : 0 : uint32_t sum_size = min_t(uint32_t, c->sector_size, MAX_SUMMARY_SIZE);
29 : :
30 : 0 : c->summary = kzalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
31 : :
32 [ # # ]: 0 : if (!c->summary) {
33 : 0 : JFFS2_WARNING("Can't allocate memory for summary information!\n");
34 : 0 : return -ENOMEM;
35 : : }
36 : :
37 : 0 : c->summary->sum_buf = kmalloc(sum_size, GFP_KERNEL);
38 : :
39 [ # # ]: 0 : if (!c->summary->sum_buf) {
40 : 0 : JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n");
41 : 0 : kfree(c->summary);
42 : 0 : return -ENOMEM;
43 : : }
44 : :
45 : : dbg_summary("returned successfully\n");
46 : :
47 : : return 0;
48 : : }
49 : :
50 : 0 : void jffs2_sum_exit(struct jffs2_sb_info *c)
51 : : {
52 : : dbg_summary("called\n");
53 : :
54 : 0 : jffs2_sum_disable_collecting(c->summary);
55 : :
56 : 0 : kfree(c->summary->sum_buf);
57 : 0 : c->summary->sum_buf = NULL;
58 : :
59 : 0 : kfree(c->summary);
60 : 0 : c->summary = NULL;
61 : 0 : }
62 : :
63 : 0 : static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item)
64 : : {
65 [ # # ]: 0 : if (!s->sum_list_head)
66 : 0 : s->sum_list_head = (union jffs2_sum_mem *) item;
67 [ # # ]: 0 : if (s->sum_list_tail)
68 : 0 : s->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
69 : 0 : s->sum_list_tail = (union jffs2_sum_mem *) item;
70 : :
71 [ # # # # : 0 : switch (je16_to_cpu(item->u.nodetype)) {
# ]
72 : : case JFFS2_NODETYPE_INODE:
73 : 0 : s->sum_size += JFFS2_SUMMARY_INODE_SIZE;
74 : 0 : s->sum_num++;
75 : : dbg_summary("inode (%u) added to summary\n",
76 : : je32_to_cpu(item->i.inode));
77 : 0 : break;
78 : : case JFFS2_NODETYPE_DIRENT:
79 : 0 : s->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
80 : 0 : s->sum_num++;
81 : : dbg_summary("dirent (%u) added to summary\n",
82 : : je32_to_cpu(item->d.ino));
83 : 0 : break;
84 : : #ifdef CONFIG_JFFS2_FS_XATTR
85 : : case JFFS2_NODETYPE_XATTR:
86 : 0 : s->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
87 : 0 : 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 : 0 : break;
91 : : case JFFS2_NODETYPE_XREF:
92 : 0 : s->sum_size += JFFS2_SUMMARY_XREF_SIZE;
93 : 0 : s->sum_num++;
94 : : dbg_summary("xref added to summary\n");
95 : 0 : break;
96 : : #endif
97 : : default:
98 : 0 : JFFS2_WARNING("UNKNOWN node type %u\n",
99 : : je16_to_cpu(item->u.nodetype));
100 : 0 : 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 : 0 : int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size)
109 : : {
110 : : dbg_summary("called with %u\n", size);
111 : 0 : s->sum_padded += size;
112 : 0 : return 0;
113 : : }
114 : :
115 : 0 : 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(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
119 : :
120 [ # # ]: 0 : if (!temp)
121 : : return -ENOMEM;
122 : :
123 : 0 : temp->nodetype = ri->nodetype;
124 : 0 : temp->inode = ri->ino;
125 : 0 : temp->version = ri->version;
126 : 0 : temp->offset = cpu_to_je32(ofs); /* relative offset from the beginning of the jeb */
127 : 0 : temp->totlen = ri->totlen;
128 : 0 : temp->next = NULL;
129 : :
130 : 0 : return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
131 : : }
132 : :
133 : 0 : 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 : 0 : kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL);
138 : :
139 [ # # ]: 0 : if (!temp)
140 : : return -ENOMEM;
141 : :
142 : 0 : temp->nodetype = rd->nodetype;
143 : 0 : temp->totlen = rd->totlen;
144 : 0 : temp->offset = cpu_to_je32(ofs); /* relative from the beginning of the jeb */
145 : 0 : temp->pino = rd->pino;
146 : 0 : temp->version = rd->version;
147 : 0 : temp->ino = rd->ino;
148 : 0 : temp->nsize = rd->nsize;
149 : 0 : temp->type = rd->type;
150 : 0 : temp->next = NULL;
151 : :
152 : 0 : memcpy(temp->name, rd->name, rd->nsize);
153 : :
154 : 0 : return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
155 : : }
156 : :
157 : : #ifdef CONFIG_JFFS2_FS_XATTR
158 : 0 : 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(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
163 [ # # ]: 0 : if (!temp)
164 : : return -ENOMEM;
165 : :
166 : 0 : temp->nodetype = rx->nodetype;
167 : 0 : temp->xid = rx->xid;
168 : 0 : temp->version = rx->version;
169 : 0 : temp->offset = cpu_to_je32(ofs);
170 : 0 : temp->totlen = rx->totlen;
171 : 0 : temp->next = NULL;
172 : :
173 : 0 : return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
174 : : }
175 : :
176 : 0 : 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(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
181 [ # # ]: 0 : if (!temp)
182 : : return -ENOMEM;
183 : :
184 : 0 : temp->nodetype = rr->nodetype;
185 : 0 : temp->offset = cpu_to_je32(ofs);
186 : 0 : temp->next = NULL;
187 : :
188 : 0 : return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
189 : : }
190 : : #endif
191 : : /* Cleanup every collected summary information */
192 : :
193 : 0 : 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 [ # # ]: 0 : while (s->sum_list_head) {
201 : : temp = s->sum_list_head;
202 : 0 : s->sum_list_head = s->sum_list_head->u.next;
203 : 0 : kfree(temp);
204 : : }
205 : 0 : s->sum_list_tail = NULL;
206 : 0 : s->sum_padded = 0;
207 : 0 : s->sum_num = 0;
208 : 0 : }
209 : :
210 : 0 : void jffs2_sum_reset_collected(struct jffs2_summary *s)
211 : : {
212 : : dbg_summary("called\n");
213 : 0 : jffs2_sum_clean_collected(s);
214 : 0 : s->sum_size = 0;
215 : 0 : }
216 : :
217 : 0 : void jffs2_sum_disable_collecting(struct jffs2_summary *s)
218 : : {
219 : : dbg_summary("called\n");
220 : 0 : jffs2_sum_clean_collected(s);
221 : 0 : s->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
222 : 0 : }
223 : :
224 : 0 : int jffs2_sum_is_disabled(struct jffs2_summary *s)
225 : : {
226 : 0 : return (s->sum_size == JFFS2_SUMMARY_NOSUM_SIZE);
227 : : }
228 : :
229 : : /* Move the collected summary information into sb (called from scan.c) */
230 : :
231 : 0 : 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 : 0 : c->summary->sum_size = s->sum_size;
238 : 0 : c->summary->sum_num = s->sum_num;
239 : 0 : c->summary->sum_padded = s->sum_padded;
240 : 0 : c->summary->sum_list_head = s->sum_list_head;
241 : 0 : c->summary->sum_list_tail = s->sum_list_tail;
242 : :
243 : 0 : s->sum_list_head = s->sum_list_tail = NULL;
244 : 0 : }
245 : :
246 : : /* Called from wbuf.c to collect writed node info */
247 : :
248 : 0 : 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 [ # # ]: 0 : 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 : 0 : node = invecs[0].iov_base;
260 : 0 : jeb = &c->blocks[ofs / c->sector_size];
261 : 0 : ofs -= jeb->offset;
262 : :
263 [ # # # # : 0 : switch (je16_to_cpu(node->u.nodetype)) {
# # # ]
264 : : case JFFS2_NODETYPE_INODE: {
265 : : struct jffs2_sum_inode_mem *temp =
266 : : kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
267 : :
268 [ # # ]: 0 : if (!temp)
269 : : goto no_mem;
270 : :
271 : 0 : temp->nodetype = node->i.nodetype;
272 : 0 : temp->inode = node->i.ino;
273 : 0 : temp->version = node->i.version;
274 : 0 : temp->offset = cpu_to_je32(ofs);
275 : 0 : temp->totlen = node->i.totlen;
276 : 0 : temp->next = NULL;
277 : :
278 : 0 : return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
279 : : }
280 : :
281 : : case JFFS2_NODETYPE_DIRENT: {
282 : : struct jffs2_sum_dirent_mem *temp =
283 : 0 : kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL);
284 : :
285 [ # # ]: 0 : if (!temp)
286 : : goto no_mem;
287 : :
288 : 0 : temp->nodetype = node->d.nodetype;
289 : 0 : temp->totlen = node->d.totlen;
290 : 0 : temp->offset = cpu_to_je32(ofs);
291 : 0 : temp->pino = node->d.pino;
292 : 0 : temp->version = node->d.version;
293 : 0 : temp->ino = node->d.ino;
294 : 0 : temp->nsize = node->d.nsize;
295 : 0 : temp->type = node->d.type;
296 : 0 : temp->next = NULL;
297 : :
298 [ # # # ]: 0 : switch (count) {
299 : : case 1:
300 : 0 : memcpy(temp->name,node->d.name,node->d.nsize);
301 : 0 : break;
302 : :
303 : : case 2:
304 : 0 : memcpy(temp->name,invecs[1].iov_base,node->d.nsize);
305 : 0 : break;
306 : :
307 : : default:
308 : 0 : BUG(); /* impossible count value */
309 : : break;
310 : : }
311 : :
312 : 0 : return jffs2_sum_add_mem(c->summary, (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(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL);
318 [ # # ]: 0 : if (!temp)
319 : : goto no_mem;
320 : :
321 : 0 : temp->nodetype = node->x.nodetype;
322 : 0 : temp->xid = node->x.xid;
323 : 0 : temp->version = node->x.version;
324 : 0 : temp->totlen = node->x.totlen;
325 : 0 : temp->offset = cpu_to_je32(ofs);
326 : 0 : temp->next = NULL;
327 : :
328 : 0 : return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
329 : : }
330 : : case JFFS2_NODETYPE_XREF: {
331 : : struct jffs2_sum_xref_mem *temp;
332 : : temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL);
333 [ # # ]: 0 : if (!temp)
334 : : goto no_mem;
335 : 0 : temp->nodetype = node->r.nodetype;
336 : 0 : temp->offset = cpu_to_je32(ofs);
337 : 0 : temp->next = NULL;
338 : :
339 : 0 : return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
340 : : }
341 : : #endif
342 : : case JFFS2_NODETYPE_PADDING:
343 : : dbg_summary("node PADDING\n");
344 : 0 : c->summary->sum_padded += je32_to_cpu(node->u.totlen);
345 : 0 : 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 : 0 : BUG();
360 : : break;
361 : : }
362 : :
363 : : return 0;
364 : :
365 : : no_mem:
366 : 0 : JFFS2_WARNING("MEMORY ALLOCATION ERROR!");
367 : 0 : return -ENOMEM;
368 : : }
369 : :
370 : 0 : 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 [ # # ]: 0 : if ((ofs & ~3) > c->sector_size - jeb->free_size) {
377 : : /* Ew. Summary doesn't actually tell us explicitly about dirty space */
378 : 0 : jffs2_scan_dirty_space(c, jeb, (ofs & ~3) - (c->sector_size - jeb->free_size));
379 : : }
380 : :
381 : 0 : return jffs2_link_node_ref(c, jeb, jeb->offset + ofs, len, ic);
382 : : }
383 : :
384 : : /* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */
385 : :
386 : 0 : 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 : 0 : sp = summary->sum;
396 : :
397 [ # # ]: 0 : for (i=0; i<je32_to_cpu(summary->sum_num); i++) {
398 : : dbg_summary("processing summary index %d\n", i);
399 : :
400 : 0 : cond_resched();
401 : :
402 : : /* Make sure there's a spare ref for dirty space */
403 : 0 : err = jffs2_prealloc_raw_node_refs(c, jeb, 2);
404 [ # # ]: 0 : if (err)
405 : : return err;
406 : :
407 [ # # # # : 0 : 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 : 0 : 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 : 0 : ic = jffs2_scan_make_ino_cache(c, ino);
419 [ # # ]: 0 : if (!ic) {
420 : 0 : JFFS2_NOTICE("scan_make_ino_cache failed\n");
421 : 0 : return -ENOMEM;
422 : : }
423 : :
424 : 0 : sum_link_node_ref(c, jeb, je32_to_cpu(spi->offset) | REF_UNCHECKED,
425 : 0 : PAD(je32_to_cpu(spi->totlen)), ic);
426 : :
427 : 0 : *pseudo_random += je32_to_cpu(spi->version);
428 : :
429 : 0 : sp += JFFS2_SUMMARY_INODE_SIZE;
430 : :
431 : 0 : 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 : 0 : checkedlen = strnlen(spd->name, spd->nsize);
446 [ # # ]: 0 : if (!checkedlen) {
447 : 0 : pr_err("Dirent at %08x has zero at start of name. Aborting mount.\n",
448 : : jeb->offset +
449 : : je32_to_cpu(spd->offset));
450 : 0 : return -EIO;
451 : : }
452 [ # # ]: 0 : if (checkedlen < spd->nsize) {
453 : 0 : 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 : 0 : fd = jffs2_alloc_full_dirent(checkedlen+1);
461 [ # # ]: 0 : if (!fd)
462 : : return -ENOMEM;
463 : :
464 : 0 : memcpy(&fd->name, spd->name, checkedlen);
465 : 0 : fd->name[checkedlen] = 0;
466 : :
467 : 0 : ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
468 [ # # ]: 0 : if (!ic) {
469 : 0 : jffs2_free_full_dirent(fd);
470 : 0 : return -ENOMEM;
471 : : }
472 : :
473 : 0 : fd->raw = sum_link_node_ref(c, jeb, je32_to_cpu(spd->offset) | REF_UNCHECKED,
474 : 0 : PAD(je32_to_cpu(spd->totlen)), ic);
475 : :
476 : 0 : fd->next = NULL;
477 : 0 : fd->version = je32_to_cpu(spd->version);
478 : 0 : fd->ino = je32_to_cpu(spd->ino);
479 : 0 : fd->nhash = full_name_hash(fd->name, checkedlen);
480 : 0 : fd->type = spd->type;
481 : :
482 : 0 : jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
483 : :
484 : 0 : *pseudo_random += je32_to_cpu(spd->version);
485 : :
486 : 0 : sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
487 : :
488 : 0 : 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 : 0 : xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid),
502 : : je32_to_cpu(spx->version));
503 [ # # ]: 0 : if (IS_ERR(xd))
504 : 0 : return PTR_ERR(xd);
505 [ # # ]: 0 : if (xd->version > je32_to_cpu(spx->version)) {
506 : : /* node is not the newest one */
507 : 0 : struct jffs2_raw_node_ref *raw
508 : 0 : = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
509 : 0 : PAD(je32_to_cpu(spx->totlen)), NULL);
510 : 0 : raw->next_in_ino = xd->node->next_in_ino;
511 : 0 : xd->node->next_in_ino = raw;
512 : : } else {
513 : 0 : xd->version = je32_to_cpu(spx->version);
514 : 0 : sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
515 : 0 : PAD(je32_to_cpu(spx->totlen)), (void *)xd);
516 : : }
517 : 0 : *pseudo_random += je32_to_cpu(spx->xid);
518 : 0 : sp += JFFS2_SUMMARY_XATTR_SIZE;
519 : :
520 : 0 : 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 : 0 : ref = jffs2_alloc_xattr_ref();
533 [ # # ]: 0 : if (!ref) {
534 : 0 : JFFS2_NOTICE("allocation of xattr_datum failed\n");
535 : 0 : return -ENOMEM;
536 : : }
537 : 0 : ref->next = c->xref_temp;
538 : 0 : c->xref_temp = ref;
539 : :
540 : 0 : sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED,
541 : : PAD(sizeof(struct jffs2_raw_xref)), (void *)ref);
542 : :
543 : 0 : *pseudo_random += ref->node->flash_offset;
544 : 0 : sp += JFFS2_SUMMARY_XREF_SIZE;
545 : :
546 : 0 : break;
547 : : }
548 : : #endif
549 : : default : {
550 : : uint16_t nodetype = je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype);
551 : 0 : JFFS2_WARNING("Unsupported node type %x found in summary! Exiting...\n", nodetype);
552 [ # # ]: 0 : 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 : 0 : c->wasted_size -= jeb->wasted_size;
557 : 0 : c->free_size += c->sector_size - jeb->free_size;
558 : 0 : c->used_size -= jeb->used_size;
559 : 0 : c->dirty_size -= jeb->dirty_size;
560 : 0 : jeb->wasted_size = jeb->used_size = jeb->dirty_size = 0;
561 : 0 : jeb->free_size = c->sector_size;
562 : :
563 : 0 : jffs2_free_jeb_node_refs(c, jeb);
564 : 0 : return -ENOTRECOVERABLE;
565 : : }
566 : : }
567 : : }
568 : : return 0;
569 : : }
570 : :
571 : : /* Process the summary node - called from jffs2_scan_eraseblock() */
572 : 0 : 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 : 0 : 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 : 0 : crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
587 : 0 : crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
588 : 0 : crcnode.totlen = summary->totlen;
589 : 0 : crc = crc32(0, &crcnode, sizeof(crcnode)-4);
590 : :
591 [ # # ]: 0 : 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 [ # # ]: 0 : if (je32_to_cpu(summary->totlen) != sumsize) {
598 : : dbg_summary("Summary node is corrupt (wrong erasesize?)\n");
599 : : goto crc_err;
600 : : }
601 : :
602 : 0 : crc = crc32(0, summary, sizeof(struct jffs2_raw_summary)-8);
603 : :
604 [ # # ]: 0 : 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 : 0 : crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_raw_summary));
610 : :
611 [ # # ]: 0 : 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 [ # # ]: 0 : if ( je32_to_cpu(summary->cln_mkr) ) {
617 : :
618 : : dbg_summary("Summary : CLEANMARKER node \n");
619 : :
620 : 0 : ret = jffs2_prealloc_raw_node_refs(c, jeb, 1);
621 [ # # ]: 0 : if (ret)
622 : : return ret;
623 : :
624 [ # # ]: 0 : 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 [ # # ]: 0 : if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
628 : : return ret;
629 [ # # ]: 0 : } else if (jeb->first_node) {
630 : : dbg_summary("CLEANMARKER node not first node in block "
631 : : "(0x%08x)\n", jeb->offset);
632 [ # # ]: 0 : if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
633 : : return ret;
634 : : } else {
635 : 0 : jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL,
636 : : je32_to_cpu(summary->cln_mkr), NULL);
637 : : }
638 : : }
639 : :
640 : 0 : 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 [ # # ]: 0 : if (ret == -ENOTRECOVERABLE)
644 : : return 0;
645 [ # # ]: 0 : if (ret)
646 : : return ret; /* real error */
647 : :
648 : : /* for PARANOIA_CHECK */
649 : 0 : ret = jffs2_prealloc_raw_node_refs(c, jeb, 2);
650 [ # # ]: 0 : if (ret)
651 : : return ret;
652 : :
653 : 0 : sum_link_node_ref(c, jeb, ofs | REF_NORMAL, sumsize, NULL);
654 : :
655 [ # # ]: 0 : if (unlikely(jeb->free_size)) {
656 : 0 : JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n",
657 : : jeb->free_size, jeb->offset);
658 : 0 : jeb->wasted_size += jeb->free_size;
659 : 0 : c->wasted_size += jeb->free_size;
660 : 0 : c->free_size -= jeb->free_size;
661 : 0 : jeb->free_size = 0;
662 : : }
663 : :
664 : 0 : return jffs2_scan_classify_jeb(c, jeb);
665 : :
666 : : crc_err:
667 : 0 : JFFS2_WARNING("Summary node crc error, skipping summary information.\n");
668 : :
669 : 0 : return 0;
670 : : }
671 : :
672 : : /* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */
673 : :
674 : 0 : 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 [ # # ]: 0 : if (padsize + datasize > MAX_SUMMARY_SIZE) {
687 : : /* It won't fit in the buffer. Abort summary for this jeb */
688 : 0 : jffs2_sum_disable_collecting(c->summary);
689 : :
690 : 0 : JFFS2_WARNING("Summary too big (%d data, %d pad) in eraseblock at %08x\n",
691 : : datasize, padsize, jeb->offset);
692 : : /* Non-fatal */
693 : 0 : return 0;
694 : : }
695 : : /* Is there enough space for summary? */
696 [ # # ]: 0 : if (padsize < 0) {
697 : : /* don't try to write out summary for this jeb */
698 : 0 : jffs2_sum_disable_collecting(c->summary);
699 : :
700 : 0 : JFFS2_WARNING("Not enough space for summary, padsize = %d\n",
701 : : padsize);
702 : : /* Non-fatal */
703 : 0 : return 0;
704 : : }
705 : :
706 [ # # ]: 0 : memset(c->summary->sum_buf, 0xff, datasize);
707 : 0 : memset(&isum, 0, sizeof(isum));
708 : :
709 : 0 : isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
710 : 0 : isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
711 : 0 : isum.totlen = cpu_to_je32(infosize);
712 : 0 : isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
713 : 0 : isum.padded = cpu_to_je32(c->summary->sum_padded);
714 : 0 : isum.cln_mkr = cpu_to_je32(c->cleanmarker_size);
715 : 0 : isum.sum_num = cpu_to_je32(c->summary->sum_num);
716 : 0 : wpage = c->summary->sum_buf;
717 : :
718 [ # # ]: 0 : while (c->summary->sum_num) {
719 : 0 : temp = c->summary->sum_list_head;
720 : :
721 [ # # # # : 0 : switch (je16_to_cpu(temp->u.nodetype)) {
# ]
722 : : case JFFS2_NODETYPE_INODE: {
723 : : struct jffs2_sum_inode_flash *sino_ptr = wpage;
724 : :
725 : 0 : sino_ptr->nodetype = temp->i.nodetype;
726 : 0 : sino_ptr->inode = temp->i.inode;
727 : 0 : sino_ptr->version = temp->i.version;
728 : 0 : sino_ptr->offset = temp->i.offset;
729 : 0 : sino_ptr->totlen = temp->i.totlen;
730 : :
731 : 0 : wpage += JFFS2_SUMMARY_INODE_SIZE;
732 : :
733 : 0 : break;
734 : : }
735 : :
736 : : case JFFS2_NODETYPE_DIRENT: {
737 : : struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
738 : :
739 : 0 : sdrnt_ptr->nodetype = temp->d.nodetype;
740 : 0 : sdrnt_ptr->totlen = temp->d.totlen;
741 : 0 : sdrnt_ptr->offset = temp->d.offset;
742 : 0 : sdrnt_ptr->pino = temp->d.pino;
743 : 0 : sdrnt_ptr->version = temp->d.version;
744 : 0 : sdrnt_ptr->ino = temp->d.ino;
745 : 0 : sdrnt_ptr->nsize = temp->d.nsize;
746 : 0 : sdrnt_ptr->type = temp->d.type;
747 : :
748 : 0 : memcpy(sdrnt_ptr->name, temp->d.name,
749 : 0 : temp->d.nsize);
750 : :
751 : 0 : wpage += JFFS2_SUMMARY_DIRENT_SIZE(temp->d.nsize);
752 : :
753 : 0 : 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 : 0 : sxattr_ptr->nodetype = temp->x.nodetype;
761 : 0 : sxattr_ptr->xid = temp->x.xid;
762 : 0 : sxattr_ptr->version = temp->x.version;
763 : 0 : sxattr_ptr->offset = temp->x.offset;
764 : 0 : sxattr_ptr->totlen = temp->x.totlen;
765 : :
766 : 0 : wpage += JFFS2_SUMMARY_XATTR_SIZE;
767 : 0 : 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 : 0 : sxref_ptr->nodetype = temp->r.nodetype;
774 : 0 : sxref_ptr->offset = temp->r.offset;
775 : :
776 : 0 : wpage += JFFS2_SUMMARY_XREF_SIZE;
777 : 0 : break;
778 : : }
779 : : #endif
780 : : default : {
781 [ # # ]: 0 : 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(c->summary);
786 : : } else {
787 : 0 : BUG(); /* unknown node in summary information */
788 : : }
789 : : }
790 : : }
791 : :
792 : 0 : c->summary->sum_list_head = temp->u.next;
793 : 0 : kfree(temp);
794 : :
795 : 0 : c->summary->sum_num--;
796 : : }
797 : :
798 : : jffs2_sum_reset_collected(c->summary);
799 : :
800 : 0 : wpage += padsize;
801 : :
802 : : sm = wpage;
803 : 0 : sm->offset = cpu_to_je32(c->sector_size - jeb->free_size);
804 : 0 : sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC);
805 : :
806 : 0 : isum.sum_crc = cpu_to_je32(crc32(0, c->summary->sum_buf, datasize));
807 : 0 : isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8));
808 : :
809 : 0 : vecs[0].iov_base = &isum;
810 : 0 : vecs[0].iov_len = sizeof(isum);
811 : 0 : vecs[1].iov_base = c->summary->sum_buf;
812 : 0 : vecs[1].iov_len = datasize;
813 : :
814 : 0 : sum_ofs = jeb->offset + c->sector_size - jeb->free_size;
815 : :
816 : : dbg_summary("writing out data to flash to pos : 0x%08x\n", sum_ofs);
817 : :
818 : 0 : ret = jffs2_flash_writev(c, vecs, 2, sum_ofs, &retlen, 0);
819 : :
820 [ # # ][ # # ]: 0 : if (ret || (retlen != infosize)) {
821 : :
822 : 0 : JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n",
823 : : infosize, sum_ofs, ret, retlen);
824 : :
825 [ # # ]: 0 : if (retlen) {
826 : : /* Waste remaining space */
827 : : spin_lock(&c->erase_completion_lock);
828 : 0 : jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL);
829 : : spin_unlock(&c->erase_completion_lock);
830 : : }
831 : :
832 : 0 : c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
833 : :
834 : 0 : return 0;
835 : : }
836 : :
837 : : spin_lock(&c->erase_completion_lock);
838 : 0 : jffs2_link_node_ref(c, jeb, sum_ofs | REF_NORMAL, infosize, NULL);
839 : : spin_unlock(&c->erase_completion_lock);
840 : :
841 : 0 : return 0;
842 : : }
843 : :
844 : : /* Write out summary information - called from jffs2_do_reserve_space */
845 : :
846 : 0 : int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
847 : : {
848 : : int datasize, infosize, padsize;
849 : : struct jffs2_eraseblock *jeb;
850 : : int ret = 0;
851 : :
852 : : dbg_summary("called\n");
853 : :
854 : : spin_unlock(&c->erase_completion_lock);
855 : :
856 : 0 : jeb = c->nextblock;
857 : 0 : jffs2_prealloc_raw_node_refs(c, jeb, 1);
858 : :
859 [ # # ][ # # ]: 0 : if (!c->summary->sum_num || !c->summary->sum_list_head) {
860 : 0 : JFFS2_WARNING("Empty summary info!!!\n");
861 : 0 : BUG();
862 : : }
863 : :
864 : 0 : datasize = c->summary->sum_size + sizeof(struct jffs2_sum_marker);
865 : 0 : infosize = sizeof(struct jffs2_raw_summary) + datasize;
866 : 0 : padsize = jeb->free_size - infosize;
867 : 0 : infosize += padsize;
868 : 0 : datasize += padsize;
869 : :
870 : 0 : ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize);
871 : : spin_lock(&c->erase_completion_lock);
872 : 0 : return ret;
873 : : }
|