aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2/summary.c
diff options
context:
space:
mode:
authorFerenc Havasi <havasi@inf.u-szeged.hu>2005-09-07 04:35:26 -0400
committerThomas Gleixner <tglx@mtd.linutronix.de>2005-11-06 15:29:48 -0500
commite631ddba588783edd521c5a89f7b2902772fb691 (patch)
treee25f322ee498b344f058ce4a40060baa22a5f105 /fs/jffs2/summary.c
parent15017876751e4c2d786ba95920618359fe2b4f0a (diff)
[JFFS2] Add erase block summary support (mount time improvement)
The goal of summary is to speed up the mount time. Erase block summary (EBS) stores summary information at the end of every (closed) erase block. It is no longer necessary to scan all nodes separetly (and read all pages of them) just read this "small" summary, where every information is stored which is needed at mount time. This summary information is stored in a JFFS2_FEATURE_RWCOMPAT_DELETE. During the mount process if there is no summary info the orignal scan process will be executed. EBS works with NAND and NOR flashes, too. There is a user space tool called sumtool to generate this summary information for a JFFS2 image. Signed-off-by: Ferenc Havasi <havasi@inf.u-szeged.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs/jffs2/summary.c')
-rw-r--r--fs/jffs2/summary.c729
1 files changed, 729 insertions, 0 deletions
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
new file mode 100644
index 00000000000..cb5dd8f11e7
--- /dev/null
+++ b/fs/jffs2/summary.c
@@ -0,0 +1,729 @@
1/*
2 * JFFS2 -- Journalling Flash File System, Version 2.
3 *
4 * Copyright (C) 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 *
9 * For licensing information, see the file 'LICENCE' in this directory.
10 *
11 * $Id: summary.c,v 1.1 2005/09/07 08:34:54 havasi Exp $
12 *
13 */
14
15#include <linux/kernel.h>
16#include <linux/sched.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
26int jffs2_sum_init(struct jffs2_sb_info *c)
27{
28 c->summary = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
29
30 if (!c->summary) {
31 JFFS2_WARNING("Can't allocate memory for summary information!\n");
32 return -ENOMEM;
33 }
34
35 memset(c->summary, 0, sizeof(struct jffs2_summary));
36
37 c->summary->sum_buf = vmalloc(c->sector_size);
38
39 if (!c->summary->sum_buf) {
40 JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n");
41 return -ENOMEM;
42 }
43
44 JFFS2_DBG_SUMMARY("returned succesfully\n");
45
46 return 0;
47}
48
49void jffs2_sum_exit(struct jffs2_sb_info *c)
50{
51 JFFS2_DBG_SUMMARY("called\n");
52
53 jffs2_sum_disable_collecting(c->summary);
54
55 vfree(c->summary->sum_buf);
56 c->summary->sum_buf = NULL;
57
58 kfree(c->summary);
59 c->summary = NULL;
60}
61
62static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item)
63{
64 if (!s->sum_list_head)
65 s->sum_list_head = (union jffs2_sum_mem *) item;
66 if (s->sum_list_tail)
67 s->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
68 s->sum_list_tail = (union jffs2_sum_mem *) item;
69
70 switch (je16_to_cpu(item->u.nodetype)) {
71 case JFFS2_NODETYPE_INODE:
72 s->sum_size += JFFS2_SUMMARY_INODE_SIZE;
73 s->sum_num++;
74 JFFS2_DBG_SUMMARY("inode (%u) added to summary\n",
75 je32_to_cpu(item->i.inode));
76 break;
77 case JFFS2_NODETYPE_DIRENT:
78 s->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
79 s->sum_num++;
80 JFFS2_DBG_SUMMARY("dirent (%u) added to summary\n",
81 je32_to_cpu(item->d.ino));
82 break;
83 default:
84 JFFS2_WARNING("UNKNOWN node type %u\n",
85 je16_to_cpu(item->u.nodetype));
86 return 1;
87 }
88 return 0;
89}
90
91
92/* The following 3 functions are called from scan.c to collect summary info for not closed jeb */
93
94int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size)
95{
96 JFFS2_DBG_SUMMARY("called with %u\n", size);
97 s->sum_padded += size;
98 return 0;
99}
100
101int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri,
102 uint32_t ofs)
103{
104 struct jffs2_sum_inode_mem *temp = kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
105
106 if (!temp)
107 return -ENOMEM;
108
109 temp->nodetype = ri->nodetype;
110 temp->inode = ri->ino;
111 temp->version = ri->version;
112 temp->offset = cpu_to_je32(ofs); /* relative offset from the begining of the jeb */
113 temp->totlen = ri->totlen;
114 temp->next = NULL;
115
116 return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
117}
118
119int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd,
120 uint32_t ofs)
121{
122 struct jffs2_sum_dirent_mem *temp =
123 kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL);
124
125 if (!temp)
126 return -ENOMEM;
127
128 temp->nodetype = rd->nodetype;
129 temp->totlen = rd->totlen;
130 temp->offset = cpu_to_je32(ofs); /* relative from the begining of the jeb */
131 temp->pino = rd->pino;
132 temp->version = rd->version;
133 temp->ino = rd->ino;
134 temp->nsize = rd->nsize;
135 temp->type = rd->type;
136 temp->next = NULL;
137
138 memcpy(temp->name, rd->name, rd->nsize);
139
140 return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
141}
142
143/* Cleanup every collected summary information */
144
145static void jffs2_sum_clean_collected(struct jffs2_summary *s)
146{
147 union jffs2_sum_mem *temp;
148
149 if (!s->sum_list_head) {
150 JFFS2_DBG_SUMMARY("already empty\n");
151 }
152 while (s->sum_list_head) {
153 temp = s->sum_list_head;
154 s->sum_list_head = s->sum_list_head->u.next;
155 kfree(temp);
156 }
157 s->sum_list_tail = NULL;
158 s->sum_padded = 0;
159 s->sum_num = 0;
160}
161
162void jffs2_sum_reset_collected(struct jffs2_summary *s)
163{
164 JFFS2_DBG_SUMMARY("called\n");
165 jffs2_sum_clean_collected(s);
166 s->sum_size = 0;
167}
168
169void jffs2_sum_disable_collecting(struct jffs2_summary *s)
170{
171 JFFS2_DBG_SUMMARY("called\n");
172 jffs2_sum_clean_collected(s);
173 s->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
174}
175
176int jffs2_sum_is_disabled(struct jffs2_summary *s)
177{
178 return (s->sum_size == JFFS2_SUMMARY_NOSUM_SIZE);
179}
180
181/* Move the collected summary information into sb (called from scan.c) */
182
183void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s)
184{
185 JFFS2_DBG_SUMMARY("oldsize=0x%x oldnum=%u => newsize=0x%x newnum=%u\n",
186 c->summary->sum_size, c->summary->sum_num,
187 s->sum_size, s->sum_num);
188
189 c->summary->sum_size = s->sum_size;
190 c->summary->sum_num = s->sum_num;
191 c->summary->sum_padded = s->sum_padded;
192 c->summary->sum_list_head = s->sum_list_head;
193 c->summary->sum_list_tail = s->sum_list_tail;
194
195 s->sum_list_head = s->sum_list_tail = NULL;
196}
197
198/* Called from wbuf.c to collect writed node info */
199
200int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
201 unsigned long count, uint32_t ofs)
202{
203 union jffs2_node_union *node;
204 struct jffs2_eraseblock *jeb;
205
206 node = invecs[0].iov_base;
207 jeb = &c->blocks[ofs / c->sector_size];
208 ofs -= jeb->offset;
209
210 switch (je16_to_cpu(node->u.nodetype)) {
211 case JFFS2_NODETYPE_INODE: {
212 struct jffs2_sum_inode_mem *temp =
213 kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
214
215 if (!temp)
216 goto no_mem;
217
218 temp->nodetype = node->i.nodetype;
219 temp->inode = node->i.ino;
220 temp->version = node->i.version;
221 temp->offset = cpu_to_je32(ofs);
222 temp->totlen = node->i.totlen;
223 temp->next = NULL;
224
225 return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
226 }
227
228 case JFFS2_NODETYPE_DIRENT: {
229 struct jffs2_sum_dirent_mem *temp =
230 kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL);
231
232 if (!temp)
233 goto no_mem;
234
235 temp->nodetype = node->d.nodetype;
236 temp->totlen = node->d.totlen;
237 temp->offset = cpu_to_je32(ofs);
238 temp->pino = node->d.pino;
239 temp->version = node->d.version;
240 temp->ino = node->d.ino;
241 temp->nsize = node->d.nsize;
242 temp->type = node->d.type;
243 temp->next = NULL;
244
245 switch (count) {
246 case 1:
247 memcpy(temp->name,node->d.name,node->d.nsize);
248 break;
249
250 case 2:
251 memcpy(temp->name,invecs[1].iov_base,node->d.nsize);
252 break;
253
254 default:
255 BUG(); /* impossible count value */
256 break;
257 }
258
259 return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
260 }
261
262 case JFFS2_NODETYPE_PADDING:
263 JFFS2_DBG_SUMMARY("node PADDING\n");
264 c->summary->sum_padded += je32_to_cpu(node->u.totlen);
265 break;
266
267 case JFFS2_NODETYPE_CLEANMARKER:
268 JFFS2_DBG_SUMMARY("node CLEANMARKER\n");
269 break;
270
271 case JFFS2_NODETYPE_SUMMARY:
272 JFFS2_DBG_SUMMARY("node SUMMARY\n");
273 break;
274
275 default:
276 /* If you implement a new node type you should also implement
277 summary support for it or disable summary.
278 */
279 BUG();
280 break;
281 }
282
283 return 0;
284
285no_mem:
286 JFFS2_WARNING("MEMORY ALLOCATION ERROR!");
287 return -ENOMEM;
288}
289
290
291/* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */
292
293static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
294 struct jffs2_summary_node *summary, uint32_t *pseudo_random)
295{
296 struct jffs2_raw_node_ref *raw;
297 struct jffs2_inode_cache *ic;
298 struct jffs2_full_dirent *fd;
299 void *sp;
300 int i, ino;
301
302 sp = summary->sum;
303
304 for (i=0; i<je32_to_cpu(summary->sum_num); i++) {
305 JFFS2_DBG_SUMMARY("processing summary index %d\n", i);
306
307 switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
308 case JFFS2_NODETYPE_INODE: {
309 struct jffs2_sum_inode_flash *spi;
310 spi = sp;
311
312 ino = je32_to_cpu(spi->inode);
313
314 JFFS2_DBG_SUMMARY("Inode at 0x%08x\n",
315 jeb->offset + je32_to_cpu(spi->offset));
316
317 raw = jffs2_alloc_raw_node_ref();
318 if (!raw) {
319 JFFS2_NOTICE("allocation of node reference failed\n");
320 kfree(summary);
321 return -ENOMEM;
322 }
323
324 ic = jffs2_scan_make_ino_cache(c, ino);
325 if (!ic) {
326 JFFS2_NOTICE("scan_make_ino_cache failed\n");
327 jffs2_free_raw_node_ref(raw);
328 kfree(summary);
329 return -ENOMEM;
330 }
331
332 raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED;
333 raw->__totlen = PAD(je32_to_cpu(spi->totlen));
334 raw->next_phys = NULL;
335 raw->next_in_ino = ic->nodes;
336
337 ic->nodes = raw;
338 if (!jeb->first_node)
339 jeb->first_node = raw;
340 if (jeb->last_node)
341 jeb->last_node->next_phys = raw;
342 jeb->last_node = raw;
343 *pseudo_random += je32_to_cpu(spi->version);
344
345 UNCHECKED_SPACE(PAD(je32_to_cpu(spi->totlen)));
346
347 sp += JFFS2_SUMMARY_INODE_SIZE;
348
349 break;
350 }
351
352 case JFFS2_NODETYPE_DIRENT: {
353 struct jffs2_sum_dirent_flash *spd;
354 spd = sp;
355
356 JFFS2_DBG_SUMMARY("Dirent at 0x%08x\n",
357 jeb->offset + je32_to_cpu(spd->offset));
358
359 fd = jffs2_alloc_full_dirent(spd->nsize+1);
360 if (!fd) {
361 kfree(summary);
362 return -ENOMEM;
363 }
364
365 memcpy(&fd->name, spd->name, spd->nsize);
366 fd->name[spd->nsize] = 0;
367
368 raw = jffs2_alloc_raw_node_ref();
369 if (!raw) {
370 jffs2_free_full_dirent(fd);
371 JFFS2_NOTICE("allocation of node reference failed\n");
372 kfree(summary);
373 return -ENOMEM;
374 }
375
376 ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
377 if (!ic) {
378 jffs2_free_full_dirent(fd);
379 jffs2_free_raw_node_ref(raw);
380 kfree(summary);
381 return -ENOMEM;
382 }
383
384 raw->__totlen = PAD(je32_to_cpu(spd->totlen));
385 raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE;
386 raw->next_phys = NULL;
387 raw->next_in_ino = ic->nodes;
388 ic->nodes = raw;
389 if (!jeb->first_node)
390 jeb->first_node = raw;
391 if (jeb->last_node)
392 jeb->last_node->next_phys = raw;
393 jeb->last_node = raw;
394
395 fd->raw = raw;
396 fd->next = NULL;
397 fd->version = je32_to_cpu(spd->version);
398 fd->ino = je32_to_cpu(spd->ino);
399 fd->nhash = full_name_hash(fd->name, spd->nsize);
400 fd->type = spd->type;
401 USED_SPACE(PAD(je32_to_cpu(spd->totlen)));
402 jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
403
404 *pseudo_random += je32_to_cpu(spd->version);
405
406 sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
407
408 break;
409 }
410
411 default : {
412 JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
413 kfree(summary);
414 return -EIO;
415 }
416 }
417 }
418
419 kfree(summary);
420 return 0;
421}
422
423/* Process the summary node - called from jffs2_scan_eraseblock() */
424
425int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
426 uint32_t ofs, uint32_t *pseudo_random)
427{
428 struct jffs2_unknown_node crcnode;
429 struct jffs2_raw_node_ref *cache_ref;
430 struct jffs2_summary_node *summary;
431 int ret, sumsize;
432 uint32_t crc;
433
434 sumsize = c->sector_size - ofs;
435 ofs += jeb->offset;
436
437 JFFS2_DBG_SUMMARY("summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
438 jeb->offset, ofs, sumsize);
439
440 summary = kmalloc(sumsize, GFP_KERNEL);
441
442 if (!summary) {
443 return -ENOMEM;
444 }
445
446 ret = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize);
447
448 if (ret) {
449 kfree(summary);
450 return ret;
451 }
452
453 /* OK, now check for node validity and CRC */
454 crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
455 crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
456 crcnode.totlen = summary->totlen;
457 crc = crc32(0, &crcnode, sizeof(crcnode)-4);
458
459 if (je32_to_cpu(summary->hdr_crc) != crc) {
460 JFFS2_DBG_SUMMARY("Summary node header is corrupt (bad CRC or "
461 "no summary at all)\n");
462 goto crc_err;
463 }
464
465 if (je32_to_cpu(summary->totlen) != sumsize) {
466 JFFS2_DBG_SUMMARY("Summary node is corrupt (wrong erasesize?)\n");
467 goto crc_err;
468 }
469
470 crc = crc32(0, summary, sizeof(struct jffs2_summary_node)-8);
471
472 if (je32_to_cpu(summary->node_crc) != crc) {
473 JFFS2_DBG_SUMMARY("Summary node is corrupt (bad CRC)\n");
474 goto crc_err;
475 }
476
477 crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_summary_node));
478
479 if (je32_to_cpu(summary->sum_crc) != crc) {
480 JFFS2_DBG_SUMMARY("Summary node data is corrupt (bad CRC)\n");
481 goto crc_err;
482 }
483
484 if ( je32_to_cpu(summary->cln_mkr) ) {
485
486 JFFS2_DBG_SUMMARY("Summary : CLEANMARKER node \n");
487
488 if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) {
489 JFFS2_DBG_SUMMARY("CLEANMARKER node has totlen 0x%x != normal 0x%x\n",
490 je32_to_cpu(summary->cln_mkr), c->cleanmarker_size);
491 UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
492 } else if (jeb->first_node) {
493 JFFS2_DBG_SUMMARY("CLEANMARKER node not first node in block "
494 "(0x%08x)\n", jeb->offset);
495 UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
496 } else {
497 struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
498
499 if (!marker_ref) {
500 JFFS2_NOTICE("Failed to allocate node ref for clean marker\n");
501 kfree(summary);
502 return -ENOMEM;
503 }
504
505 marker_ref->next_in_ino = NULL;
506 marker_ref->next_phys = NULL;
507 marker_ref->flash_offset = jeb->offset | REF_NORMAL;
508 marker_ref->__totlen = je32_to_cpu(summary->cln_mkr);
509 jeb->first_node = jeb->last_node = marker_ref;
510
511 USED_SPACE( PAD(je32_to_cpu(summary->cln_mkr)) );
512 }
513 }
514
515 if (je32_to_cpu(summary->padded)) {
516 DIRTY_SPACE(je32_to_cpu(summary->padded));
517 }
518
519 ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random);
520 if (ret)
521 return ret;
522
523 /* for PARANOIA_CHECK */
524 cache_ref = jffs2_alloc_raw_node_ref();
525
526 if (!cache_ref) {
527 JFFS2_NOTICE("Failed to allocate node ref for cache\n");
528 return -ENOMEM;
529 }
530
531 cache_ref->next_in_ino = NULL;
532 cache_ref->next_phys = NULL;
533 cache_ref->flash_offset = ofs | REF_NORMAL;
534 cache_ref->__totlen = sumsize;
535
536 if (!jeb->first_node)
537 jeb->first_node = cache_ref;
538 if (jeb->last_node)
539 jeb->last_node->next_phys = cache_ref;
540 jeb->last_node = cache_ref;
541
542 USED_SPACE(sumsize);
543
544 jeb->wasted_size += jeb->free_size;
545 c->wasted_size += jeb->free_size;
546 c->free_size -= jeb->free_size;
547 jeb->free_size = 0;
548
549 return jffs2_scan_classify_jeb(c, jeb);
550
551crc_err:
552 JFFS2_WARNING("Summary node crc error, skipping summary information.\n");
553
554 return 0;
555}
556
557/* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */
558
559static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
560 uint32_t infosize, uint32_t datasize, int padsize)
561{
562 struct jffs2_summary_node isum;
563 union jffs2_sum_mem *temp;
564 struct jffs2_sum_marker *sm;
565 struct kvec vecs[2];
566 void *wpage;
567 int ret;
568 size_t retlen;
569
570 memset(c->summary->sum_buf, 0xff, datasize);
571 memset(&isum, 0, sizeof(isum));
572
573 isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
574 isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
575 isum.totlen = cpu_to_je32(infosize);
576 isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
577 isum.padded = cpu_to_je32(c->summary->sum_padded);
578 isum.cln_mkr = cpu_to_je32(c->cleanmarker_size);
579 isum.sum_num = cpu_to_je32(c->summary->sum_num);
580 wpage = c->summary->sum_buf;
581
582 while (c->summary->sum_num) {
583
584 switch (je16_to_cpu(c->summary->sum_list_head->u.nodetype)) {
585 case JFFS2_NODETYPE_INODE: {
586 struct jffs2_sum_inode_flash *sino_ptr = wpage;
587
588 sino_ptr->nodetype = c->summary->sum_list_head->i.nodetype;
589 sino_ptr->inode = c->summary->sum_list_head->i.inode;
590 sino_ptr->version = c->summary->sum_list_head->i.version;
591 sino_ptr->offset = c->summary->sum_list_head->i.offset;
592 sino_ptr->totlen = c->summary->sum_list_head->i.totlen;
593
594 wpage += JFFS2_SUMMARY_INODE_SIZE;
595
596 break;
597 }
598
599 case JFFS2_NODETYPE_DIRENT: {
600 struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
601
602 sdrnt_ptr->nodetype = c->summary->sum_list_head->d.nodetype;
603 sdrnt_ptr->totlen = c->summary->sum_list_head->d.totlen;
604 sdrnt_ptr->offset = c->summary->sum_list_head->d.offset;
605 sdrnt_ptr->pino = c->summary->sum_list_head->d.pino;
606 sdrnt_ptr->version = c->summary->sum_list_head->d.version;
607 sdrnt_ptr->ino = c->summary->sum_list_head->d.ino;
608 sdrnt_ptr->nsize = c->summary->sum_list_head->d.nsize;
609 sdrnt_ptr->type = c->summary->sum_list_head->d.type;
610
611 memcpy(sdrnt_ptr->name, c->summary->sum_list_head->d.name,
612 c->summary->sum_list_head->d.nsize);
613
614 wpage += JFFS2_SUMMARY_DIRENT_SIZE(c->summary->sum_list_head->d.nsize);
615
616 break;
617 }
618
619 default : {
620 BUG(); /* unknown node in summary information */
621 }
622 }
623
624 temp = c->summary->sum_list_head;
625 c->summary->sum_list_head = c->summary->sum_list_head->u.next;
626 kfree(temp);
627
628 c->summary->sum_num--;
629 }
630
631 jffs2_sum_reset_collected(c->summary);
632
633 wpage += padsize;
634
635 sm = wpage;
636 sm->offset = cpu_to_je32(c->sector_size - jeb->free_size);
637 sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC);
638
639 isum.sum_crc = cpu_to_je32(crc32(0, c->summary->sum_buf, datasize));
640 isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8));
641
642 vecs[0].iov_base = &isum;
643 vecs[0].iov_len = sizeof(isum);
644 vecs[1].iov_base = c->summary->sum_buf;
645 vecs[1].iov_len = datasize;
646
647 JFFS2_DBG_SUMMARY("JFFS2: writing out data to flash to pos : 0x%08x\n",
648 jeb->offset + c->sector_size - jeb->free_size);
649
650 spin_unlock(&c->erase_completion_lock);
651 ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size -
652 jeb->free_size, &retlen, 0);
653 spin_lock(&c->erase_completion_lock);
654
655
656 if (ret || (retlen != infosize)) {
657 JFFS2_WARNING("Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
658 infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen);
659
660 c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
661 WASTED_SPACE(infosize);
662
663 return 1;
664 }
665
666 return 0;
667}
668
669/* Write out summary information - called from jffs2_do_reserve_space */
670
671int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
672{
673 struct jffs2_raw_node_ref *summary_ref;
674 int datasize, infosize, padsize, ret;
675 struct jffs2_eraseblock *jeb;
676
677 JFFS2_DBG_SUMMARY("called\n");
678
679 jeb = c->nextblock;
680
681 if (!c->summary->sum_num || !c->summary->sum_list_head) {
682 JFFS2_WARNING("Empty summary info!!!\n");
683 BUG();
684 }
685
686 datasize = c->summary->sum_size + sizeof(struct jffs2_sum_marker);
687 infosize = sizeof(struct jffs2_summary_node) + datasize;
688 padsize = jeb->free_size - infosize;
689 infosize += padsize;
690 datasize += padsize;
691
692 /* Is there enough space for summary? */
693 if (padsize < 0) {
694 /* don't try to write out summary for this jeb */
695 jffs2_sum_disable_collecting(c->summary);
696
697 JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize);
698 return 0;
699 }
700
701 ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize);
702 if (ret)
703 return 0; /* can't write out summary, block is marked as NOSUM_SIZE */
704
705 /* for ACCT_PARANOIA_CHECK */
706 spin_unlock(&c->erase_completion_lock);
707 summary_ref = jffs2_alloc_raw_node_ref();
708 spin_lock(&c->erase_completion_lock);
709
710 if (!summary_ref) {
711 JFFS2_NOTICE("Failed to allocate node ref for summary\n");
712 return -ENOMEM;
713 }
714
715 summary_ref->next_in_ino = NULL;
716 summary_ref->next_phys = NULL;
717 summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL;
718 summary_ref->__totlen = infosize;
719
720 if (!jeb->first_node)
721 jeb->first_node = summary_ref;
722 if (jeb->last_node)
723 jeb->last_node->next_phys = summary_ref;
724 jeb->last_node = summary_ref;
725
726 USED_SPACE(infosize);
727
728 return 0;
729}