aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/Kconfig13
-rw-r--r--fs/jffs2/Makefile3
-rw-r--r--fs/jffs2/build.c12
-rw-r--r--fs/jffs2/debug.h10
-rw-r--r--fs/jffs2/dir.c20
-rw-r--r--fs/jffs2/file.c5
-rw-r--r--fs/jffs2/fs.c5
-rw-r--r--fs/jffs2/gc.c26
-rw-r--r--fs/jffs2/nodelist.h13
-rw-r--r--fs/jffs2/nodemgmt.c250
-rw-r--r--fs/jffs2/os-linux.h19
-rw-r--r--fs/jffs2/scan.c198
-rw-r--r--fs/jffs2/summary.c729
-rw-r--r--fs/jffs2/summary.h183
-rw-r--r--fs/jffs2/super.c8
-rw-r--r--fs/jffs2/wbuf.c12
-rw-r--r--fs/jffs2/write.c29
-rw-r--r--fs/jffs2/writev.c34
-rw-r--r--include/linux/jffs2.h21
-rw-r--r--include/linux/jffs2_fs_sb.h4
20 files changed, 1395 insertions, 199 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index 01a295232f75..37d86c5072eb 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1050,6 +1050,19 @@ config JFFS2_FS_WRITEBUFFER
1050 - NOR flash with transparent ECC 1050 - NOR flash with transparent ECC
1051 - DataFlash 1051 - DataFlash
1052 1052
1053config JFFS2_SUMMARY
1054 bool "JFFS2 summary support (EXPERIMENTAL)"
1055 depends on JFFS2_FS && EXPERIMENTAL
1056 default n
1057 help
1058 This feature makes it possible to use summary information
1059 for faster filesystem mount.
1060
1061 The summary information can be inserted into a filesystem image
1062 by the utility 'sumtool'.
1063
1064 If unsure, say 'N'.
1065
1053config JFFS2_COMPRESSION_OPTIONS 1066config JFFS2_COMPRESSION_OPTIONS
1054 bool "Advanced compression options for JFFS2" 1067 bool "Advanced compression options for JFFS2"
1055 depends on JFFS2_FS 1068 depends on JFFS2_FS
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile
index e6230f1bba73..77dc5561a04e 100644
--- a/fs/jffs2/Makefile
+++ b/fs/jffs2/Makefile
@@ -1,7 +1,7 @@
1# 1#
2# Makefile for the Linux Journalling Flash File System v2 (JFFS2) 2# Makefile for the Linux Journalling Flash File System v2 (JFFS2)
3# 3#
4# $Id: Makefile.common,v 1.10 2005/07/17 06:56:20 dedekind Exp $ 4# $Id: Makefile.common,v 1.11 2005/09/07 08:34:53 havasi Exp $
5# 5#
6 6
7obj-$(CONFIG_JFFS2_FS) += jffs2.o 7obj-$(CONFIG_JFFS2_FS) += jffs2.o
@@ -15,3 +15,4 @@ jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o
15jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o 15jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
16jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o 16jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
17jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o 17jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
18jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 1522eace932e..f4a47a3b2a01 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: build.c,v 1.77 2005/08/31 13:51:00 havasi Exp $ 10 * $Id: build.c,v 1.78 2005/09/07 08:34:54 havasi Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -350,6 +350,10 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
350 INIT_LIST_HEAD(&c->bad_list); 350 INIT_LIST_HEAD(&c->bad_list);
351 INIT_LIST_HEAD(&c->bad_used_list); 351 INIT_LIST_HEAD(&c->bad_used_list);
352 c->highest_ino = 1; 352 c->highest_ino = 1;
353 c->summary = NULL;
354
355 if (jffs2_sum_init(c))
356 return -ENOMEM;
353 357
354 if (jffs2_build_filesystem(c)) { 358 if (jffs2_build_filesystem(c)) {
355 D1(printk(KERN_DEBUG "build_fs failed\n")); 359 D1(printk(KERN_DEBUG "build_fs failed\n"));
@@ -357,11 +361,11 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
357 jffs2_free_raw_node_refs(c); 361 jffs2_free_raw_node_refs(c);
358#ifndef __ECOS 362#ifndef __ECOS
359 if (jffs2_blocks_use_vmalloc(c)) 363 if (jffs2_blocks_use_vmalloc(c))
360 vfree(c->blocks); 364 vfree(c->blocks);
361 else 365 else
362#endif 366#endif
363 kfree(c->blocks); 367 kfree(c->blocks);
364 368
365 return -EIO; 369 return -EIO;
366 } 370 }
367 371
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h
index 03d9626ad1ce..60e5dbb3946a 100644
--- a/fs/jffs2/debug.h
+++ b/fs/jffs2/debug.h
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: debug.h,v 1.14 2005/08/17 13:48:59 dedekind Exp $ 10 * $Id: debug.h,v 1.15 2005/09/07 08:34:54 havasi Exp $
11 * 11 *
12 */ 12 */
13#ifndef _JFFS2_DEBUG_H_ 13#ifndef _JFFS2_DEBUG_H_
@@ -28,6 +28,7 @@
28#define JFFS2_DBG_DENTLIST_MESSAGES 28#define JFFS2_DBG_DENTLIST_MESSAGES
29#define JFFS2_DBG_NODEREF_MESSAGES 29#define JFFS2_DBG_NODEREF_MESSAGES
30#define JFFS2_DBG_INOCACHE_MESSAGES 30#define JFFS2_DBG_INOCACHE_MESSAGES
31#define JFFS2_DBG_SUMMARY_MESSAGES
31#endif 32#endif
32 33
33#if CONFIG_JFFS2_FS_DEBUG == 2 34#if CONFIG_JFFS2_FS_DEBUG == 2
@@ -137,6 +138,13 @@
137#define JFFS2_DBG_INOCACHE(fmt, ...) 138#define JFFS2_DBG_INOCACHE(fmt, ...)
138#endif 139#endif
139 140
141/* Summary debugging messages */
142#ifdef JFFS2_DBG_SUMMARY_MESSAGES
143#define JFFS2_DBG_SUMMARY(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
144#else
145#define JFFS2_DBG_SUMMARY(fmt, ...)
146#endif
147
140/* Watch the object allocations */ 148/* Watch the object allocations */
141#ifdef JFFS2_DBG_MEMALLOC_MESSAGES 149#ifdef JFFS2_DBG_MEMALLOC_MESSAGES
142#define JFFS2_DBG_MEMALLOC(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) 150#define JFFS2_DBG_MEMALLOC(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 0fd15aaf2458..19bea0f95ac1 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: dir.c,v 1.88 2005/08/17 13:46:22 dedekind Exp $ 10 * $Id: dir.c,v 1.89 2005/09/07 08:34:54 havasi Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -310,7 +310,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
310 * Just the node will do for now, though 310 * Just the node will do for now, though
311 */ 311 */
312 namelen = dentry->d_name.len; 312 namelen = dentry->d_name.len;
313 ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL); 313 ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen,
314 ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
314 315
315 if (ret) { 316 if (ret) {
316 jffs2_free_raw_inode(ri); 317 jffs2_free_raw_inode(ri);
@@ -370,7 +371,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
370 up(&f->sem); 371 up(&f->sem);
371 372
372 jffs2_complete_reservation(c); 373 jffs2_complete_reservation(c);
373 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); 374 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
375 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
374 if (ret) { 376 if (ret) {
375 /* Eep. */ 377 /* Eep. */
376 jffs2_clear_inode(inode); 378 jffs2_clear_inode(inode);
@@ -455,7 +457,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
455 * Just the node will do for now, though 457 * Just the node will do for now, though
456 */ 458 */
457 namelen = dentry->d_name.len; 459 namelen = dentry->d_name.len;
458 ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); 460 ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL,
461 JFFS2_SUMMARY_INODE_SIZE);
459 462
460 if (ret) { 463 if (ret) {
461 jffs2_free_raw_inode(ri); 464 jffs2_free_raw_inode(ri);
@@ -498,7 +501,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
498 up(&f->sem); 501 up(&f->sem);
499 502
500 jffs2_complete_reservation(c); 503 jffs2_complete_reservation(c);
501 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); 504 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
505 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
502 if (ret) { 506 if (ret) {
503 /* Eep. */ 507 /* Eep. */
504 jffs2_clear_inode(inode); 508 jffs2_clear_inode(inode);
@@ -607,7 +611,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
607 * Just the node will do for now, though 611 * Just the node will do for now, though
608 */ 612 */
609 namelen = dentry->d_name.len; 613 namelen = dentry->d_name.len;
610 ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen, ALLOC_NORMAL); 614 ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen,
615 ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
611 616
612 if (ret) { 617 if (ret) {
613 jffs2_free_raw_inode(ri); 618 jffs2_free_raw_inode(ri);
@@ -652,7 +657,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
652 up(&f->sem); 657 up(&f->sem);
653 658
654 jffs2_complete_reservation(c); 659 jffs2_complete_reservation(c);
655 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); 660 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
661 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
656 if (ret) { 662 if (ret) {
657 /* Eep. */ 663 /* Eep. */
658 jffs2_clear_inode(inode); 664 jffs2_clear_inode(inode);
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 8279bf0133ff..231404a74728 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: file.c,v 1.102 2005/07/06 12:13:09 dwmw2 Exp $ 10 * $Id: file.c,v 1.103 2005/09/07 08:34:54 havasi Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -134,7 +134,8 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg,
134 D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", 134 D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
135 (unsigned int)inode->i_size, pageofs)); 135 (unsigned int)inode->i_size, pageofs));
136 136
137 ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL); 137 ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len,
138 ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
138 if (ret) 139 if (ret)
139 return ret; 140 return ret;
140 141
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index c99451ae4b77..c15c30220475 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: fs.c,v 1.64 2005/09/01 08:42:31 havasi Exp $ 10 * $Id: fs.c,v 1.65 2005/09/07 08:34:54 havasi Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -74,7 +74,8 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
74 return -ENOMEM; 74 return -ENOMEM;
75 } 75 }
76 76
77 ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL); 77 ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen,
78 ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
78 if (ret) { 79 if (ret) {
79 jffs2_free_raw_inode(ri); 80 jffs2_free_raw_inode(ri);
80 if (S_ISLNK(inode->i_mode & S_IFMT)) 81 if (S_ISLNK(inode->i_mode & S_IFMT))
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index def97157ecbd..ee54cdc59e06 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: gc.c,v 1.153 2005/08/17 13:46:22 dedekind Exp $ 10 * $Id: gc.c,v 1.154 2005/09/07 08:34:54 havasi Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -513,8 +513,11 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
513 /* Ask for a small amount of space (or the totlen if smaller) because we 513 /* Ask for a small amount of space (or the totlen if smaller) because we
514 don't want to force wastage of the end of a block if splitting would 514 don't want to force wastage of the end of a block if splitting would
515 work. */ 515 work. */
516 ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, 516 ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) +
517 rawlen), &phys_ofs, &alloclen); 517 JFFS2_MIN_DATA_LEN, rawlen), &phys_ofs, &alloclen, rawlen);
518 /* this is not the exact summary size of it,
519 it is only an upper estimation */
520
518 if (ret) 521 if (ret)
519 return ret; 522 return ret;
520 523
@@ -622,7 +625,9 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
622 jffs2_dbg_acct_sanity_check(c,jeb); 625 jffs2_dbg_acct_sanity_check(c,jeb);
623 jffs2_dbg_acct_paranoia_check(c, jeb); 626 jffs2_dbg_acct_paranoia_check(c, jeb);
624 627
625 ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy); 628 ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy, rawlen);
629 /* this is not the exact summary size of it,
630 it is only an upper estimation */
626 631
627 if (!ret) { 632 if (!ret) {
628 D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs)); 633 D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));
@@ -701,7 +706,8 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
701 706
702 } 707 }
703 708
704 ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen); 709 ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen,
710 JFFS2_SUMMARY_INODE_SIZE);
705 if (ret) { 711 if (ret) {
706 printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n", 712 printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n",
707 sizeof(ri)+ mdatalen, ret); 713 sizeof(ri)+ mdatalen, ret);
@@ -781,7 +787,8 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er
781 rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8)); 787 rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8));
782 rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize)); 788 rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize));
783 789
784 ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen); 790 ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen,
791 JFFS2_SUMMARY_DIRENT_SIZE(rd.nsize));
785 if (ret) { 792 if (ret) {
786 printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n", 793 printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n",
787 sizeof(rd)+rd.nsize, ret); 794 sizeof(rd)+rd.nsize, ret);
@@ -994,7 +1001,8 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
994 ri.data_crc = cpu_to_je32(0); 1001 ri.data_crc = cpu_to_je32(0);
995 ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); 1002 ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
996 1003
997 ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen); 1004 ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen,
1005 JFFS2_SUMMARY_INODE_SIZE);
998 if (ret) { 1006 if (ret) {
999 printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n", 1007 printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n",
1000 sizeof(ri), ret); 1008 sizeof(ri), ret);
@@ -1219,7 +1227,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
1219 uint32_t cdatalen; 1227 uint32_t cdatalen;
1220 uint16_t comprtype = JFFS2_COMPR_NONE; 1228 uint16_t comprtype = JFFS2_COMPR_NONE;
1221 1229
1222 ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen); 1230 ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs,
1231 &alloclen, JFFS2_SUMMARY_INODE_SIZE);
1223 1232
1224 if (ret) { 1233 if (ret) {
1225 printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n", 1234 printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n",
@@ -1276,4 +1285,3 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
1276 jffs2_gc_release_page(c, pg_ptr, &pg); 1285 jffs2_gc_release_page(c, pg_ptr, &pg);
1277 return ret; 1286 return ret;
1278} 1287}
1279
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index 1533af8b3959..1222372cb290 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: nodelist.h,v 1.139 2005/08/31 13:51:00 havasi Exp $ 10 * $Id: nodelist.h,v 1.140 2005/09/07 08:34:54 havasi Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -20,6 +20,7 @@
20#include <linux/jffs2.h> 20#include <linux/jffs2.h>
21#include <linux/jffs2_fs_sb.h> 21#include <linux/jffs2_fs_sb.h>
22#include <linux/jffs2_fs_i.h> 22#include <linux/jffs2_fs_i.h>
23#include "summary.h"
23 24
24#ifdef __ECOS 25#ifdef __ECOS
25#include "os-ecos.h" 26#include "os-ecos.h"
@@ -326,8 +327,10 @@ int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode
326 327
327/* nodemgmt.c */ 328/* nodemgmt.c */
328int jffs2_thread_should_wake(struct jffs2_sb_info *c); 329int jffs2_thread_should_wake(struct jffs2_sb_info *c);
329int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio); 330int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
330int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); 331 uint32_t *len, int prio, uint32_t sumsize);
332int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
333 uint32_t *len, uint32_t sumsize);
331int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new); 334int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new);
332void jffs2_complete_reservation(struct jffs2_sb_info *c); 335void jffs2_complete_reservation(struct jffs2_sb_info *c);
333void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw); 336void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw);
@@ -386,6 +389,10 @@ char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
386/* scan.c */ 389/* scan.c */
387int jffs2_scan_medium(struct jffs2_sb_info *c); 390int jffs2_scan_medium(struct jffs2_sb_info *c);
388void jffs2_rotate_lists(struct jffs2_sb_info *c); 391void jffs2_rotate_lists(struct jffs2_sb_info *c);
392int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf,
393 uint32_t ofs, uint32_t len);
394struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino);
395int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
389 396
390/* build.c */ 397/* build.c */
391int jffs2_do_mount_fs(struct jffs2_sb_info *c); 398int jffs2_do_mount_fs(struct jffs2_sb_info *c);
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index fe7e70a4055b..208b2bdf01e5 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: nodemgmt.c,v 1.124 2005/07/20 15:32:28 dedekind Exp $ 10 * $Id: nodemgmt.c,v 1.125 2005/09/07 08:34:54 havasi Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -17,6 +17,7 @@
17#include <linux/compiler.h> 17#include <linux/compiler.h>
18#include <linux/sched.h> /* For cond_resched() */ 18#include <linux/sched.h> /* For cond_resched() */
19#include "nodelist.h" 19#include "nodelist.h"
20#include "debug.h"
20 21
21/** 22/**
22 * jffs2_reserve_space - request physical space to write nodes to flash 23 * jffs2_reserve_space - request physical space to write nodes to flash
@@ -38,9 +39,11 @@
38 * for the requested allocation. 39 * for the requested allocation.
39 */ 40 */
40 41
41static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); 42static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
43 uint32_t *ofs, uint32_t *len, uint32_t sumsize);
42 44
43int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio) 45int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
46 uint32_t *len, int prio, uint32_t sumsize)
44{ 47{
45 int ret = -EAGAIN; 48 int ret = -EAGAIN;
46 int blocksneeded = c->resv_blocks_write; 49 int blocksneeded = c->resv_blocks_write;
@@ -129,7 +132,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
129 spin_lock(&c->erase_completion_lock); 132 spin_lock(&c->erase_completion_lock);
130 } 133 }
131 134
132 ret = jffs2_do_reserve_space(c, minsize, ofs, len); 135 ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize);
133 if (ret) { 136 if (ret) {
134 D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret)); 137 D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret));
135 } 138 }
@@ -140,7 +143,8 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
140 return ret; 143 return ret;
141} 144}
142 145
143int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) 146int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
147 uint32_t *len, uint32_t sumsize)
144{ 148{
145 int ret = -EAGAIN; 149 int ret = -EAGAIN;
146 minsize = PAD(minsize); 150 minsize = PAD(minsize);
@@ -149,7 +153,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *
149 153
150 spin_lock(&c->erase_completion_lock); 154 spin_lock(&c->erase_completion_lock);
151 while(ret == -EAGAIN) { 155 while(ret == -EAGAIN) {
152 ret = jffs2_do_reserve_space(c, minsize, ofs, len); 156 ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize);
153 if (ret) { 157 if (ret) {
154 D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); 158 D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
155 } 159 }
@@ -158,105 +162,183 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *
158 return ret; 162 return ret;
159} 163}
160 164
161/* Called with alloc sem _and_ erase_completion_lock */ 165
162static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) 166/* Classify nextblock (clean, dirty of verydirty) and force to select an other one */
167
168static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
163{ 169{
164 struct jffs2_eraseblock *jeb = c->nextblock; 170
171 /* Check, if we have a dirty block now, or if it was dirty already */
172 if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
173 c->dirty_size += jeb->wasted_size;
174 c->wasted_size -= jeb->wasted_size;
175 jeb->dirty_size += jeb->wasted_size;
176 jeb->wasted_size = 0;
177 if (VERYDIRTY(c, jeb->dirty_size)) {
178 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
179 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
180 list_add_tail(&jeb->list, &c->very_dirty_list);
181 } else {
182 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
183 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
184 list_add_tail(&jeb->list, &c->dirty_list);
185 }
186 } else {
187 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
188 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
189 list_add_tail(&jeb->list, &c->clean_list);
190 }
191 c->nextblock = NULL;
192
193}
194
195/* Select a new jeb for nextblock */
196
197static int jffs2_find_nextblock(struct jffs2_sb_info *c)
198{
199 struct list_head *next;
165 200
166 restart: 201 /* Take the next block off the 'free' list */
167 if (jeb && minsize > jeb->free_size) { 202
168 /* Skip the end of this block and file it as having some dirty space */ 203 if (list_empty(&c->free_list)) {
169 /* If there's a pending write to it, flush now */ 204
170 if (jffs2_wbuf_dirty(c)) { 205 if (!c->nr_erasing_blocks &&
206 !list_empty(&c->erasable_list)) {
207 struct jffs2_eraseblock *ejeb;
208
209 ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
210 list_del(&ejeb->list);
211 list_add_tail(&ejeb->list, &c->erase_pending_list);
212 c->nr_erasing_blocks++;
213 jffs2_erase_pending_trigger(c);
214 D1(printk(KERN_DEBUG "jffs2_find_nextblock: Triggering erase of erasable block at 0x%08x\n",
215 ejeb->offset));
216 }
217
218 if (!c->nr_erasing_blocks &&
219 !list_empty(&c->erasable_pending_wbuf_list)) {
220 D1(printk(KERN_DEBUG "jffs2_find_nextblock: Flushing write buffer\n"));
221 /* c->nextblock is NULL, no update to c->nextblock allowed */
171 spin_unlock(&c->erase_completion_lock); 222 spin_unlock(&c->erase_completion_lock);
172 D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
173 jffs2_flush_wbuf_pad(c); 223 jffs2_flush_wbuf_pad(c);
174 spin_lock(&c->erase_completion_lock); 224 spin_lock(&c->erase_completion_lock);
175 jeb = c->nextblock; 225 /* Have another go. It'll be on the erasable_list now */
176 goto restart; 226 return -EAGAIN;
177 } 227 }
178 c->wasted_size += jeb->free_size; 228
179 c->free_size -= jeb->free_size; 229 if (!c->nr_erasing_blocks) {
180 jeb->wasted_size += jeb->free_size; 230 /* Ouch. We're in GC, or we wouldn't have got here.
181 jeb->free_size = 0; 231 And there's no space left. At all. */
182 232 printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n",
183 /* Check, if we have a dirty block now, or if it was dirty already */ 233 c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no",
184 if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { 234 list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
185 c->dirty_size += jeb->wasted_size; 235 return -ENOSPC;
186 c->wasted_size -= jeb->wasted_size;
187 jeb->dirty_size += jeb->wasted_size;
188 jeb->wasted_size = 0;
189 if (VERYDIRTY(c, jeb->dirty_size)) {
190 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
191 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
192 list_add_tail(&jeb->list, &c->very_dirty_list);
193 } else {
194 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
195 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
196 list_add_tail(&jeb->list, &c->dirty_list);
197 }
198 } else {
199 D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
200 jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
201 list_add_tail(&jeb->list, &c->clean_list);
202 } 236 }
203 c->nextblock = jeb = NULL; 237
238 spin_unlock(&c->erase_completion_lock);
239 /* Don't wait for it; just erase one right now */
240 jffs2_erase_pending_blocks(c, 1);
241 spin_lock(&c->erase_completion_lock);
242
243 /* An erase may have failed, decreasing the
244 amount of free space available. So we must
245 restart from the beginning */
246 return -EAGAIN;
204 } 247 }
248
249 next = c->free_list.next;
250 list_del(next);
251 c->nextblock = list_entry(next, struct jffs2_eraseblock, list);
252 c->nr_free_blocks--;
205 253
206 if (!jeb) { 254 jffs2_sum_reset_collected(c->summary); /* reset collected summary */
207 struct list_head *next;
208 /* Take the next block off the 'free' list */
209 255
210 if (list_empty(&c->free_list)) { 256 D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset));
211 257
212 if (!c->nr_erasing_blocks && 258 return 0;
213 !list_empty(&c->erasable_list)) { 259}
214 struct jffs2_eraseblock *ejeb;
215 260
216 ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list); 261/* Called with alloc sem _and_ erase_completion_lock */
217 list_del(&ejeb->list); 262static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, uint32_t sumsize)
218 list_add_tail(&ejeb->list, &c->erase_pending_list); 263{
219 c->nr_erasing_blocks++; 264 struct jffs2_eraseblock *jeb = c->nextblock;
220 jffs2_erase_pending_trigger(c); 265 uint32_t reserved_size; /* for summary information at the end of the jeb */
221 D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n", 266 int ret;
222 ejeb->offset)); 267
268 restart:
269 reserved_size = 0;
270
271 if (jffs2_sum_active() && (sumsize != JFFS2_SUMMARY_NOSUM_SIZE)) {
272 /* NOSUM_SIZE means not to generate summary */
273
274 if (jeb) {
275 reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE);
276 JFFS2_DBG_SUMMARY("minsize=%d , jeb->free=%d ,"
277 "summary->size=%d , sumsize=%d\n",
278 minsize, jeb->free_size,
279 c->summary->sum_size, sumsize);
280 }
281
282 /* Is there enough space for writing out the current node, or we have to
283 write out summary information now, close this jeb and select new nextblock? */
284 if (jeb && (PAD(minsize) + PAD(c->summary->sum_size + sumsize +
285 JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size)) {
286
287 /* Has summary been disabled for this jeb? */
288 if (jffs2_sum_is_disabled(c->summary)) {
289 sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
290 goto restart;
223 } 291 }
224 292
225 if (!c->nr_erasing_blocks && 293 /* Writing out the collected summary information */
226 !list_empty(&c->erasable_pending_wbuf_list)) { 294 JFFS2_DBG_SUMMARY("generating summary for 0x%08x.\n", jeb->offset);
227 D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); 295 ret = jffs2_sum_write_sumnode(c);
228 /* c->nextblock is NULL, no update to c->nextblock allowed */ 296
297 if (ret)
298 return ret;
299
300 if (jffs2_sum_is_disabled(c->summary)) {
301 /* jffs2_write_sumnode() couldn't write out the summary information
302 diabling summary for this jeb and free the collected information
303 */
304 sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
305 goto restart;
306 }
307
308 jffs2_close_nextblock(c, jeb);
309 jeb = NULL;
310 }
311 } else {
312 if (jeb && minsize > jeb->free_size) {
313 /* Skip the end of this block and file it as having some dirty space */
314 /* If there's a pending write to it, flush now */
315
316 if (jffs2_wbuf_dirty(c)) {
229 spin_unlock(&c->erase_completion_lock); 317 spin_unlock(&c->erase_completion_lock);
318 D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
230 jffs2_flush_wbuf_pad(c); 319 jffs2_flush_wbuf_pad(c);
231 spin_lock(&c->erase_completion_lock); 320 spin_lock(&c->erase_completion_lock);
232 /* Have another go. It'll be on the erasable_list now */ 321 jeb = c->nextblock;
233 return -EAGAIN; 322 goto restart;
234 }
235
236 if (!c->nr_erasing_blocks) {
237 /* Ouch. We're in GC, or we wouldn't have got here.
238 And there's no space left. At all. */
239 printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n",
240 c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no",
241 list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
242 return -ENOSPC;
243 } 323 }
244 324
245 spin_unlock(&c->erase_completion_lock); 325 c->wasted_size += jeb->free_size;
246 /* Don't wait for it; just erase one right now */ 326 c->free_size -= jeb->free_size;
247 jffs2_erase_pending_blocks(c, 1); 327 jeb->wasted_size += jeb->free_size;
248 spin_lock(&c->erase_completion_lock); 328 jeb->free_size = 0;
249 329
250 /* An erase may have failed, decreasing the 330 jffs2_close_nextblock(c, jeb);
251 amount of free space available. So we must 331 jeb = NULL;
252 restart from the beginning */
253 return -EAGAIN;
254 } 332 }
333 }
334
335 if (!jeb) {
336
337 ret = jffs2_find_nextblock(c);
338 if (ret)
339 return ret;
255 340
256 next = c->free_list.next; 341 jeb = c->nextblock;
257 list_del(next);
258 c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list);
259 c->nr_free_blocks--;
260 342
261 if (jeb->free_size != c->sector_size - c->cleanmarker_size) { 343 if (jeb->free_size != c->sector_size - c->cleanmarker_size) {
262 printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size); 344 printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
@@ -266,7 +348,7 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
266 /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has 348 /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has
267 enough space */ 349 enough space */
268 *ofs = jeb->offset + (c->sector_size - jeb->free_size); 350 *ofs = jeb->offset + (c->sector_size - jeb->free_size);
269 *len = jeb->free_size; 351 *len = jeb->free_size - reserved_size;
270 352
271 if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && 353 if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
272 !jeb->first_node->next_in_ino) { 354 !jeb->first_node->next_in_ino) {
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index c3c1619fb137..e026888cf1cb 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: os-linux.h,v 1.60 2005/08/06 04:51:30 nico Exp $ 10 * $Id: os-linux.h,v 1.61 2005/09/07 08:34:54 havasi Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -67,12 +67,18 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
67 67
68#ifndef CONFIG_JFFS2_FS_WRITEBUFFER 68#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
69#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) 69#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
70
71#ifdef CONFIG_JFFS2_SUMMARY
72#define jffs2_can_mark_obsolete(c) (0)
73#else
70#define jffs2_can_mark_obsolete(c) (1) 74#define jffs2_can_mark_obsolete(c) (1)
75#endif
76
71#define jffs2_is_writebuffered(c) (0) 77#define jffs2_is_writebuffered(c) (0)
72#define jffs2_cleanmarker_oob(c) (0) 78#define jffs2_cleanmarker_oob(c) (0)
73#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) 79#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
74 80
75#define jffs2_flash_write(c, ofs, len, retlen, buf) ((c)->mtd->write((c)->mtd, ofs, len, retlen, buf)) 81#define jffs2_flash_write(c, ofs, len, retlen, buf) jffs2_flash_direct_write(c, ofs, len, retlen, buf)
76#define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf)) 82#define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
77#define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; }) 83#define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; })
78#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; }) 84#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; })
@@ -97,9 +103,15 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
97 103
98#define jffs2_is_writebuffered(c) (c->wbuf != NULL) 104#define jffs2_is_writebuffered(c) (c->wbuf != NULL)
99#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) 105#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size )
106
107#ifdef CONFIG_JFFS2_SUMMARY
108#define jffs2_can_mark_obsolete(c) (0)
109#else
100#define jffs2_can_mark_obsolete(c) \ 110#define jffs2_can_mark_obsolete(c) \
101 ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & (MTD_ECC|MTD_PROGRAM_REGIONS))) || \ 111 ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & (MTD_ECC|MTD_PROGRAM_REGIONS))) || \
102 c->mtd->type == MTD_RAM) 112 c->mtd->type == MTD_RAM)
113#endif
114
103#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) 115#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
104 116
105#define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf)) 117#define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
@@ -192,7 +204,8 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c);
192/* writev.c */ 204/* writev.c */
193int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, 205int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
194 unsigned long count, loff_t to, size_t *retlen); 206 unsigned long count, loff_t to, size_t *retlen);
195 207int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
208 size_t *retlen, const u_char *buf);
196 209
197#endif /* __JFFS2_OS_LINUX_H__ */ 210#endif /* __JFFS2_OS_LINUX_H__ */
198 211
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index fcd6314cf179..4e60ba8da197 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: scan.c,v 1.121 2005/07/20 15:32:28 dedekind Exp $ 10 * $Id: scan.c,v 1.122 2005/09/07 08:34:54 havasi Exp $
11 * 11 *
12 */ 12 */
13#include <linux/kernel.h> 13#include <linux/kernel.h>
@@ -18,22 +18,11 @@
18#include <linux/crc32.h> 18#include <linux/crc32.h>
19#include <linux/compiler.h> 19#include <linux/compiler.h>
20#include "nodelist.h" 20#include "nodelist.h"
21#include "summary.h"
22#include "debug.h"
21 23
22#define DEFAULT_EMPTY_SCAN_SIZE 1024 24#define DEFAULT_EMPTY_SCAN_SIZE 1024
23 25
24#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
25 c->free_size -= _x; c->dirty_size += _x; \
26 jeb->free_size -= _x ; jeb->dirty_size += _x; \
27 }while(0)
28#define USED_SPACE(x) do { typeof(x) _x = (x); \
29 c->free_size -= _x; c->used_size += _x; \
30 jeb->free_size -= _x ; jeb->used_size += _x; \
31 }while(0)
32#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
33 c->free_size -= _x; c->unchecked_size += _x; \
34 jeb->free_size -= _x ; jeb->unchecked_size += _x; \
35 }while(0)
36
37#define noisy_printk(noise, args...) do { \ 26#define noisy_printk(noise, args...) do { \
38 if (*(noise)) { \ 27 if (*(noise)) { \
39 printk(KERN_NOTICE args); \ 28 printk(KERN_NOTICE args); \
@@ -47,23 +36,16 @@
47static uint32_t pseudo_random; 36static uint32_t pseudo_random;
48 37
49static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 38static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
50 unsigned char *buf, uint32_t buf_size); 39 unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s);
51 40
52/* These helper functions _must_ increase ofs and also do the dirty/used space accounting. 41/* These helper functions _must_ increase ofs and also do the dirty/used space accounting.
53 * Returning an error will abort the mount - bad checksums etc. should just mark the space 42 * Returning an error will abort the mount - bad checksums etc. should just mark the space
54 * as dirty. 43 * as dirty.
55 */ 44 */
56static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 45static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
57 struct jffs2_raw_inode *ri, uint32_t ofs); 46 struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s);
58static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 47static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
59 struct jffs2_raw_dirent *rd, uint32_t ofs); 48 struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s);
60
61#define BLK_STATE_ALLFF 0
62#define BLK_STATE_CLEAN 1
63#define BLK_STATE_PARTDIRTY 2
64#define BLK_STATE_CLEANMARKER 3
65#define BLK_STATE_ALLDIRTY 4
66#define BLK_STATE_BADBLOCK 5
67 49
68static inline int min_free(struct jffs2_sb_info *c) 50static inline int min_free(struct jffs2_sb_info *c)
69{ 51{
@@ -89,6 +71,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
89 uint32_t empty_blocks = 0, bad_blocks = 0; 71 uint32_t empty_blocks = 0, bad_blocks = 0;
90 unsigned char *flashbuf = NULL; 72 unsigned char *flashbuf = NULL;
91 uint32_t buf_size = 0; 73 uint32_t buf_size = 0;
74 struct jffs2_summary *s = NULL; /* summary info collected by the scan process */
92#ifndef __ECOS 75#ifndef __ECOS
93 size_t pointlen; 76 size_t pointlen;
94 77
@@ -122,10 +105,23 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
122 return -ENOMEM; 105 return -ENOMEM;
123 } 106 }
124 107
108 if (jffs2_sum_active()) {
109 s = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
110 if (!s) {
111 JFFS2_WARNING("Can't allocate memory for summary\n");
112 return -ENOMEM;
113 }
114 memset(s, 0, sizeof(struct jffs2_summary));
115 }
116
125 for (i=0; i<c->nr_blocks; i++) { 117 for (i=0; i<c->nr_blocks; i++) {
126 struct jffs2_eraseblock *jeb = &c->blocks[i]; 118 struct jffs2_eraseblock *jeb = &c->blocks[i];
127 119
128 ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size); 120 /* reset summary info for next eraseblock scan */
121 jffs2_sum_reset_collected(s);
122
123 ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
124 buf_size, s);
129 125
130 if (ret < 0) 126 if (ret < 0)
131 goto out; 127 goto out;
@@ -162,18 +158,18 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
162 break; 158 break;
163 159
164 case BLK_STATE_CLEAN: 160 case BLK_STATE_CLEAN:
165 /* Full (or almost full) of clean data. Clean list */ 161 /* Full (or almost full) of clean data. Clean list */
166 list_add(&jeb->list, &c->clean_list); 162 list_add(&jeb->list, &c->clean_list);
167 break; 163 break;
168 164
169 case BLK_STATE_PARTDIRTY: 165 case BLK_STATE_PARTDIRTY:
170 /* Some data, but not full. Dirty list. */ 166 /* Some data, but not full. Dirty list. */
171 /* We want to remember the block with most free space 167 /* We want to remember the block with most free space
172 and stick it in the 'nextblock' position to start writing to it. */ 168 and stick it in the 'nextblock' position to start writing to it. */
173 if (jeb->free_size > min_free(c) && 169 if (jeb->free_size > min_free(c) &&
174 (!c->nextblock || c->nextblock->free_size < jeb->free_size)) { 170 (!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
175 /* Better candidate for the next writes to go to */ 171 /* Better candidate for the next writes to go to */
176 if (c->nextblock) { 172 if (c->nextblock) {
177 c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; 173 c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
178 c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; 174 c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
179 c->free_size -= c->nextblock->free_size; 175 c->free_size -= c->nextblock->free_size;
@@ -184,9 +180,14 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
184 } else { 180 } else {
185 list_add(&c->nextblock->list, &c->dirty_list); 181 list_add(&c->nextblock->list, &c->dirty_list);
186 } 182 }
183 /* deleting summary information of the old nextblock */
184 jffs2_sum_reset_collected(c->summary);
187 } 185 }
188 c->nextblock = jeb; 186 /* update collected summary infromation for the current nextblock */
189 } else { 187 jffs2_sum_move_collected(c, s);
188 D1(printk(KERN_DEBUG "jffs2_scan_medium(): new nextblock = 0x%08x\n", jeb->offset));
189 c->nextblock = jeb;
190 } else {
190 jeb->dirty_size += jeb->free_size + jeb->wasted_size; 191 jeb->dirty_size += jeb->free_size + jeb->wasted_size;
191 c->dirty_size += jeb->free_size + jeb->wasted_size; 192 c->dirty_size += jeb->free_size + jeb->wasted_size;
192 c->free_size -= jeb->free_size; 193 c->free_size -= jeb->free_size;
@@ -197,30 +198,33 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
197 } else { 198 } else {
198 list_add(&jeb->list, &c->dirty_list); 199 list_add(&jeb->list, &c->dirty_list);
199 } 200 }
200 } 201 }
201 break; 202 break;
202 203
203 case BLK_STATE_ALLDIRTY: 204 case BLK_STATE_ALLDIRTY:
204 /* Nothing valid - not even a clean marker. Needs erasing. */ 205 /* Nothing valid - not even a clean marker. Needs erasing. */
205 /* For now we just put it on the erasing list. We'll start the erases later */ 206 /* For now we just put it on the erasing list. We'll start the erases later */
206 D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset)); 207 D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset));
207 list_add(&jeb->list, &c->erase_pending_list); 208 list_add(&jeb->list, &c->erase_pending_list);
208 c->nr_erasing_blocks++; 209 c->nr_erasing_blocks++;
209 break; 210 break;
210 211
211 case BLK_STATE_BADBLOCK: 212 case BLK_STATE_BADBLOCK:
212 D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset)); 213 D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset));
213 list_add(&jeb->list, &c->bad_list); 214 list_add(&jeb->list, &c->bad_list);
214 c->bad_size += c->sector_size; 215 c->bad_size += c->sector_size;
215 c->free_size -= c->sector_size; 216 c->free_size -= c->sector_size;
216 bad_blocks++; 217 bad_blocks++;
217 break; 218 break;
218 default: 219 default:
219 printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n"); 220 printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n");
220 BUG(); 221 BUG();
221 } 222 }
222 } 223 }
223 224
225 if (jffs2_sum_active() && s)
226 kfree(s);
227
224 /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */ 228 /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */
225 if (c->nextblock && (c->nextblock->dirty_size)) { 229 if (c->nextblock && (c->nextblock->dirty_size)) {
226 c->nextblock->wasted_size += c->nextblock->dirty_size; 230 c->nextblock->wasted_size += c->nextblock->dirty_size;
@@ -265,7 +269,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
265 return ret; 269 return ret;
266} 270}
267 271
268static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf, 272int jffs2_fill_scan_buf (struct jffs2_sb_info *c, void *buf,
269 uint32_t ofs, uint32_t len) 273 uint32_t ofs, uint32_t len)
270{ 274{
271 int ret; 275 int ret;
@@ -286,14 +290,36 @@ static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf,
286 return 0; 290 return 0;
287} 291}
288 292
293int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
294{
295 if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size
296 && (!jeb->first_node || !jeb->first_node->next_phys) )
297 return BLK_STATE_CLEANMARKER;
298
299 /* move blocks with max 4 byte dirty space to cleanlist */
300 else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
301 c->dirty_size -= jeb->dirty_size;
302 c->wasted_size += jeb->dirty_size;
303 jeb->wasted_size += jeb->dirty_size;
304 jeb->dirty_size = 0;
305 return BLK_STATE_CLEAN;
306 } else if (jeb->used_size || jeb->unchecked_size)
307 return BLK_STATE_PARTDIRTY;
308 else
309 return BLK_STATE_ALLDIRTY;
310}
311
289static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 312static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
290 unsigned char *buf, uint32_t buf_size) { 313 unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
291 struct jffs2_unknown_node *node; 314 struct jffs2_unknown_node *node;
292 struct jffs2_unknown_node crcnode; 315 struct jffs2_unknown_node crcnode;
316 struct jffs2_sum_marker *sm;
293 uint32_t ofs, prevofs; 317 uint32_t ofs, prevofs;
294 uint32_t hdr_crc, buf_ofs, buf_len; 318 uint32_t hdr_crc, buf_ofs, buf_len;
295 int err; 319 int err;
296 int noise = 0; 320 int noise = 0;
321
322
297#ifdef CONFIG_JFFS2_FS_WRITEBUFFER 323#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
298 int cleanmarkerfound = 0; 324 int cleanmarkerfound = 0;
299#endif 325#endif
@@ -319,10 +345,46 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
319 } 345 }
320 } 346 }
321#endif 347#endif
348
349 if (jffs2_sum_active()) {
350 sm = kmalloc(sizeof(struct jffs2_sum_marker), GFP_KERNEL);
351 if (!sm) {
352 return -ENOMEM;
353 }
354
355 err = jffs2_fill_scan_buf(c, (unsigned char *) sm, jeb->offset + c->sector_size -
356 sizeof(struct jffs2_sum_marker), sizeof(struct jffs2_sum_marker));
357 if (err) {
358 kfree(sm);
359 return err;
360 }
361
362 if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC ) {
363 err = jffs2_sum_scan_sumnode(c, jeb, je32_to_cpu(sm->offset), &pseudo_random);
364 if (err) {
365 kfree(sm);
366 return err;
367 }
368 }
369
370 kfree(sm);
371
372 ofs = jeb->offset;
373 prevofs = jeb->offset - 1;
374 }
375
322 buf_ofs = jeb->offset; 376 buf_ofs = jeb->offset;
323 377
324 if (!buf_size) { 378 if (!buf_size) {
325 buf_len = c->sector_size; 379 buf_len = c->sector_size;
380
381 if (jffs2_sum_active()) {
382 /* must reread because of summary test */
383 err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
384 if (err)
385 return err;
386 }
387
326 } else { 388 } else {
327 buf_len = EMPTY_SCAN_SIZE(c->sector_size); 389 buf_len = EMPTY_SCAN_SIZE(c->sector_size);
328 err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); 390 err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
@@ -367,6 +429,8 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
367 429
368 noise = 10; 430 noise = 10;
369 431
432 JFFS2_DBG_SUMMARY("no summary found in jeb 0x%08x. Apply original scan.\n",jeb->offset);
433
370scan_more: 434scan_more:
371 while(ofs < jeb->offset + c->sector_size) { 435 while(ofs < jeb->offset + c->sector_size) {
372 436
@@ -532,7 +596,7 @@ scan_more:
532 buf_ofs = ofs; 596 buf_ofs = ofs;
533 node = (void *)buf; 597 node = (void *)buf;
534 } 598 }
535 err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs); 599 err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs, s);
536 if (err) return err; 600 if (err) return err;
537 ofs += PAD(je32_to_cpu(node->totlen)); 601 ofs += PAD(je32_to_cpu(node->totlen));
538 break; 602 break;
@@ -548,7 +612,7 @@ scan_more:
548 buf_ofs = ofs; 612 buf_ofs = ofs;
549 node = (void *)buf; 613 node = (void *)buf;
550 } 614 }
551 err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs); 615 err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs, s);
552 if (err) return err; 616 if (err) return err;
553 ofs += PAD(je32_to_cpu(node->totlen)); 617 ofs += PAD(je32_to_cpu(node->totlen));
554 break; 618 break;
@@ -582,6 +646,8 @@ scan_more:
582 break; 646 break;
583 647
584 case JFFS2_NODETYPE_PADDING: 648 case JFFS2_NODETYPE_PADDING:
649 if (jffs2_sum_active())
650 jffs2_sum_add_padding_mem(s, je32_to_cpu(node->totlen));
585 DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); 651 DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
586 ofs += PAD(je32_to_cpu(node->totlen)); 652 ofs += PAD(je32_to_cpu(node->totlen));
587 break; 653 break;
@@ -616,6 +682,13 @@ scan_more:
616 } 682 }
617 } 683 }
618 684
685 if (jffs2_sum_active()) {
686 if (PAD(s->sum_size + JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size) {
687 JFFS2_DBG_SUMMARY("There is not enough space for "
688 "summary information, disabling for this jeb!\n");
689 jffs2_sum_disable_collecting(s);
690 }
691 }
619 692
620 D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, 693 D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset,
621 jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size)); 694 jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size));
@@ -628,24 +701,10 @@ scan_more:
628 jeb->wasted_size = 0; 701 jeb->wasted_size = 0;
629 } 702 }
630 703
631 if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size 704 return jffs2_scan_classify_jeb(c, jeb);
632 && (!jeb->first_node || !jeb->first_node->next_phys) )
633 return BLK_STATE_CLEANMARKER;
634
635 /* move blocks with max 4 byte dirty space to cleanlist */
636 else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
637 c->dirty_size -= jeb->dirty_size;
638 c->wasted_size += jeb->dirty_size;
639 jeb->wasted_size += jeb->dirty_size;
640 jeb->dirty_size = 0;
641 return BLK_STATE_CLEAN;
642 } else if (jeb->used_size || jeb->unchecked_size)
643 return BLK_STATE_PARTDIRTY;
644 else
645 return BLK_STATE_ALLDIRTY;
646} 705}
647 706
648static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino) 707struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
649{ 708{
650 struct jffs2_inode_cache *ic; 709 struct jffs2_inode_cache *ic;
651 710
@@ -672,7 +731,7 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info
672} 731}
673 732
674static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 733static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
675 struct jffs2_raw_inode *ri, uint32_t ofs) 734 struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s)
676{ 735{
677 struct jffs2_raw_node_ref *raw; 736 struct jffs2_raw_node_ref *raw;
678 struct jffs2_inode_cache *ic; 737 struct jffs2_inode_cache *ic;
@@ -739,11 +798,16 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
739 pseudo_random += je32_to_cpu(ri->version); 798 pseudo_random += je32_to_cpu(ri->version);
740 799
741 UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen))); 800 UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen)));
801
802 if (jffs2_sum_active()) {
803 jffs2_sum_add_inode_mem(s, ri, ofs - jeb->offset);
804 }
805
742 return 0; 806 return 0;
743} 807}
744 808
745static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 809static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
746 struct jffs2_raw_dirent *rd, uint32_t ofs) 810 struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s)
747{ 811{
748 struct jffs2_raw_node_ref *raw; 812 struct jffs2_raw_node_ref *raw;
749 struct jffs2_full_dirent *fd; 813 struct jffs2_full_dirent *fd;
@@ -817,6 +881,10 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
817 USED_SPACE(PAD(je32_to_cpu(rd->totlen))); 881 USED_SPACE(PAD(je32_to_cpu(rd->totlen)));
818 jffs2_add_fd_to_list(c, fd, &ic->scan_dents); 882 jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
819 883
884 if (jffs2_sum_active()) {
885 jffs2_sum_add_dirent_mem(s, rd, ofs - jeb->offset);
886 }
887
820 return 0; 888 return 0;
821} 889}
822 890
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c
new file mode 100644
index 000000000000..cb5dd8f11e73
--- /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}
diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h
new file mode 100644
index 000000000000..e6b0a69acbd4
--- /dev/null
+++ b/fs/jffs2/summary.h
@@ -0,0 +1,183 @@
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.h,v 1.1 2005/09/07 08:34:54 havasi Exp $
12 *
13 */
14
15#ifndef JFFS2_SUMMARY_H
16#define JFFS2_SUMMARY_H
17
18#include <linux/uio.h>
19#include <linux/jffs2.h>
20
21#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
22 c->free_size -= _x; c->dirty_size += _x; \
23 jeb->free_size -= _x ; jeb->dirty_size += _x; \
24 }while(0)
25#define USED_SPACE(x) do { typeof(x) _x = (x); \
26 c->free_size -= _x; c->used_size += _x; \
27 jeb->free_size -= _x ; jeb->used_size += _x; \
28 }while(0)
29#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
30 c->free_size -= _x; c->wasted_size += _x; \
31 jeb->free_size -= _x ; jeb->wasted_size += _x; \
32 }while(0)
33#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
34 c->free_size -= _x; c->unchecked_size += _x; \
35 jeb->free_size -= _x ; jeb->unchecked_size += _x; \
36 }while(0)
37
38#define BLK_STATE_ALLFF 0
39#define BLK_STATE_CLEAN 1
40#define BLK_STATE_PARTDIRTY 2
41#define BLK_STATE_CLEANMARKER 3
42#define BLK_STATE_ALLDIRTY 4
43#define BLK_STATE_BADBLOCK 5
44
45#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
46#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
47#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
48
49/* Summary structures used on flash */
50
51struct jffs2_sum_unknown_flash
52{
53 jint16_t nodetype; /* node type */
54};
55
56struct jffs2_sum_inode_flash
57{
58 jint16_t nodetype; /* node type */
59 jint32_t inode; /* inode number */
60 jint32_t version; /* inode version */
61 jint32_t offset; /* offset on jeb */
62 jint32_t totlen; /* record length */
63} __attribute__((packed));
64
65struct jffs2_sum_dirent_flash
66{
67 jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
68 jint32_t totlen; /* record length */
69 jint32_t offset; /* offset on jeb */
70 jint32_t pino; /* parent inode */
71 jint32_t version; /* dirent version */
72 jint32_t ino; /* == zero for unlink */
73 uint8_t nsize; /* dirent name size */
74 uint8_t type; /* dirent type */
75 uint8_t name[0]; /* dirent name */
76} __attribute__((packed));
77
78union jffs2_sum_flash
79{
80 struct jffs2_sum_unknown_flash u;
81 struct jffs2_sum_inode_flash i;
82 struct jffs2_sum_dirent_flash d;
83};
84
85/* Summary structures used in the memory */
86
87struct jffs2_sum_unknown_mem
88{
89 union jffs2_sum_mem *next;
90 jint16_t nodetype; /* node type */
91};
92
93struct jffs2_sum_inode_mem
94{
95 union jffs2_sum_mem *next;
96 jint16_t nodetype; /* node type */
97 jint32_t inode; /* inode number */
98 jint32_t version; /* inode version */
99 jint32_t offset; /* offset on jeb */
100 jint32_t totlen; /* record length */
101} __attribute__((packed));
102
103struct jffs2_sum_dirent_mem
104{
105 union jffs2_sum_mem *next;
106 jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
107 jint32_t totlen; /* record length */
108 jint32_t offset; /* ofset on jeb */
109 jint32_t pino; /* parent inode */
110 jint32_t version; /* dirent version */
111 jint32_t ino; /* == zero for unlink */
112 uint8_t nsize; /* dirent name size */
113 uint8_t type; /* dirent type */
114 uint8_t name[0]; /* dirent name */
115} __attribute__((packed));
116
117union jffs2_sum_mem
118{
119 struct jffs2_sum_unknown_mem u;
120 struct jffs2_sum_inode_mem i;
121 struct jffs2_sum_dirent_mem d;
122};
123
124/* Summary related information stored in superblock */
125
126struct jffs2_summary
127{
128 uint32_t sum_size; /* collected summary information for nextblock */
129 uint32_t sum_num;
130 uint32_t sum_padded;
131 union jffs2_sum_mem *sum_list_head;
132 union jffs2_sum_mem *sum_list_tail;
133
134 jint32_t *sum_buf; /* buffer for writing out summary */
135};
136
137/* Summary marker is stored at the end of every sumarized erase block */
138
139struct jffs2_sum_marker
140{
141 jint32_t offset; /* offset of the summary node in the jeb */
142 jint32_t magic; /* == JFFS2_SUM_MAGIC */
143};
144
145#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_summary_node) + sizeof(struct jffs2_sum_marker))
146
147#ifdef CONFIG_JFFS2_SUMMARY /* SUMMARY SUPPORT ENABLED */
148
149#define jffs2_sum_active() (1)
150int jffs2_sum_init(struct jffs2_sb_info *c);
151void jffs2_sum_exit(struct jffs2_sb_info *c);
152void jffs2_sum_disable_collecting(struct jffs2_summary *s);
153int jffs2_sum_is_disabled(struct jffs2_summary *s);
154void jffs2_sum_reset_collected(struct jffs2_summary *s);
155void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s);
156int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
157 unsigned long count, uint32_t to);
158int jffs2_sum_write_sumnode(struct jffs2_sb_info *c);
159int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size);
160int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs);
161int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs);
162int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
163 uint32_t ofs, uint32_t *pseudo_random);
164
165#else /* SUMMARY DISABLED */
166
167#define jffs2_sum_active() (0)
168#define jffs2_sum_init(a) (0)
169#define jffs2_sum_exit(a)
170#define jffs2_sum_disable_collecting(a)
171#define jffs2_sum_is_disabled(a) (0)
172#define jffs2_sum_reset_collected(a)
173#define jffs2_sum_add_kvec(a,b,c,d) (0)
174#define jffs2_sum_move_collected(a,b)
175#define jffs2_sum_write_sumnode(a) (0)
176#define jffs2_sum_add_padding_mem(a,b)
177#define jffs2_sum_add_inode_mem(a,b,c)
178#define jffs2_sum_add_dirent_mem(a,b,c)
179#define jffs2_sum_scan_sumnode(a,b,c,d) (0)
180
181#endif /* CONFIG_JFFS2_SUMMARY */
182
183#endif /* JFFS2_SUMMARY_H */
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 58496a03a1d2..99028af3f69e 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: super.c,v 1.108 2005/08/31 13:51:00 havasi Exp $ 10 * $Id: super.c,v 1.109 2005/09/07 08:34:55 havasi Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -282,6 +282,9 @@ static void jffs2_put_super (struct super_block *sb)
282 down(&c->alloc_sem); 282 down(&c->alloc_sem);
283 jffs2_flush_wbuf_pad(c); 283 jffs2_flush_wbuf_pad(c);
284 up(&c->alloc_sem); 284 up(&c->alloc_sem);
285
286 jffs2_sum_exit(c);
287
285 jffs2_free_ino_caches(c); 288 jffs2_free_ino_caches(c);
286 jffs2_free_raw_node_refs(c); 289 jffs2_free_raw_node_refs(c);
287 if (jffs2_blocks_use_vmalloc(c)) 290 if (jffs2_blocks_use_vmalloc(c))
@@ -321,6 +324,9 @@ static int __init init_jffs2_fs(void)
321#ifdef CONFIG_JFFS2_FS_WRITEBUFFER 324#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
322 " (NAND)" 325 " (NAND)"
323#endif 326#endif
327#ifdef CONFIG_JFFS2_SUMMARY
328 " (SUMMARY) "
329#endif
324 " (C) 2001-2003 Red Hat, Inc.\n"); 330 " (C) 2001-2003 Red Hat, Inc.\n");
325 331
326 jffs2_inode_cachep = kmem_cache_create("jffs2_i", 332 jffs2_inode_cachep = kmem_cache_create("jffs2_i",
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 8c06d3a2b17d..86860dbc670c 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -9,7 +9,7 @@
9 * 9 *
10 * For licensing information, see the file 'LICENCE' in this directory. 10 * For licensing information, see the file 'LICENCE' in this directory.
11 * 11 *
12 * $Id: wbuf.c,v 1.97 2005/08/06 04:51:30 nico Exp $ 12 * $Id: wbuf.c,v 1.98 2005/09/07 08:34:55 havasi Exp $
13 * 13 *
14 */ 14 */
15 15
@@ -265,7 +265,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
265 265
266 266
267 /* ... and get an allocation of space from a shiny new block instead */ 267 /* ... and get an allocation of space from a shiny new block instead */
268 ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len); 268 ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len, JFFS2_SUMMARY_NOSUM_SIZE);
269 if (ret) { 269 if (ret) {
270 printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); 270 printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
271 kfree(buf); 271 kfree(buf);
@@ -836,6 +836,12 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
836alldone: 836alldone:
837 *retlen = donelen; 837 *retlen = donelen;
838 838
839 if (jffs2_sum_active()) {
840 int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to);
841 if (res)
842 return res;
843 }
844
839 if (c->wbuf_len && ino) 845 if (c->wbuf_len && ino)
840 jffs2_wbuf_dirties_inode(c, ino); 846 jffs2_wbuf_dirties_inode(c, ino);
841 847
@@ -855,7 +861,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r
855 struct kvec vecs[1]; 861 struct kvec vecs[1];
856 862
857 if (!jffs2_is_writebuffered(c)) 863 if (!jffs2_is_writebuffered(c))
858 return c->mtd->write(c->mtd, ofs, len, retlen, buf); 864 return jffs2_flash_direct_write(c, ofs, len, retlen, buf);
859 865
860 vecs[0].iov_base = (unsigned char *) buf; 866 vecs[0].iov_base = (unsigned char *) buf;
861 vecs[0].iov_len = len; 867 vecs[0].iov_len = len;
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 0a194759bbbd..ea411518d801 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: write.c,v 1.95 2005/08/17 13:46:23 dedekind Exp $ 10 * $Id: write.c,v 1.96 2005/09/07 08:34:55 havasi Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -153,13 +153,15 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
153 jffs2_dbg_acct_paranoia_check(c, jeb); 153 jffs2_dbg_acct_paranoia_check(c, jeb);
154 154
155 if (alloc_mode == ALLOC_GC) { 155 if (alloc_mode == ALLOC_GC) {
156 ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy); 156 ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs,
157 &dummy, JFFS2_SUMMARY_INODE_SIZE);
157 } else { 158 } else {
158 /* Locking pain */ 159 /* Locking pain */
159 up(&f->sem); 160 up(&f->sem);
160 jffs2_complete_reservation(c); 161 jffs2_complete_reservation(c);
161 162
162 ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode); 163 ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs,
164 &dummy, alloc_mode, JFFS2_SUMMARY_INODE_SIZE);
163 down(&f->sem); 165 down(&f->sem);
164 } 166 }
165 167
@@ -299,13 +301,15 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
299 jffs2_dbg_acct_paranoia_check(c, jeb); 301 jffs2_dbg_acct_paranoia_check(c, jeb);
300 302
301 if (alloc_mode == ALLOC_GC) { 303 if (alloc_mode == ALLOC_GC) {
302 ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy); 304 ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs,
305 &dummy, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
303 } else { 306 } else {
304 /* Locking pain */ 307 /* Locking pain */
305 up(&f->sem); 308 up(&f->sem);
306 jffs2_complete_reservation(c); 309 jffs2_complete_reservation(c);
307 310
308 ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode); 311 ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs,
312 &dummy, alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
309 down(&f->sem); 313 down(&f->sem);
310 } 314 }
311 315
@@ -362,7 +366,8 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
362 retry: 366 retry:
363 D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset)); 367 D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset));
364 368
365 ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL); 369 ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs,
370 &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
366 if (ret) { 371 if (ret) {
367 D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); 372 D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
368 break; 373 break;
@@ -449,7 +454,8 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
449 /* Try to reserve enough space for both node and dirent. 454 /* Try to reserve enough space for both node and dirent.
450 * Just the node will do for now, though 455 * Just the node will do for now, though
451 */ 456 */
452 ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); 457 ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL,
458 JFFS2_SUMMARY_INODE_SIZE);
453 D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); 459 D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
454 if (ret) { 460 if (ret) {
455 up(&f->sem); 461 up(&f->sem);
@@ -478,7 +484,8 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
478 484
479 up(&f->sem); 485 up(&f->sem);
480 jffs2_complete_reservation(c); 486 jffs2_complete_reservation(c);
481 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); 487 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
488 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
482 489
483 if (ret) { 490 if (ret) {
484 /* Eep. */ 491 /* Eep. */
@@ -549,7 +556,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
549 if (!rd) 556 if (!rd)
550 return -ENOMEM; 557 return -ENOMEM;
551 558
552 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION); 559 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
560 ALLOC_DELETION, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
553 if (ret) { 561 if (ret) {
554 jffs2_free_raw_dirent(rd); 562 jffs2_free_raw_dirent(rd);
555 return ret; 563 return ret;
@@ -658,7 +666,8 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
658 if (!rd) 666 if (!rd)
659 return -ENOMEM; 667 return -ENOMEM;
660 668
661 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); 669 ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
670 ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
662 if (ret) { 671 if (ret) {
663 jffs2_free_raw_dirent(rd); 672 jffs2_free_raw_dirent(rd);
664 return ret; 673 return ret;
diff --git a/fs/jffs2/writev.c b/fs/jffs2/writev.c
index f079f8388566..6d8c27c5e723 100644
--- a/fs/jffs2/writev.c
+++ b/fs/jffs2/writev.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * For licensing information, see the file 'LICENCE' in this directory. 8 * For licensing information, see the file 'LICENCE' in this directory.
9 * 9 *
10 * $Id: writev.c,v 1.6 2004/11/16 20:36:12 dwmw2 Exp $ 10 * $Id: writev.c,v 1.7 2005/09/07 08:34:55 havasi Exp $
11 * 11 *
12 */ 12 */
13 13
@@ -44,7 +44,37 @@ int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
44{ 44{
45 if (c->mtd->writev) 45 if (c->mtd->writev)
46 return c->mtd->writev(c->mtd, vecs, count, to, retlen); 46 return c->mtd->writev(c->mtd, vecs, count, to, retlen);
47 else 47 else {
48 if (jffs2_sum_active()) {
49 int res;
50
51 res = jffs2_sum_add_kvec(c, vecs, count, (uint32_t) to);
52 if (res) {
53 return res;
54 }
55 }
56
48 return mtd_fake_writev(c->mtd, vecs, count, to, retlen); 57 return mtd_fake_writev(c->mtd, vecs, count, to, retlen);
58 }
49} 59}
50 60
61int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
62 size_t *retlen, const u_char *buf)
63{
64 int ret;
65 ret = c->mtd->write(c->mtd, ofs, len, retlen, buf);
66
67 if (jffs2_sum_active()) {
68 struct kvec vecs[1];
69 int res;
70
71 vecs[0].iov_base = (unsigned char *) buf;
72 vecs[0].iov_len = len;
73
74 res = jffs2_sum_add_kvec(c, vecs, 1, (uint32_t) ofs);
75 if (res) {
76 return res;
77 }
78 }
79 return ret;
80}
diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h
index a66d0a8b70e4..acb51a3669a2 100644
--- a/include/linux/jffs2.h
+++ b/include/linux/jffs2.h
@@ -8,7 +8,7 @@
8 * For licensing information, see the file 'LICENCE' in the 8 * For licensing information, see the file 'LICENCE' in the
9 * jffs2 directory. 9 * jffs2 directory.
10 * 10 *
11 * $Id: jffs2.h,v 1.36 2005/07/26 13:19:36 havasi Exp $ 11 * $Id: jffs2.h,v 1.37 2005/09/07 08:34:55 havasi Exp $
12 * 12 *
13 */ 13 */
14 14
@@ -28,6 +28,9 @@
28#define JFFS2_EMPTY_BITMASK 0xffff 28#define JFFS2_EMPTY_BITMASK 0xffff
29#define JFFS2_DIRTY_BITMASK 0x0000 29#define JFFS2_DIRTY_BITMASK 0x0000
30 30
31/* Summary node MAGIC marker */
32#define JFFS2_SUM_MAGIC 0x02851885
33
31/* We only allow a single char for length, and 0xFF is empty flash so 34/* We only allow a single char for length, and 0xFF is empty flash so
32 we don't want it confused with a real length. Hence max 254. 35 we don't want it confused with a real length. Hence max 254.
33*/ 36*/
@@ -60,6 +63,8 @@
60#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) 63#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
61#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) 64#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
62 65
66#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
67
63// Maybe later... 68// Maybe later...
64//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) 69//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
65//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) 70//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
@@ -146,10 +151,24 @@ struct jffs2_raw_inode
146 uint8_t data[0]; 151 uint8_t data[0];
147} __attribute__((packed)); 152} __attribute__((packed));
148 153
154struct jffs2_summary_node{
155 jint16_t magic;
156 jint16_t nodetype; /* = JFFS2_NODETYPE_INODE_SUM */
157 jint32_t totlen;
158 jint32_t hdr_crc;
159 jint32_t sum_num; /* number of sum entries*/
160 jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */
161 jint32_t padded; /* sum of the size of padding nodes */
162 jint32_t sum_crc; /* summary information crc */
163 jint32_t node_crc; /* node crc */
164 jint32_t sum[0]; /* inode summary info */
165} __attribute__((packed));
166
149union jffs2_node_union { 167union jffs2_node_union {
150 struct jffs2_raw_inode i; 168 struct jffs2_raw_inode i;
151 struct jffs2_raw_dirent d; 169 struct jffs2_raw_dirent d;
152 struct jffs2_unknown_node u; 170 struct jffs2_unknown_node u;
171 struct jffs2_summary_node s;
153}; 172};
154 173
155#endif /* __LINUX_JFFS2_H__ */ 174#endif /* __LINUX_JFFS2_H__ */
diff --git a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h
index 1e21546622de..5087612ed9ac 100644
--- a/include/linux/jffs2_fs_sb.h
+++ b/include/linux/jffs2_fs_sb.h
@@ -1,4 +1,4 @@
1/* $Id: jffs2_fs_sb.h,v 1.52 2005/05/19 16:12:17 gleixner Exp $ */ 1/* $Id: jffs2_fs_sb.h,v 1.53 2005/09/07 08:34:56 havasi Exp $ */
2 2
3#ifndef _JFFS2_FS_SB 3#ifndef _JFFS2_FS_SB
4#define _JFFS2_FS_SB 4#define _JFFS2_FS_SB
@@ -112,6 +112,8 @@ struct jffs2_sb_info {
112 uint32_t fsdata_len; 112 uint32_t fsdata_len;
113#endif 113#endif
114 114
115 struct jffs2_summary *summary; /* Summary information */
116
115 /* OS-private pointer for getting back to master superblock info */ 117 /* OS-private pointer for getting back to master superblock info */
116 void *os_priv; 118 void *os_priv;
117}; 119};