aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorFerenc Havasi <havasi@inf.u-szeged.hu>2005-09-07 09:35:26 +0100
committerThomas Gleixner <tglx@mtd.linutronix.de>2005-11-06 21:29:48 +0100
commite631ddba588783edd521c5a89f7b2902772fb691 (patch)
treee25f322ee498b344f058ce4a40060baa22a5f105 /fs
parent15017876751e4c2d786ba95920618359fe2b4f0a (diff)
[JFFS2] Add erase block summary support (mount time improvement)
The goal of summary is to speed up the mount time. Erase block summary (EBS) stores summary information at the end of every (closed) erase block. It is no longer necessary to scan all nodes separetly (and read all pages of them) just read this "small" summary, where every information is stored which is needed at mount time. This summary information is stored in a JFFS2_FEATURE_RWCOMPAT_DELETE. During the mount process if there is no summary info the orignal scan process will be executed. EBS works with NAND and NOR flashes, too. There is a user space tool called sumtool to generate this summary information for a JFFS2 image. Signed-off-by: Ferenc Havasi <havasi@inf.u-szeged.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig13
-rw-r--r--fs/jffs2/Makefile3
-rw-r--r--fs/jffs2/build.c12
-rw-r--r--fs/jffs2/debug.h10
-rw-r--r--fs/jffs2/dir.c20
-rw-r--r--fs/jffs2/file.c5
-rw-r--r--fs/jffs2/fs.c5
-rw-r--r--fs/jffs2/gc.c26
-rw-r--r--fs/jffs2/nodelist.h13
-rw-r--r--fs/jffs2/nodemgmt.c250
-rw-r--r--fs/jffs2/os-linux.h19
-rw-r--r--fs/jffs2/scan.c198
-rw-r--r--fs/jffs2/summary.c729
-rw-r--r--fs/jffs2/summary.h183
-rw-r--r--fs/jffs2/super.c8
-rw-r--r--fs/jffs2/wbuf.c12
-rw-r--r--fs/jffs2/write.c29
-rw-r--r--fs/jffs2/writev.c34
18 files changed, 1372 insertions, 197 deletions
diff --git a/fs/Kconfig b/fs/Kconfig
index 01a295232f7..37d86c5072e 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1050,6 +1050,19 @@ config JFFS2_FS_WRITEBUFFER
- NOR flash with transparent ECC
- DataFlash
+config JFFS2_SUMMARY
+ bool "JFFS2 summary support (EXPERIMENTAL)"
+ depends on JFFS2_FS && EXPERIMENTAL
+ default n
+ help
+ This feature makes it possible to use summary information
+ for faster filesystem mount.
+
+ The summary information can be inserted into a filesystem image
+ by the utility 'sumtool'.
+
+ If unsure, say 'N'.
+
config JFFS2_COMPRESSION_OPTIONS
bool "Advanced compression options for JFFS2"
depends on JFFS2_FS
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile
index e6230f1bba7..77dc5561a04 100644
--- a/fs/jffs2/Makefile
+++ b/fs/jffs2/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the Linux Journalling Flash File System v2 (JFFS2)
#
-# $Id: Makefile.common,v 1.10 2005/07/17 06:56:20 dedekind Exp $
+# $Id: Makefile.common,v 1.11 2005/09/07 08:34:53 havasi Exp $
#
obj-$(CONFIG_JFFS2_FS) += jffs2.o
@@ -15,3 +15,4 @@ jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o
jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
+jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index 1522eace932..f4a47a3b2a0 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: build.c,v 1.77 2005/08/31 13:51:00 havasi Exp $
+ * $Id: build.c,v 1.78 2005/09/07 08:34:54 havasi Exp $
*
*/
@@ -350,6 +350,10 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
INIT_LIST_HEAD(&c->bad_list);
INIT_LIST_HEAD(&c->bad_used_list);
c->highest_ino = 1;
+ c->summary = NULL;
+
+ if (jffs2_sum_init(c))
+ return -ENOMEM;
if (jffs2_build_filesystem(c)) {
D1(printk(KERN_DEBUG "build_fs failed\n"));
@@ -357,11 +361,11 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
jffs2_free_raw_node_refs(c);
#ifndef __ECOS
if (jffs2_blocks_use_vmalloc(c))
- vfree(c->blocks);
+ vfree(c->blocks);
else
#endif
- kfree(c->blocks);
-
+ kfree(c->blocks);
+
return -EIO;
}
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h
index 03d9626ad1c..60e5dbb3946 100644
--- a/fs/jffs2/debug.h
+++ b/fs/jffs2/debug.h
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: debug.h,v 1.14 2005/08/17 13:48:59 dedekind Exp $
+ * $Id: debug.h,v 1.15 2005/09/07 08:34:54 havasi Exp $
*
*/
#ifndef _JFFS2_DEBUG_H_
@@ -28,6 +28,7 @@
#define JFFS2_DBG_DENTLIST_MESSAGES
#define JFFS2_DBG_NODEREF_MESSAGES
#define JFFS2_DBG_INOCACHE_MESSAGES
+#define JFFS2_DBG_SUMMARY_MESSAGES
#endif
#if CONFIG_JFFS2_FS_DEBUG == 2
@@ -137,6 +138,13 @@
#define JFFS2_DBG_INOCACHE(fmt, ...)
#endif
+/* Summary debugging messages */
+#ifdef JFFS2_DBG_SUMMARY_MESSAGES
+#define JFFS2_DBG_SUMMARY(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
+#else
+#define JFFS2_DBG_SUMMARY(fmt, ...)
+#endif
+
/* Watch the object allocations */
#ifdef JFFS2_DBG_MEMALLOC_MESSAGES
#define JFFS2_DBG_MEMALLOC(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 0fd15aaf245..19bea0f95ac 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: dir.c,v 1.88 2005/08/17 13:46:22 dedekind Exp $
+ * $Id: dir.c,v 1.89 2005/09/07 08:34:54 havasi Exp $
*
*/
@@ -310,7 +310,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
* Just the node will do for now, though
*/
namelen = dentry->d_name.len;
- ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+ ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen,
+ ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
if (ret) {
jffs2_free_raw_inode(ri);
@@ -370,7 +371,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
up(&f->sem);
jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+ ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
if (ret) {
/* Eep. */
jffs2_clear_inode(inode);
@@ -455,7 +457,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
* Just the node will do for now, though
*/
namelen = dentry->d_name.len;
- ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
+ ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL,
+ JFFS2_SUMMARY_INODE_SIZE);
if (ret) {
jffs2_free_raw_inode(ri);
@@ -498,7 +501,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
up(&f->sem);
jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+ ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
if (ret) {
/* Eep. */
jffs2_clear_inode(inode);
@@ -607,7 +611,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
* Just the node will do for now, though
*/
namelen = dentry->d_name.len;
- ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+ ret = jffs2_reserve_space(c, sizeof(*ri) + devlen, &phys_ofs, &alloclen,
+ ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
if (ret) {
jffs2_free_raw_inode(ri);
@@ -652,7 +657,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
up(&f->sem);
jffs2_complete_reservation(c);
- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
+ ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
if (ret) {
/* Eep. */
jffs2_clear_inode(inode);
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 8279bf0133f..231404a7472 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: file.c,v 1.102 2005/07/06 12:13:09 dwmw2 Exp $
+ * $Id: file.c,v 1.103 2005/09/07 08:34:54 havasi Exp $
*
*/
@@ -134,7 +134,8 @@ static int jffs2_prepare_write (struct file *filp, struct page *pg,
D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
(unsigned int)inode->i_size, pageofs));
- ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL);
+ ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len,
+ ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
if (ret)
return ret;
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index c99451ae4b7..c15c3022047 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: fs.c,v 1.64 2005/09/01 08:42:31 havasi Exp $
+ * $Id: fs.c,v 1.65 2005/09/07 08:34:54 havasi Exp $
*
*/
@@ -74,7 +74,8 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
return -ENOMEM;
}
- ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
+ ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen,
+ ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
if (ret) {
jffs2_free_raw_inode(ri);
if (S_ISLNK(inode->i_mode & S_IFMT))
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index def97157ecb..ee54cdc59e0 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: gc.c,v 1.153 2005/08/17 13:46:22 dedekind Exp $
+ * $Id: gc.c,v 1.154 2005/09/07 08:34:54 havasi Exp $
*
*/
@@ -513,8 +513,11 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
/* Ask for a small amount of space (or the totlen if smaller) because we
don't want to force wastage of the end of a block if splitting would
work. */
- ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN,
- rawlen), &phys_ofs, &alloclen);
+ ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) +
+ JFFS2_MIN_DATA_LEN, rawlen), &phys_ofs, &alloclen, rawlen);
+ /* this is not the exact summary size of it,
+ it is only an upper estimation */
+
if (ret)
return ret;
@@ -622,7 +625,9 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
jffs2_dbg_acct_sanity_check(c,jeb);
jffs2_dbg_acct_paranoia_check(c, jeb);
- ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy);
+ ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy, rawlen);
+ /* this is not the exact summary size of it,
+ it is only an upper estimation */
if (!ret) {
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_
}
- ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen);
+ ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen,
+ JFFS2_SUMMARY_INODE_SIZE);
if (ret) {
printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n",
sizeof(ri)+ mdatalen, ret);
@@ -781,7 +787,8 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er
rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8));
rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize));
- ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen);
+ ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen,
+ JFFS2_SUMMARY_DIRENT_SIZE(rd.nsize));
if (ret) {
printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n",
sizeof(rd)+rd.nsize, ret);
@@ -994,7 +1001,8 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
ri.data_crc = cpu_to_je32(0);
ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
- ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen);
+ ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen,
+ JFFS2_SUMMARY_INODE_SIZE);
if (ret) {
printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n",
sizeof(ri), ret);
@@ -1219,7 +1227,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
uint32_t cdatalen;
uint16_t comprtype = JFFS2_COMPR_NONE;
- ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen);
+ ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs,
+ &alloclen, JFFS2_SUMMARY_INODE_SIZE);
if (ret) {
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
jffs2_gc_release_page(c, pg_ptr, &pg);
return ret;
}
-
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index 1533af8b395..1222372cb29 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodelist.h,v 1.139 2005/08/31 13:51:00 havasi Exp $
+ * $Id: nodelist.h,v 1.140 2005/09/07 08:34:54 havasi Exp $
*
*/
@@ -20,6 +20,7 @@
#include <linux/jffs2.h>
#include <linux/jffs2_fs_sb.h>
#include <linux/jffs2_fs_i.h>
+#include "summary.h"
#ifdef __ECOS
#include "os-ecos.h"
@@ -326,8 +327,10 @@ int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode
/* nodemgmt.c */
int jffs2_thread_should_wake(struct jffs2_sb_info *c);
-int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio);
-int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len);
+int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
+ uint32_t *len, int prio, uint32_t sumsize);
+int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
+ uint32_t *len, uint32_t sumsize);
int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new);
void jffs2_complete_reservation(struct jffs2_sb_info *c);
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);
/* scan.c */
int jffs2_scan_medium(struct jffs2_sb_info *c);
void jffs2_rotate_lists(struct jffs2_sb_info *c);
+int jffs2_fill_scan_buf(struct jffs2_sb_info *c, void *buf,
+ uint32_t ofs, uint32_t len);
+struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino);
+int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
/* build.c */
int jffs2_do_mount_fs(struct jffs2_sb_info *c);
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index fe7e70a4055..208b2bdf01e 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodemgmt.c,v 1.124 2005/07/20 15:32:28 dedekind Exp $
+ * $Id: nodemgmt.c,v 1.125 2005/09/07 08:34:54 havasi Exp $
*
*/
@@ -17,6 +17,7 @@
#include <linux/compiler.h>
#include <linux/sched.h> /* For cond_resched() */
#include "nodelist.h"
+#include "debug.h"
/**
* jffs2_reserve_space - request physical space to write nodes to flash
@@ -38,9 +39,11 @@
* for the requested allocation.
*/
-static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len);
+static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
+ uint32_t *ofs, uint32_t *len, uint32_t sumsize);
-int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio)
+int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
+ uint32_t *len, int prio, uint32_t sumsize)
{
int ret = -EAGAIN;
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
spin_lock(&c->erase_completion_lock);
}
- ret = jffs2_do_reserve_space(c, minsize, ofs, len);
+ ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize);
if (ret) {
D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret));
}
@@ -140,7 +143,8 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
return ret;
}
-int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len)
+int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
+ uint32_t *len, uint32_t sumsize)
{
int ret = -EAGAIN;
minsize = PAD(minsize);
@@ -149,7 +153,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *
spin_lock(&c->erase_completion_lock);
while(ret == -EAGAIN) {
- ret = jffs2_do_reserve_space(c, minsize, ofs, len);
+ ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize);
if (ret) {
D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
}
@@ -158,105 +162,183 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *
return ret;
}
-/* Called with alloc sem _and_ erase_completion_lock */
-static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len)
+
+/* Classify nextblock (clean, dirty of verydirty) and force to select an other one */
+
+static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
- struct jffs2_eraseblock *jeb = c->nextblock;
+
+ /* Check, if we have a dirty block now, or if it was dirty already */
+ if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
+ c->dirty_size += jeb->wasted_size;
+ c->wasted_size -= jeb->wasted_size;
+ jeb->dirty_size += jeb->wasted_size;
+ jeb->wasted_size = 0;
+ if (VERYDIRTY(c, jeb->dirty_size)) {
+ 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",
+ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
+ list_add_tail(&jeb->list, &c->very_dirty_list);
+ } else {
+ D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
+ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
+ list_add_tail(&jeb->list, &c->dirty_list);
+ }
+ } else {
+ D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
+ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
+ list_add_tail(&jeb->list, &c->clean_list);
+ }
+ c->nextblock = NULL;
+
+}
+
+/* Select a new jeb for nextblock */
+
+static int jffs2_find_nextblock(struct jffs2_sb_info *c)
+{
+ struct list_head *next;
- restart:
- if (jeb && minsize > jeb->free_size) {
- /* Skip the end of this block and file it as having some dirty space */
- /* If there's a pending write to it, flush now */
- if (jffs2_wbuf_dirty(c)) {
+ /* Take the next block off the 'free' list */
+
+ if (list_empty(&c->free_list)) {
+
+ if (!c->nr_erasing_blocks &&
+ !list_empty(&c->erasable_list)) {
+ struct jffs2_eraseblock *ejeb;
+
+ ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
+ list_del(&ejeb->list);
+ list_add_tail(&ejeb->list, &c->erase_pending_list);
+ c->nr_erasing_blocks++;
+ jffs2_erase_pending_trigger(c);
+ D1(printk(KERN_DEBUG "jffs2_find_nextblock: Triggering erase of erasable block at 0x%08x\n",
+ ejeb->offset));
+ }
+
+ if (!c->nr_erasing_blocks &&
+ !list_empty(&c->erasable_pending_wbuf_list)) {
+ D1(printk(KERN_DEBUG "jffs2_find_nextblock: Flushing write buffer\n"));
+ /* c->nextblock is NULL, no update to c->nextblock allowed */
spin_unlock(&c->erase_completion_lock);
- D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
jffs2_flush_wbuf_pad(c);
spin_lock(&c->erase_completion_lock);
- jeb = c->nextblock;
- goto restart;
+ /* Have another go. It'll be on the erasable_list now */
+ return -EAGAIN;
}
- c->wasted_size += jeb->free_size;
- c->free_size -= jeb->free_size;
- jeb->wasted_size += jeb->free_size;
- jeb->free_size = 0;
-
- /* Check, if we have a dirty block now, or if it was dirty already */
- if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
- c->dirty_size += jeb->wasted_size;
- c->wasted_size -= jeb->wasted_size;
- jeb->dirty_size += jeb->wasted_size;
- jeb->wasted_size = 0;
- if (VERYDIRTY(c, jeb->dirty_size)) {
- 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",
- jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
- list_add_tail(&jeb->list, &c->very_dirty_list);
- } else {
- D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
- jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
- list_add_tail(&jeb->list, &c->dirty_list);
- }
- } else {
- D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
- jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
- list_add_tail(&jeb->list, &c->clean_list);
+
+ if (!c->nr_erasing_blocks) {
+ /* Ouch. We're in GC, or we wouldn't have got here.
+ And there's no space left. At all. */
+ 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",
+ c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no",
+ list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
+ return -ENOSPC;
}
- c->nextblock = jeb = NULL;
+
+ spin_unlock(&c->erase_completion_lock);
+ /* Don't wait for it; just erase one right now */
+ jffs2_erase_pending_blocks(c, 1);
+ spin_lock(&c->erase_completion_lock);
+
+ /* An erase may have failed, decreasing the
+ amount of free space available. So we must
+ restart from the beginning */
+ return -EAGAIN;
}
+
+ next = c->free_list.next;
+ list_del(next);
+ c->nextblock = list_entry(next, struct jffs2_eraseblock, list);
+ c->nr_free_blocks--;
- if (!jeb) {
- struct list_head *next;
- /* Take the next block off the 'free' list */
+ jffs2_sum_reset_collected(c->summary); /* reset collected summary */
- if (list_empty(&c->free_list)) {
+ D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset));
- if (!c->nr_erasing_blocks &&
- !list_empty(&c->erasable_list)) {
- struct jffs2_eraseblock *ejeb;
+ return 0;
+}
- ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
- list_del(&ejeb->list);
- list_add_tail(&ejeb->list, &c->erase_pending_list);
- c->nr_erasing_blocks++;
- jffs2_erase_pending_trigger(c);
- D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n",
- ejeb->offset));
+/* Called with alloc sem _and_ erase_completion_lock */
+static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, uint32_t sumsize)
+{
+ struct jffs2_eraseblock *jeb = c->nextblock;
+ uint32_t reserved_size; /* for summary information at the end of the jeb */
+ int ret;
+
+ restart:
+ reserved_size = 0;
+
+ if (jffs2_sum_active() && (sumsize != JFFS2_SUMMARY_NOSUM_SIZE)) {
+ /* NOSUM_SIZE means not to generate summary */
+
+ if (jeb) {
+ reserved_size = PAD(sumsize + c->summary->sum_size + JFFS2_SUMMARY_FRAME_SIZE);
+ JFFS2_DBG_SUMMARY("minsize=%d , jeb->free=%d ,"
+ "summary->size=%d , sumsize=%d\n",
+ minsize, jeb->free_size,
+ c->summary->sum_size, sumsize);
+ }
+
+ /* Is there enough space for writing out the current node, or we have to
+ write out summary information now, close this jeb and select new nextblock? */
+ if (jeb && (PAD(minsize) + PAD(c->summary->sum_size + sumsize +
+ JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size)) {
+
+ /* Has summary been disabled for this jeb? */
+ if (jffs2_sum_is_disabled(c->summary)) {
+ sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
+ goto restart;
}
- if (!c->nr_erasing_blocks &&
- !list_empty(&c->erasable_pending_wbuf_list)) {
- D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
- /* c->nextblock is NULL, no update to c->nextblock allowed */
+ /* Writing out the collected summary information */
+ JFFS2_DBG_SUMMARY("generating summary for 0x%08x.\n", jeb->offset);
+ ret = jffs2_sum_write_sumnode(c);
+
+ if (ret)
+ return ret;
+
+ if (jffs2_sum_is_disabled(c->summary)) {
+ /* jffs2_write_sumnode() couldn't write out the summary information
+ diabling summary for this jeb and free the collected information
+ */
+ sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
+ goto restart;
+ }
+
+ jffs2_close_nextblock(c, jeb);
+ jeb = NULL;
+ }
+ } else {
+ if (jeb && minsize > jeb->free_size) {
+ /* Skip the end of this block and file it as having some dirty space */
+ /* If there's a pending write to it, flush now */
+
+ if (jffs2_wbuf_dirty(c)) {
spin_unlock(&c->erase_completion_lock);
+ D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
jffs2_flush_wbuf_pad(c);
spin_lock(&c->erase_completion_lock);
- /* Have another go. It'll be on the erasable_list now */
- return -EAGAIN;
- }
-
- if (!c->nr_erasing_blocks) {
- /* Ouch. We're in GC, or we wouldn't have got here.
- And there's no space left. At all. */
- 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",
- c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no",
- list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
- return -ENOSPC;
+ jeb = c->nextblock;
+ goto restart;
}
- spin_unlock(&c->erase_completion_lock);
- /* Don't wait for it; just erase one right now */
- jffs2_erase_pending_blocks(c, 1);
- spin_lock(&c->erase_completion_lock);
+ c->wasted_size += jeb->free_size;
+ c->free_size -= jeb->free_size;
+ jeb->wasted_size += jeb->free_size;
+ jeb->free_size = 0;
- /* An erase may have failed, decreasing the
- amount of free space available. So we must
- restart from the beginning */
- return -EAGAIN;
+ jffs2_close_nextblock(c, jeb);
+ jeb = NULL;
}
+ }
+
+ if (!jeb) {
+
+ ret = jffs2_find_nextblock(c);
+ if (ret)
+ return ret;
- next = c->free_list.next;
- list_del(next);
- c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list);
- c->nr_free_blocks--;
+ jeb = c->nextblock;
if (jeb->free_size != c->sector_size - c->cleanmarker_size) {
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
/* OK, jeb (==c->nextblock) is now pointing at a block which definitely has
enough space */
*ofs = jeb->offset + (c->sector_size - jeb->free_size);
- *len = jeb->free_size;
+ *len = jeb->free_size - reserved_size;
if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
!jeb->first_node->next_in_ino) {
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index c3c1619fb13..e026888cf1c 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: os-linux.h,v 1.60 2005/08/06 04:51:30 nico Exp $
+ * $Id: os-linux.h,v 1.61 2005/09/07 08:34:54 havasi Exp $
*
*/
@@ -67,12 +67,18 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
+
+#ifdef CONFIG_JFFS2_SUMMARY
+#define jffs2_can_mark_obsolete(c) (0)
+#else
#define jffs2_can_mark_obsolete(c) (1)
+#endif
+
#define jffs2_is_writebuffered(c) (0)
#define jffs2_cleanmarker_oob(c) (0)
#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
-#define jffs2_flash_write(c, ofs, len, retlen, buf) ((c)->mtd->write((c)->mtd, ofs, len, retlen, buf))
+#define jffs2_flash_write(c, ofs, len, retlen, buf) jffs2_flash_direct_write(c, ofs, len, retlen, buf)
#define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
#define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; })
#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)
#define jffs2_is_writebuffered(c) (c->wbuf != NULL)
#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size )
+
+#ifdef CONFIG_JFFS2_SUMMARY
+#define jffs2_can_mark_obsolete(c) (0)
+#else
#define jffs2_can_mark_obsolete(c) \
((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & (MTD_ECC|MTD_PROGRAM_REGIONS))) || \
c->mtd->type == MTD_RAM)
+#endif
+
#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
#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);
/* writev.c */
int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen);
-
+int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
+ size_t *retlen, const u_char *buf);
#endif /* __JFFS2_OS_LINUX_H__ */
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index fcd6314cf17..4e60ba8da19 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: scan.c,v 1.121 2005/07/20 15:32:28 dedekind Exp $
+ * $Id: scan.c,v 1.122 2005/09/07 08:34:54 havasi Exp $
*
*/
#include <linux/kernel.h>
@@ -18,22 +18,11 @@
#include <linux/crc32.h>
#include <linux/compiler.h>
#include "nodelist.h"
+#include "summary.h"
+#include "debug.h"
#define DEFAULT_EMPTY_SCAN_SIZE 1024
-#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
- c->free_size -= _x; c->dirty_size += _x; \
- jeb->free_size -= _x ; jeb->dirty_size += _x; \
- }while(0)
-#define USED_SPACE(x) do { typeof(x) _x = (x); \
- c->free_size -= _x; c->used_size += _x; \
- jeb->free_size -= _x ; jeb->used_size += _x; \
- }while(0)
-#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
- c->free_size -= _x; c->unchecked_size += _x; \
- jeb->free_size -= _x ; jeb->unchecked_size += _x; \
- }while(0)
-
#define noisy_printk(noise, args...) do { \
if (*(noise)) { \
printk(KERN_NOTICE args); \
@@ -47,23 +36,16 @@
static uint32_t pseudo_random;
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
- unsigned char *buf, uint32_t buf_size);
+ unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s);
/* These helper functions _must_ increase ofs and also do the dirty/used space accounting.
* Returning an error will abort the mount - bad checksums etc. should just mark the space
* as dirty.
*/
static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
- struct jffs2_raw_inode *ri, uint32_t ofs);
+ struct jffs2_raw_inode *ri, uint32_t ofs, struct jffs2_summary *s);
static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
- struct jffs2_raw_dirent *rd, uint32_t ofs);
-
-#define BLK_STATE_ALLFF 0
-#define BLK_STATE_CLEAN 1
-#define BLK_STATE_PARTDIRTY 2
-#define BLK_STATE_CLEANMARKER 3
-#define BLK_STATE_ALLDIRTY 4
-#define BLK_STATE_BADBLOCK 5
+