Skip to content

Commit

Permalink
[JFFS2] Add erase block summary support (mount time improvement)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ferenc Havasi authored and Thomas Gleixner committed Nov 6, 2005
1 parent 1501787 commit e631ddb
Show file tree
Hide file tree
Showing 20 changed files with 1,395 additions and 199 deletions.
13 changes: 13 additions & 0 deletions fs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion fs/jffs2/Makefile
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
12 changes: 8 additions & 4 deletions fs/jffs2/build.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 $
*
*/

Expand Down Expand Up @@ -350,18 +350,22 @@ 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"));
jffs2_free_ino_caches(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;
}

Expand Down
10 changes: 9 additions & 1 deletion fs/jffs2/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_
Expand All @@ -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
Expand Down Expand Up @@ -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__)
Expand Down
20 changes: 13 additions & 7 deletions fs/jffs2/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 $
*
*/

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions fs/jffs2/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 $
*
*/

Expand Down Expand Up @@ -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;

Expand Down
5 changes: 3 additions & 2 deletions fs/jffs2/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 $
*
*/

Expand Down Expand Up @@ -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))
Expand Down
26 changes: 17 additions & 9 deletions fs/jffs2/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 $
*
*/

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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;
}

13 changes: 10 additions & 3 deletions fs/jffs2/nodelist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 $
*
*/

Expand All @@ -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"
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit e631ddb

Please sign in to comment.