diff options
| author | David Woodhouse <dwmw2@infradead.org> | 2003-05-28 18:03:33 +0100 |
|---|---|---|
| committer | David Woodhouse <dwmw2@infradead.org> | 2003-05-28 18:03:33 +0100 |
| commit | 5af017c0de780cb463b784ef909406ce397332ee (patch) | |
| tree | ecfae73f9c51082ebe4cbe6d228adcba21ca524d /fs | |
| parent | 015498d534572f8a9c3bf5f1dfc02bd02bfb2c9d (diff) | |
MTD and JFFS2 update.
- JFFS2 bugfixes and performance improvements
- Support for 64-bit flash arrangements
- Optimise for linear mappings of flash, without out-of-line access functions
- New map drivers
- Updated NAND flash support, new board drivers
- Support for DiskOnChip Millennium Plus and INFTL translation layer
- Clean up all translation layers with a single blkdev helper library.
- Fix races in MTD device registration/deregistration
- Add support for new flash chips
- Clean up partition parsing code
More detailed comments in per-file changelogs.
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/jffs2/background.c | 30 | ||||
| -rw-r--r-- | fs/jffs2/build.c | 28 | ||||
| -rw-r--r-- | fs/jffs2/compr.c | 5 | ||||
| -rw-r--r-- | fs/jffs2/compr_rtime.c | 6 | ||||
| -rw-r--r-- | fs/jffs2/compr_zlib.c | 129 | ||||
| -rw-r--r-- | fs/jffs2/dir.c | 31 | ||||
| -rw-r--r-- | fs/jffs2/erase.c | 74 | ||||
| -rw-r--r-- | fs/jffs2/file.c | 36 | ||||
| -rw-r--r-- | fs/jffs2/fs.c | 58 | ||||
| -rw-r--r-- | fs/jffs2/gc.c | 436 | ||||
| -rw-r--r-- | fs/jffs2/malloc.c | 41 | ||||
| -rw-r--r-- | fs/jffs2/nodelist.c | 135 | ||||
| -rw-r--r-- | fs/jffs2/nodelist.h | 31 | ||||
| -rw-r--r-- | fs/jffs2/nodemgmt.c | 114 | ||||
| -rw-r--r-- | fs/jffs2/os-linux.h | 35 | ||||
| -rw-r--r-- | fs/jffs2/read.c | 9 | ||||
| -rw-r--r-- | fs/jffs2/readinode.c | 261 | ||||
| -rw-r--r-- | fs/jffs2/scan.c | 41 | ||||
| -rw-r--r-- | fs/jffs2/super.c | 23 | ||||
| -rw-r--r-- | fs/jffs2/wbuf.c | 178 | ||||
| -rw-r--r-- | fs/jffs2/write.c | 42 |
21 files changed, 1211 insertions, 532 deletions
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index f72b1107c766..3cc44044a70a 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: background.c,v 1.33 2002/11/12 09:44:30 dwmw2 Exp $ + * $Id: background.c,v 1.38 2003/05/26 09:50:38 dwmw2 Exp $ * */ @@ -16,9 +16,8 @@ #include <linux/kernel.h> #include <linux/jffs2.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> #include <linux/completion.h> -#include <linux/mtd/compatmac.h> /* recalc_sigpending() */ +#include <linux/sched.h> #include <linux/unistd.h> #include "nodelist.h" @@ -28,10 +27,10 @@ static int thread_should_wake(struct jffs2_sb_info *c); void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) { - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (c->gc_task && thread_should_wake(c)) send_sig(SIGHUP, c->gc_task, 1); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); } /* This must only ever be called when no GC thread is currently running */ @@ -69,12 +68,12 @@ void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) flush_scheduled_work(); } - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (c->gc_task) { D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid)); send_sig(SIGKILL, c->gc_task, 1); } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); wait_for_completion(&c->gc_thread_exit); } @@ -126,9 +125,9 @@ static int jffs2_garbage_collect_thread(void *_c) case SIGKILL: D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n")); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); c->gc_task = NULL; - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); complete_and_exit(&c->gc_thread_exit, 0); case SIGHUP: @@ -152,6 +151,7 @@ static int jffs2_garbage_collect_thread(void *_c) static int thread_should_wake(struct jffs2_sb_info *c) { int ret = 0; + uint32_t dirty; if (c->unchecked_size) { D1(printk(KERN_DEBUG "thread_should_wake(): unchecked_size %d, checked_ino #%d\n", @@ -159,8 +159,18 @@ static int thread_should_wake(struct jffs2_sb_info *c) return 1; } + /* dirty_size contains blocks on erase_pending_list + * those blocks are counted in c->nr_erasing_blocks. + * If one block is actually erased, it is not longer counted as dirty_space + * but it is counted in c->nr_erasing_blocks, so we add it and subtract it + * with c->nr_erasing_blocks * c->sector_size again. + * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks + * This helps us to force gc and pick eventually a clean block to spread the load. + */ + dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size; + if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER && - (c->dirty_size > c->sector_size)) + (dirty > c->sector_size)) ret = 1; D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index 2049d0d1e4d2..01a575d6bfae 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -7,19 +7,42 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: build.c,v 1.42 2002/09/09 16:29:08 dwmw2 Exp $ + * $Id: build.c,v 1.46 2003/04/29 17:12:26 gleixner Exp $ * */ #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/slab.h> #include "nodelist.h" int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *); int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *); +static inline struct jffs2_inode_cache * +first_inode_chain(int *i, struct jffs2_sb_info *c) +{ + for (; *i < INOCACHE_HASHSIZE; (*i)++) { + if (c->inocache_list[*i]) + return c->inocache_list[*i]; + } + return NULL; +} + +static inline struct jffs2_inode_cache * +next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c) +{ + /* More in this chain? */ + if (ic->next) + return ic->next; + (*i)++; + return first_inode_chain(i, c); +} -#define for_each_inode(i, c, ic) for (i=0; i<INOCACHE_HASHSIZE; i++) for (ic=c->inocache_list[i]; ic; ic=ic->next) +#define for_each_inode(i, c, ic) \ + for (i = 0, ic = first_inode_chain(&i, (c)); \ + ic; \ + ic = next_inode(&i, ic, (c))) /* Scan plan: - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go @@ -229,6 +252,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) init_MUTEX(&c->alloc_sem); init_MUTEX(&c->erase_free_sem); init_waitqueue_head(&c->erase_wait); + init_waitqueue_head(&c->inocache_wq); spin_lock_init(&c->erase_completion_lock); spin_lock_init(&c->inocache_lock); diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 5750fc2aac6e..a2479e837acd 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -7,14 +7,15 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr.c,v 1.24 2002/05/20 14:56:37 dwmw2 Exp $ + * $Id: compr.c,v 1.26 2003/01/12 13:21:28 dwmw2 Exp $ * */ -#ifdef __KERNEL__ +#if defined(__KERNEL__) || defined (__ECOS) #include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> +#include <linux/types.h> #else #define KERN_DEBUG #define KERN_NOTICE diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 83dfe53fe91b..9dec50194a2c 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr_rtime.c,v 1.9 2002/05/20 14:56:37 dwmw2 Exp $ + * $Id: compr_rtime.c,v 1.10 2003/05/11 10:47:13 dwmw2 Exp $ * * * Very simple lz77-ish encoder. @@ -30,7 +30,7 @@ int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen) { - int positions[256]; + short positions[256]; int outpos = 0; int pos=0; @@ -70,7 +70,7 @@ int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen) { - int positions[256]; + short positions[256]; int outpos = 0; int pos=0; diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index e1dbbbf169ec..76ad2570a301 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c @@ -7,20 +7,22 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr_zlib.c,v 1.18 2002/05/20 14:56:37 dwmw2 Exp $ + * $Id: compr_zlib.c,v 1.23 2003/05/26 09:15:19 dwmw2 Exp $ * */ -#ifndef __KERNEL__ +#if !defined(__KERNEL__) && !defined(__ECOS) #error "The userspace support got too messy and was removed. Update your mkfs.jffs2" #endif #include <linux/config.h> #include <linux/kernel.h> -#include <linux/mtd/compatmac.h> /* for min() */ +#include <linux/vmalloc.h> +#include <linux/init.h> #include <linux/slab.h> -#include <linux/jffs2.h> #include <linux/zlib.h> +#include <linux/zutil.h> +#include <asm/semaphore.h> #include "nodelist.h" /* Plan: call deflate() with avail_in == *sourcelen, @@ -34,21 +36,21 @@ static DECLARE_MUTEX(deflate_sem); static DECLARE_MUTEX(inflate_sem); -static void *deflate_workspace; -static void *inflate_workspace; +static z_stream inf_strm, def_strm; +#ifdef __KERNEL__ /* Linux-only */ int __init jffs2_zlib_init(void) { - deflate_workspace = vmalloc(zlib_deflate_workspacesize()); - if (!deflate_workspace) { + def_strm.workspace = vmalloc(zlib_deflate_workspacesize()); + if (!def_strm.workspace) { printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize()); return -ENOMEM; } D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize())); - inflate_workspace = vmalloc(zlib_inflate_workspacesize()); - if (!inflate_workspace) { + inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); + if (!inf_strm.workspace) { printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize()); - vfree(deflate_workspace); + vfree(def_strm.workspace); return -ENOMEM; } D1(printk(KERN_DEBUG "Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize())); @@ -57,97 +59,120 @@ int __init jffs2_zlib_init(void) void jffs2_zlib_exit(void) { - vfree(deflate_workspace); - vfree(inflate_workspace); + vfree(def_strm.workspace); + vfree(inf_strm.workspace); } +#endif /* __KERNEL__ */ int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen) { - z_stream strm; int ret; if (*dstlen <= STREAM_END_SPACE) return -1; down(&deflate_sem); - strm.workspace = deflate_workspace; - if (Z_OK != zlib_deflateInit(&strm, 3)) { + if (Z_OK != zlib_deflateInit(&def_strm, 3)) { printk(KERN_WARNING "deflateInit failed\n"); up(&deflate_sem); return -1; } - strm.next_in = data_in; - strm.total_in = 0; + def_strm.next_in = data_in; + def_strm.total_in = 0; - strm.next_out = cpage_out; - strm.total_out = 0; + def_strm.next_out = cpage_out; + def_strm.total_out = 0; - while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) { - strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE); - strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out); + while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) { + def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE); + def_strm.avail_in = min((unsigned)(*sourcelen-def_strm.total_in), def_strm.avail_out); D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n", - strm.avail_in, strm.avail_out)); - ret = zlib_deflate(&strm, Z_PARTIAL_FLUSH); + def_strm.avail_in, def_strm.avail_out)); + ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH); D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", - strm.avail_in, strm.avail_out, strm.total_in, strm.total_out)); + def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out)); if (ret != Z_OK) { D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret)); - zlib_deflateEnd(&strm); + zlib_deflateEnd(&def_strm); up(&deflate_sem); return -1; } } - strm.avail_out += STREAM_END_SPACE; - strm.avail_in = 0; - ret = zlib_deflate(&strm, Z_FINISH); - zlib_deflateEnd(&strm); - up(&deflate_sem); + def_strm.avail_out += STREAM_END_SPACE; + def_strm.avail_in = 0; + ret = zlib_deflate(&def_strm, Z_FINISH); + zlib_deflateEnd(&def_strm); + if (ret != Z_STREAM_END) { D1(printk(KERN_DEBUG "final deflate returned %d\n", ret)); - return -1; + ret = -1; + goto out; } - D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", - strm.total_in, strm.total_out)); + if (def_strm.total_out >= def_strm.total_in) { + D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld; failing\n", + def_strm.total_in, def_strm.total_out)); + ret = -1; + goto out; + } - if (strm.total_out >= strm.total_in) - return -1; + D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", + def_strm.total_in, def_strm.total_out)); - *dstlen = strm.total_out; - *sourcelen = strm.total_in; - return 0; + *dstlen = def_strm.total_out; + *sourcelen = def_strm.total_in; + ret = 0; + out: + up(&deflate_sem); + return ret; } void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen) { - z_stream strm; int ret; + int wbits = MAX_WBITS; down(&inflate_sem); - strm.workspace = inflate_workspace; - if (Z_OK != zlib_inflateInit(&strm)) { + inf_strm.next_in = data_in; + inf_strm.avail_in = srclen; + inf_strm.total_in = 0; + + inf_strm.next_out = cpage_out; + inf_strm.avail_out = destlen; + inf_strm.total_out = 0; + + /* If it's deflate, and it's got no preset dictionary, then + we can tell zlib to skip the adler32 check. */ + if (srclen > 2 && !(data_in[1] & PRESET_DICT) && + ((data_in[0] & 0x0f) == Z_DEFLATED) && + !(((data_in[0]<<8) + data_in[1]) % 31)) { + + D2(printk(KERN_DEBUG "inflate skipping adler32\n")); + wbits = -((data_in[0] >> 4) + 8); + inf_strm.next_in += 2; + inf_strm.avail_in -= 2; + } else { + /* Let this remain D1 for now -- it should never happen */ + D1(printk(KERN_DEBUG "inflate not skipping adler32\n")); + } + + + if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) { printk(KERN_WARNING "inflateInit failed\n"); up(&inflate_sem); return; } - strm.next_in = data_in; - strm.avail_in = srclen; - strm.total_in = 0; - - strm.next_out = cpage_out; - strm.avail_out = destlen; - strm.total_out = 0; - while((ret = zlib_inflate(&strm, Z_FINISH)) == Z_OK) + while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK) ; if (ret != Z_STREAM_END) { printk(KERN_NOTICE "inflate returned %d\n", ret); } - zlib_inflateEnd(&strm); + zlib_inflateEnd(&inf_strm); up(&inflate_sem); } diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 9c60f565699a..dceb9cbce3b9 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: dir.c,v 1.73 2002/08/26 15:00:51 dwmw2 Exp $ + * $Id: dir.c,v 1.76 2003/05/26 09:50:38 dwmw2 Exp $ * */ @@ -16,13 +16,20 @@ #include <linux/sched.h> #include <linux/fs.h> #include <linux/crc32.h> -#include <linux/mtd/compatmac.h> /* For completion */ #include <linux/jffs2.h> #include <linux/jffs2_fs_i.h> #include <linux/jffs2_fs_sb.h> #include <linux/time.h> #include "nodelist.h" +/* Urgh. Please tell me there's a nicer way of doing this. */ +#include <linux/version.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48) +typedef int mknod_arg_t; +#else +typedef dev_t mknod_arg_t; +#endif + static int jffs2_readdir (struct file *, void *, filldir_t); static int jffs2_create (struct inode *,struct dentry *,int); @@ -32,7 +39,7 @@ static int jffs2_unlink (struct inode *,struct dentry *); static int jffs2_symlink (struct inode *,struct dentry *,const char *); static int jffs2_mkdir (struct inode *,struct dentry *,int); static int jffs2_rmdir (struct inode *,struct dentry *); -static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t); +static int jffs2_mknod (struct inode *,struct dentry *,int,mknod_arg_t); static int jffs2_rename (struct inode *, struct dentry *, struct inode *, struct dentry *); @@ -211,8 +218,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode) return ret; } - dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(ri->ctime); - dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0; + dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime)); jffs2_free_raw_inode(ri); d_instantiate(dentry, inode); @@ -402,8 +408,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char return PTR_ERR(fd); } - dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(rd->mctime); - dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0; + dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); jffs2_free_raw_dirent(rd); @@ -540,8 +545,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) return PTR_ERR(fd); } - dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(rd->mctime); - dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0; + dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); dir_i->i_nlink++; jffs2_free_raw_dirent(rd); @@ -573,7 +577,7 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) return ret; } -static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev) +static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mknod_arg_t rdev) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; @@ -583,7 +587,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; - unsigned short dev; + jint16_t dev; int devlen = 0; uint32_t alloclen, phys_ofs; uint32_t writtenlen; @@ -596,7 +600,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de c = JFFS2_SB_INFO(dir_i->i_sb); if (S_ISBLK(mode) || S_ISCHR(mode)) { - dev = (MAJOR(rdev) << 8) | MINOR(rdev); + dev = cpu_to_je16((MAJOR(rdev) << 8) | MINOR(rdev)); devlen = sizeof(dev); } @@ -704,8 +708,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de return PTR_ERR(fd); } - dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(rd->mctime); - dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0; + dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); jffs2_free_raw_dirent(rd); diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index ada5721b730f..6e4327692e8d 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -7,16 +7,17 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: erase.c,v 1.45 2002/10/09 08:27:08 dwmw2 Exp $ + * $Id: erase.c,v 1.51 2003/05/11 22:47:36 dwmw2 Exp $ * */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> #include <linux/compiler.h> #include <linux/crc32.h> +#include <linux/sched.h> +#include <linux/pagemap.h> #include "nodelist.h" struct erase_priv_struct { @@ -24,7 +25,10 @@ struct erase_priv_struct { struct jffs2_sb_info *c; }; +#ifndef __ECOS static void jffs2_erase_callback(struct erase_info *); +#endif +static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); @@ -32,16 +36,25 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { int ret; +#ifdef __ECOS + ret = jffs2_flash_erase(c, jeb); + if (!ret) { + jffs2_erase_succeeded(c, jeb); + return; + } +#else /* Linux */ struct erase_info *instr; instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); if (!instr) { printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); list_del(&jeb->list); list_add(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; - spin_unlock_bh(&c->erase_completion_lock); + c->dirty_size += c->sector_size; + jeb->dirty_size = c->sector_size; + spin_unlock(&c->erase_completion_lock); return; } @@ -65,15 +78,18 @@ void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) return; kfree(instr); +#endif /* __ECOS */ if (ret == -ENOMEM || ret == -EAGAIN) { /* Erase failed immediately. Refile it on the list */ D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); list_del(&jeb->list); list_add(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; - spin_unlock_bh(&c->erase_completion_lock); + c->dirty_size += c->sector_size; + jeb->dirty_size = c->sector_size; + spin_unlock(&c->erase_completion_lock); return; } @@ -82,20 +98,7 @@ void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) else printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret); - /* Note: This is almost identical to jffs2_erase_failed() except - for the fact that we used spin_lock_bh() not spin_lock(). If - we could use spin_lock_bh() from a BH, we could merge them. - Or if we abandon the idea that MTD drivers may call the erase - callback from a BH, I suppose :) - */ - spin_lock_bh(&c->erase_completion_lock); - c->erasing_size -= c->sector_size; - c->bad_size += c->sector_size; - list_del(&jeb->list); - list_add(&jeb->list, &c->bad_list); - c->nr_erasing_blocks--; - spin_unlock_bh(&c->erase_completion_lock); - wake_up(&c->erase_wait); + jffs2_erase_failed(c, jeb); } void jffs2_erase_pending_blocks(struct jffs2_sb_info *c) @@ -104,7 +107,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c) down(&c->erase_free_sem); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); while (!list_empty(&c->erase_complete_list) || !list_empty(&c->erase_pending_list)) { @@ -112,7 +115,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c) if (!list_empty(&c->erase_complete_list)) { jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); list_del(&jeb->list); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); jffs2_mark_erased_block(c, jeb); } else if (!list_empty(&c->erase_pending_list)) { @@ -126,7 +129,7 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c) jeb->used_size = jeb->dirty_size = jeb->free_size = 0; jffs2_free_all_node_refs(c, jeb); list_add(&jeb->list, &c->erasing_list); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); jffs2_erase_block(c, jeb); @@ -136,10 +139,10 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c) /* Be nice */ cond_resched(); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); up(&c->erase_free_sem); @@ -156,8 +159,7 @@ static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblo jffs2_erase_pending_trigger(c); } - -static inline void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { spin_lock(&c->erase_completion_lock); c->erasing_size -= c->sector_size; @@ -169,6 +171,7 @@ static inline void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eras wake_up(&c->erase_wait); } +#ifndef __ECOS static void jffs2_erase_callback(struct erase_info *instr) { struct erase_priv_struct *priv = (void *)instr->priv; @@ -181,6 +184,7 @@ static void jffs2_erase_callback(struct erase_info *instr) } kfree(instr); } +#endif /* !__ECOS */ /* Hmmm. Maybe we should accept the extra space it takes and make this a standard doubly-linked list? */ @@ -290,9 +294,9 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); /* Stick it back on the list from whence it came and come back later */ jffs2_erase_pending_trigger(c); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); list_add(&jeb->list, &c->erase_complete_list); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); return; } } @@ -313,7 +317,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb goto bad; } if (retlen != readlen) { - printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %d\n", ofs, readlen, retlen); + printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen); goto bad; } for (i=0; i<readlen; i += sizeof(unsigned long)) { @@ -328,13 +332,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb jffs2_write_nand_badblock( c ,jeb ); kfree(ebuf); bad2: - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); c->erasing_size -= c->sector_size; c->bad_size += c->sector_size; list_add_tail(&jeb->list, &c->bad_list); c->nr_erasing_blocks--; - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); wake_up(&c->erase_wait); return; } @@ -374,7 +378,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb goto bad2; } if (retlen != je32_to_cpu(marker.totlen)) { - printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %d\n", + printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %zd\n", jeb->offset, je32_to_cpu(marker.totlen), retlen); goto bad2; } @@ -392,7 +396,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb jeb->wasted_size = 0; } - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); c->erasing_size -= c->sector_size; c->free_size += jeb->free_size; c->used_size += jeb->used_size; @@ -403,7 +407,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb list_add_tail(&jeb->list, &c->free_list); c->nr_erasing_blocks--; c->nr_free_blocks++; - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); wake_up(&c->erase_wait); } diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index f7fadfa10640..4d241373dc15 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -7,12 +7,11 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: file.c,v 1.81 2002/11/12 09:46:22 dwmw2 Exp $ + * $Id: file.c,v 1.85 2003/05/26 09:50:38 dwmw2 Exp $ * */ #include <linux/kernel.h> -#include <linux/mtd/compatmac.h> /* for min() */ #include <linux/slab.h> #include <linux/fs.h> #include <linux/time.h> @@ -153,17 +152,20 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr) if (ivalid & ATTR_MODE) if (iattr->ia_mode & S_ISGID && !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID)) - ri->mode = cpu_to_je32(iattr->ia_mode & ~S_ISGID); + ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID); else - ri->mode = cpu_to_je32(iattr->ia_mode); + ri->mode = cpu_to_jemode(iattr->ia_mode); else - ri->mode = cpu_to_je32(inode->i_mode); + ri->mode = cpu_to_jemode(inode->i_mode); ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size); - ri->atime = cpu_to_je32((ivalid & ATTR_ATIME)?iattr->ia_atime.tv_sec:inode->i_atime.tv_sec); - ri->mtime = cpu_to_je32((ivalid & ATTR_MTIME)?iattr->ia_mtime.tv_sec:inode->i_mtime.tv_sec); - ri->ctime = cpu_to_je32((ivalid & ATTR_CTIME)?iattr->ia_ctime.tv_sec:inode->i_ctime.tv_sec); + ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime)); + ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime)); + ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime)); + + ri->offset = cpu_to_je32(0); + ri->csize = ri->dsize = cpu_to_je32(mdatalen); ri->compr = JFFS2_COMPR_NONE; if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { /* It's an extension. Make it a hole node */ @@ -188,13 +190,10 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr) return PTR_ERR(new_metadata); } /* It worked. Update the inode */ - inode->i_atime.tv_sec = je32_to_cpu(ri->atime); - inode->i_ctime.tv_sec = je32_to_cpu(ri->ctime); - inode->i_mtime.tv_sec = je32_to_cpu(ri->mtime); - inode->i_atime.tv_nsec = - inode->i_ctime.tv_nsec = - inode->i_mtime.tv_nsec = 0; - inode->i_mode = je32_to_cpu(ri->mode); + inode->i_atime = ITIME(je32_to_cpu(ri->atime)); + inode->i_ctime = ITIME(je32_to_cpu(ri->ctime)); + inode->i_mtime = ITIME(je32_to_cpu(ri->mtime)); + inode->i_mode = jemode_to_cpu(ri->mode); inode->i_uid = je16_to_cpu(ri->uid); inode->i_gid = je16_to_cpu(ri->gid); @@ -309,7 +308,7 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns ri.ino = cpu_to_je32(f->inocache->ino); ri.version = cpu_to_je32(++f->highest_version); - ri.mode = cpu_to_je32(inode->i_mode); + ri.mode = cpu_to_jemode(inode->i_mode); ri.uid = cpu_to_je16(inode->i_uid); ri.gid = cpu_to_je16(inode->i_gid); ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs)); @@ -390,7 +389,7 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi /* Set the fields that the generic jffs2_write_inode_range() code can't find */ ri->ino = cpu_to_je32(inode->i_ino); - ri->mode = cpu_to_je32(inode->i_mode); + ri->mode = cpu_to_jemode(inode->i_mode); ri->uid = cpu_to_je16(inode->i_uid); ri->gid = cpu_to_je16(inode->i_gid); ri->isize = cpu_to_je32((uint32_t)inode->i_size); @@ -416,8 +415,7 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen; inode->i_blocks = (inode->i_size + 511) >> 9; - inode->i_ctime.tv_sec = inode->i_mtime.tv_sec = je32_to_cpu(ri->ctime); - inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0; + inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime)); } } diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index b785d9a36055..a027504cd82d 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs.c,v 1.19 2002/11/12 09:53:40 dwmw2 Exp $ + * $Id: fs.c,v 1.24 2003/04/29 09:52:58 dwmw2 Exp $ * */ @@ -16,7 +16,6 @@ #include <linux/sched.h> #include <linux/fs.h> #include <linux/list.h> -#include <linux/interrupt.h> #include <linux/mtd/mtd.h> #include <linux/pagemap.h> #include <linux/slab.h> @@ -35,7 +34,7 @@ int jffs2_statfs(struct super_block *sb, struct statfs *buf) buf->f_ffree = 0; buf->f_namelen = JFFS2_MAX_NAME_LEN; - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); avail = c->dirty_size + c->free_size; if (avail > c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE) @@ -47,7 +46,7 @@ int jffs2_statfs(struct super_block *sb, struct statfs *buf) D1(jffs2_dump_block_lists(c)); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); return 0; } @@ -87,16 +86,13 @@ void jffs2_read_inode (struct inode *inode) up(&f->sem); return; } - inode->i_mode = je32_to_cpu(latest_node.mode); + inode->i_mode = jemode_to_cpu(latest_node.mode); inode->i_uid = je16_to_cpu(latest_node.uid); inode->i_gid = je16_to_cpu(latest_node.gid); inode->i_size = je32_to_cpu(latest_node.isize); - inode->i_atime.tv_sec = je32_to_cpu(latest_node.atime); - inode->i_mtime.tv_sec = je32_to_cpu(latest_node.mtime); - inode->i_ctime.tv_sec = je32_to_cpu(latest_node.ctime); - inode->i_atime.tv_nsec = - inode->i_mtime.tv_nsec = - inode->i_ctime.tv_nsec = 0; + inode->i_atime = ITIME(je32_to_cpu(latest_node.atime)); + inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime)); + inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime)); inode->i_nlink = f->inocache->nlink; @@ -104,7 +100,7 @@ void jffs2_read_inode (struct inode *inode) inode->i_blocks = (inode->i_size + 511) >> 9; switch (inode->i_mode & S_IFMT) { - unsigned short rdev; + jint16_t rdev; case S_IFLNK: inode->i_op = &jffs2_symlink_inode_operations; @@ -151,7 +147,7 @@ void jffs2_read_inode (struct inode *inode) case S_IFSOCK: case S_IFIFO: inode->i_op = &jffs2_file_inode_operations; - init_special_inode(inode, inode->i_mode, kdev_t_to_nr(mk_kdev(rdev>>8, rdev&0xff))); + init_special_inode(inode, inode->i_mode, kdev_t_to_nr(mk_kdev(je16_to_cpu(rdev)>>8, je16_to_cpu(rdev)&0xff))); break; default: @@ -232,7 +228,7 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i } else { ri->gid = cpu_to_je16(current->fsgid); } - ri->mode = cpu_to_je32(mode); + ri->mode = cpu_to_jemode(mode); ret = jffs2_do_new_inode (c, f, mode, ri); if (ret) { make_bad_inode(inode); @@ -241,12 +237,11 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i } inode->i_nlink = 1; inode->i_ino = je32_to_cpu(ri->ino); - inode->i_mode = je32_to_cpu(ri->mode); + inode->i_mode = jemode_to_cpu(ri->mode); inode->i_gid = je16_to_cpu(ri->gid); inode->i_uid = je16_to_cpu(ri->uid); - inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0; - inode->i_atime.tv_sec = inode->i_ctime.tv_sec = inode->i_mtime.tv_sec = get_seconds(); - ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime.tv_sec); + inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; + ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime)); inode->i_blksize = PAGE_SIZE; inode->i_blocks = 0; @@ -263,27 +258,32 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) struct jffs2_sb_info *c; struct inode *root_i; int ret; + size_t blocks; c = JFFS2_SB_INFO(sb); - c->sector_size = c->mtd->erasesize; c->flash_size = c->mtd->size; -#if 0 - if (c->sector_size < 0x10000) { - printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using 64KiB instead\n", - c->sector_size / 1024); - c->sector_size = 0x10000; - } -#endif + /* + * Check, if we have to concatenate physical blocks to larger virtual blocks + * to reduce the memorysize for c->blocks. (kmalloc allows max. 128K allocation) + */ + blocks = c->flash_size / c->mtd->erasesize; + while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) + blocks >>= 1; + + c->sector_size = c->flash_size / blocks; + if (c->sector_size != c->mtd->erasesize) + printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n", + c->mtd->erasesize / 1024, c->sector_size / 1024); + if (c->flash_size < 5*c->sector_size) { - printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", - c->flash_size / c->sector_size); + printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size); return -EINVAL; } c->cleanmarker_size = sizeof(struct jffs2_unknown_node); - /* Jörn -- stick alignment for weird 8-byte-page flash here */ + /* Joern -- stick alignment for weird 8-byte-page flash here */ if (jffs2_cleanmarker_oob(c)) { /* Cleanmarker is out-of-band, so inline size zero */ diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 6a36bbbd0e5a..a715475bdec7 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -7,19 +7,22 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: gc.c,v 1.88 2002/10/08 16:56:08 dwmw2 Exp $ + * $Id: gc.c,v 1.103 2003/05/22 18:01:02 dwmw2 Exp $ * */ #include <linux/kernel.h> #include <linux/mtd/mtd.h> #include <linux/slab.h> -#include <linux/interrupt.h> #include <linux/pagemap.h> #include <linux/crc32.h> #include <linux/compiler.h> +#include <linux/stat.h> #include "nodelist.h" +static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, + struct jffs2_inode_cache *ic, + struct jffs2_raw_node_ref *raw); static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dnode *fd); static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, @@ -32,6 +35,8 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, uint32_t start, uint32_t end); +static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic); /* Called with erase_completion_lock held */ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) @@ -107,61 +112,87 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) */ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) { + struct jffs2_inode_cache *ic; struct jffs2_eraseblock *jeb; - struct jffs2_inode_info *f; struct jffs2_raw_node_ref *raw; - struct jffs2_node_frag *frag; - struct jffs2_full_dnode *fn = NULL; - struct jffs2_full_dirent *fd; - uint32_t start = 0, end = 0, nrfrags = 0; uint32_t inum; - struct inode *inode; int ret = 0; if (down_interruptible(&c->alloc_sem)) return -EINTR; - spin_lock_bh(&c->erase_completion_lock); + for (;;) { + spin_lock(&c->erase_completion_lock); + if (!c->unchecked_size) + break; - while (c->unchecked_size) { /* We can't start doing GC yet. We haven't finished checking - the node CRCs etc. Do it now and wait for it. */ - struct jffs2_inode_cache *ic; - + the node CRCs etc. Do it now. */ + + /* checked_ino is protected by the alloc_sem */ if (c->checked_ino > c->highest_ino) { printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n", c->unchecked_size); D1(jffs2_dump_block_lists(c)); + spin_unlock(&c->erase_completion_lock); BUG(); } + + spin_unlock(&c->erase_completion_lock); + + spin_lock(&c->inocache_lock); + ic = jffs2_get_ino_cache(c, c->checked_ino++); - if (!ic) + + if (!ic) { + spin_unlock(&c->inocache_lock); continue; + } + if (!ic->nlink) { D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n", ic->ino)); + spin_unlock(&c->inocache_lock); continue; } - if (ic->state != INO_STATE_UNCHECKED) { - D1(printk(KERN_DEBUG "Skipping check of ino #%d already in state %d\n", - ic->ino, ic->state)); + switch(ic->state) { + case INO_STATE_CHECKEDABSENT: + case INO_STATE_PRESENT: + D1(printk(KERN_DEBUG "Skipping ino #%u already checked\n", ic->ino)); + spin_unlock(&c->inocache_lock); continue; - } - spin_unlock_bh(&c->erase_completion_lock); + case INO_STATE_GC: + case INO_STATE_CHECKING: + printk(KERN_WARNING "Inode #%u is in state %d during CRC check phase!\n", ic->ino, ic->state); + spin_unlock(&c->inocache_lock); + BUG(); - D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%d\n", ic->ino)); - - { - /* XXX: This wants doing more sensibly -- split the core of jffs2_do_read_inode up */ - struct inode *i = iget(OFNI_BS_2SFFJ(c), ic->ino); - if (is_bad_inode(i)) { - printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", ic->ino); - ret = -EIO; - } - iput(i); + case INO_STATE_READING: + /* We need to wait for it to finish, lest we move on + and trigger the BUG() above while we haven't yet + finished checking all its nodes */ + D1(printk(KERN_DEBUG "Waiting for ino #%u to finish reading\n", ic->ino)); + up(&c->alloc_sem); + sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); + return 0; + + default: + BUG(); + + case INO_STATE_UNCHECKED: + ; } + ic->state = INO_STATE_CHECKING; + spin_unlock(&c->inocache_lock); + D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%d\n", ic->ino)); + + ret = jffs2_do_crccheck_inode(c, ic); + if (ret) + printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino); + + jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); up(&c->alloc_sem); return ret; } @@ -174,7 +205,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) if (!jeb) { printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); up(&c->alloc_sem); return -EIO; } @@ -197,7 +228,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n"); printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); up(&c->alloc_sem); BUG(); } @@ -207,7 +238,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) /* Inode-less node. Clean marker, snapshot or something like that */ /* FIXME: If it's something that needs to be copied, including something we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); jffs2_mark_node_obsolete(c, raw); up(&c->alloc_sem); goto eraseit_lock; @@ -216,13 +247,136 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) inum = jffs2_raw_ref_to_inum(raw); D1(printk(KERN_DEBUG "Inode number is #%u\n", inum)); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); + + D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), inum)); + + /* Three possibilities: + 1. Inode is already in-core. We must iget it and do proper + updating to its fragtree, etc. + 2. Inode is not in-core, node is REF_PRISTINE. We lock the + inocache to prevent a read_inode(), copy the node intact. + 3. Inode is not in-core, node is not pristine. We must iget() + and take the slow path. + */ + spin_lock(&c->inocache_lock); + ic = jffs2_get_ino_cache(c, inum); + + /* This should never fail unless I'm particularly stupid. + So we don't check before dereferencing it */ + + switch(ic->state) { + case INO_STATE_CHECKEDABSENT: + /* It's been checked, but it's not currently in-core. + We can just copy any pristine nodes, but have + to prevent anyone else from doing read_inode() while + we're at it, so we set the state accordingly */ + if (ref_flags(raw) == REF_PRISTINE) + ic->state = INO_STATE_GC; + else { + D1(printk("Ino #%u is absent but node not REF_PRISTINE. Reading.\n", + inum)); + } + break; + + case INO_STATE_PRESENT: + case INO_STATE_UNCHECKED: + /* It's in-core or hasn't been checked. GC must iget() it. */ + break; + + case INO_STATE_CHECKING: + /* Should never happen. We should have finished checking + by the time we actually start doing any GC. */ + BUG(); + + + case INO_STATE_GC: + /* Should never happen. We are holding the alloc_sem, + no other garbage collection can happen. Note that we + do depend on this later when deciding to do a simple + node copy */ + BUG(); + + case INO_STATE_READING: + /* Someone's currently trying to read it. We must wait for + them to finish and then go through the full iget() route + to do the GC. However, sometimes read_inode() needs to get + the alloc_sem() (for marking nodes invalid) so we must + drop the alloc_sem before sleeping. */ + + up(&c->alloc_sem); + D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n", + inum, ic->state)); + sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); + /* And because we dropped the alloc_sem we must start again from the + beginning. Ponder chance of livelock here -- we're returning success + without actually making any progress. + + Q: What are the chances that the inode is back in INO_STATE_READING + again by the time we next enter this function? And that this happens + enough times to cause a real delay? + + A: Small enough that I don't care :) + */ + return 0; + + } + + spin_unlock(&c->inocache_lock); + + /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the + node intact, and we don't have to muck about with the fragtree etc. + because we know it's not in-core. If it _was_ in-core, we go through + all the iget() crap anyway */ + + if (ic->state == INO_STATE_GC) { + ret = jffs2_garbage_collect_pristine(c, ic, raw); + jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); + + if (ret != -EBADFD) + goto release_sem; + + /* Fall through if it wanted us to */ + } + + ret = jffs2_garbage_collect_live(c, jeb, raw, ic); + + release_sem: + up(&c->alloc_sem); + + eraseit_lock: + /* If we've finished this block, start it erasing */ + spin_lock(&c->erase_completion_lock); + + eraseit: + if (c->gcblock && !c->gcblock->used_size) { + D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset)); + /* We're GC'ing an empty block? */ + list_add_tail(&c->gcblock->list, &c->erase_pending_list); + c->gcblock = NULL; + c->nr_erasing_blocks++; + jffs2_erase_pending_trigger(c); + } + spin_unlock(&c->erase_completion_lock); + + return ret; +} - D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x, ino #%u\n", jeb->offset, ref_offset(raw), inum)); - inode = iget(OFNI_BS_2SFFJ(c), inum); +static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic) +{ + struct jffs2_inode_info *f; + struct jffs2_node_frag *frag; + struct jffs2_full_dnode *fn = NULL; + struct jffs2_full_dirent *fd; + uint32_t start = 0, end = 0, nrfrags = 0; + struct inode *inode; + int ret = 0; + + inode = iget(OFNI_BS_2SFFJ(c), ic->ino); if (is_bad_inode(inode)) { - printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", inum); + printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", ic->ino); /* NB. This will happen again. We need to do something appropriate here. */ up(&c->alloc_sem); iput(inode); @@ -254,16 +408,26 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) end = frag->ofs + frag->size; #if 1 /* Temporary debugging sanity checks, till we're ready to _trust_ the REF_PRISTINE flag stuff */ if (!nrfrags && ref_flags(fn->raw) == REF_PRISTINE) { - if (fn->frags > 1) + if (fn->frags > 1) { printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(raw), fn->frags); - - if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->node) + mark_ref_normal(raw); + } + /* A hole node which isn't multi-page should be garbage-collected + and merged anyway, so we just check for the frag size here, + rather than mucking around with actually reading the node + and checking the compression type, which is the real way + to tell a hole node. */ + if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE) { printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n", ref_offset(raw)); + mark_ref_normal(raw); + } - if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->node) + if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE) { printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n", ref_offset(raw), frag->ofs, frag->ofs+frag->size); + mark_ref_normal(raw); + } } #endif if (!nrfrags++) @@ -273,6 +437,15 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) } } if (fn) { + if (ref_flags(raw) == REF_PRISTINE) { + ret = jffs2_garbage_collect_pristine(c, ic, raw); + if (!ret) { + /* Urgh. Return it sensibly. */ + frag->node->raw = ic->nodes; + } + if (ret != -EBADFD) + goto upnout; + } /* We found a datanode. Do the GC */ if((start >> PAGE_CACHE_SHIFT) < ((end-1) >> PAGE_CACHE_SHIFT)) { /* It crosses a page boundary. Therefore, it must be a hole. */ @@ -305,25 +478,145 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) } upnout: up(&f->sem); - up(&c->alloc_sem); iput(inode); - eraseit_lock: - /* If we've finished this block, start it erasing */ - spin_lock_bh(&c->erase_completion_lock); + return ret; +} - eraseit: - if (c->gcblock && !c->gcblock->used_size) { - D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset)); - /* We're GC'ing an empty block? */ - list_add_tail(&c->gcblock->list, &c->erase_pending_list); - c->gcblock = NULL; - c->nr_erasing_blocks++; - jffs2_erase_pending_trigger(c); +static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, + struct jffs2_inode_cache *ic, + struct jffs2_raw_node_ref *raw) +{ + union jffs2_node_union *node; + struct jffs2_raw_node_ref *nraw; + size_t retlen; + int ret; + uint32_t phys_ofs, alloclen; + uint32_t crc; + + D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw))); + + /* 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, raw->totlen), + &phys_ofs, &alloclen); + if (ret) + return ret; + + if (alloclen < raw->totlen) { + /* Doesn't fit untouched. We'll go the old route and split it */ + return -EBADFD; + } + + node = kmalloc(raw->totlen, GFP_KERNEL); + if (!node) + return -ENOMEM; + + ret = jffs2_flash_read(c, ref_offset(raw), raw->totlen, &retlen, (char *)node); + if (!ret && retlen != raw->totlen) + ret = -EIO; + if (ret) + goto out_node; + + crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4); + if (je32_to_cpu(node->u.hdr_crc) != crc) { + printk(KERN_WARNING "Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc); + goto bail; + } + + switch(je16_to_cpu(node->u.nodetype)) { + case JFFS2_NODETYPE_INODE: + crc = crc32(0, node, sizeof(node->i)-8); + if (je32_to_cpu(node->i.node_crc) != crc) { + printk(KERN_WARNING "Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->i.node_crc), crc); + goto bail; + } + + if (je32_to_cpu(node->i.dsize)) { + crc = crc32(0, node->i.data, je32_to_cpu(node->i.csize)); + if (je32_to_cpu(node->i.data_crc) != crc) { + printk(KERN_WARNING "Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->i.data_crc), crc); + goto bail; + } + } + break; + + case JFFS2_NODETYPE_DIRENT: + crc = crc32(0, node, sizeof(node->d)-8); + if (je32_to_cpu(node->d.node_crc) != crc) { + printk(KERN_WARNING "Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->d.node_crc), crc); + goto bail; + } + + if (node->d.nsize) { + crc = crc32(0, node->d.name, node->d.nsize); + if (je32_to_cpu(node->d.name_crc) != crc) { + printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->d.name_crc), crc); + goto bail; + } + } + break; + default: + printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", + ref_offset(raw), je16_to_cpu(node->u.nodetype)); + goto bail; } - spin_unlock_bh(&c->erase_completion_lock); + nraw = jffs2_alloc_raw_node_ref(); + if (!nraw) { + ret = -ENOMEM; + goto out_node; + } + nraw->flash_offset = phys_ofs; + nraw->totlen = raw->totlen; + nraw->next_phys = NULL; + + /* OK, all the CRCs are good; this node can just be copied as-is. */ + + ret = jffs2_flash_write(c, phys_ofs, raw->totlen, &retlen, (char *)node); + if (ret || (retlen != raw->totlen)) { + printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", + raw->totlen, phys_ofs, ret, retlen); + if (retlen) { + /* Doesn't belong to any inode */ + nraw->next_in_ino = NULL; + + nraw->flash_offset |= REF_OBSOLETE; + jffs2_add_physical_node_ref(c, nraw); + jffs2_mark_node_obsolete(c, nraw); + } else { + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset); + jffs2_free_raw_node_ref(raw); + } + if (!ret) + ret = -EIO; + goto out_node; + } + nraw->flash_offset |= REF_PRISTINE; + jffs2_add_physical_node_ref(c, nraw); + + /* Link into per-inode list. This is safe because of the ic + state being INO_STATE_GC. Note that if we're doing this + for an inode which is in-code, the 'nraw' pointer is then + going to be fetched from ic->nodes by our caller. */ + nraw->next_in_ino = ic->nodes; + ic->nodes = nraw; + + jffs2_mark_node_obsolete(c, raw); + D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw))); + + out_node: + kfree(node); return ret; + bail: + ret = -EBADFD; + goto out_node; } static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, @@ -331,7 +624,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ { struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; - unsigned short dev; + jint16_t dev; char *mdata = NULL, mdatalen = 0; uint32_t alloclen, phys_ofs; int ret; @@ -340,8 +633,8 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ S_ISCHR(JFFS2_F_I_MODE(f)) ) { /* For these, we don't actually need to read the old node */ /* FIXME: for minor or major > 255. */ - dev = ((JFFS2_F_I_RDEV_MAJ(f) << 8) | - JFFS2_F_I_RDEV_MIN(f)); + dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | + JFFS2_F_I_RDEV_MIN(f))); mdata = (char *)&dev; mdatalen = sizeof(dev); D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen)); @@ -364,7 +657,7 @@ 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); if (ret) { - printk(KERN_WARNING "jffs2_reserve_space_gc of %d 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); goto out; } @@ -377,7 +670,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ ri.ino = cpu_to_je32(f->inocache->ino); ri.version = cpu_to_je32(++f->highest_version); - ri.mode = cpu_to_je32(JFFS2_F_I_MODE(f)); + ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); @@ -431,7 +724,7 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen); if (ret) { - printk(KERN_WARNING "jffs2_reserve_space_gc of %d 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); return ret; } @@ -489,7 +782,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct continue; } if (retlen != sizeof(struct jffs2_unknown_node)) { - printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading header from obsolete node at %08x\n", + printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading header from obsolete node at %08x\n", retlen, sizeof(struct jffs2_unknown_node), ref_offset(raw)); continue; } @@ -506,7 +799,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct continue; } if (retlen != sizeof(rd)) { - printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading from obsolete node at %08x\n", + printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading from obsolete node at %08x\n", retlen, sizeof(rd), ref_offset(raw)); continue; } @@ -534,7 +827,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct continue; } if (retlen != name_len+1) { - printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading name from obsolete node at %08x\n", + printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %d) reading name from obsolete node at %08x\n", retlen, name_len+1, ref_offset(raw)); continue; } @@ -597,7 +890,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras write it out again with the _same_ version as before */ ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri); if (readlen != sizeof(ri) || ret) { - printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hole node\n", ret, readlen); + printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n", ret, readlen); goto fill; } if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) { @@ -607,7 +900,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras return -EIO; } if (je32_to_cpu(ri.totlen) != sizeof(ri)) { - printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x\n", + printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%zx\n", ref_offset(fn->raw), je32_to_cpu(ri.totlen), sizeof(ri)); return -EIO; @@ -642,7 +935,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras ri.csize = cpu_to_je32(0); ri.compr = JFFS2_COMPR_ZERO; } - ri.mode = cpu_to_je32(JFFS2_F_I_MODE(f)); + ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); @@ -654,7 +947,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen); if (ret) { - printk(KERN_WARNING "jffs2_reserve_space_gc of %d 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); return ret; } @@ -762,8 +1055,11 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era * page OK. We'll actually write it out again in commit_write, which is a little * suboptimal, but at least we're correct. */ +#ifdef __ECOS + pg = read_cache_page(start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode); +#else pg = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode); - +#endif if (IS_ERR(pg)) { printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg)); return PTR_ERR(pg); @@ -780,11 +1076,11 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen); if (ret) { - printk(KERN_WARNING "jffs2_reserve_space_gc of %d 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", sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret); break; } - cdatalen = min(alloclen - sizeof(ri), end - offset); + cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset); datalen = end - offset; writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1)); @@ -804,7 +1100,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era ri.ino = cpu_to_je32(f->inocache->ino); ri.version = cpu_to_je32(++f->highest_version); - ri.mode = cpu_to_je32(JFFS2_F_I_MODE(f)); + ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c index f8b7ba5a46d8..4346f9874a2f 100644 --- a/fs/jffs2/malloc.c +++ b/fs/jffs2/malloc.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: malloc.c,v 1.22 2002/05/20 14:56:38 dwmw2 Exp $ + * $Id: malloc.c,v 1.24 2003/03/11 17:30:29 gleixner Exp $ * */ @@ -23,6 +23,9 @@ #define JFFS2_SLAB_POISON 0 #endif +// replace this by #define D3 (x) x for cache debugging +#define D3(x) + /* These are initialised to NULL in the kernel startup code. If you're porting to other operating systems, beware */ static kmem_cache_t *full_dnode_slab; @@ -73,8 +76,7 @@ int __init jffs2_create_slab_caches(void) inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), - 0, JFFS2_SLAB_POISON|SLAB_RECLAIM_ACCOUNT, - NULL, NULL); + 0, JFFS2_SLAB_POISON, NULL, NULL); if (inode_cache_slab) return 0; err: @@ -112,75 +114,92 @@ void jffs2_free_full_dirent(struct jffs2_full_dirent *x) struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) { - void *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); + struct jffs2_full_dnode *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_full_dnode at %p\n", ret)); return ret; } void jffs2_free_full_dnode(struct jffs2_full_dnode *x) { + D3 (printk (KERN_DEBUG "free full_dnode at %p\n", x)); kmem_cache_free(full_dnode_slab, x); } struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) { - return kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); + struct jffs2_raw_dirent *ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_raw_dirent\n", ret)); + return ret; } void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) { + D3 (printk (KERN_DEBUG "free_raw_dirent at %p\n", x)); kmem_cache_free(raw_dirent_slab, x); } struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) { - return kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); + struct jffs2_raw_inode *ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_raw_inode at %p\n", ret)); + return ret; } void jffs2_free_raw_inode(struct jffs2_raw_inode *x) { + D3 (printk (KERN_DEBUG "free_raw_inode at %p\n", x)); kmem_cache_free(raw_inode_slab, x); } struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) { - return kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); + struct jffs2_tmp_dnode_info *ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_tmp_dnode_info at %p\n", ret)); + return ret; } void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) { + D3 (printk (KERN_DEBUG "free_tmp_dnode_info at %p\n", x)); kmem_cache_free(tmp_dnode_info_slab, x); } struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) { - return kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); + struct jffs2_raw_node_ref *ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_raw_node_ref at %p\n", ret)); + return ret; } void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) { + D3 (printk (KERN_DEBUG "free_raw_node_ref at %p\n", x)); kmem_cache_free(raw_node_ref_slab, x); } struct jffs2_node_frag *jffs2_alloc_node_frag(void) { - return kmem_cache_alloc(node_frag_slab, GFP_KERNEL); + struct jffs2_node_frag *ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_node_frag at %p\n", ret)); + return ret; } void jffs2_free_node_frag(struct jffs2_node_frag *x) { + D3 (printk (KERN_DEBUG "free_node_frag at %p\n", x)); kmem_cache_free(node_frag_slab, x); } struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) { struct jffs2_inode_cache *ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); - D1(printk(KERN_DEBUG "Allocated inocache at %p\n", ret)); + D3 (printk(KERN_DEBUG "Allocated inocache at %p\n", ret)); return ret; } void jffs2_free_inode_cache(struct jffs2_inode_cache *x) { - D1(printk(KERN_DEBUG "Freeing inocache at %p\n", x)); + D3 (printk(KERN_DEBUG "Freeing inocache at %p\n", x)); kmem_cache_free(inode_cache_slab, x); } diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 4bd3c3d65960..294854d372f7 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -7,17 +7,18 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.c,v 1.65 2002/11/12 09:50:13 dwmw2 Exp $ + * $Id: nodelist.c,v 1.79 2003/04/08 08:20:01 dwmw2 Exp $ * */ #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/fs.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> #include <linux/rbtree.h> #include <linux/crc32.h> #include <linux/slab.h> +#include <linux/pagemap.h> #include "nodelist.h" void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list) @@ -112,10 +113,10 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%lu\n", ino)); if (!f->inocache->nodes) { - printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", ino); + printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", (unsigned long)ino); } - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); for (ref = f->inocache->nodes; ref && ref->next_in_ino; ref = ref->next_in_ino) { /* Work out whether it's a data node or a dirent node */ @@ -127,12 +128,12 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode /* We can hold a pointer to a non-obsolete node without the spinlock, but _obsolete_ nodes may disappear at any time, if the block they're in gets erased */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); cond_resched(); /* FIXME: point() */ - err = jffs2_flash_read(c, (ref_offset(ref)), min(ref->totlen, sizeof(node)), &retlen, (void *)&node); + err = jffs2_flash_read(c, (ref_offset(ref)), min_t(uint32_t, ref->totlen, sizeof(node)), &retlen, (void *)&node); if (err) { printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref)); goto free_out; @@ -140,7 +141,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode /* Check we've managed to read at least the common node header */ - if (retlen < min(ref->totlen, sizeof(node.u))) { + if (retlen < min_t(uint32_t, ref->totlen, sizeof(node.u))) { printk(KERN_WARNING "short read in get_inode_nodes()\n"); err = -EIO; goto free_out; @@ -158,6 +159,14 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode err = -EIO; goto free_out; } + /* sanity check */ + if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) { + printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n", + ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen)); + jffs2_mark_node_obsolete(c, ref); + spin_lock(&c->erase_completion_lock); + continue; + } if (je32_to_cpu(node.d.version) > *highest_version) *highest_version = je32_to_cpu(node.d.version); if (ref_obsolete(ref)) { @@ -166,6 +175,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode ref_offset(ref)); BUG(); } + fd = jffs2_alloc_full_dirent(node.d.nsize+1); if (!fd) { err = -ENOMEM; @@ -187,7 +197,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode dirent we've already read from the flash */ if (retlen > sizeof(struct jffs2_raw_dirent)) - memcpy(&fd->name[0], &node.d.name[0], min((uint32_t)node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent)))); + memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent)))); /* Do we need to copy any more of the name directly from the flash? @@ -244,46 +254,95 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ref_offset(ref), je32_to_cpu(node.i.node_crc), crc); jffs2_mark_node_obsolete(c, ref); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); + continue; + } + + /* sanity checks */ + if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) || + PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) { + printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino %d, version %d, isize %d, csize %d, dsize %d \n", + ref_offset(ref), je32_to_cpu(node.i.totlen), je32_to_cpu(node.i.ino), + je32_to_cpu(node.i.version), je32_to_cpu(node.i.isize), + je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize)); + jffs2_mark_node_obsolete(c, ref); + spin_lock(&c->erase_completion_lock); continue; } if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) { - /* FIXME: point() */ - char *buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL); - if (!buf) - return -ENOMEM; - - err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), - &retlen, buf); - if (!err && retlen != je32_to_cpu(node.i.csize)) - err = -EIO; - if (err) { - kfree(buf); - return err; + unsigned char *buf=NULL; + uint32_t pointed = 0; +#ifndef __ECOS + if (c->mtd->point) { + err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), + &retlen, &buf); + if (!err && retlen < je32_to_cpu(node.i.csize)) { + D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); + c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize)); + } else if (err){ + D1(printk(KERN_DEBUG "MTD point failed %d\n", err)); + } else + pointed = 1; /* succefully pointed to device */ + } +#endif + if(!pointed){ + buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), + &retlen, buf); + if (!err && retlen != je32_to_cpu(node.i.csize)) + err = -EIO; + if (err) { + kfree(buf); + return err; + } } - crc = crc32(0, buf, je32_to_cpu(node.i.csize)); - kfree(buf); + if(!pointed) + kfree(buf); +#ifndef __ECOS + else + c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize)); +#endif if (crc != je32_to_cpu(node.i.data_crc)) { printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ref_offset(ref), je32_to_cpu(node.i.data_crc), crc); jffs2_mark_node_obsolete(c, ref); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); continue; } } /* Mark the node as having been checked and fix the accounting accordingly */ + spin_lock(&c->erase_completion_lock); jeb = &c->blocks[ref->flash_offset / c->sector_size]; jeb->used_size += ref->totlen; jeb->unchecked_size -= ref->totlen; c->used_size += ref->totlen; c->unchecked_size -= ref->totlen; - mark_ref_normal(ref); + /* If node covers at least a whole page, or if it starts at the + beginning of a page and runs to the end of the file, or if + it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. + + If it's actually overlapped, it'll get made NORMAL (or OBSOLETE) + when the overlapping node(s) get added to the tree anyway. + */ + if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) || + ( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) && + (je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) == je32_to_cpu(node.i.isize)))) { + D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref))); + ref->flash_offset = ref_offset(ref) | REF_PRISTINE; + } else { + D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref))); + ref->flash_offset = ref_offset(ref) | REF_NORMAL; + } + spin_unlock(&c->erase_completion_lock); } tn = jffs2_alloc_tmp_dnode_info(); @@ -323,13 +382,15 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode je16_to_cpu(node.u.nodetype), ref_offset(ref)); /* Mark the node as having been checked and fix the accounting accordingly */ + spin_lock(&c->erase_completion_lock); jeb = &c->blocks[ref->flash_offset / c->sector_size]; jeb->used_size += ref->totlen; jeb->unchecked_size -= ref->totlen; c->used_size += ref->totlen; c->unchecked_size -= ref->totlen; - + mark_ref_normal(ref); + spin_unlock(&c->erase_completion_lock); } node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype)); if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) { @@ -361,10 +422,10 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode } } - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); *tnp = ret_tn; *fdp = ret_fd; @@ -376,12 +437,24 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode return err; } -struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, int ino) +void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) +{ + spin_lock(&c->inocache_lock); + ic->state = state; + wake_up(&c->inocache_wq); + spin_unlock(&c->inocache_lock); +} + +/* During mount, this needs no locking. During normal operation, its + callers want to do other stuff while still holding the inocache_lock. + Rather than introducing special case get_ino_cache functions or + callbacks, we just let the caller do the locking itself. */ + +struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino) { struct jffs2_inode_cache *ret; D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino)); - spin_lock (&c->inocache_lock); ret = c->inocache_list[ino % INOCACHE_HASHSIZE]; while (ret && ret->ino < ino) { @@ -391,8 +464,6 @@ struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, int ino) if (ret && ret->ino != ino) ret = NULL; - spin_unlock(&c->inocache_lock); - D2(printk(KERN_DEBUG "jffs2_get_ino_cache found %p for ino %u\n", ret, ino)); return ret; } diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 5ead344453d1..0cfad439f844 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.h,v 1.87 2002/11/12 13:36:18 dwmw2 Exp $ + * $Id: nodelist.h,v 1.93 2003/02/24 21:47:28 dwmw2 Exp $ * */ @@ -16,12 +16,17 @@ #include <linux/config.h> #include <linux/fs.h> - -#include <linux/mtd/compatmac.h> /* For min/max in older kernels */ +#include <linux/types.h> #include <linux/jffs2.h> #include <linux/jffs2_fs_sb.h> #include <linux/jffs2_fs_i.h> + +#ifdef __ECOS +#include "os-ecos.h" +#else +#include <linux/mtd/compatmac.h> /* For min/max in older kernels */ #include "os-linux.h" +#endif #ifndef CONFIG_JFFS2_FS_DEBUG #define CONFIG_JFFS2_FS_DEBUG 2 @@ -98,13 +103,18 @@ struct jffs2_inode_cache { uint32_t ino; int nlink; int state; -#define INO_STATE_UNCHECKED 0 -#define INO_STATE_CHECKING 1 -#define INO_STATE_CHECKEDABSENT 2 -#define INO_STATE_READINGINODE 3 -#define INO_STATE_PRESENT 5 }; +/* Inode states for 'state' above. We need the 'GC' state to prevent + someone from doing a read_inode() while we're moving a 'REF_PRISTINE' + node without going through all the iget() nonsense */ +#define INO_STATE_UNCHECKED 0 /* CRC checks not yet done */ +#define INO_STATE_CHECKING 1 /* CRC checks in progress */ +#define INO_STATE_PRESENT 2 /* In core */ +#define INO_STATE_CHECKEDABSENT 3 /* Checked, cleared again */ +#define INO_STATE_GC 4 /* GCing a 'pristine' node */ +#define INO_STATE_READING 5 /* In read_inode() */ + #define INOCACHE_HASHSIZE 128 struct jffs2_scan_info { @@ -281,7 +291,8 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp, uint32_t *highest_version, uint32_t *latest_mctime, uint32_t *mctime_ver); -struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, int ino); +void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); +struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino); void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new); void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old); void jffs2_free_ino_caches(struct jffs2_sb_info *c); @@ -315,10 +326,10 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint /* readinode.c */ void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); -int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_full_dnode *fn); int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t ino, struct jffs2_raw_inode *latest_node); +int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f); /* malloc.c */ diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 8baac2d30906..62ab0469ac03 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -7,14 +7,15 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodemgmt.c,v 1.84 2002/11/12 11:17:29 dwmw2 Exp $ + * $Id: nodemgmt.c,v 1.94 2003/02/19 17:50:26 gleixner Exp $ * */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> +#include <linux/compiler.h> +#include <linux/sched.h> /* For cond_resched() */ #include "nodelist.h" /** @@ -54,26 +55,57 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n")); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); - /* this needs a little more thought */ + /* this needs a little more thought (true <tglx> :)) */ while(ret == -EAGAIN) { while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { int ret; + uint32_t dirty, avail; up(&c->alloc_sem); - if (c->dirty_size + c->unchecked_size < c->sector_size) { + /* calculate real dirty size + * dirty_size contains blocks on erase_pending_list + * those blocks are counted in c->nr_erasing_blocks. + * If one block is actually erased, it is not longer counted as dirty_space + * but it is counted in c->nr_erasing_blocks, so we add it and subtract it + * with c->nr_erasing_blocks * c->sector_size again. + * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks + * This helps us to force gc and pick eventually a clean block to spread the load. + * We add unchecked_size here, as we hopefully will find some space to use. + * This will affect the sum only once, as gc first finishes checking + * of nodes. + */ + dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size; + if (dirty < c->sector_size) { D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < sector size 0x%08x, returning -ENOSPC\n", - c->dirty_size, c->unchecked_size, c->sector_size)); - spin_unlock_bh(&c->erase_completion_lock); + dirty, c->unchecked_size, c->sector_size)); + spin_unlock(&c->erase_completion_lock); + return -ENOSPC; + } + + /* Calc possibly available space. Possibly available means that we + * don't know, if unchecked size contains obsoleted nodes, which could give us some + * more usable space. This will affect the sum only once, as gc first finishes checking + * of nodes. + + Return -ENOSPC, if the maximum possibly available space is less or equal than + * blocksneeded * sector_size. + * This blocks endless gc looping on a filesystem, which is nearly full, even if + * the check above passes. + */ + avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size; + if ( (avail / c->sector_size) <= blocksneeded) { + D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n", + avail, blocksneeded * c->sector_size)); + spin_unlock(&c->erase_completion_lock); return -ENOSPC; } D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n", c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size, c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size)); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); ret = jffs2_garbage_collect_pass(c); if (ret) @@ -85,7 +117,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs return -EINTR; down(&c->alloc_sem); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); } ret = jffs2_do_reserve_space(c, minsize, ofs, len); @@ -93,7 +125,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret)); } } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); if (ret) up(&c->alloc_sem); return ret; @@ -106,14 +138,14 @@ int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t * D1(printk(KERN_DEBUG "jffs2_reserve_space_gc(): Requested 0x%x bytes\n", minsize)); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); while(ret == -EAGAIN) { ret = jffs2_do_reserve_space(c, minsize, ofs, len); if (ret) { D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); } } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); return ret; } @@ -127,10 +159,10 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui /* 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 (c->wbuf_len) { - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); jffs2_flush_wbuf(c, 1); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); /* We know nobody's going to have changed nextblock. Just continue */ } c->wasted_size += jeb->free_size; @@ -186,9 +218,9 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui !list_empty(&c->erasable_pending_wbuf_list)) { D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); /* c->nextblock is NULL, no update to c->nextblock allowed */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); jffs2_flush_wbuf(c, 1); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); /* Have another go. It'll be on the erasable_list now */ return -EAGAIN; } @@ -203,6 +235,11 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui } /* Make sure this can't deadlock. Someone has to start the erases of erase_pending blocks */ +#ifdef __ECOS + /* In eCos, we don't have a handy kernel thread doing the erases for + us. We do them ourselves right now. */ + jffs2_erase_pending_blocks(c); +#else set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&c->erase_wait, &wait); D1(printk(KERN_DEBUG "Waiting for erases to complete. erasing_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", @@ -212,13 +249,14 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui D1(printk(KERN_DEBUG "Triggering pending erases\n")); jffs2_erase_pending_trigger(c); } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); schedule(); remove_wait_queue(&c->erase_wait, &wait); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (signal_pending(current)) { return -EINTR; } +#endif /* An erase may have failed, decreasing the amount of free space available. So we must restart from the beginning */ @@ -248,9 +286,9 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui already set c->nextblock so that jffs2_mark_node_obsolete() won't try to refile it to the dirty_list. */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); jffs2_mark_node_obsolete(c, jeb->first_node); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); } D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", *len, *ofs)); @@ -276,7 +314,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r uint32_t len = new->totlen; jeb = &c->blocks[new->flash_offset / c->sector_size]; - D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x\n", ref_offset(new), len)); + D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len)); #if 1 if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) { printk(KERN_WARNING "argh. node added in wrong place\n"); @@ -284,7 +322,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r return -EINVAL; } #endif - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (!jeb->first_node) jeb->first_node = new; @@ -308,9 +346,9 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); if (c->wbuf_len) { /* Flush the last write in the block if it's outstanding */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); jffs2_flush_wbuf(c, 1); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); } list_add_tail(&jeb->list, &c->clean_list); @@ -319,7 +357,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r ACCT_SANITY_CHECK(c,jeb); D1(ACCT_PARANOIA_CHECK(jeb)); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); return 0; } @@ -337,7 +375,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref struct jffs2_eraseblock *jeb; int blocknr; struct jffs2_unknown_node n; - int ret; + int ret, addedsize; size_t retlen; if(!ref) { @@ -355,7 +393,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref } jeb = &c->blocks[blocknr]; - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (ref_flags(ref) == REF_UNCHECKED) { D1(if (unlikely(jeb->unchecked_size < ref->totlen)) { @@ -377,14 +415,17 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref c->used_size -= ref->totlen; } + // Take care, that wasted size is taken into concern if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref->totlen)) && jeb != c->nextblock) { D1(printk("Dirtying\n")); - jeb->dirty_size += ref->totlen + jeb->wasted_size; - c->dirty_size += ref->totlen + jeb->wasted_size; + addedsize = ref->totlen + jeb->wasted_size; + jeb->dirty_size += addedsize; + c->dirty_size += addedsize; c->wasted_size -= jeb->wasted_size; jeb->wasted_size = 0; } else { D1(printk("Wasting\n")); + addedsize = 0; jeb->wasted_size += ref->totlen; c->wasted_size += ref->totlen; } @@ -400,7 +441,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref obliterate nodes that look obsolete. If they weren't marked obsolete on the flash at the time they _became_ obsolete, there was probably a reason for that. */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); return; } @@ -417,6 +458,10 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref if (c->wbuf_len) { D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n")); list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list); +#if 0 /* This check was added to allow us to find places where we added nodes to the lists + after dropping the alloc_sem, and it did that just fine. But it also caused us to + lock the alloc_sem in other places, like clear_inode(), when we wouldn't otherwise + have needed to. So I suspect it's outlived its usefulness. Thomas? */ /* We've changed the rules slightly. After writing a node you now mustn't drop the @@ -436,6 +481,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref printk(KERN_CRIT "jffs2_mark_node_obsolete() called with wbuf active but alloc_sem not locked!\n"); BUG(); } +#endif } else { if (jiffies & 127) { /* Most of the time, we just erase it immediately. Otherwise we @@ -454,7 +500,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref D1(printk(KERN_DEBUG "Done OK\n")); } else if (jeb == c->gcblock) { D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty_list\n", jeb->offset)); - } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - ref->totlen)) { + } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - addedsize)) { D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset)); list_del(&jeb->list); D1(printk(KERN_DEBUG "...and adding to dirty_list\n")); @@ -470,7 +516,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); if (!jffs2_can_mark_obsolete(c)) return; @@ -484,7 +530,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref return; } if (retlen != sizeof(n)) { - printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %d\n", ref_offset(ref), retlen); + printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); return; } if (PAD(je32_to_cpu(n.totlen)) != PAD(ref->totlen)) { @@ -503,7 +549,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref return; } if (retlen != sizeof(n)) { - printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), retlen); + printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); return; } } diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index a5c35fdb51c8..d08ca2e3a152 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.21 2002/11/12 09:44:30 dwmw2 Exp $ + * $Id: os-linux.h,v 1.26 2003/05/16 18:45:25 dwmw2 Exp $ * */ @@ -15,6 +15,11 @@ #define __JFFS2_OS_LINUX_H__ #include <linux/version.h> +/* JFFS2 uses Linux mode bits natively -- no need for conversion */ +#define os_to_jffs2_mode(x) (x) +#define jffs2_to_os_mode(x) (x) + + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) #define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode)) #define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode) @@ -37,9 +42,6 @@ #define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode) #define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid) #define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid) -#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec) -#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec) -#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec) #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,1) #define JFFS2_F_I_RDEV_MIN(f) (minor(OFNI_EDONI_2SFFJ(f)->i_rdev)) @@ -49,6 +51,21 @@ #define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev))) #endif +/* Urgh. The things we do to keep the 2.4 build working */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,47) +#define ITIME(sec) ((struct timespec){sec, 0}) +#define I_SEC(tv) ((tv).tv_sec) +#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec) +#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec) +#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec) +#else +#define ITIME(x) (x) +#define I_SEC(x) (x) +#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime) +#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime) +#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime) +#endif + /* Hmmm. P'raps generic code should only ever see versions of signal functions which do the locking automatically? */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40) @@ -57,6 +74,16 @@ #define current_sig_lock current->sighand->siglock #endif +#define sleep_on_spinunlock(wq, s) \ + do { \ + DECLARE_WAITQUEUE(__wait, current); \ + add_wait_queue((wq), &__wait); \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + spin_unlock(s); \ + schedule(); \ + remove_wait_queue((wq), &__wait); \ + } while(0) + static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) { #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c index 4e8b3a1c624c..7216eb97cd46 100644 --- a/fs/jffs2/read.c +++ b/fs/jffs2/read.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: read.c,v 1.29 2002/11/12 09:51:22 dwmw2 Exp $ + * $Id: read.c,v 1.31 2003/01/14 14:06:22 dwmw2 Exp $ * */ @@ -39,7 +39,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig } if (readlen != sizeof(*ri)) { jffs2_free_raw_inode(ri); - printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%x bytes, got 0x%x\n", + printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n", ref_offset(fd->raw), sizeof(*ri), readlen); return -EIO; } @@ -197,8 +197,9 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, fragofs = offset - frag->ofs; readlen = min(frag->size - fragofs, end - offset); - D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%x\n", frag->ofs+fragofs, frag->ofs+fragofs+readlen, - ref_offset(frag->node->raw))); + D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n", + frag->ofs+fragofs, frag->ofs+fragofs+readlen, + ref_offset(frag->node->raw), ref_flags(frag->node->raw))); ret = jffs2_read_dnode(c, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen); D2(printk(KERN_DEBUG "node read done\n")); if (ret) { diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 92ba6f553d2d..4f935bfa2fd0 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: readinode.c,v 1.95 2002/11/12 11:17:29 dwmw2 Exp $ + * $Id: readinode.c,v 1.106 2003/05/14 06:53:26 dwmw2 Exp $ * */ @@ -17,11 +17,13 @@ #include <linux/crc32.h> #include <linux/pagemap.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> +#include <linux/compiler.h> #include "nodelist.h" +static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag); -D1(static void jffs2_print_fragtree(struct rb_root *list, int permitbug) +#if CONFIG_JFFS2_FS_DEBUG >= 1 +static void jffs2_print_fragtree(struct rb_root *list, int permitbug) { struct jffs2_node_frag *this = frag_first(list); uint32_t lastofs = 0; @@ -44,31 +46,17 @@ D1(static void jffs2_print_fragtree(struct rb_root *list, int permitbug) printk(KERN_CRIT "Frag tree got a hole in it\n"); BUG(); } -}) +} -D1(void jffs2_print_frag_list(struct jffs2_inode_info *f) +void jffs2_print_frag_list(struct jffs2_inode_info *f) { jffs2_print_fragtree(&f->fragtree, 0); if (f->metadata) { printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); } -}) - - -/* Given an inode, probably with existing list of fragments, add the new node - * to the fragment list. - */ -int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) -{ - int ret; - D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); - - ret = jffs2_add_full_dnode_to_fraglist(c, &f->fragtree, fn); - - D2(jffs2_print_frag_list(f)); - return ret; } +#endif /* D1 */ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this) { @@ -91,26 +79,24 @@ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_ jffs2_free_node_frag(this); } -/* Doesn't set inode->i_size */ -int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_full_dnode *fn) +/* Given an inode, probably with existing list of fragments, add the new node + * to the fragment list. + */ +int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) { - struct jffs2_node_frag *this; + int ret; struct jffs2_node_frag *newfrag; - uint32_t lastend; + + D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); newfrag = jffs2_alloc_node_frag(); - if (!newfrag) { + if (unlikely(!newfrag)) return -ENOMEM; - } - - if (!fn->raw) { - printk(KERN_WARNING "dwmw2 is stupid. j_a_f_d_t_f should never happen with ->raw == NULL\n"); - BUG(); - } - D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag)); + D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", + fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag)); - if (!fn->size) { + if (unlikely(!fn->size)) { jffs2_free_node_frag(newfrag); return 0; } @@ -120,8 +106,42 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct rb_root *li newfrag->node = fn; newfrag->node->frags = 1; + ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag); + if (ret) + return ret; + + /* If we now share a page with other nodes, mark either previous + or next node REF_NORMAL, as appropriate. */ + if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) { + struct jffs2_node_frag *prev = frag_prev(newfrag); + + mark_ref_normal(fn->raw); + /* If we don't start at zero there's _always_ a previous */ + if (prev->node) + mark_ref_normal(prev->node->raw); + } + + if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) { + struct jffs2_node_frag *next = frag_next(newfrag); + + if (next) { + mark_ref_normal(fn->raw); + if (next->node) + mark_ref_normal(next->node->raw); + } + } + D2(jffs2_print_frag_list(f)); + return 0; +} + +/* Doesn't set inode->i_size */ +static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag) +{ + struct jffs2_node_frag *this; + uint32_t lastend; + /* Skip all the nodes which are completed before this one starts */ - this = jffs2_lookup_node_frag(list, fn->ofs); + this = jffs2_lookup_node_frag(list, newfrag->node->ofs); if (this) { D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", @@ -143,16 +163,18 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct rb_root *li if ((lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { if (this->node) mark_ref_normal(this->node->raw); - mark_ref_normal(fn->raw); + mark_ref_normal(newfrag->node->raw); } - if (lastend < fn->ofs) { + if (lastend < newfrag->node->ofs) { /* ... and we need to put a hole in before the new node */ struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag(); - if (!holefrag) + if (!holefrag) { + jffs2_free_node_frag(newfrag); return -ENOMEM; + } holefrag->ofs = lastend; - holefrag->size = fn->ofs - lastend; + holefrag->size = newfrag->node->ofs - lastend; holefrag->node = NULL; if (this) { /* By definition, the 'this' node has no right-hand child, @@ -190,9 +212,9 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct rb_root *li if (newfrag->ofs > this->ofs) { /* This node isn't completely obsoleted. The start of it remains valid */ - /* Mark the new node and the partially covered node REF_NORMAL -- let + /* Mark the new node and the partially covered node REF_NORMAL -- let the GC take a look at them */ - mark_ref_normal(fn->raw); + mark_ref_normal(newfrag->node->raw); if (this->node) mark_ref_normal(this->node->raw); @@ -283,7 +305,7 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct rb_root *li /* And mark them REF_NORMAL so the GC takes a look at them */ if (this->node) mark_ref_normal(this->node->raw); - mark_ref_normal(fn->raw); + mark_ref_normal(newfrag->node->raw); return 0; } @@ -314,24 +336,54 @@ void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uin /* Scan the list of all nodes present for this ino, build map of versions, etc. */ +static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, + struct jffs2_inode_info *f, + struct jffs2_raw_inode *latest_node); + int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t ino, struct jffs2_raw_inode *latest_node) { - struct jffs2_tmp_dnode_info *tn_list, *tn; - struct jffs2_full_dirent *fd_list; - struct jffs2_full_dnode *fn = NULL; - uint32_t crc; - uint32_t latest_mctime, mctime_ver; - uint32_t mdata_ver = 0; - size_t retlen; - int ret; - D2(printk(KERN_DEBUG "jffs2_do_read_inode(): getting inocache\n")); + retry_inocache: + spin_lock(&c->inocache_lock); f->inocache = jffs2_get_ino_cache(c, ino); D2(printk(KERN_DEBUG "jffs2_do_read_inode(): Got inocache at %p\n", f->inocache)); + if (f->inocache) { + /* Check its state. We may need to wait before we can use it */ + switch(f->inocache->state) { + case INO_STATE_UNCHECKED: + case INO_STATE_CHECKEDABSENT: + f->inocache->state = INO_STATE_READING; + break; + + case INO_STATE_CHECKING: + case INO_STATE_GC: + /* If it's in either of these states, we need + to wait for whoever's got it to finish and + put it back. */ + D1(printk(KERN_DEBUG "jffs2_get_ino_cache_read waiting for ino #%u in state %d\n", + ino, f->inocache->state)); + sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); + goto retry_inocache; + + case INO_STATE_READING: + case INO_STATE_PRESENT: + /* Eep. This should never happen. It can + happen if Linux calls read_inode() again + before clear_inode() has finished though. */ + printk(KERN_WARNING "Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state); + /* Fail. That's probably better than allowing it to succeed */ + f->inocache = NULL; + break; + + default: + BUG(); + } + } + spin_unlock(&c->inocache_lock); if (!f->inocache && ino == 1) { /* Special case - no root inode on medium */ f->inocache = jffs2_alloc_inode_cache(); @@ -343,19 +395,61 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); f->inocache->ino = f->inocache->nlink = 1; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; + f->inocache->state = INO_STATE_READING; jffs2_add_ino_cache(c, f->inocache); } if (!f->inocache) { printk(KERN_WARNING "jffs2_do_read_inode() on nonexistent ino %u\n", ino); return -ENOENT; } - D1(printk(KERN_DEBUG "jffs2_do_read_inode(): ino #%u nlink is %d\n", ino, f->inocache->nlink)); + + return jffs2_do_read_inode_internal(c, f, latest_node); +} + +int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +{ + struct jffs2_raw_inode n; + struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL); + int ret; + + if (!f) + return -ENOMEM; + + memset(f, 0, sizeof(*f)); + init_MUTEX_LOCKED(&f->sem); + f->inocache = ic; + + ret = jffs2_do_read_inode_internal(c, f, &n); + if (!ret) { + up(&f->sem); + jffs2_do_clear_inode(c, f); + } + kfree (f); + return ret; +} + +static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, + struct jffs2_inode_info *f, + struct jffs2_raw_inode *latest_node) +{ + struct jffs2_tmp_dnode_info *tn_list, *tn; + struct jffs2_full_dirent *fd_list; + struct jffs2_full_dnode *fn = NULL; + uint32_t crc; + uint32_t latest_mctime, mctime_ver; + uint32_t mdata_ver = 0; + size_t retlen; + int ret; + + D1(printk(KERN_DEBUG "jffs2_do_read_inode_internal(): ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink)); /* Grab all nodes relevant to this ino */ - ret = jffs2_get_inode_nodes(c, ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); + ret = jffs2_get_inode_nodes(c, f->inocache->ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); if (ret) { - printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", ino, ret); + printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", f->inocache->ino, ret); + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); return ret; } f->dents = fd_list; @@ -365,13 +459,21 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, fn = tn->fn; - if (f->metadata && tn->version > mdata_ver) { - D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw))); - jffs2_mark_node_obsolete(c, f->metadata->raw); - jffs2_free_full_dnode(f->metadata); - f->metadata = NULL; - - mdata_ver = 0; + if (f->metadata) { + if (tn->version > mdata_ver) { + D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw))); + jffs2_mark_node_obsolete(c, f->metadata->raw); + jffs2_free_full_dnode(f->metadata); + f->metadata = NULL; + + mdata_ver = 0; + } else { + D1(printk(KERN_DEBUG "Er. New metadata at 0x%08x with ver %d is actually older than previous %d\n", + ref_offset(f->metadata->raw), tn->version, mdata_ver)); + jffs2_mark_node_obsolete(c, fn->raw); + jffs2_free_full_dnode(fn); + goto next_tn; + } } if (fn->size) { @@ -382,31 +484,36 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, f->metadata = fn; mdata_ver = tn->version; } + next_tn: tn_list = tn->next; jffs2_free_tmp_dnode_info(tn); } if (!fn) { /* No data nodes for this inode. */ - if (ino != 1) { - printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", ino); + if (f->inocache->ino != 1) { + printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", f->inocache->ino); if (!fd_list) { + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); return -EIO; } printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n"); } - latest_node->mode = cpu_to_je32(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO); + latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO); latest_node->version = cpu_to_je32(0); latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0); latest_node->isize = cpu_to_je32(0); latest_node->gid = cpu_to_je16(0); latest_node->uid = cpu_to_je16(0); + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); return 0; } ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node); if (ret || retlen != sizeof(*latest_node)) { - printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %ld of %d bytes read\n", - ret, (long)retlen, sizeof(*latest_node)); + printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %zd of %zd bytes read\n", + ret, retlen, sizeof(*latest_node)); /* FIXME: If this fails, there seems to be a memory leak. Find it. */ up(&f->sem); jffs2_do_clear_inode(c, f); @@ -415,13 +522,13 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, crc = crc32(0, latest_node, sizeof(*latest_node)-8); if (crc != je32_to_cpu(latest_node->node_crc)) { - printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", ino, ref_offset(fn->raw)); + printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", f->inocache->ino, ref_offset(fn->raw)); up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; } - switch(je32_to_cpu(latest_node->mode) & S_IFMT) { + switch(jemode_to_cpu(latest_node->mode) & S_IFMT) { case S_IFDIR: if (mctime_ver > je32_to_cpu(latest_node->version)) { /* The times in the latest_node are actually older than @@ -447,23 +554,26 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, case S_IFBLK: case S_IFCHR: - /* Xertain inode types should have only one data node, and it's + /* Certain inode types should have only one data node, and it's kept as the metadata node */ if (f->metadata) { - printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n", ino, je32_to_cpu(latest_node->mode)); + printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n", + f->inocache->ino, jemode_to_cpu(latest_node->mode)); up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; } if (!frag_first(&f->fragtree)) { - printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", ino, je32_to_cpu(latest_node->mode)); + printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", + f->inocache->ino, jemode_to_cpu(latest_node->mode)); up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; } /* ASSERT: f->fraglist != NULL */ if (frag_next(frag_first(&f->fragtree))) { - printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had more than one node\n", ino, je32_to_cpu(latest_node->mode)); + printk(KERN_WARNING "Argh. Special inode #%u with mode 0x%x had more than one node\n", + f->inocache->ino, jemode_to_cpu(latest_node->mode)); /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ up(&f->sem); jffs2_do_clear_inode(c, f); @@ -475,7 +585,8 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, f->fragtree = RB_ROOT; break; } - f->inocache->state = INO_STATE_PRESENT; + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); return 0; } @@ -494,7 +605,7 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) the nodes are marked obsolete, and jffs2_g_c_pass() won't call iget() for the inode in question. - We also do this to keep the (maybe temporary) BUG() in + We also used to do this to keep the temporary BUG() in jffs2_mark_node_obsolete() from triggering. */ if(deleted) @@ -518,8 +629,8 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) jffs2_free_full_dirent(fd); } - if (f->inocache) - f->inocache->state = INO_STATE_CHECKEDABSENT; + if (f->inocache && f->inocache->state != INO_STATE_CHECKING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); up(&f->sem); diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 889f055133b4..8ed8212bb5eb 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -7,10 +7,11 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: scan.c,v 1.92 2002/09/09 16:29:08 dwmw2 Exp $ + * $Id: scan.c,v 1.99 2003/04/28 10:17:17 dwmw2 Exp $ * */ #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/pagemap.h> @@ -70,23 +71,21 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) uint32_t empty_blocks = 0, bad_blocks = 0; unsigned char *flashbuf = NULL; uint32_t buf_size = 0; +#ifndef __ECOS size_t pointlen; - if (!c->blocks) { - printk(KERN_WARNING "EEEK! c->blocks is NULL!\n"); - return -EINVAL; - } if (c->mtd->point) { ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf); if (!ret && pointlen < c->mtd->size) { /* Don't muck about if it won't let us point to the whole flash */ - D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%x\n", pointlen)); - c->mtd->unpoint(c->mtd, flashbuf); + D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); + c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); flashbuf = NULL; } if (ret) D1(printk(KERN_DEBUG "MTD point failed %d\n", ret)); } +#endif if (!flashbuf) { /* For NAND it's quicker to read a whole eraseblock at a time, apparently */ @@ -237,9 +236,10 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) } if (buf_size) kfree(flashbuf); +#ifndef __ECOS else - c->mtd->unpoint(c->mtd, flashbuf); - + c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); +#endif return 0; } @@ -255,7 +255,7 @@ static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf, return ret; } if (retlen < len) { - D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%x bytes\n", ofs, retlen)); + D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%zx bytes\n", ofs, retlen)); return -EIO; } D2(printk(KERN_DEBUG "Read 0x%x bytes from 0x%08x into buf\n", len, ofs)); @@ -366,7 +366,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo prevofs = ofs; if (jeb->offset + c->sector_size < ofs + sizeof(*node)) { - D1(printk(KERN_DEBUG "Fewer than %d bytes left to end of block. (%x+%x<%x+%x) Not reading\n", sizeof(struct jffs2_unknown_node), + D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node), jeb->offset, c->sector_size, ofs, sizeof(*node))); DIRTY_SPACE((jeb->offset + c->sector_size)-ofs); break; @@ -374,7 +374,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo if (buf_ofs + buf_len < ofs + sizeof(*node)) { buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); - D1(printk(KERN_DEBUG "Fewer than %d bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n", + D1(printk(KERN_DEBUG "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n", sizeof(struct jffs2_unknown_node), buf_len, ofs)); err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); if (err) @@ -410,8 +410,8 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo /* Ran off end. */ D1(printk(KERN_DEBUG "Empty flash ends normally at 0x%08x\n", ofs)); - if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && - !jeb->first_node->next_in_ino && !jeb->dirty_size) + if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && + c->cleanmarker_size && !jeb->first_node->next_in_ino && !jeb->dirty_size) return BLK_STATE_CLEANMARKER; wasempty = 1; continue; @@ -430,7 +430,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo continue; } if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) { - D1(printk(KERN_DEBUG "Empty bitmask at 0x%08x\n", ofs)); + D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs)); DIRTY_SPACE(4); ofs += 4; continue; @@ -492,7 +492,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo case JFFS2_NODETYPE_INODE: if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) { buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); - D1(printk(KERN_DEBUG "Fewer than %d bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n", + D1(printk(KERN_DEBUG "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n", sizeof(struct jffs2_raw_inode), buf_len, ofs)); err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); if (err) @@ -585,8 +585,8 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo } - D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset, - jeb->free_size, jeb->dirty_size, jeb->used_size)); + 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)); /* mark_node_obsolete can add to wasted !! */ if (jeb->wasted_size) { @@ -596,9 +596,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo jeb->wasted_size = 0; } - if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && - !jeb->first_node->next_in_ino && !jeb->dirty_size) + if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size + && (!jeb->first_node || jeb->first_node->next_in_ino) ) 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; diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index e87cdaececb6..8bc53c400875 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: super.c,v 1.74 2002/11/12 09:37:39 dwmw2 Exp $ + * $Id: super.c,v 1.79 2003/05/27 22:35:42 dwmw2 Exp $ * */ @@ -23,7 +23,6 @@ #include <linux/jffs2.h> #include <linux/pagemap.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> #include <linux/ctype.h> #include <linux/namei.h> #include "nodelist.h" @@ -53,7 +52,7 @@ static void jffs2_i_init_once(void * foo, kmem_cache_t * cachep, unsigned long f if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { - init_MUTEX(&ei->sem); + init_MUTEX_LOCKED(&ei->sem); inode_init_once(&ei->vfs_inode); } } @@ -101,9 +100,9 @@ static int jffs2_sb_set(struct super_block *sb, void *data) return 0; } -static struct super_block * -jffs2_get_sb_mtd(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct mtd_info *mtd) +static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct mtd_info *mtd) { struct super_block *sb; struct jffs2_sb_info *c; @@ -153,9 +152,9 @@ jffs2_get_sb_mtd(struct file_system_type *fs_type, int flags, return sb; } -static struct super_block * -jffs2_get_sb_mtdnr(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, int mtdnr) +static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, int mtdnr) { struct mtd_info *mtd; @@ -168,9 +167,9 @@ jffs2_get_sb_mtdnr(struct file_system_type *fs_type, int flags, return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd); } -static struct super_block * -jffs2_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data) +static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) { int err; struct nameidata nd; diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index b63b05425e55..2ba43b76297a 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -7,39 +7,40 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: wbuf.c,v 1.20 2002/11/12 11:33:02 dwmw2 Exp $ - * + some of the dependencies on later MTD NAND code temporarily reverted. + * $Id: wbuf.c,v 1.30 2003/02/19 17:48:49 gleixner Exp $ * */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> #include <linux/crc32.h> #include <linux/mtd/nand.h> #include "nodelist.h" -/* FIXME duplicated defines in wbuf.c and nand.c - * Constants for out of band layout - */ -#ifndef NAND_BADBLOCK_POS -#define NAND_BADBLOCK_POS 5 -#endif -#ifndef NAND_JFFS2_OOB_BADBPOS -#define NAND_JFFS2_OOB_BADBPOS 5 -#define NAND_JFFS2_OOB8_FSDAPOS 6 -#define NAND_JFFS2_OOB16_FSDAPOS 8 -#define NAND_JFFS2_OOB8_FSDALEN 2 -#define NAND_JFFS2_OOB16_FSDALEN 8 -#endif - /* max. erase failures before we mark a block bad */ #define MAX_ERASE_FAILURES 5 /* two seconds timeout for timed wbuf-flushing */ #define WBUF_FLUSH_TIMEOUT 2 * HZ +#define JFFS2_OOB_ECCPOS0 0 +#define JFFS2_OOB_ECCPOS1 1 +#define JFFS2_OOB_ECCPOS2 2 +#define JFFS2_OOB_ECCPOS3 3 +#define JFFS2_OOB_ECCPOS4 6 +#define JFFS2_OOB_ECCPOS5 7 + +#define NAND_JFFS2_OOB8_FSDAPOS 6 +#define NAND_JFFS2_OOB16_FSDAPOS 8 +#define NAND_JFFS2_OOB8_FSDALEN 2 +#define NAND_JFFS2_OOB16_FSDALEN 8 + +struct nand_oobinfo jffs2_oobinfo = { + useecc: 1, + eccpos: {JFFS2_OOB_ECCPOS0, JFFS2_OOB_ECCPOS1, JFFS2_OOB_ECCPOS2, JFFS2_OOB_ECCPOS3, JFFS2_OOB_ECCPOS4, JFFS2_OOB_ECCPOS5} +}; + static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c) { struct list_head *this, *next; @@ -178,13 +179,14 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) /* else jffs2_flash_writev has actually filled in the rest of the buffer for us, and will deal with the node refs etc. later. */ - ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); + ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, &jffs2_oobinfo); if (ret || retlen != c->wbuf_pagesize) { if (ret) printk(KERN_CRIT "jffs2_flush_wbuf(): Write failed with %d\n",ret); else - printk(KERN_CRIT "jffs2_flush_wbuf(): Write was short %d instead of %d\n",retlen,c->wbuf_pagesize); + printk(KERN_CRIT "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", + retlen, c->wbuf_pagesize); ret = -EIO; /* CHECKME NAND @@ -205,7 +207,7 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) /* Adjusting free size of next block only, if it's called from fsync ! */ if (pad == 2) { D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of c->nextblock\n")); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (!c->nextblock) BUG(); /* wbuf_pagesize - wbuf_len is the amount of space that's to be @@ -222,13 +224,13 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) c->free_size -= (c->wbuf_pagesize - c->wbuf_len); c->nextblock->wasted_size += (c->wbuf_pagesize - c->wbuf_len); c->wasted_size += (c->wbuf_pagesize - c->wbuf_len); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); } /* Stick any now-obsoleted blocks on the erase_pending_list */ - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); jffs2_refile_wbuf_blocks(c); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); memset(c->wbuf,0xff,c->wbuf_pagesize); /* adjust write buffer offset, else we get a non contigous write bug */ @@ -394,7 +396,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *invecs, unsi outvecs[splitvec].iov_len = split_ofs; /* We did cross a page boundary, so we write some now */ - ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen); + ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, &jffs2_oobinfo); if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { /* At this point we have no problem, c->wbuf is empty. @@ -442,11 +444,19 @@ alldone: } /* - This is the entry for NOR-Flash. We use it also for NAND to flush wbuf + * This is the entry for flash write. + * Check, if we work on NAND FLASH, if so build an iovec and write it via vritev */ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf) { - return c->mtd->write(c->mtd, ofs, len, retlen, buf); + struct iovec vecs[1]; + + if (jffs2_can_mark_obsolete(c)) + return c->mtd->write(c->mtd, ofs, len, retlen, buf); + + vecs[0].iov_base = (unsigned char *) buf; + vecs[0].iov_len = len; + return jffs2_flash_writev(c, vecs, 1, ofs, retlen); } /* @@ -459,10 +469,11 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re /* Read flash */ if (!jffs2_can_mark_obsolete(c)) { - ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); + ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, &jffs2_oobinfo); if ( (ret == -EIO) && (*retlen == len) ) { - printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%llx) returned ECC error\n", len, ofs); + printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", + len, ofs); /* * We have the raw data without ECC correction in the buffer, maybe * we are lucky and all data or parts are correct. We check the node. @@ -549,7 +560,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb if (retlen < len) { D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read " - "(%d bytes not %d) for block at %08x\n", retlen, len, jeb->offset)); + "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset)); ret = -EIO; goto out; } @@ -593,69 +604,83 @@ out: return ret; } -int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +/* +* Scan for a valid cleanmarker and for bad blocks +* For virtual blocks (concatenated physical blocks) check the cleanmarker +* only in the first page of the first physical block, but scan for bad blocks in all +* physical blocks +*/ +int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { struct jffs2_unknown_node n; unsigned char buf[32]; unsigned char *p; - int ret,i; - size_t retlen; - int fsdata_pos,fsdata_len, oob_size, badblock_pos; + int ret, i, cnt, retval = 0; + size_t retlen, offset; + int fsdata_pos, fsdata_len, oob_size, badblock_pos; + offset = jeb->offset; oob_size = c->mtd->oobsize; - switch(c->mtd->ecctype) { - case MTD_ECC_SW: + switch (c->mtd->ecctype) { + case MTD_ECC_SW: fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS; fsdata_len = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDALEN : NAND_JFFS2_OOB16_FSDALEN; badblock_pos = NAND_BADBLOCK_POS; break; default: - D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Invalid ECC type\n")); + D1 (printk (KERN_WARNING "jffs2_write_nand_cleanmarker(): Invalid ECC type\n")); return -EINVAL; - } - - /* - * We read oob data from page 0 and 1 of the block. - * page 0 contains cleanmarker and badblock info - * page 2 contains failure count of this block - */ - ret = c->mtd->read_oob(c->mtd, jeb->offset, oob_size << 1 , &retlen, buf); - - if (ret) { - D1(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); - return ret; - } - if (retlen < (oob_size << 1) ) { - D1(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%d bytes not %d) for block at %08x\n", retlen, oob_size << 1 , jeb->offset)); - return -EIO; } - /* Check for bad block marker */ - if (buf[badblock_pos] != 0xff) { - D1(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n",jeb->offset)); - return 2; - } - /* Check for failure counter in the second page */ - if (buf[badblock_pos+oob_size] != 0xff) { - D1(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n",jeb->offset,buf[badblock_pos+oob_size])); - return 3; - } + /* Loop through the physical blocks */ + for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) { + /* + * We read oob data from page 0 and 1 of the block. + * page 0 contains cleanmarker and badblock info + * page 1 contains failure count of this block + */ + ret = c->mtd->read_oob (c->mtd, offset, oob_size << 1, &retlen, buf); - n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); - n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); - n.totlen = cpu_to_je32(8); - p = (unsigned char *) &n; - - for (i = 0; i < fsdata_len; i++) { - if (buf[fsdata_pos+i] != p[i]) { - D2(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset)); - return 1; + if (ret) { + D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); + return ret; } + if (retlen < (oob_size << 1)) { + D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size << 1, jeb->offset)); + return -EIO; + } + + /* Check for bad block marker */ + if (buf[badblock_pos] != 0xff) { + D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset)); + return 2; + } + + /* Check for failure counter in the second page */ + if (buf[badblock_pos + oob_size] != 0xff) { + D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n", jeb->offset, buf[badblock_pos + oob_size])); + return 3; + } + + /* Check cleanmarker only on the first physical block */ + if (!cnt) { + n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); + n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); + n.totlen = cpu_to_je32 (8); + p = (unsigned char *) &n; + + for (i = 0; i < fsdata_len; i++) { + if (buf[fsdata_pos + i] != p[i]) { + D2 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset)); + retval = 1; + } + } + } + offset += c->mtd->erasesize; } - - return 0; + return retval; } int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) @@ -686,7 +711,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc return ret; } if (retlen != fsdata_len) { - D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %d not %d\n", jeb->offset, retlen, fsdata_len)); + D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, fsdata_len)); return ret; } return 0; @@ -721,7 +746,7 @@ int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *je } if (retlen < oob_size) { - D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB return short read (%d bytes not %d) for block at %08x\n", retlen, oob_size, jeb->offset)); + D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size, jeb->offset)); return -EIO; } @@ -767,9 +792,8 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock * return ret; } if (retlen != 1) { - D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Short write for block at %08x: %d not 1\n", jeb->offset, retlen)); + D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Short write for block at %08x: %zd not 1\n", jeb->offset, retlen)); return ret; } return 0; } - diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 8a4a8d9890f1..cc50ffbaea3d 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: write.c,v 1.60 2002/09/09 16:29:08 dwmw2 Exp $ + * $Id: write.c,v 1.65 2003/01/21 18:11:29 dwmw2 Exp $ * */ @@ -47,7 +47,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); ri->totlen = cpu_to_je32(PAD(sizeof(*ri))); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); - ri->mode = cpu_to_je32(mode); + ri->mode = cpu_to_jemode(mode); f->highest_version = 1; ri->version = cpu_to_je32(f->highest_version); @@ -55,6 +55,7 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint return 0; } +#if CONFIG_JFFS2_FS_DEBUG > 0 static void writecheck(struct jffs2_sb_info *c, uint32_t ofs) { unsigned char buf[16]; @@ -63,7 +64,7 @@ static void writecheck(struct jffs2_sb_info *c, uint32_t ofs) ret = jffs2_flash_read(c, ofs, 16, &retlen, buf); if (ret || (retlen != 16)) { - D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %d\n", ret, retlen)); + D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %zd\n", ret, retlen)); return; } ret = 0; @@ -79,7 +80,7 @@ static void writecheck(struct jffs2_sb_info *c, uint32_t ofs) buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); } } - +#endif /* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, @@ -105,10 +106,10 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 vecs[1].iov_base = (unsigned char *)data; vecs[1].iov_len = datalen; - writecheck(c, flash_ofs); + D1(writecheck(c, flash_ofs)); if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) { - printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen); + printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen); } raw = jffs2_alloc_raw_node_ref(); if (!raw) @@ -135,7 +136,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen); if (ret || (retlen != sizeof(*ri) + datalen)) { - printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n", + printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", sizeof(*ri)+datalen, flash_ofs, ret, retlen); /* Mark the space as dirtied */ if (retlen) { @@ -162,20 +163,27 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 return ERR_PTR(ret?ret:-EIO); } /* Mark the space used */ - if (datalen == PAGE_CACHE_SIZE) + /* If node covers at least a whole page, or if it starts at the + beginning of a page and runs to the end of the file, or if + it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. + */ + if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) || + ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) && + (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) == je32_to_cpu(ri->isize)))) { raw->flash_offset |= REF_PRISTINE; - else + } else { raw->flash_offset |= REF_NORMAL; + } jffs2_add_physical_node_ref(c, raw); /* Link into per-inode list */ raw->next_in_ino = f->inocache->nodes; f->inocache->nodes = raw; - D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", - flash_ofs, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize), - je32_to_cpu(ri->node_crc), je32_to_cpu(ri->data_crc), - je32_to_cpu(ri->totlen))); + D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", + flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), + je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc), + je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen))); if (writelen) *writelen = retlen; @@ -194,7 +202,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino), je32_to_cpu(rd->name_crc))); - writecheck(c, flash_ofs); + D1(writecheck(c, flash_ofs)); D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n"); @@ -233,7 +241,7 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen); if (ret || (retlen != sizeof(*rd) + namelen)) { - printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n", + printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", sizeof(*rd)+namelen, flash_ofs, ret, retlen); /* Mark the space as dirtied */ if (retlen) { @@ -290,7 +298,7 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, } down(&f->sem); datalen = writelen; - cdatalen = min(alloclen - sizeof(*ri), writelen); + cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), writelen); comprbuf = kmalloc(cdatalen, GFP_KERNEL); if (comprbuf) { @@ -392,7 +400,7 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen); D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n", - je32_to_cpu(ri->mode))); + jemode_to_cpu(ri->mode))); if (IS_ERR(fn)) { D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); |
