diff options
Diffstat (limited to 'linux-2.4.x/fs/jffs2/wear_leveling.c')
-rw-r--r-- | linux-2.4.x/fs/jffs2/wear_leveling.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/linux-2.4.x/fs/jffs2/wear_leveling.c b/linux-2.4.x/fs/jffs2/wear_leveling.c new file mode 100644 index 0000000..1eeb713 --- /dev/null +++ b/linux-2.4.x/fs/jffs2/wear_leveling.c @@ -0,0 +1,107 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2005 Zhao Forrest <forrest.zhao@intel.com> + * + * For licensing information, see the file 'LICENCE' in this directory. + * + */ + +#include "nodelist.h" + +void jffs2_add_to_hash_table(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint8_t flag) +{ + struct jffs2_blocks_bucket *hash_table; + uint32_t index, *current_index_p; + + if (flag == 1) { + hash_table = c->used_blocks; + current_index_p = &(c->used_blocks_current_index); + }else if (flag == 2) { + hash_table = c->free_blocks; + current_index_p = &(c->free_blocks_current_index); + }else { + return; + } + + index = (jeb->erase_count >> BUCKET_RANGE_BIT_LEN); + if (index >= HASH_SIZE) { + return; + } + if (index < *current_index_p) { + *current_index_p = index; + } + hash_table[index].number++; + list_add_tail(&jeb->hash_list, &(hash_table[index].chain)); + return; +} + +void jffs2_remove_from_hash_table(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint8_t flag) +{ + struct jffs2_blocks_bucket *hash_table; + uint32_t index, *current_index_p, i; + + if (flag == 1) { + hash_table = c->used_blocks; + current_index_p = &(c->used_blocks_current_index); + }else if (flag == 2) { + hash_table = c->free_blocks; + current_index_p = &(c->free_blocks_current_index); + }else { + return; + } + + index = (jeb->erase_count >> BUCKET_RANGE_BIT_LEN); + if (index >= HASH_SIZE) { + return; + } + hash_table[index].number--; + list_del(&jeb->hash_list); + + if (hash_table[index].number == 0) { + for (i=index+1; i<HASH_SIZE; i++) { + if (hash_table[i].number != 0) { + *current_index_p = i; + break; + } + } + if (i == HASH_SIZE) { + *current_index_p = HASH_SIZE; + } + } + return; +} + +struct jffs2_eraseblock *jffs2_get_free_block(struct jffs2_sb_info *c) +{ + struct list_head *next; + struct jffs2_eraseblock *jeb; + + if (c->free_blocks_current_index == HASH_SIZE) { + return NULL; + } + next = c->free_blocks[c->free_blocks_current_index].chain.next; + jeb = list_entry(next, struct jffs2_eraseblock, hash_list); + list_del(&jeb->list); + jffs2_remove_from_hash_table(c, jeb, 2); + c->nr_free_blocks--; + + return jeb; +} + +struct jffs2_eraseblock *jffs2_get_used_block(struct jffs2_sb_info *c) +{ + struct list_head *next; + struct jffs2_eraseblock *jeb; + + if (c->used_blocks_current_index == HASH_SIZE) { + return NULL; + } + next = c->used_blocks[c->used_blocks_current_index].chain.next; + jeb = list_entry(next, struct jffs2_eraseblock, hash_list); + list_del(&jeb->list); + jffs2_remove_from_hash_table(c, jeb, 1); + + return jeb; +} + |