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>
 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];
        }
 
        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)
 {
        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;
 
        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;
 
 
 {
        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;
        }
 
        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;
        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;
        int i;
        struct jffs2_inode_cache *this, *next;
 
-       for (i=0; i<INOCACHE_HASHSIZE; i++) {
+       for (i=0; i < c->inocache_hashsize; i++) {
                this = c->inocache_list[i];
                while (this) {
                        next = this->next;
 
 #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)