Commit e631ddba authored by Ferenc Havasi's avatar Ferenc Havasi Committed by Thomas Gleixner

[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: default avatarFerenc Havasi <havasi@inf.u-szeged.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 15017876
...@@ -1050,6 +1050,19 @@ config JFFS2_FS_WRITEBUFFER ...@@ -1050,6 +1050,19 @@ config JFFS2_FS_WRITEBUFFER
- NOR flash with transparent ECC - NOR flash with transparent ECC
- DataFlash - 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 config JFFS2_COMPRESSION_OPTIONS
bool "Advanced compression options for JFFS2" bool "Advanced compression options for JFFS2"
depends on JFFS2_FS depends on JFFS2_FS
......
# #
# Makefile for the Linux Journalling Flash File System v2 (JFFS2) # 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 obj-$(CONFIG_JFFS2_FS) += jffs2.o
...@@ -15,3 +15,4 @@ jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o ...@@ -15,3 +15,4 @@ jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o
jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
jffs2-$(CONFIG_JFFS2_SUMMARY) += summary.o
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * 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) ...@@ -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_list);
INIT_LIST_HEAD(&c->bad_used_list); INIT_LIST_HEAD(&c->bad_used_list);
c->highest_ino = 1; c->highest_ino = 1;
c->summary = NULL;
if (jffs2_sum_init(c))
return -ENOMEM;
if (jffs2_build_filesystem(c)) { if (jffs2_build_filesystem(c)) {
D1(printk(KERN_DEBUG "build_fs failed\n")); D1(printk(KERN_DEBUG "build_fs failed\n"));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * 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_ #ifndef _JFFS2_DEBUG_H_
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#define JFFS2_DBG_DENTLIST_MESSAGES #define JFFS2_DBG_DENTLIST_MESSAGES
#define JFFS2_DBG_NODEREF_MESSAGES #define JFFS2_DBG_NODEREF_MESSAGES
#define JFFS2_DBG_INOCACHE_MESSAGES #define JFFS2_DBG_INOCACHE_MESSAGES
#define JFFS2_DBG_SUMMARY_MESSAGES
#endif #endif
#if CONFIG_JFFS2_FS_DEBUG == 2 #if CONFIG_JFFS2_FS_DEBUG == 2
...@@ -137,6 +138,13 @@ ...@@ -137,6 +138,13 @@
#define JFFS2_DBG_INOCACHE(fmt, ...) #define JFFS2_DBG_INOCACHE(fmt, ...)
#endif #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 */ /* Watch the object allocations */
#ifdef JFFS2_DBG_MEMALLOC_MESSAGES #ifdef JFFS2_DBG_MEMALLOC_MESSAGES
#define JFFS2_DBG_MEMALLOC(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #define JFFS2_DBG_MEMALLOC(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * 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 ...@@ -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 * Just the node will do for now, though
*/ */
namelen = dentry->d_name.len; 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) { if (ret) {
jffs2_free_raw_inode(ri); jffs2_free_raw_inode(ri);
...@@ -370,7 +371,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ...@@ -370,7 +371,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
up(&f->sem); up(&f->sem);
jffs2_complete_reservation(c); 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) { if (ret) {
/* Eep. */ /* Eep. */
jffs2_clear_inode(inode); jffs2_clear_inode(inode);
...@@ -455,7 +457,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -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 * Just the node will do for now, though
*/ */
namelen = dentry->d_name.len; 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) { if (ret) {
jffs2_free_raw_inode(ri); jffs2_free_raw_inode(ri);
...@@ -498,7 +501,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -498,7 +501,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
up(&f->sem); up(&f->sem);
jffs2_complete_reservation(c); 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) { if (ret) {
/* Eep. */ /* Eep. */
jffs2_clear_inode(inode); jffs2_clear_inode(inode);
...@@ -607,7 +611,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de ...@@ -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 * Just the node will do for now, though
*/ */
namelen = dentry->d_name.len; 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) { if (ret) {
jffs2_free_raw_inode(ri); jffs2_free_raw_inode(ri);
...@@ -652,7 +657,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de ...@@ -652,7 +657,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
up(&f->sem); up(&f->sem);
jffs2_complete_reservation(c); 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) { if (ret) {
/* Eep. */ /* Eep. */
jffs2_clear_inode(inode); jffs2_clear_inode(inode);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * 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, ...@@ -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", 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)); (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) if (ret)
return ret; return ret;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * 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) ...@@ -74,7 +74,8 @@ static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
return -ENOMEM; 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) { if (ret) {
jffs2_free_raw_inode(ri); jffs2_free_raw_inode(ri);
if (S_ISLNK(inode->i_mode & S_IFMT)) if (S_ISLNK(inode->i_mode & S_IFMT))
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * 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, ...@@ -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 /* 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 don't want to force wastage of the end of a block if splitting would
work. */ work. */
ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) +
rawlen), &phys_ofs, &alloclen); 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) if (ret)
return ret; return ret;
...@@ -622,7 +625,9 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, ...@@ -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_sanity_check(c,jeb);
jffs2_dbg_acct_paranoia_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) { if (!ret) {
D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs)); 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,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) { if (ret) {
printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n", printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n",
sizeof(ri)+ mdatalen, ret); sizeof(ri)+ mdatalen, ret);
...@@ -781,7 +787,8 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er ...@@ -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.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8));
rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize)); 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) { if (ret) {
printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n", printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n",
sizeof(rd)+rd.nsize, ret); sizeof(rd)+rd.nsize, ret);
...@@ -994,7 +1001,8 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -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.data_crc = cpu_to_je32(0);
ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); 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) { if (ret) {
printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n", printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n",
sizeof(ri), ret); sizeof(ri), ret);
...@@ -1219,7 +1227,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era ...@@ -1219,7 +1227,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
uint32_t cdatalen; uint32_t cdatalen;
uint16_t comprtype = JFFS2_COMPR_NONE; 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) { if (ret) {
printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n", 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,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); jffs2_gc_release_page(c, pg_ptr, &pg);
return ret; return ret;
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * 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 @@ ...@@ -20,6 +20,7 @@
#include <linux/jffs2.h> #include <linux/jffs2.h>
#include <linux/jffs2_fs_sb.h> #include <linux/jffs2_fs_sb.h>
#include <linux/jffs2_fs_i.h> #include <linux/jffs2_fs_i.h>
#include "summary.h"
#ifdef __ECOS #ifdef __ECOS
#include "os-ecos.h" #include "os-ecos.h"
...@@ -326,8 +327,10 @@ int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode ...@@ -326,8 +327,10 @@ int jffs2_add_older_frag_to_fragtree(struct jffs2_sb_info *c, struct jffs2_inode
/* nodemgmt.c */ /* nodemgmt.c */
int jffs2_thread_should_wake(struct jffs2_sb_info *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(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs,
int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); 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); 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_complete_reservation(struct jffs2_sb_info *c);
void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw); 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,6 +389,10 @@ char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
/* scan.c */ /* scan.c */
int jffs2_scan_medium(struct jffs2_sb_info *c); int jffs2_scan_medium(struct jffs2_sb_info *c);
void jffs2_rotate_lists(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 */ /* build.c */
int jffs2_do_mount_fs(struct jffs2_sb_info *c); int jffs2_do_mount_fs(struct jffs2_sb_info *c);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * 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 @@ ...@@ -17,6 +17,7 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/sched.h> /* For cond_resched() */ #include <linux/sched.h> /* For cond_resched() */
#include "nodelist.h" #include "nodelist.h"
#include "debug.h"
/** /**
* jffs2_reserve_space - request physical space to write nodes to flash * jffs2_reserve_space - request physical space to write nodes to flash
...@@ -38,9 +39,11 @@ ...@@ -38,9 +39,11 @@
* for the requested allocation. * 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 ret = -EAGAIN;
int blocksneeded = c->resv_blocks_write; 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,7 +132,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
spin_lock(&c->erase_completion_lock); 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) { if (ret) {
D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", 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 ...@@ -140,7 +143,8 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
return ret; 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; int ret = -EAGAIN;
minsize = PAD(minsize); minsize = PAD(minsize);
...@@ -149,7 +153,7 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t * ...@@ -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); spin_lock(&c->erase_completion_lock);
while(ret == -EAGAIN) { while(ret == -EAGAIN) {
ret = jffs2_do_reserve_space(c, minsize, ofs, len); ret = jffs2_do_reserve_space(c, minsize, ofs, len, sumsize);
if (ret) { if (ret) {
D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret));
} }
...@@ -158,27 +162,11 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t * ...@@ -158,27 +162,11 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *
return ret; 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)
{
struct jffs2_eraseblock *jeb = c->nextblock;
restart: /* Classify nextblock (clean, dirty of verydirty) and force to select an other one */
if (jeb && minsize > jeb->free_size) {
/* Skip the end of this block and file it as having some dirty space */ static void jffs2_close_nextblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
/* 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);
jeb = c->nextblock;
goto restart;
}
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 */ /* Check, if we have a dirty block now, or if it was dirty already */
if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
...@@ -200,11 +188,16 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui ...@@ -200,11 +188,16 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
list_add_tail(&jeb->list, &c->clean_list); list_add_tail(&jeb->list, &c->clean_list);
} }
c->nextblock = jeb = NULL; c->nextblock = NULL;
}
if (!jeb) { }
/* Select a new jeb for nextblock */
static int jffs2_find_nextblock(struct jffs2_sb_info *c)
{
struct list_head *next; struct list_head *next;
/* Take the next block off the 'free' list */ /* Take the next block off the 'free' list */
if (list_empty(&c->free_list)) { if (list_empty(&c->free_list)) {
...@@ -218,13 +211,13 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui ...@@ -218,13 +211,13 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
list_add_tail(&ejeb->list, &c->erase_pending_list); list_add_tail(&ejeb->list, &c->erase_pending_list);
c->nr_erasing_blocks++; c->nr_erasing_blocks++;
jffs2_erase_pending_trigger(c); jffs2_erase_pending_trigger(c);
D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n", D1(printk(KERN_DEBUG "jffs2_find_nextblock: Triggering erase of erasable block at 0x%08x\n",
ejeb->offset)); ejeb->offset));
} }
if (!c->nr_erasing_blocks && if (!c->nr_erasing_blocks &&
!list_empty(&c->erasable_pending_wbuf_list)) { !list_empty(&c->erasable_pending_wbuf_list)) {
D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); D1(printk(KERN_DEBUG "jffs2_find_nextblock: Flushing write buffer\n"));
/* c->nextblock is NULL, no update to c->nextblock allowed */ /* c->nextblock is NULL, no update to c->nextblock allowed */
spin_unlock(&c->erase_completion_lock); spin_unlock(&c->erase_completion_lock);
jffs2_flush_wbuf_pad(c); jffs2_flush_wbuf_pad(c);
...@@ -255,9 +248,98 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui ...@@ -255,9 +248,98 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
next = c->free_list.next; next = c->free_list.next;
list_del(next); list_del(next);
c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list); c->nextblock = list_entry(next, struct jffs2_eraseblock, list);
c->nr_free_blocks--; c->nr_free_blocks--;
jffs2_sum_reset_collected(c->summary); /* reset collected summary */
D1(printk(KERN_DEBUG "jffs2_find_nextblock(): new nextblock = 0x%08x\n", c->nextblock->offset));
return 0;
}
/* 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;
}
/* 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);
jeb = c->nextblock;
goto restart;
}
c->wasted_size += jeb->free_size;
c->free_size -= jeb->free_size;
jeb->wasted_size += jeb->free_size;
jeb->free_size = 0;
jffs2_close_nextblock(c, jeb);
jeb = NULL;
}
}
if (!jeb) {
ret = jffs2_find_nextblock(c);
if (ret)
return ret;
jeb = c->nextblock;
if (jeb->free_size != c->sector_size - c->cleanmarker_size) { 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); printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
goto restart; goto restart;
...@@ -266,7 +348,7 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui ...@@ -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 /* OK, jeb (==c->nextblock) is now pointing at a block which definitely has
enough space */ enough space */
*ofs = jeb->offset + (c->sector_size - jeb->free_size); *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 && if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
!jeb->first_node->next_in_ino) { !jeb->first_node->next_in_ino) {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * 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) ...@@ -67,12 +67,18 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
#ifndef CONFIG_JFFS2_FS_WRITEBUFFER #ifndef CONFIG_JFFS2_FS_WRITEBUFFER
#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) #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) #define jffs2_can_mark_obsolete(c) (1)
#endif
#define jffs2_is_writebuffered(c) (0) #define jffs2_is_writebuffered(c) (0)
#define jffs2_cleanmarker_oob(c) (0) #define jffs2_cleanmarker_oob(c) (0)
#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) #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_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_pad(c) ({ (void)(c), 0; })
#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 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) ...@@ -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 jffs2_is_writebuffered(c) (c->wbuf != NULL)
#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) #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) \ #define jffs2_can_mark_obsolete(c) \
((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & (MTD_ECC|MTD_PROGRAM_REGIONS))) || \ ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & (MTD_ECC|MTD_PROGRAM_REGIONS))) || \
c->mtd->type == MTD_RAM) c->mtd->type == MTD_RAM)
#endif
#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) #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)) #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,7 +204,8 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c);
/* writev.c */ /* writev.c */
int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen); 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__ */ #endif /* __JFFS2_OS_LINUX_H__ */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * 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> #include <linux/kernel.h>
...@@ -18,22 +18,11 @@ ...@@ -18,22 +18,11 @@
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include "nodelist.h" #include "nodelist.h"
#include "summary.h"
#include "debug.h"
#define DEFAULT_EMPTY_SCAN_SIZE 1024 #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 { \ #define noisy_printk(noise, args...) do { \
if (*(noise)) { \ if (*(noise)) { \
printk(KERN_NOTICE args); \ printk(KERN_NOTICE args); \
...@@ -47,23 +36,16 @@ ...@@ -47,23 +36,16 @@
static uint32_t pseudo_random; static uint32_t pseudo_random;
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 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. /* 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 * Returning an error will abort the mount - bad checksums etc. should just mark the space
* as dirty. * as dirty.
*/ */
static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 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, static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
struct jffs2_raw_dirent *rd, uint32_t ofs); struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s);
#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
static inline int min_free(struct jffs2_sb_info *c) static inline int min_free(struct jffs2_sb_info *c)
{ {
...@@ -89,6 +71,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -89,6 +71,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
uint32_t empty_blocks = 0, bad_blocks = 0; uint32_t empty_blocks = 0, bad_blocks = 0;
unsigned char *flashbuf = NULL; unsigned char *flashbuf = NULL;
uint32_t buf_size = 0; uint32_t buf_size = 0;
struct jffs2_summary *s = NULL; /* summary info collected by the scan process */
#ifndef __ECOS #ifndef __ECOS
size_t pointlen; size_t pointlen;
...@@ -122,10 +105,23 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -122,10 +105,23 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
return -ENOMEM; return -ENOMEM;
} }
if (jffs2_sum_active()) {
s = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
if (!s) {
JFFS2_WARNING("Can't allocate memory for summary\n");
return -ENOMEM;
}
memset(s, 0, sizeof(struct jffs2_summary));
}
for (i=0; i<c->nr_blocks; i++) { for (i=0; i<c->nr_blocks; i++) {
struct jffs2_eraseblock *jeb = &c->blocks[i]; struct jffs2_eraseblock *jeb = &c->blocks[i];
ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size); /* reset summary info for next eraseblock scan */
jffs2_sum_reset_collected(s);
ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
buf_size, s);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -184,7 +180,12 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -184,7 +180,12 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
} else { } else {
list_add(&c->nextblock->list, &c->dirty_list); list_add(&c->nextblock->list, &c->dirty_list);
} }
/* deleting summary information of the old nextblock */
jffs2_sum_reset_collected(c->summary);
} }
/* update collected summary infromation for the current nextblock */
jffs2_sum_move_collected(c, s);
D1(printk(KERN_DEBUG "jffs2_scan_medium(): new nextblock = 0x%08x\n", jeb->offset));
c->nextblock = jeb; c->nextblock = jeb;
} else { } else {
jeb->dirty_size += jeb->free_size + jeb->wasted_size; jeb->dirty_size += jeb->free_size + jeb->wasted_size;
...@@ -221,6 +222,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -221,6 +222,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
} }
} }
if (jffs2_sum_active() && s)
kfree(s);
/* Nextblock dirty is always seen as wasted, because we cannot recycle it now */ /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */
if (c->nextblock && (c->nextblock->dirty_size)) { if (c->nextblock && (c->nextblock->dirty_size)) {
c->nextblock->wasted_size += c->nextblock->dirty_size; c->nextblock->wasted_size += c->nextblock->dirty_size;
...@@ -265,7 +269,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -265,7 +269,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
return ret; return ret;
} }
static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf, int jffs2_fill_scan_buf (struct jffs2_sb_info *c, void *buf,
uint32_t ofs, uint32_t len) uint32_t ofs, uint32_t len)
{ {
int ret; int ret;
...@@ -286,14 +290,36 @@ static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf, ...@@ -286,14 +290,36 @@ static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf,
return 0; return 0;
} }
int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size
&& (!jeb->first_node || !jeb->first_node->next_phys) )
return BLK_STATE_CLEANMARKER;
/* move blocks with max 4 byte dirty space to cleanlist */
else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
c->dirty_size -= jeb->dirty_size;
c->wasted_size += jeb->dirty_size;
jeb->wasted_size += jeb->dirty_size;
jeb->dirty_size = 0;
return BLK_STATE_CLEAN;
} else if (jeb->used_size || jeb->unchecked_size)
return BLK_STATE_PARTDIRTY;
else
return BLK_STATE_ALLDIRTY;
}
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 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) {
struct jffs2_unknown_node *node; struct jffs2_unknown_node *node;
struct jffs2_unknown_node crcnode; struct jffs2_unknown_node crcnode;
struct jffs2_sum_marker *sm;
uint32_t ofs, prevofs; uint32_t ofs, prevofs;
uint32_t hdr_crc, buf_ofs, buf_len; uint32_t hdr_crc, buf_ofs, buf_len;
int err; int err;
int noise = 0; int noise = 0;
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
int cleanmarkerfound = 0; int cleanmarkerfound = 0;
#endif #endif
...@@ -319,10 +345,46 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -319,10 +345,46 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
} }
} }
#endif #endif
if (jffs2_sum_active()) {
sm = kmalloc(sizeof(struct jffs2_sum_marker), GFP_KERNEL);
if (!sm) {
return -ENOMEM;
}
err = jffs2_fill_scan_buf(c, (unsigned char *) sm, jeb->offset + c->sector_size -
sizeof(struct jffs2_sum_marker), sizeof(struct jffs2_sum_marker));
if (err) {
kfree(sm);
return err;
}
if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC ) {
err = jffs2_sum_scan_sumnode(c, jeb, je32_to_cpu(sm->offset), &pseudo_random);
if (err) {
kfree(sm);
return err;
}
}
kfree(sm);
ofs = jeb->offset;
prevofs = jeb->offset - 1;
}
buf_ofs = jeb->offset; buf_ofs = jeb->offset;
if (!buf_size) { if (!buf_size) {
buf_len = c->sector_size; buf_len = c->sector_size;
if (jffs2_sum_active()) {
/* must reread because of summary test */
err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
if (err)
return err;
}
} else { } else {
buf_len = EMPTY_SCAN_SIZE(c->sector_size); buf_len = EMPTY_SCAN_SIZE(c->sector_size);
err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); 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,6 +429,8 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
noise = 10; noise = 10;
JFFS2_DBG_SUMMARY("no summary found in jeb 0x%08x. Apply original scan.\n",jeb->offset);
scan_more: scan_more:
while(ofs < jeb->offset + c->sector_size) { while(ofs < jeb->offset + c->sector_size) {
...@@ -532,7 +596,7 @@ scan_more: ...@@ -532,7 +596,7 @@ scan_more:
buf_ofs = ofs; buf_ofs = ofs;
node = (void *)buf; node = (void *)buf;
} }
err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs); err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs, s);
if (err) return err; if (err) return err;
ofs += PAD(je32_to_cpu(node->totlen)); ofs += PAD(je32_to_cpu(node->totlen));
break; break;
...@@ -548,7 +612,7 @@ scan_more: ...@@ -548,7 +612,7 @@ scan_more:
buf_ofs = ofs; buf_ofs = ofs;
node = (void *)buf; node = (void *)buf;
} }
err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs); err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs, s);
if (err) return err; if (err) return err;
ofs += PAD(je32_to_cpu(node->totlen)); ofs += PAD(je32_to_cpu(node->totlen));
break; break;
...@@ -582,6 +646,8 @@ scan_more: ...@@ -582,6 +646,8 @@ scan_more:
break; break;
case JFFS2_NODETYPE_PADDING: case JFFS2_NODETYPE_PADDING:
if (jffs2_sum_active())
jffs2_sum_add_padding_mem(s, je32_to_cpu(node->totlen));
DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
ofs += PAD(je32_to_cpu(node->totlen)); ofs += PAD(je32_to_cpu(node->totlen));
break; break;
...@@ -616,6 +682,13 @@ scan_more: ...@@ -616,6 +682,13 @@ scan_more:
} }
} }
if (jffs2_sum_active()) {
if (PAD(s->sum_size + JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size) {
JFFS2_DBG_SUMMARY("There is not enough space for "
"summary information, disabling for this jeb!\n");
jffs2_sum_disable_collecting(s);
}
}
D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset,
jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size)); jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size));
...@@ -628,24 +701,10 @@ scan_more: ...@@ -628,24 +701,10 @@ scan_more:
jeb->wasted_size = 0; jeb->wasted_size = 0;
} }
if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size return jffs2_scan_classify_jeb(c, jeb);
&& (!jeb->first_node || !jeb->first_node->next_phys) )
return BLK_STATE_CLEANMARKER;
/* move blocks with max 4 byte dirty space to cleanlist */
else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
c->dirty_size -= jeb->dirty_size;
c->wasted_size += jeb->dirty_size;
jeb->wasted_size += jeb->dirty_size;
jeb->dirty_size = 0;
return BLK_STATE_CLEAN;
} else if (jeb->used_size || jeb->unchecked_size)
return BLK_STATE_PARTDIRTY;
else
return BLK_STATE_ALLDIRTY;
} }
static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino) struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
{ {
struct jffs2_inode_cache *ic; struct jffs2_inode_cache *ic;
...@@ -672,7 +731,7 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info ...@@ -672,7 +731,7 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info
} }
static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 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)
{ {
struct jffs2_raw_node_ref *raw; struct jffs2_raw_node_ref *raw;
struct jffs2_inode_cache *ic; struct jffs2_inode_cache *ic;
...@@ -739,11 +798,16 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc ...@@ -739,11 +798,16 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
pseudo_random += je32_to_cpu(ri->version); pseudo_random += je32_to_cpu(ri->version);
UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen))); UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen)));
if (jffs2_sum_active()) {
jffs2_sum_add_inode_mem(s, ri, ofs - jeb->offset);
}
return 0; return 0;
} }
static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
struct jffs2_raw_dirent *rd, uint32_t ofs) struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s)
{ {
struct jffs2_raw_node_ref *raw; struct jffs2_raw_node_ref *raw;
struct jffs2_full_dirent *fd; struct jffs2_full_dirent *fd;
...@@ -817,6 +881,10 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -817,6 +881,10 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
USED_SPACE(PAD(je32_to_cpu(rd->totlen))); USED_SPACE(PAD(je32_to_cpu(rd->totlen)));
jffs2_add_fd_to_list(c, fd, &ic->scan_dents); jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
if (jffs2_sum_active()) {
jffs2_sum_add_dirent_mem(s, rd, ofs - jeb->offset);
}
return 0; return 0;
} }
......
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
* Zoltan Sogor <weth@inf.u-szeged.hu>,
* Patrik Kluba <pajko@halom.u-szeged.hu>,
* University of Szeged, Hungary
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: summary.c,v 1.1 2005/09/07 08:34:54 havasi Exp $
*
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/pagemap.h>
#include <linux/crc32.h>
#include <linux/compiler.h>
#include <linux/vmalloc.h>
#include "nodelist.h"
#include "debug.h"
int jffs2_sum_init(struct jffs2_sb_info *c)
{
c->summary = kmalloc(sizeof(struct jffs2_summary), GFP_KERNEL);
if (!c->summary) {
JFFS2_WARNING("Can't allocate memory for summary information!\n");
return -ENOMEM;
}
memset(c->summary, 0, sizeof(struct jffs2_summary));
c->summary->sum_buf = vmalloc(c->sector_size);
if (!c->summary->sum_buf) {
JFFS2_WARNING("Can't allocate buffer for writing out summary information!\n");
return -ENOMEM;
}
JFFS2_DBG_SUMMARY("returned succesfully\n");
return 0;
}
void jffs2_sum_exit(struct jffs2_sb_info *c)
{
JFFS2_DBG_SUMMARY("called\n");
jffs2_sum_disable_collecting(c->summary);
vfree(c->summary->sum_buf);
c->summary->sum_buf = NULL;
kfree(c->summary);
c->summary = NULL;
}
static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item)
{
if (!s->sum_list_head)
s->sum_list_head = (union jffs2_sum_mem *) item;
if (s->sum_list_tail)
s->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
s->sum_list_tail = (union jffs2_sum_mem *) item;
switch (je16_to_cpu(item->u.nodetype)) {
case JFFS2_NODETYPE_INODE:
s->sum_size += JFFS2_SUMMARY_INODE_SIZE;
s->sum_num++;
JFFS2_DBG_SUMMARY("inode (%u) added to summary\n",
je32_to_cpu(item->i.inode));
break;
case JFFS2_NODETYPE_DIRENT:
s->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
s->sum_num++;
JFFS2_DBG_SUMMARY("dirent (%u) added to summary\n",
je32_to_cpu(item->d.ino));
break;
default:
JFFS2_WARNING("UNKNOWN node type %u\n",
je16_to_cpu(item->u.nodetype));
return 1;
}
return 0;
}
/* The following 3 functions are called from scan.c to collect summary info for not closed jeb */
int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size)
{
JFFS2_DBG_SUMMARY("called with %u\n", size);
s->sum_padded += size;
return 0;
}
int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri,
uint32_t ofs)
{
struct jffs2_sum_inode_mem *temp = kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
if (!temp)
return -ENOMEM;
temp->nodetype = ri->nodetype;
temp->inode = ri->ino;
temp->version = ri->version;
temp->offset = cpu_to_je32(ofs); /* relative offset from the begining of the jeb */
temp->totlen = ri->totlen;
temp->next = NULL;
return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
}
int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd,
uint32_t ofs)
{
struct jffs2_sum_dirent_mem *temp =
kmalloc(sizeof(struct jffs2_sum_dirent_mem) + rd->nsize, GFP_KERNEL);
if (!temp)
return -ENOMEM;
temp->nodetype = rd->nodetype;
temp->totlen = rd->totlen;
temp->offset = cpu_to_je32(ofs); /* relative from the begining of the jeb */
temp->pino = rd->pino;
temp->version = rd->version;
temp->ino = rd->ino;
temp->nsize = rd->nsize;
temp->type = rd->type;
temp->next = NULL;
memcpy(temp->name, rd->name, rd->nsize);
return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp);
}
/* Cleanup every collected summary information */
static void jffs2_sum_clean_collected(struct jffs2_summary *s)
{
union jffs2_sum_mem *temp;
if (!s->sum_list_head) {
JFFS2_DBG_SUMMARY("already empty\n");
}
while (s->sum_list_head) {
temp = s->sum_list_head;
s->sum_list_head = s->sum_list_head->u.next;
kfree(temp);
}
s->sum_list_tail = NULL;
s->sum_padded = 0;
s->sum_num = 0;
}
void jffs2_sum_reset_collected(struct jffs2_summary *s)
{
JFFS2_DBG_SUMMARY("called\n");
jffs2_sum_clean_collected(s);
s->sum_size = 0;
}
void jffs2_sum_disable_collecting(struct jffs2_summary *s)
{
JFFS2_DBG_SUMMARY("called\n");
jffs2_sum_clean_collected(s);
s->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
}
int jffs2_sum_is_disabled(struct jffs2_summary *s)
{
return (s->sum_size == JFFS2_SUMMARY_NOSUM_SIZE);
}
/* Move the collected summary information into sb (called from scan.c) */
void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s)
{
JFFS2_DBG_SUMMARY("oldsize=0x%x oldnum=%u => newsize=0x%x newnum=%u\n",
c->summary->sum_size, c->summary->sum_num,
s->sum_size, s->sum_num);
c->summary->sum_size = s->sum_size;
c->summary->sum_num = s->sum_num;
c->summary->sum_padded = s->sum_padded;
c->summary->sum_list_head = s->sum_list_head;
c->summary->sum_list_tail = s->sum_list_tail;
s->sum_list_head = s->sum_list_tail = NULL;
}
/* Called from wbuf.c to collect writed node info */
int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
unsigned long count, uint32_t ofs)
{
union jffs2_node_union *node;
struct jffs2_eraseblock *jeb;
node = invecs[0].iov_base;
jeb = &c->blocks[ofs / c->sector_size];
ofs -= jeb->offset;
switch (je16_to_cpu(node->u.nodetype)) {
case JFFS2_NODETYPE_INODE: {
struct jffs2_sum_inode_mem *temp =
kmalloc(sizeof(struct jffs2_sum_inode_mem), GFP_KERNEL);
if (!temp)
goto no_mem;
temp->nodetype = node->i.nodetype;
temp->inode = node->i.ino;
temp->version = node->i.version;
temp->offset = cpu_to_je32(ofs);
temp->totlen = node->i.totlen;
temp->next = NULL;
return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
}
case JFFS2_NODETYPE_DIRENT: {
struct jffs2_sum_dirent_mem *temp =
kmalloc(sizeof(struct jffs2_sum_dirent_mem) + node->d.nsize, GFP_KERNEL);
if (!temp)
goto no_mem;
temp->nodetype = node->d.nodetype;
temp->totlen = node->d.totlen;
temp->offset = cpu_to_je32(ofs);
temp->pino = node->d.pino;
temp->version = node->d.version;
temp->ino = node->d.ino;
temp->nsize = node->d.nsize;
temp->type = node->d.type;
temp->next = NULL;
switch (count) {
case 1:
memcpy(temp->name,node->d.name,node->d.nsize);
break;
case 2:
memcpy(temp->name,invecs[1].iov_base,node->d.nsize);
break;
default:
BUG(); /* impossible count value */
break;
}
return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp);
}
case JFFS2_NODETYPE_PADDING:
JFFS2_DBG_SUMMARY("node PADDING\n");
c->summary->sum_padded += je32_to_cpu(node->u.totlen);
break;
case JFFS2_NODETYPE_CLEANMARKER:
JFFS2_DBG_SUMMARY("node CLEANMARKER\n");
break;
case JFFS2_NODETYPE_SUMMARY:
JFFS2_DBG_SUMMARY("node SUMMARY\n");
break;
default:
/* If you implement a new node type you should also implement
summary support for it or disable summary.
*/
BUG();
break;
}
return 0;
no_mem:
JFFS2_WARNING("MEMORY ALLOCATION ERROR!");
return -ENOMEM;
}
/* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */
static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
struct jffs2_summary_node *summary, uint32_t *pseudo_random)
{
struct jffs2_raw_node_ref *raw;
struct jffs2_inode_cache *ic;
struct jffs2_full_dirent *fd;
void *sp;
int i, ino;
sp = summary->sum;
for (i=0; i<je32_to_cpu(summary->sum_num); i++) {
JFFS2_DBG_SUMMARY("processing summary index %d\n", i);
switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
case JFFS2_NODETYPE_INODE: {
struct jffs2_sum_inode_flash *spi;
spi = sp;
ino = je32_to_cpu(spi->inode);
JFFS2_DBG_SUMMARY("Inode at 0x%08x\n",
jeb->offset + je32_to_cpu(spi->offset));
raw = jffs2_alloc_raw_node_ref();
if (!raw) {
JFFS2_NOTICE("allocation of node reference failed\n");
kfree(summary);
return -ENOMEM;
}
ic = jffs2_scan_make_ino_cache(c, ino);
if (!ic) {
JFFS2_NOTICE("scan_make_ino_cache failed\n");
jffs2_free_raw_node_ref(raw);
kfree(summary);
return -ENOMEM;
}
raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED;
raw->__totlen = PAD(je32_to_cpu(spi->totlen));
raw->next_phys = NULL;
raw->next_in_ino = ic->nodes;
ic->nodes = raw;
if (!jeb->first_node)
jeb->first_node = raw;
if (jeb->last_node)
jeb->last_node->next_phys = raw;
jeb->last_node = raw;
*pseudo_random += je32_to_cpu(spi->version);
UNCHECKED_SPACE(PAD(je32_to_cpu(spi->totlen)));
sp += JFFS2_SUMMARY_INODE_SIZE;
break;
}
case JFFS2_NODETYPE_DIRENT: {
struct jffs2_sum_dirent_flash *spd;
spd = sp;
JFFS2_DBG_SUMMARY("Dirent at 0x%08x\n",
jeb->offset + je32_to_cpu(spd->offset));
fd = jffs2_alloc_full_dirent(spd->nsize+1);
if (!fd) {
kfree(summary);
return -ENOMEM;
}
memcpy(&fd->name, spd->name, spd->nsize);
fd->name[spd->nsize] = 0;
raw = jffs2_alloc_raw_node_ref();
if (!raw) {
jffs2_free_full_dirent(fd);
JFFS2_NOTICE("allocation of node reference failed\n");
kfree(summary);
return -ENOMEM;
}
ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
if (!ic) {
jffs2_free_full_dirent(fd);
jffs2_free_raw_node_ref(raw);
kfree(summary);
return -ENOMEM;
}
raw->__totlen = PAD(je32_to_cpu(spd->totlen));
raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE;
raw->next_phys = NULL;
raw->next_in_ino = ic->nodes;
ic->nodes = raw;
if (!jeb->first_node)
jeb->first_node = raw;
if (jeb->last_node)
jeb->last_node->next_phys = raw;
jeb->last_node = raw;
fd->raw = raw;
fd->next = NULL;
fd->version = je32_to_cpu(spd->version);
fd->ino = je32_to_cpu(spd->ino);
fd->nhash = full_name_hash(fd->name, spd->nsize);
fd->type = spd->type;
USED_SPACE(PAD(je32_to_cpu(spd->totlen)));
jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
*pseudo_random += je32_to_cpu(spd->version);
sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);
break;
}
default : {
JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
kfree(summary);
return -EIO;
}
}
}
kfree(summary);
return 0;
}
/* Process the summary node - called from jffs2_scan_eraseblock() */
int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
uint32_t ofs, uint32_t *pseudo_random)
{
struct jffs2_unknown_node crcnode;
struct jffs2_raw_node_ref *cache_ref;
struct jffs2_summary_node *summary;
int ret, sumsize;
uint32_t crc;
sumsize = c->sector_size - ofs;
ofs += jeb->offset;
JFFS2_DBG_SUMMARY("summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
jeb->offset, ofs, sumsize);
summary = kmalloc(sumsize, GFP_KERNEL);
if (!summary) {
return -ENOMEM;
}
ret = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize);
if (ret) {
kfree(summary);
return ret;
}
/* OK, now check for node validity and CRC */
crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
crcnode.totlen = summary->totlen;
crc = crc32(0, &crcnode, sizeof(crcnode)-4);
if (je32_to_cpu(summary->hdr_crc) != crc) {
JFFS2_DBG_SUMMARY("Summary node header is corrupt (bad CRC or "
"no summary at all)\n");
goto crc_err;
}
if (je32_to_cpu(summary->totlen) != sumsize) {
JFFS2_DBG_SUMMARY("Summary node is corrupt (wrong erasesize?)\n");
goto crc_err;
}
crc = crc32(0, summary, sizeof(struct jffs2_summary_node)-8);
if (je32_to_cpu(summary->node_crc) != crc) {
JFFS2_DBG_SUMMARY("Summary node is corrupt (bad CRC)\n");
goto crc_err;
}
crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_summary_node));
if (je32_to_cpu(summary->sum_crc) != crc) {
JFFS2_DBG_SUMMARY("Summary node data is corrupt (bad CRC)\n");
goto crc_err;
}
if ( je32_to_cpu(summary->cln_mkr) ) {
JFFS2_DBG_SUMMARY("Summary : CLEANMARKER node \n");
if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) {
JFFS2_DBG_SUMMARY("CLEANMARKER node has totlen 0x%x != normal 0x%x\n",
je32_to_cpu(summary->cln_mkr), c->cleanmarker_size);
UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
} else if (jeb->first_node) {
JFFS2_DBG_SUMMARY("CLEANMARKER node not first node in block "
"(0x%08x)\n", jeb->offset);
UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
} else {
struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
if (!marker_ref) {
JFFS2_NOTICE("Failed to allocate node ref for clean marker\n");
kfree(summary);
return -ENOMEM;
}
marker_ref->next_in_ino = NULL;
marker_ref->next_phys = NULL;
marker_ref->flash_offset = jeb->offset | REF_NORMAL;
marker_ref->__totlen = je32_to_cpu(summary->cln_mkr);
jeb->first_node = jeb->last_node = marker_ref;
USED_SPACE( PAD(je32_to_cpu(summary->cln_mkr)) );
}
}
if (je32_to_cpu(summary->padded)) {
DIRTY_SPACE(je32_to_cpu(summary->padded));
}
ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random);
if (ret)
return ret;
/* for PARANOIA_CHECK */
cache_ref = jffs2_alloc_raw_node_ref();
if (!cache_ref) {
JFFS2_NOTICE("Failed to allocate node ref for cache\n");
return -ENOMEM;
}
cache_ref->next_in_ino = NULL;
cache_ref->next_phys = NULL;
cache_ref->flash_offset = ofs | REF_NORMAL;
cache_ref->__totlen = sumsize;
if (!jeb->first_node)
jeb->first_node = cache_ref;
if (jeb->last_node)
jeb->last_node->next_phys = cache_ref;
jeb->last_node = cache_ref;
USED_SPACE(sumsize);
jeb->wasted_size += jeb->free_size;
c->wasted_size += jeb->free_size;
c->free_size -= jeb->free_size;
jeb->free_size = 0;
return jffs2_scan_classify_jeb(c, jeb);
crc_err:
JFFS2_WARNING("Summary node crc error, skipping summary information.\n");
return 0;
}
/* Write summary data to flash - helper function for jffs2_sum_write_sumnode() */
static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
uint32_t infosize, uint32_t datasize, int padsize)
{
struct jffs2_summary_node isum;
union jffs2_sum_mem *temp;
struct jffs2_sum_marker *sm;
struct kvec vecs[2];
void *wpage;
int ret;
size_t retlen;
memset(c->summary->sum_buf, 0xff, datasize);
memset(&isum, 0, sizeof(isum));
isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
isum.totlen = cpu_to_je32(infosize);
isum.hdr_crc = cpu_to_je32(crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
isum.padded = cpu_to_je32(c->summary->sum_padded);
isum.cln_mkr = cpu_to_je32(c->cleanmarker_size);
isum.sum_num = cpu_to_je32(c->summary->sum_num);
wpage = c->summary->sum_buf;
while (c->summary->sum_num) {
switch (je16_to_cpu(c->summary->sum_list_head->u.nodetype)) {
case JFFS2_NODETYPE_INODE: {
struct jffs2_sum_inode_flash *sino_ptr = wpage;
sino_ptr->nodetype = c->summary->sum_list_head->i.nodetype;
sino_ptr->inode = c->summary->sum_list_head->i.inode;
sino_ptr->version = c->summary->sum_list_head->i.version;
sino_ptr->offset = c->summary->sum_list_head->i.offset;
sino_ptr->totlen = c->summary->sum_list_head->i.totlen;
wpage += JFFS2_SUMMARY_INODE_SIZE;
break;
}
case JFFS2_NODETYPE_DIRENT: {
struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage;
sdrnt_ptr->nodetype = c->summary->sum_list_head->d.nodetype;
sdrnt_ptr->totlen = c->summary->sum_list_head->d.totlen;
sdrnt_ptr->offset = c->summary->sum_list_head->d.offset;
sdrnt_ptr->pino = c->summary->sum_list_head->d.pino;
sdrnt_ptr->version = c->summary->sum_list_head->d.version;
sdrnt_ptr->ino = c->summary->sum_list_head->d.ino;
sdrnt_ptr->nsize = c->summary->sum_list_head->d.nsize;
sdrnt_ptr->type = c->summary->sum_list_head->d.type;
memcpy(sdrnt_ptr->name, c->summary->sum_list_head->d.name,
c->summary->sum_list_head->d.nsize);
wpage += JFFS2_SUMMARY_DIRENT_SIZE(c->summary->sum_list_head->d.nsize);
break;
}
default : {
BUG(); /* unknown node in summary information */
}
}
temp = c->summary->sum_list_head;
c->summary->sum_list_head = c->summary->sum_list_head->u.next;
kfree(temp);
c->summary->sum_num--;
}
jffs2_sum_reset_collected(c->summary);
wpage += padsize;
sm = wpage;
sm->offset = cpu_to_je32(c->sector_size - jeb->free_size);
sm->magic = cpu_to_je32(JFFS2_SUM_MAGIC);
isum.sum_crc = cpu_to_je32(crc32(0, c->summary->sum_buf, datasize));
isum.node_crc = cpu_to_je32(crc32(0, &isum, sizeof(isum) - 8));
vecs[0].iov_base = &isum;
vecs[0].iov_len = sizeof(isum);
vecs[1].iov_base = c->summary->sum_buf;
vecs[1].iov_len = datasize;
JFFS2_DBG_SUMMARY("JFFS2: writing out data to flash to pos : 0x%08x\n",
jeb->offset + c->sector_size - jeb->free_size);
spin_unlock(&c->erase_completion_lock);
ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size -
jeb->free_size, &retlen, 0);
spin_lock(&c->erase_completion_lock);
if (ret || (retlen != infosize)) {
JFFS2_WARNING("Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n",
infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen);
c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
WASTED_SPACE(infosize);
return 1;
}
return 0;
}
/* Write out summary information - called from jffs2_do_reserve_space */
int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
{
struct jffs2_raw_node_ref *summary_ref;
int datasize, infosize, padsize, ret;
struct jffs2_eraseblock *jeb;
JFFS2_DBG_SUMMARY("called\n");
jeb = c->nextblock;
if (!c->summary->sum_num || !c->summary->sum_list_head) {
JFFS2_WARNING("Empty summary info!!!\n");
BUG();
}
datasize = c->summary->sum_size + sizeof(struct jffs2_sum_marker);
infosize = sizeof(struct jffs2_summary_node) + datasize;
padsize = jeb->free_size - infosize;
infosize += padsize;
datasize += padsize;
/* Is there enough space for summary? */
if (padsize < 0) {
/* don't try to write out summary for this jeb */
jffs2_sum_disable_collecting(c->summary);
JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize);
return 0;
}
ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize);
if (ret)
return 0; /* can't write out summary, block is marked as NOSUM_SIZE */
/* for ACCT_PARANOIA_CHECK */
spin_unlock(&c->erase_completion_lock);
summary_ref = jffs2_alloc_raw_node_ref();
spin_lock(&c->erase_completion_lock);
if (!summary_ref) {
JFFS2_NOTICE("Failed to allocate node ref for summary\n");
return -ENOMEM;
}
summary_ref->next_in_ino = NULL;
summary_ref->next_phys = NULL;
summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL;
summary_ref->__totlen = infosize;
if (!jeb->first_node)
jeb->first_node = summary_ref;
if (jeb->last_node)
jeb->last_node->next_phys = summary_ref;
jeb->last_node = summary_ref;
USED_SPACE(infosize);
return 0;
}
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
* Zoltan Sogor <weth@inf.u-szeged.hu>,
* Patrik Kluba <pajko@halom.u-szeged.hu>,
* University of Szeged, Hungary
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: summary.h,v 1.1 2005/09/07 08:34:54 havasi Exp $
*
*/
#ifndef JFFS2_SUMMARY_H
#define JFFS2_SUMMARY_H
#include <linux/uio.h>
#include <linux/jffs2.h>
#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 WASTED_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->wasted_size += _x; \
jeb->free_size -= _x ; jeb->wasted_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 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
#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
/* Summary structures used on flash */
struct jffs2_sum_unknown_flash
{
jint16_t nodetype; /* node type */
};
struct jffs2_sum_inode_flash
{
jint16_t nodetype; /* node type */
jint32_t inode; /* inode number */
jint32_t version; /* inode version */
jint32_t offset; /* offset on jeb */
jint32_t totlen; /* record length */
} __attribute__((packed));
struct jffs2_sum_dirent_flash
{
jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
jint32_t totlen; /* record length */
jint32_t offset; /* offset on jeb */
jint32_t pino; /* parent inode */
jint32_t version; /* dirent version */
jint32_t ino; /* == zero for unlink */
uint8_t nsize; /* dirent name size */
uint8_t type; /* dirent type */
uint8_t name[0]; /* dirent name */
} __attribute__((packed));
union jffs2_sum_flash
{
struct jffs2_sum_unknown_flash u;
struct jffs2_sum_inode_flash i;
struct jffs2_sum_dirent_flash d;
};
/* Summary structures used in the memory */
struct jffs2_sum_unknown_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype; /* node type */
};
struct jffs2_sum_inode_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype; /* node type */
jint32_t inode; /* inode number */
jint32_t version; /* inode version */
jint32_t offset; /* offset on jeb */
jint32_t totlen; /* record length */
} __attribute__((packed));
struct jffs2_sum_dirent_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
jint32_t totlen; /* record length */
jint32_t offset; /* ofset on jeb */
jint32_t pino; /* parent inode */
jint32_t version; /* dirent version */
jint32_t ino; /* == zero for unlink */
uint8_t nsize; /* dirent name size */
uint8_t type; /* dirent type */
uint8_t name[0]; /* dirent name */
} __attribute__((packed));
union jffs2_sum_mem
{
struct jffs2_sum_unknown_mem u;
struct jffs2_sum_inode_mem i;
struct jffs2_sum_dirent_mem d;
};
/* Summary related information stored in superblock */
struct jffs2_summary
{
uint32_t sum_size; /* collected summary information for nextblock */
uint32_t sum_num;
uint32_t sum_padded;
union jffs2_sum_mem *sum_list_head;
union jffs2_sum_mem *sum_list_tail;
jint32_t *sum_buf; /* buffer for writing out summary */
};
/* Summary marker is stored at the end of every sumarized erase block */
struct jffs2_sum_marker
{
jint32_t offset; /* offset of the summary node in the jeb */
jint32_t magic; /* == JFFS2_SUM_MAGIC */
};
#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_summary_node) + sizeof(struct jffs2_sum_marker))
#ifdef CONFIG_JFFS2_SUMMARY /* SUMMARY SUPPORT ENABLED */
#define jffs2_sum_active() (1)
int jffs2_sum_init(struct jffs2_sb_info *c);
void jffs2_sum_exit(struct jffs2_sb_info *c);
void jffs2_sum_disable_collecting(struct jffs2_summary *s);
int jffs2_sum_is_disabled(struct jffs2_summary *s);
void jffs2_sum_reset_collected(struct jffs2_summary *s);
void jffs2_sum_move_collected(struct jffs2_sb_info *c, struct jffs2_summary *s);
int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs,
unsigned long count, uint32_t to);
int jffs2_sum_write_sumnode(struct jffs2_sb_info *c);
int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size);
int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs);
int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs);
int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
uint32_t ofs, uint32_t *pseudo_random);
#else /* SUMMARY DISABLED */
#define jffs2_sum_active() (0)
#define jffs2_sum_init(a) (0)
#define jffs2_sum_exit(a)
#define jffs2_sum_disable_collecting(a)
#define jffs2_sum_is_disabled(a) (0)
#define jffs2_sum_reset_collected(a)
#define jffs2_sum_add_kvec(a,b,c,d) (0)
#define jffs2_sum_move_collected(a,b)
#define jffs2_sum_write_sumnode(a) (0)
#define jffs2_sum_add_padding_mem(a,b)
#define jffs2_sum_add_inode_mem(a,b,c)
#define jffs2_sum_add_dirent_mem(a,b,c)
#define jffs2_sum_scan_sumnode(a,b,c,d) (0)
#endif /* CONFIG_JFFS2_SUMMARY */
#endif /* JFFS2_SUMMARY_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: super.c,v 1.108 2005/08/31 13:51:00 havasi Exp $ * $Id: super.c,v 1.109 2005/09/07 08:34:55 havasi Exp $
* *
*/ */
...@@ -282,6 +282,9 @@ static void jffs2_put_super (struct super_block *sb) ...@@ -282,6 +282,9 @@ static void jffs2_put_super (struct super_block *sb)
down(&c->alloc_sem); down(&c->alloc_sem);
jffs2_flush_wbuf_pad(c); jffs2_flush_wbuf_pad(c);
up(&c->alloc_sem); up(&c->alloc_sem);
jffs2_sum_exit(c);
jffs2_free_ino_caches(c); jffs2_free_ino_caches(c);
jffs2_free_raw_node_refs(c); jffs2_free_raw_node_refs(c);
if (jffs2_blocks_use_vmalloc(c)) if (jffs2_blocks_use_vmalloc(c))
...@@ -320,6 +323,9 @@ static int __init init_jffs2_fs(void) ...@@ -320,6 +323,9 @@ static int __init init_jffs2_fs(void)
printk(KERN_INFO "JFFS2 version 2.2." printk(KERN_INFO "JFFS2 version 2.2."
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
" (NAND)" " (NAND)"
#endif
#ifdef CONFIG_JFFS2_SUMMARY
" (SUMMARY) "
#endif #endif
" (C) 2001-2003 Red Hat, Inc.\n"); " (C) 2001-2003 Red Hat, Inc.\n");
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: wbuf.c,v 1.97 2005/08/06 04:51:30 nico Exp $ * $Id: wbuf.c,v 1.98 2005/09/07 08:34:55 havasi Exp $
* *
*/ */
...@@ -265,7 +265,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ...@@ -265,7 +265,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
/* ... and get an allocation of space from a shiny new block instead */ /* ... and get an allocation of space from a shiny new block instead */
ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len); ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len, JFFS2_SUMMARY_NOSUM_SIZE);
if (ret) { if (ret) {
printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
kfree(buf); kfree(buf);
...@@ -836,6 +836,12 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig ...@@ -836,6 +836,12 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
alldone: alldone:
*retlen = donelen; *retlen = donelen;
if (jffs2_sum_active()) {
int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to);
if (res)
return res;
}
if (c->wbuf_len && ino) if (c->wbuf_len && ino)
jffs2_wbuf_dirties_inode(c, ino); jffs2_wbuf_dirties_inode(c, ino);
...@@ -855,7 +861,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r ...@@ -855,7 +861,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r
struct kvec vecs[1]; struct kvec vecs[1];
if (!jffs2_is_writebuffered(c)) if (!jffs2_is_writebuffered(c))
return c->mtd->write(c->mtd, ofs, len, retlen, buf); return jffs2_flash_direct_write(c, ofs, len, retlen, buf);
vecs[0].iov_base = (unsigned char *) buf; vecs[0].iov_base = (unsigned char *) buf;
vecs[0].iov_len = len; vecs[0].iov_len = len;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: write.c,v 1.95 2005/08/17 13:46:23 dedekind Exp $ * $Id: write.c,v 1.96 2005/09/07 08:34:55 havasi Exp $
* *
*/ */
...@@ -153,13 +153,15 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 ...@@ -153,13 +153,15 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
jffs2_dbg_acct_paranoia_check(c, jeb); jffs2_dbg_acct_paranoia_check(c, jeb);
if (alloc_mode == ALLOC_GC) { if (alloc_mode == ALLOC_GC) {
ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy); ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs,
&dummy, JFFS2_SUMMARY_INODE_SIZE);
} else { } else {
/* Locking pain */ /* Locking pain */
up(&f->sem); up(&f->sem);
jffs2_complete_reservation(c); jffs2_complete_reservation(c);
ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode); ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs,
&dummy, alloc_mode, JFFS2_SUMMARY_INODE_SIZE);
down(&f->sem); down(&f->sem);
} }
...@@ -299,13 +301,15 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff ...@@ -299,13 +301,15 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
jffs2_dbg_acct_paranoia_check(c, jeb); jffs2_dbg_acct_paranoia_check(c, jeb);
if (alloc_mode == ALLOC_GC) { if (alloc_mode == ALLOC_GC) {
ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy); ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs,
&dummy, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
} else { } else {
/* Locking pain */ /* Locking pain */
up(&f->sem); up(&f->sem);
jffs2_complete_reservation(c); jffs2_complete_reservation(c);
ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode); ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs,
&dummy, alloc_mode, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
down(&f->sem); down(&f->sem);
} }
...@@ -362,7 +366,8 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, ...@@ -362,7 +366,8 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
retry: retry:
D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset)); D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset));
ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL); ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs,
&alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
if (ret) { if (ret) {
D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
break; break;
...@@ -449,7 +454,8 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str ...@@ -449,7 +454,8 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
/* Try to reserve enough space for both node and dirent. /* Try to reserve enough space for both node and dirent.
* Just the node will do for now, though * Just the node will do for now, though
*/ */
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);
D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
if (ret) { if (ret) {
up(&f->sem); up(&f->sem);
...@@ -478,7 +484,8 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str ...@@ -478,7 +484,8 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
up(&f->sem); up(&f->sem);
jffs2_complete_reservation(c); 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) { if (ret) {
/* Eep. */ /* Eep. */
...@@ -549,7 +556,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, ...@@ -549,7 +556,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
if (!rd) if (!rd)
return -ENOMEM; return -ENOMEM;
ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION); ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen,
ALLOC_DELETION, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
if (ret) { if (ret) {
jffs2_free_raw_dirent(rd); jffs2_free_raw_dirent(rd);
return ret; return ret;
...@@ -658,7 +666,8 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint ...@@ -658,7 +666,8 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
if (!rd) if (!rd)
return -ENOMEM; return -ENOMEM;
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) { if (ret) {
jffs2_free_raw_dirent(rd); jffs2_free_raw_dirent(rd);
return ret; return ret;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: writev.c,v 1.6 2004/11/16 20:36:12 dwmw2 Exp $ * $Id: writev.c,v 1.7 2005/09/07 08:34:55 havasi Exp $
* *
*/ */
...@@ -44,7 +44,37 @@ int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs, ...@@ -44,7 +44,37 @@ int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct kvec *vecs,
{ {
if (c->mtd->writev) if (c->mtd->writev)
return c->mtd->writev(c->mtd, vecs, count, to, retlen); return c->mtd->writev(c->mtd, vecs, count, to, retlen);
else else {
if (jffs2_sum_active()) {
int res;
res = jffs2_sum_add_kvec(c, vecs, count, (uint32_t) to);
if (res) {
return res;
}
}
return mtd_fake_writev(c->mtd, vecs, count, to, retlen); return mtd_fake_writev(c->mtd, vecs, count, to, retlen);
}
} }
int jffs2_flash_direct_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
size_t *retlen, const u_char *buf)
{
int ret;
ret = c->mtd->write(c->mtd, ofs, len, retlen, buf);
if (jffs2_sum_active()) {
struct kvec vecs[1];
int res;
vecs[0].iov_base = (unsigned char *) buf;
vecs[0].iov_len = len;
res = jffs2_sum_add_kvec(c, vecs, 1, (uint32_t) ofs);
if (res) {
return res;
}
}
return ret;
}
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* For licensing information, see the file 'LICENCE' in the * For licensing information, see the file 'LICENCE' in the
* jffs2 directory. * jffs2 directory.
* *
* $Id: jffs2.h,v 1.36 2005/07/26 13:19:36 havasi Exp $ * $Id: jffs2.h,v 1.37 2005/09/07 08:34:55 havasi Exp $
* *
*/ */
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
#define JFFS2_EMPTY_BITMASK 0xffff #define JFFS2_EMPTY_BITMASK 0xffff
#define JFFS2_DIRTY_BITMASK 0x0000 #define JFFS2_DIRTY_BITMASK 0x0000
/* Summary node MAGIC marker */
#define JFFS2_SUM_MAGIC 0x02851885
/* We only allow a single char for length, and 0xFF is empty flash so /* We only allow a single char for length, and 0xFF is empty flash so
we don't want it confused with a real length. Hence max 254. we don't want it confused with a real length. Hence max 254.
*/ */
...@@ -60,6 +63,8 @@ ...@@ -60,6 +63,8 @@
#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) #define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
// Maybe later... // Maybe later...
//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
...@@ -146,10 +151,24 @@ struct jffs2_raw_inode ...@@ -146,10 +151,24 @@ struct jffs2_raw_inode
uint8_t data[0]; uint8_t data[0];
} __attribute__((packed)); } __attribute__((packed));
struct jffs2_summary_node{
jint16_t magic;
jint16_t nodetype; /* = JFFS2_NODETYPE_INODE_SUM */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t sum_num; /* number of sum entries*/
jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */
jint32_t padded; /* sum of the size of padding nodes */
jint32_t sum_crc; /* summary information crc */
jint32_t node_crc; /* node crc */
jint32_t sum[0]; /* inode summary info */
} __attribute__((packed));
union jffs2_node_union { union jffs2_node_union {
struct jffs2_raw_inode i; struct jffs2_raw_inode i;
struct jffs2_raw_dirent d; struct jffs2_raw_dirent d;
struct jffs2_unknown_node u; struct jffs2_unknown_node u;
struct jffs2_summary_node s;
}; };
#endif /* __LINUX_JFFS2_H__ */ #endif /* __LINUX_JFFS2_H__ */
/* $Id: jffs2_fs_sb.h,v 1.52 2005/05/19 16:12:17 gleixner Exp $ */ /* $Id: jffs2_fs_sb.h,v 1.53 2005/09/07 08:34:56 havasi Exp $ */
#ifndef _JFFS2_FS_SB #ifndef _JFFS2_FS_SB
#define _JFFS2_FS_SB #define _JFFS2_FS_SB
...@@ -112,6 +112,8 @@ struct jffs2_sb_info { ...@@ -112,6 +112,8 @@ struct jffs2_sb_info {
uint32_t fsdata_len; uint32_t fsdata_len;
#endif #endif
struct jffs2_summary *summary; /* Summary information */
/* OS-private pointer for getting back to master superblock info */ /* OS-private pointer for getting back to master superblock info */
void *os_priv; void *os_priv;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment