From 3866f673ebd86e5be2533923f5c0aed91fe1669f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 1 Sep 2010 18:03:41 +0200 Subject: jffs2: use cond_resched() instead of yield() yield() has different semantics meanwhile and even causes RT-kernels to BUG. Replace the only appearance left in jffs2. Signed-off-by: Wolfram Sang Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- fs/jffs2/erase.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index abac961f617b..e513f1913c15 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -151,7 +151,7 @@ int jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) } /* Be nice */ - yield(); + cond_resched(); mutex_lock(&c->erase_free_sem); spin_lock(&c->erase_completion_lock); } -- cgit v1.2.3 From 088bd455c954c0c42edde9d4463e44be10101aac Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 22 Sep 2010 22:52:33 -0400 Subject: jffs2: drop unused model argument The jffs2 compression framework provides a "model" argument when compressing and decompressing, but the caller always passes in NULL and the callees never use it. So punt this useless overhead. Signed-off-by: Mike Frysinger Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- fs/jffs2/compr.c | 6 +++--- fs/jffs2/compr.h | 4 ++-- fs/jffs2/compr_lzo.c | 4 ++-- fs/jffs2/compr_rtime.c | 6 ++---- fs/jffs2/compr_rubin.c | 11 ++++------- fs/jffs2/compr_zlib.c | 6 ++---- 6 files changed, 15 insertions(+), 22 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index 617a1e5694c1..de4247021d25 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c @@ -103,7 +103,7 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, spin_unlock(&jffs2_compressor_list_lock); *datalen = orig_slen; *cdatalen = orig_dlen; - compr_ret = this->compress(data_in, output_buf, datalen, cdatalen, NULL); + compr_ret = this->compress(data_in, output_buf, datalen, cdatalen); spin_lock(&jffs2_compressor_list_lock); this->usecount--; if (!compr_ret) { @@ -152,7 +152,7 @@ uint16_t jffs2_compress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, spin_unlock(&jffs2_compressor_list_lock); *datalen = orig_slen; *cdatalen = orig_dlen; - compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen, NULL); + compr_ret = this->compress(data_in, this->compr_buf, datalen, cdatalen); spin_lock(&jffs2_compressor_list_lock); this->usecount--; if (!compr_ret) { @@ -220,7 +220,7 @@ int jffs2_decompress(struct jffs2_sb_info *c, struct jffs2_inode_info *f, if (comprtype == this->compr) { this->usecount++; spin_unlock(&jffs2_compressor_list_lock); - ret = this->decompress(cdata_in, data_out, cdatalen, datalen, NULL); + ret = this->decompress(cdata_in, data_out, cdatalen, datalen); spin_lock(&jffs2_compressor_list_lock); if (ret) { printk(KERN_WARNING "Decompressor \"%s\" returned %d\n", this->name, ret); diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index e471a9106fd9..13bb7597ab39 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h @@ -49,9 +49,9 @@ struct jffs2_compressor { char *name; char compr; /* JFFS2_COMPR_XXX */ int (*compress)(unsigned char *data_in, unsigned char *cpage_out, - uint32_t *srclen, uint32_t *destlen, void *model); + uint32_t *srclen, uint32_t *destlen); int (*decompress)(unsigned char *cdata_in, unsigned char *data_out, - uint32_t cdatalen, uint32_t datalen, void *model); + uint32_t cdatalen, uint32_t datalen); int usecount; int disabled; /* if set the compressor won't compress */ unsigned char *compr_buf; /* used by size compr. mode */ diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c index ed25ae7c98eb..af186ee674d8 100644 --- a/fs/jffs2/compr_lzo.c +++ b/fs/jffs2/compr_lzo.c @@ -42,7 +42,7 @@ static int __init alloc_workspace(void) } static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out, - uint32_t *sourcelen, uint32_t *dstlen, void *model) + uint32_t *sourcelen, uint32_t *dstlen) { size_t compress_size; int ret; @@ -67,7 +67,7 @@ static int jffs2_lzo_compress(unsigned char *data_in, unsigned char *cpage_out, } static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, - uint32_t srclen, uint32_t destlen, void *model) + uint32_t srclen, uint32_t destlen) { size_t dl = destlen; int ret; diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 9696ad9ef5f7..16a5047903a6 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c @@ -31,8 +31,7 @@ /* _compress returns the compressed size, -1 if bigger */ static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, - uint32_t *sourcelen, uint32_t *dstlen, - void *model) + uint32_t *sourcelen, uint32_t *dstlen) { short positions[256]; int outpos = 0; @@ -73,8 +72,7 @@ static int jffs2_rtime_compress(unsigned char *data_in, static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, - uint32_t srclen, uint32_t destlen, - void *model) + uint32_t srclen, uint32_t destlen) { short positions[256]; int outpos = 0; diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index a12b4f763373..9e7cec808c4c 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c @@ -298,7 +298,7 @@ static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, #if 0 /* _compress returns the compressed size, -1 if bigger */ int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, - uint32_t *sourcelen, uint32_t *dstlen, void *model) + uint32_t *sourcelen, uint32_t *dstlen) { return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); @@ -306,8 +306,7 @@ int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, #endif static int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, - uint32_t *sourcelen, uint32_t *dstlen, - void *model) + uint32_t *sourcelen, uint32_t *dstlen) { int bits[8]; unsigned char histo[256]; @@ -387,8 +386,7 @@ static void rubin_do_decompress(int bit_divider, int *bits, static int jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, - uint32_t sourcelen, uint32_t dstlen, - void *model) + uint32_t sourcelen, uint32_t dstlen) { rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); @@ -397,8 +395,7 @@ static int jffs2_rubinmips_decompress(unsigned char *data_in, static int jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, - uint32_t sourcelen, uint32_t dstlen, - void *model) + uint32_t sourcelen, uint32_t dstlen) { int bits[8]; int c; diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 97fc45de6f81..fd05a0b9431d 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c @@ -68,8 +68,7 @@ static void free_workspaces(void) static int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, - uint32_t *sourcelen, uint32_t *dstlen, - void *model) + uint32_t *sourcelen, uint32_t *dstlen) { int ret; @@ -136,8 +135,7 @@ static int jffs2_zlib_compress(unsigned char *data_in, static int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, - uint32_t srclen, uint32_t destlen, - void *model) + uint32_t srclen, uint32_t destlen) { int ret; int wbits = MAX_WBITS; -- cgit v1.2.3 From 65e5a0e18e5fb5bc6cfabd8ef4b9fc1c8569ba62 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Thu, 7 Oct 2010 19:14:02 +0100 Subject: jffs2: Dynamically choose inocache hash size When JFFS2 is used for large volumes, the mount times are quite long. Increasing the hash size provides a significant speed boost on the OLPC XO-1 laptop. Add logic that dynamically selects a hash size based on the size of the medium. A 64mb medium will result in a hash size of 128, and a 512mb medium will result in a hash size of 1024. Signed-off-by: Daniel Drake Signed-off-by: David Woodhouse --- fs/jffs2/build.c | 2 +- fs/jffs2/fs.c | 22 +++++++++++++++++++++- fs/jffs2/jffs2_fs_sb.h | 1 + fs/jffs2/nodelist.c | 8 ++++---- fs/jffs2/nodelist.h | 3 ++- 5 files changed, 29 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index a906f538d11c..85c6be2db02f 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -23,7 +23,7 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, static inline struct jffs2_inode_cache * first_inode_chain(int *i, struct jffs2_sb_info *c) { - for (; *i < INOCACHE_HASHSIZE; (*i)++) { + for (; *i < c->inocache_hashsize; (*i)++) { if (c->inocache_list[*i]) return c->inocache_list[*i]; } diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 6b2964a19850..2701b372da78 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -478,6 +478,25 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i return inode; } +static int calculate_inocache_hashsize(uint32_t flash_size) +{ + /* + * Pick a inocache hash size based on the size of the medium. + * Count how many megabytes we're dealing with, apply a hashsize twice + * that size, but rounding down to the usual big powers of 2. And keep + * to sensible bounds. + */ + + int size_mb = flash_size / 1024 / 1024; + int hashsize = (size_mb * 2) & ~0x3f; + + if (hashsize < INOCACHE_HASHSIZE_MIN) + return INOCACHE_HASHSIZE_MIN; + if (hashsize > INOCACHE_HASHSIZE_MAX) + return INOCACHE_HASHSIZE_MAX; + + return hashsize; +} int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) { @@ -524,7 +543,8 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) if (ret) return ret; - c->inocache_list = kcalloc(INOCACHE_HASHSIZE, sizeof(struct jffs2_inode_cache *), GFP_KERNEL); + c->inocache_hashsize = calculate_inocache_hashsize(c->flash_size); + c->inocache_list = kcalloc(c->inocache_hashsize, sizeof(struct jffs2_inode_cache *), GFP_KERNEL); if (!c->inocache_list) { ret = -ENOMEM; goto out_wbuf; diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 6784bc89add1..f864005de64c 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h @@ -100,6 +100,7 @@ struct jffs2_sb_info { wait_queue_head_t erase_wait; /* For waiting for erases to complete */ wait_queue_head_t inocache_wq; + int inocache_hashsize; struct jffs2_inode_cache **inocache_list; spinlock_t inocache_lock; diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index af02bd138469..5e03233c2363 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -420,7 +420,7 @@ struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t { struct jffs2_inode_cache *ret; - ret = c->inocache_list[ino % INOCACHE_HASHSIZE]; + ret = c->inocache_list[ino % c->inocache_hashsize]; while (ret && ret->ino < ino) { ret = ret->next; } @@ -441,7 +441,7 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new dbg_inocache("add %p (ino #%u)\n", new, new->ino); - prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; + prev = &c->inocache_list[new->ino % c->inocache_hashsize]; while ((*prev) && (*prev)->ino < new->ino) { prev = &(*prev)->next; @@ -462,7 +462,7 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) dbg_inocache("del %p (ino #%u)\n", old, old->ino); spin_lock(&c->inocache_lock); - prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; + prev = &c->inocache_list[old->ino % c->inocache_hashsize]; while ((*prev) && (*prev)->ino < old->ino) { prev = &(*prev)->next; @@ -487,7 +487,7 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c) int i; struct jffs2_inode_cache *this, *next; - for (i=0; iinocache_hashsize; i++) { this = c->inocache_list[i]; while (this) { next = this->next; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 523a91691052..5a53d9bdb2b5 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -199,7 +199,8 @@ struct jffs2_inode_cache { #define RAWNODE_CLASS_XATTR_DATUM 1 #define RAWNODE_CLASS_XATTR_REF 2 -#define INOCACHE_HASHSIZE 128 +#define INOCACHE_HASHSIZE_MIN 128 +#define INOCACHE_HASHSIZE_MAX 1024 #define write_ofs(c) ((c)->nextblock->offset + (c)->sector_size - (c)->nextblock->free_size) -- cgit v1.2.3 From 81cfc9f1f4ad8d335367bb393bd042cc45b00047 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 7 Oct 2010 18:01:44 +0200 Subject: jffs2: Fix serious write stall due to erase Drop the alloc_sem before erasing flash in jffs2_garbage_collect_pass(). Otherwise writes are put on hold until the erase has finised. Signed-off-by: Joakim Tjernlund Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- fs/jffs2/gc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 846a79452497..31dce611337c 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -219,13 +219,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) if (!list_empty(&c->erase_complete_list) || !list_empty(&c->erase_pending_list)) { spin_unlock(&c->erase_completion_lock); + mutex_unlock(&c->alloc_sem); D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() erasing pending blocks\n")); - if (jffs2_erase_pending_blocks(c, 1)) { - mutex_unlock(&c->alloc_sem); + if (jffs2_erase_pending_blocks(c, 1)) return 0; - } + D1(printk(KERN_DEBUG "No progress from erasing blocks; doing GC anyway\n")); spin_lock(&c->erase_completion_lock); + mutex_lock(&c->alloc_sem); } /* First, work out which block we're garbage-collecting */ -- cgit v1.2.3 From 41bdc602eca8738d6f3c71235744f72d888fe6b4 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Thu, 7 Oct 2010 19:09:34 +0200 Subject: jffs2: Reduce excessive scan of empty blocks Scanning 1024 bytes to see if an EB is empty is a bit much. Lower it to 256 bytes and make sure the while loop is optimized. Signed-off-by: Joakim Tjernlund Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- fs/jffs2/scan.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 46f870d1cc36..b632dddcb482 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -20,7 +20,7 @@ #include "summary.h" #include "debug.h" -#define DEFAULT_EMPTY_SCAN_SIZE 1024 +#define DEFAULT_EMPTY_SCAN_SIZE 256 #define noisy_printk(noise, args...) do { \ if (*(noise)) { \ @@ -435,7 +435,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { struct jffs2_unknown_node *node; struct jffs2_unknown_node crcnode; - uint32_t ofs, prevofs; + uint32_t ofs, prevofs, max_ofs; uint32_t hdr_crc, buf_ofs, buf_len; int err; int noise = 0; @@ -550,12 +550,12 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ ofs = 0; - - /* Scan only 4KiB of 0xFF before declaring it's empty */ - while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) + max_ofs = EMPTY_SCAN_SIZE(c->sector_size); + /* Scan only EMPTY_SCAN_SIZE of 0xFF before declaring it's empty */ + while(ofs < max_ofs && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) ofs += 4; - if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) { + if (ofs == max_ofs) { #ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (jffs2_cleanmarker_oob(c)) { /* scan oob, take care of cleanmarker */ -- cgit v1.2.3 From 04aadf36de625647c72ec24c7e901896dd2a99e6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 17 Oct 2010 21:56:15 +0200 Subject: jffs2: use kmemdup Convert a sequence of kmalloc and memcpy to use kmemdup. The semantic patch that performs this transformation is: (http://coccinelle.lip6.fr/) // @@ expression a,flag,len; expression arg,e1,e2; statement S; @@ a = - \(kmalloc\|kzalloc\)(len,flag) + kmemdup(arg,len,flag) <... when != a if (a == NULL || ...) S ...> - memcpy(a,arg,len+1); // Signed-off-by: Julia Lawall Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse --- fs/jffs2/dir.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index ed78a3cf3cb0..dd745c361d7c 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -367,7 +367,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char } /* We use f->target field to store the target path. */ - f->target = kmalloc(targetlen + 1, GFP_KERNEL); + f->target = kmemdup(target, targetlen + 1, GFP_KERNEL); if (!f->target) { printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); mutex_unlock(&f->sem); @@ -376,7 +376,6 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char goto fail; } - memcpy(f->target, target, targetlen + 1); D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->target)); /* No data here. Only a metadata node, which will be -- cgit v1.2.3