diff options
author | Daniel Drake <dsd@laptop.org> | 2010-10-07 14:14:02 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2010-10-24 19:57:19 -0400 |
commit | 65e5a0e18e5fb5bc6cfabd8ef4b9fc1c8569ba62 (patch) | |
tree | 0790ae9e682c5de24b0ffd7111a0bfab4f03aab3 | |
parent | b46daf7eb1a143169699a8f9df634aa751a6ddde (diff) |
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 <dsd@laptop.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r-- | fs/jffs2/build.c | 2 | ||||
-rw-r--r-- | fs/jffs2/fs.c | 22 | ||||
-rw-r--r-- | fs/jffs2/jffs2_fs_sb.h | 1 | ||||
-rw-r--r-- | fs/jffs2/nodelist.c | 8 | ||||
-rw-r--r-- | fs/jffs2/nodelist.h | 3 |
5 files changed, 29 insertions, 7 deletions
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 *, | |||
23 | static inline struct jffs2_inode_cache * | 23 | static inline struct jffs2_inode_cache * |
24 | first_inode_chain(int *i, struct jffs2_sb_info *c) | 24 | first_inode_chain(int *i, struct jffs2_sb_info *c) |
25 | { | 25 | { |
26 | for (; *i < INOCACHE_HASHSIZE; (*i)++) { | 26 | for (; *i < c->inocache_hashsize; (*i)++) { |
27 | if (c->inocache_list[*i]) | 27 | if (c->inocache_list[*i]) |
28 | return c->inocache_list[*i]; | 28 | return c->inocache_list[*i]; |
29 | } | 29 | } |
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 | |||
478 | return inode; | 478 | return inode; |
479 | } | 479 | } |
480 | 480 | ||
481 | static int calculate_inocache_hashsize(uint32_t flash_size) | ||
482 | { | ||
483 | /* | ||
484 | * Pick a inocache hash size based on the size of the medium. | ||
485 | * Count how many megabytes we're dealing with, apply a hashsize twice | ||
486 | * that size, but rounding down to the usual big powers of 2. And keep | ||
487 | * to sensible bounds. | ||
488 | */ | ||
489 | |||
490 | int size_mb = flash_size / 1024 / 1024; | ||
491 | int hashsize = (size_mb * 2) & ~0x3f; | ||
492 | |||
493 | if (hashsize < INOCACHE_HASHSIZE_MIN) | ||
494 | return INOCACHE_HASHSIZE_MIN; | ||
495 | if (hashsize > INOCACHE_HASHSIZE_MAX) | ||
496 | return INOCACHE_HASHSIZE_MAX; | ||
497 | |||
498 | return hashsize; | ||
499 | } | ||
481 | 500 | ||
482 | int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | 501 | int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) |
483 | { | 502 | { |
@@ -524,7 +543,8 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) | |||
524 | if (ret) | 543 | if (ret) |
525 | return ret; | 544 | return ret; |
526 | 545 | ||
527 | c->inocache_list = kcalloc(INOCACHE_HASHSIZE, sizeof(struct jffs2_inode_cache *), GFP_KERNEL); | 546 | c->inocache_hashsize = calculate_inocache_hashsize(c->flash_size); |
547 | c->inocache_list = kcalloc(c->inocache_hashsize, sizeof(struct jffs2_inode_cache *), GFP_KERNEL); | ||
528 | if (!c->inocache_list) { | 548 | if (!c->inocache_list) { |
529 | ret = -ENOMEM; | 549 | ret = -ENOMEM; |
530 | goto out_wbuf; | 550 | 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 { | |||
100 | wait_queue_head_t erase_wait; /* For waiting for erases to complete */ | 100 | wait_queue_head_t erase_wait; /* For waiting for erases to complete */ |
101 | 101 | ||
102 | wait_queue_head_t inocache_wq; | 102 | wait_queue_head_t inocache_wq; |
103 | int inocache_hashsize; | ||
103 | struct jffs2_inode_cache **inocache_list; | 104 | struct jffs2_inode_cache **inocache_list; |
104 | spinlock_t inocache_lock; | 105 | spinlock_t inocache_lock; |
105 | 106 | ||
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 | |||
420 | { | 420 | { |
421 | struct jffs2_inode_cache *ret; | 421 | struct jffs2_inode_cache *ret; |
422 | 422 | ||
423 | ret = c->inocache_list[ino % INOCACHE_HASHSIZE]; | 423 | ret = c->inocache_list[ino % c->inocache_hashsize]; |
424 | while (ret && ret->ino < ino) { | 424 | while (ret && ret->ino < ino) { |
425 | ret = ret->next; | 425 | ret = ret->next; |
426 | } | 426 | } |
@@ -441,7 +441,7 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new | |||
441 | 441 | ||
442 | dbg_inocache("add %p (ino #%u)\n", new, new->ino); | 442 | dbg_inocache("add %p (ino #%u)\n", new, new->ino); |
443 | 443 | ||
444 | prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; | 444 | prev = &c->inocache_list[new->ino % c->inocache_hashsize]; |
445 | 445 | ||
446 | while ((*prev) && (*prev)->ino < new->ino) { | 446 | while ((*prev) && (*prev)->ino < new->ino) { |
447 | prev = &(*prev)->next; | 447 | prev = &(*prev)->next; |
@@ -462,7 +462,7 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) | |||
462 | dbg_inocache("del %p (ino #%u)\n", old, old->ino); | 462 | dbg_inocache("del %p (ino #%u)\n", old, old->ino); |
463 | spin_lock(&c->inocache_lock); | 463 | spin_lock(&c->inocache_lock); |
464 | 464 | ||
465 | prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; | 465 | prev = &c->inocache_list[old->ino % c->inocache_hashsize]; |
466 | 466 | ||
467 | while ((*prev) && (*prev)->ino < old->ino) { | 467 | while ((*prev) && (*prev)->ino < old->ino) { |
468 | prev = &(*prev)->next; | 468 | prev = &(*prev)->next; |
@@ -487,7 +487,7 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c) | |||
487 | int i; | 487 | int i; |
488 | struct jffs2_inode_cache *this, *next; | 488 | struct jffs2_inode_cache *this, *next; |
489 | 489 | ||
490 | for (i=0; i<INOCACHE_HASHSIZE; i++) { | 490 | for (i=0; i < c->inocache_hashsize; i++) { |
491 | this = c->inocache_list[i]; | 491 | this = c->inocache_list[i]; |
492 | while (this) { | 492 | while (this) { |
493 | next = this->next; | 493 | 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 { | |||
199 | #define RAWNODE_CLASS_XATTR_DATUM 1 | 199 | #define RAWNODE_CLASS_XATTR_DATUM 1 |
200 | #define RAWNODE_CLASS_XATTR_REF 2 | 200 | #define RAWNODE_CLASS_XATTR_REF 2 |
201 | 201 | ||
202 | #define INOCACHE_HASHSIZE 128 | 202 | #define INOCACHE_HASHSIZE_MIN 128 |
203 | #define INOCACHE_HASHSIZE_MAX 1024 | ||
203 | 204 | ||
204 | #define write_ofs(c) ((c)->nextblock->offset + (c)->sector_size - (c)->nextblock->free_size) | 205 | #define write_ofs(c) ((c)->nextblock->offset + (c)->sector_size - (c)->nextblock->free_size) |
205 | 206 | ||