[PATCH] Enhancement to current 1:1 mapping handling in JFFS2

Jörn Engel joern at wohnheim.fh-wedel.de
Sun Sep 25 06:30:38 EDT 2005


On Thu, 22 September 2005 16:37:45 +0800, zhao forrest wrote:
> 
> This patch gave a possible method to improve the current 1:1
> mapping handling in JFFS2.
> 
> Data structure:
> 1 A slab cache for struct jffs2_eraseblock; is created, so
> struc jffs2_eraseblock is allocated from this slab cache.
> 2 A pointer array is created by kmalloc(), and the pointer
> point to the struct jffs2_eraseblock allocated from slab cache.
> 
> By storing pointers instead of "struct jffs2_eraseblock"s into
> continuous memory space, we reduce the pressure of continuous
> memory space requirement.
> 
> On a 32-bit system, 128K continuous memory allocated by kmalloc()
> can hold 32K pointers. 
> So if the eraseblock size is 4K, it can support 128M flash memory.
> if the eraseblock size is 8K, it can support 256M flash memory.
> 
> I think this patch can support most of flashes now. If there's
> size limitation report in the future, we can add another level of
> pointers to meet the requirement.

This could become a limit already.  Block devices going through a
translation usually have 4k as erase size.  Any USB key above 128KiB
will be a problem.

Not sure what we want to do about this.

> diff -auNrp ./mtd_EBH_EBS/fs/jffs2/build.c ./mtd_EBH_EBS_1on1/fs/jffs2/build.c
> --- ./mtd_EBH_EBS/fs/jffs2/build.c	2005-09-22 13:13:51.000000000 +0800
> +++ ./mtd_EBH_EBS_1on1/fs/jffs2/build.c	2005-09-22 15:01:40.000000000 +0800
> @@ -305,34 +305,51 @@ static void jffs2_calc_trigger_levels(st
>  		  c->nospc_dirty_size);
>  } 
>  
> +void jffs2_free_eraseblocks(struct jffs2_sb_info *c, uint32_t number)
> +{
> +	uint32_t i;
> +
> +	for(i=0; i<number; i++) {
> +		jffs2_free_eraseblock(c->blocks[i]);
> +	}
> +	return;
> +}

Is there a reason why this function doesn't encapsulate everything to
free all objects?

void jffs2_free_eraseblocks(struct jffs2_sb_info *c)
{
	u32 i = c->nr_blocks - 1;

	for (; i>=0; i--)
		jffs2_free_eraseblock(c->blocks[i]);
	kfree(c->blocks);
}

Should be safe from all contexts.  Failure case is a slow path anyway,
so iterating through the full array shouldn't matter too much.

>  int jffs2_do_mount_fs(struct jffs2_sb_info *c)
>  {
>  	int ret;
> -	int i;
> +	uint32_t i, number = 0;
>  
>  	c->free_size = c->flash_size;
>  	c->nr_blocks = c->flash_size / c->sector_size;
> -#ifndef __ECOS
> -	if (jffs2_blocks_use_vmalloc(c))
> -		c->blocks = vmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks);
> -	else
> -#endif
> -		c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
> +
> +	c->blocks = kmalloc(sizeof(char *) * c->nr_blocks, GFP_KERNEL);
>  	if (!c->blocks)
>  		return -ENOMEM;
> +
> +	for (i=0; i<c->nr_blocks; i++) {
> +		c->blocks[i] = jffs2_alloc_eraseblock();
> +		if (!c->blocks[i]) {
> +			ret = -ENOMEM;
> +			number = i;
> +			goto failed;
> +		}
> +	}
> +	number = c->nr_blocks;

This could be moved into a function, analog to the above.

static int jffs2_alloc_eraseblocks(struct jffs2_sb_info *c)
{
	int i = c->nr_blocks - 1;

	c->blocks = kzalloc(sizeof(char *) * c->nr_blocks, GFP_KERNEL);
	if (!c->blocks)
		return -ENOMEM;

	for (; i>=0; i--) {
		c->blocks[i] = jffs2_alloc_eraseblock();
		if (!c->blocks[i]) {
			jffs2_free_eraseblocks(c);
			return -ENOMEM;
		}
	}
	return 0;
}

>  	for (i=0; i<c->nr_blocks; i++) {
> -		INIT_LIST_HEAD(&c->blocks[i].list);
> -		c->blocks[i].offset = i * c->sector_size;
> -		c->blocks[i].free_size = c->sector_size;
> -		c->blocks[i].dirty_size = 0;
> -		c->blocks[i].wasted_size = 0;
> -		c->blocks[i].unchecked_size = 0;
> -		c->blocks[i].used_size = 0;
> -		c->blocks[i].first_node = NULL;
> -		c->blocks[i].last_node = NULL;
> -		c->blocks[i].bad_count = 0;
> -		c->blocks[i].has_eraseblock_header = 0;
> -		c->blocks[i].erase_count = 0;
> +		INIT_LIST_HEAD(&c->blocks[i]->list);
> +		c->blocks[i]->offset = i * c->sector_size;
> +		c->blocks[i]->free_size = c->sector_size;
> +		c->blocks[i]->dirty_size = 0;
> +		c->blocks[i]->wasted_size = 0;
> +		c->blocks[i]->unchecked_size = 0;
> +		c->blocks[i]->used_size = 0;
> +		c->blocks[i]->first_node = NULL;
> +		c->blocks[i]->last_node = NULL;
> +		c->blocks[i]->bad_count = 0;
> +		c->blocks[i]->has_eraseblock_header = 0;
> +		c->blocks[i]->erase_count = 0;
>  	}

Most of those fields are initialized to 0 or NULL.  Maybe we should
just kzalloc() or memset() the complete object, then initialize the
few fields that are non-zero.  If that reduces the text size, it'd be
worth it.

>  	INIT_LIST_HEAD(&c->clean_list);
> @@ -351,22 +368,22 @@ int jffs2_do_mount_fs(struct jffs2_sb_in
>  
>  	ret = jffs2_sum_init(c);
>  	if (ret)
> -		return ret;
> +		goto failed;
>  
>  	if (jffs2_build_filesystem(c)) {
>  		dbg_fsbuild("build_fs failed\n");
> -		jffs2_free_ino_caches(c);
> -		jffs2_free_raw_node_refs(c);
> -#ifndef __ECOS
> -		if (jffs2_blocks_use_vmalloc(c))
> -			vfree(c->blocks);
> -		else 
> -#endif
> -			kfree(c->blocks);
> -
> -		return -EIO;
> -	}
> +		ret = -EIO;
> +	} else
> +		goto out;
> +
> +failed:
> +	jffs2_free_ino_caches(c);
> +	jffs2_free_raw_node_refs(c);
> +	jffs2_free_eraseblocks(c, number);
> +	kfree(jffs2_free_eraseblocks);
> +	return ret;

This logic would be a bit simpler if allocation is moved into a
function.

> +out:
>  	jffs2_calc_trigger_levels(c);
>  
>  	return 0;
> @@ -205,3 +214,17 @@ void jffs2_free_inode_cache(struct jffs2
>  	dbg_memalloc("%p\n", x);
>  	kmem_cache_free(inode_cache_slab, x);
>  }
> +
> +struct jffs2_eraseblock *jffs2_alloc_eraseblock(void)
> +{
> +	struct jffs2_eraseblock *ret;
> +	ret = kmem_cache_alloc(eraseblock_slab, GFP_KERNEL);
> +	dbg_memalloc("%p\n", ret);
> +	return ret;
> +}

And now that we have this function, we can move the object
initialization into it.

	memset(ret, 0, sizeof(*ret));
	ret->foo = bar;
	...

>  void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count);
> diff -auNrp ./mtd_EBH_EBS/fs/jffs2/super.c ./mtd_EBH_EBS_1on1/fs/jffs2/super.c
> --- ./mtd_EBH_EBS/fs/jffs2/super.c	2005-09-22 13:13:51.000000000 +0800
> +++ ./mtd_EBH_EBS_1on1/fs/jffs2/super.c	2005-09-22 15:03:49.000000000 +0800
> @@ -287,10 +287,8 @@ static void jffs2_put_super (struct supe
>  
>  	jffs2_free_ino_caches(c);
>  	jffs2_free_raw_node_refs(c);
> -	if (jffs2_blocks_use_vmalloc(c))
> -		vfree(c->blocks);
> -	else
> -		kfree(c->blocks);
> +	jffs2_free_eraseblocks(c, c->nr_blocks);
> +	kfree(c->blocks);
	jffs2_free_eraseblocks(c);

Would be much nicer. ;)

>  	jffs2_flash_cleanup(c);
>  	kfree(c->inocache_list);
>  	if (c->mtd->sync)


Jörn

-- 
Fools ignore complexity.  Pragmatists suffer it.
Some can avoid it.  Geniuses remove it.
-- Perlis's Programming Proverb #58, SIGPLAN Notices, Sept.  1982




More information about the linux-mtd mailing list