diff options
Diffstat (limited to 'fs/jffs2')
-rw-r--r-- | fs/jffs2/Makefile | 3 | ||||
-rw-r--r-- | fs/jffs2/build.c | 12 | ||||
-rw-r--r-- | fs/jffs2/debug.h | 10 | ||||
-rw-r--r-- | fs/jffs2/dir.c | 20 | ||||
-rw-r--r-- | fs/jffs2/file.c | 5 | ||||
-rw-r--r-- | fs/jffs2/fs.c | 5 | ||||
-rw-r--r-- | fs/jffs2/gc.c | 26 | ||||
-rw-r--r-- | fs/jffs2/nodelist.h | 13 | ||||
-rw-r--r-- | fs/jffs2/nodemgmt.c | 250 | ||||
-rw-r--r-- | fs/jffs2/os-linux.h | 19 | ||||
-rw-r--r-- | fs/jffs2/scan.c | 198 | ||||
-rw-r--r-- | fs/jffs2/summary.c | 729 | ||||
-rw-r--r-- | fs/jffs2/summary.h | 183 | ||||
-rw-r--r-- | fs/jffs2/super.c | 8 | ||||
-rw-r--r-- | fs/jffs2/wbuf.c | 12 | ||||
-rw-r--r-- | fs/jffs2/write.c | 29 | ||||
-rw-r--r-- | fs/jffs2/writev.c | 34 |
17 files changed, 1359 insertions, 197 deletions
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 | ||
7 | obj-$(CONFIG_JFFS2_FS) += jffs2.o | 7 | obj-$(CONFIG_JFFS2_FS) += jffs2.o |
@@ -15,3 +15,4 @@ jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o | |||
15 | jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o | 15 | jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o |
16 | jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o | 16 | jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o |
17 | jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o | 17 | jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o |
18 | jffs2-$(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 */ |
328 | int jffs2_thread_should_wake(struct jffs2_sb_info *c); | 329 | int jffs2_thread_should_wake(struct jffs2_sb_info *c); |
329 | int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio); | 330 | int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, |
330 | int 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); |
332 | int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, | ||
333 | uint32_t *len, uint32_t sumsize); | ||
331 | int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new); | 334 | int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new); |
332 | void jffs2_complete_reservation(struct jffs2_sb_info *c); | 335 | void jffs2_complete_reservation(struct jffs2_sb_info *c); |
333 | void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw); | 336 | void 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 */ |
387 | int jffs2_scan_medium(struct jffs2_sb_info *c); | 390 | int jffs2_scan_medium(struct jffs2_sb_info *c); |
388 | void jffs2_rotate_lists(struct jffs2_sb_info *c); | 391 | void jffs2_rotate_lists(struct jffs2_sb_info *c); |
392 | int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf, | ||
393 | uint32_t ofs, uint32_t len); | ||
394 | struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino); | ||
395 | int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); | ||
389 | 396 | ||
390 | /* build.c */ | 397 | /* build.c */ |
391 | int jffs2_do_mount_fs(struct jffs2_sb_info *c); | 398 | int 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 | ||
41 | static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); | 42 | static 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 | ||
43 | int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio) | 45 | int 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 | ||
143 | int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) | 146 | int 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 | |
162 | static 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 | |||
168 | static 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 | |||
197 | static 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); | 262 | static 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 */ |
193 | int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, | 205 | int 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 | 207 | int 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 @@ | |||
47 | static uint32_t pseudo_random; | 36 | static uint32_t pseudo_random; |
48 | 37 | ||
49 | static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 38 | static 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 | */ |
56 | static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 45 | static 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); |
58 | static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 47 | static 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 | ||
68 | static inline int min_free(struct jffs2_sb_info *c) | 50 | static 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 | ||
268 | static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf, | 272 | int 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 | ||
293 | int 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 | |||
289 | static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 312 | static 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 | |||
370 | scan_more: | 434 | scan_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 | ||
648 | static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino) | 707 | struct 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 | ||
674 | static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 733 | static 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 | ||
745 | static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 809 | static 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 | |||
26 | int 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 | |||
49 | void 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 | |||
62 | static 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 | |||
94 | int 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 | |||
101 | int 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 | |||
119 | int 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 | |||
145 | static 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 | |||
162 | void 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 | |||
169 | void 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 | |||
176 | int 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 | |||
183 | void 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 | |||
200 | int 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 | |||
285 | no_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 | |||
293 | static 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 | |||
425 | int 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 | |||
551 | crc_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 | |||
559 | static 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 | |||
671 | int 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 | |||
51 | struct jffs2_sum_unknown_flash | ||
52 | { | ||
53 | jint16_t nodetype; /* node type */ | ||
54 | }; | ||
55 | |||
56 | struct 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 | |||
65 | struct 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 | |||
78 | union 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 | |||
87 | struct jffs2_sum_unknown_mem | ||
88 | { | ||
89 | union jffs2_sum_mem *next; | ||
90 | jint16_t nodetype; /* node type */ | ||
91 | }; | ||
92 | |||
93 | struct 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 | |||
103 | struct 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 | |||
117 | union 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 | |||
126 | struct 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 | |||
139 | struct 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) | ||
150 | int jffs2_sum_init(struct jffs2_sb_info *c); | ||
151 | void jffs2_sum_exit(struct jffs2_sb_info *c); | ||
152 | void jffs2_sum_disable_collecting(struct jffs2_summary *s); | ||
153 | int jffs2_sum_is_disabled(struct jffs2_summary *s); | ||
154 | void jffs2_sum_reset_collected(struct jffs2_summary *s); | ||
155 | void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s); | ||
156 | int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, | ||
157 | unsigned long count, uint32_t to); | ||
158 | int jffs2_sum_write_sumnode(struct jffs2_sb_info *c); | ||
159 | int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size); | ||
160 | int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs); | ||
161 | int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs); | ||
162 | int 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 | |||
836 | alldone: | 836 | alldone: |
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 | ||
61 | int 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 | } | ||