aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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};