Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9bfeb691 authored by David Woodhouse's avatar David Woodhouse
Browse files

[JFFS2] Switch to using an array of jffs2_raw_node_refs instead of a list.



This allows us to drop another pointer from the struct jffs2_raw_node_ref,
shrinking it to 8 bytes on 32-bit machines (if the TEST_TOTLEN) paranoia
check is turned off, which will be committed soon).

Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent f75e5097
Loading
Loading
Loading
Loading
+13 −8
Original line number Diff line number Diff line
@@ -285,20 +285,25 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,

void jffs2_free_jeb_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
	struct jffs2_raw_node_ref *ref;
	struct jffs2_raw_node_ref *block, *ref;
	D1(printk(KERN_DEBUG "Freeing all node refs for eraseblock offset 0x%08x\n", jeb->offset));
	while(jeb->first_node) {
		ref = jeb->first_node;
		jeb->first_node = ref->next_phys;

		/* Remove from the inode-list */
		if (ref->next_in_ino)
	block = ref = jeb->first_node;

	while (ref) {
		if (ref->flash_offset == REF_LINK_NODE) {
			ref = ref->next_in_ino;
			jffs2_free_refblock(block);
			block = ref;
			continue;
		}
		if (ref->flash_offset != REF_EMPTY_NODE && ref->next_in_ino)
			jffs2_remove_node_refs_from_ino_list(c, ref, jeb);
		/* else it was a non-inode node or already removed, so don't bother */

		__jffs2_free_raw_node_ref(ref);
		ref++;
	}
	jeb->last_node = NULL;
	jeb->first_node = jeb->last_node = NULL;
}

static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *bad_offset)
+0 −3
Original line number Diff line number Diff line
@@ -26,9 +26,6 @@ struct jffs2_inodirty;
struct jffs2_sb_info {
	struct mtd_info *mtd;

	struct jffs2_raw_node_ref *refs;
	int reserved_refs;

	uint32_t highest_ino;
	uint32_t checked_ino;

+51 −24
Original line number Diff line number Diff line
@@ -57,8 +57,8 @@ int __init jffs2_create_slab_caches(void)
	if (!tmp_dnode_info_slab)
		goto err;

	raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref",
					      sizeof(struct jffs2_raw_node_ref),
	raw_node_ref_slab = kmem_cache_create("jffs2_refblock",
					      sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1),
					      0, 0, NULL, NULL);
	if (!raw_node_ref_slab)
		goto err;
@@ -190,38 +190,65 @@ void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x)
	kmem_cache_free(tmp_dnode_info_slab, x);
}

struct jffs2_raw_node_ref *jffs2_alloc_refblock(void)
{
	struct jffs2_raw_node_ref *ret;

	ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
	if (ret) {
		int i = 0;
		for (i=0; i < REFS_PER_BLOCK; i++) {
			ret[i].flash_offset = REF_EMPTY_NODE;
			ret[i].next_in_ino = NULL;
		}
		ret[i].flash_offset = REF_LINK_NODE;
		ret[i].next_in_ino = NULL;
	}
	return ret;
}

int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c,
				 struct jffs2_eraseblock *jeb, int nr)
{
	struct jffs2_raw_node_ref *p = c->refs;
	struct jffs2_raw_node_ref **p, *ref;
	int i = nr;

	dbg_memalloc("%d\n", nr);

	while (nr && p) {
		p = p->next_in_ino;
		nr--;
	}
	while (nr) {
		p = __jffs2_alloc_raw_node_ref();
		if (!p)
	p = &jeb->last_node;
	ref = *p;

	dbg_memalloc("Reserving %d refs for block @0x%08x\n", nr, jeb->offset);

	/* If jeb->last_node is really a valid node then skip over it */
	if (ref && ref->flash_offset != REF_EMPTY_NODE)
		ref++;

	while (i) {
		if (!ref) {
			dbg_memalloc("Allocating new refblock linked from %p\n", p);
			ref = *p = jffs2_alloc_refblock();
			if (!ref)
				return -ENOMEM;
		p->next_in_ino = c->refs;
		c->refs = p;
		nr--;
		}
	c->reserved_refs = nr;
	return 0;
		if (ref->flash_offset == REF_LINK_NODE) {
			p = &ref->next_in_ino;
			ref = *p;
			continue;
		}
		i--;
		ref++;
	}
	jeb->allocated_refs = nr;

struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void)
{
	struct jffs2_raw_node_ref *ret;
	ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
	dbg_memalloc("%p\n", ret);
	return ret;
	dbg_memalloc("Reserved %d refs for block @0x%08x, last_node is %p (%08x,%p)\n",
		  nr, jeb->offset, jeb->last_node, jeb->last_node->flash_offset,
		  jeb->last_node->next_in_ino);

	return 0;
}

void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x)
void jffs2_free_refblock(struct jffs2_raw_node_ref *x)
{
	dbg_memalloc("%p\n", x);
	kmem_cache_free(raw_node_ref_slab, x);
+47 −46
Original line number Diff line number Diff line
@@ -954,18 +954,16 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c)
	for (i=0; i<c->nr_blocks; i++) {
		this = c->blocks[i].first_node;
		while (this) {
			next = this->next_phys;
			__jffs2_free_raw_node_ref(this);
			if (this[REFS_PER_BLOCK].flash_offset == REF_LINK_NODE)
				next = this[REFS_PER_BLOCK].next_in_ino;
			else
				next = NULL;

			jffs2_free_refblock(this);
			this = next;
		}
		c->blocks[i].first_node = c->blocks[i].last_node = NULL;
	}
	this = c->refs;
	while (this) {
		next = this->next_in_ino;
		__jffs2_free_raw_node_ref(this);
		this = next;
	}
}

struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset)
@@ -1060,32 +1058,37 @@ struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c,
{
	struct jffs2_raw_node_ref *ref;

	/* These will be preallocated _very_ shortly. */
	ref = c->refs;
	if (!c->refs) {
		JFFS2_WARNING("Using non-preallocated refs!\n");
		ref = __jffs2_alloc_raw_node_ref();
		BUG_ON(!ref);
		WARN_ON(1);
	} else {
		c->refs = ref->next_in_ino;
	BUG_ON(!jeb->allocated_refs);
	jeb->allocated_refs--;

	ref = jeb->last_node;

	dbg_noderef("Last node at %p is (%08x,%p)\n", ref, ref->flash_offset,
		    ref->next_in_ino);

	while (ref->flash_offset != REF_EMPTY_NODE) {
		if (ref->flash_offset == REF_LINK_NODE)
			ref = ref->next_in_ino;
		else
			ref++;
	}

	ref->next_phys = NULL;
	dbg_noderef("New ref is %p (%08x becomes %08x,%p) len 0x%x\n", ref, 
		    ref->flash_offset, ofs, ref->next_in_ino, len);

	ref->flash_offset = ofs;

	if (!jeb->first_node)
	if (!jeb->first_node) {
		jeb->first_node = ref;
	if (jeb->last_node) {
		jeb->last_node->next_phys = ref;
#ifdef TEST_TOTLEN
		if (ref_offset(jeb->last_node) + jeb->last_node->__totlen != ref_offset(ref)) {
			printk(KERN_CRIT "Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n",
			       ref, ref_offset(ref), ref_offset(ref)+ref->__totlen,
			       ref_offset(jeb->last_node), ref_offset(jeb->last_node)+jeb->last_node->__totlen);
			WARN_ON(1);
		}
#endif
		BUG_ON(ref_offset(ref) != jeb->offset);
	} else if (unlikely(ref_offset(ref) != jeb->offset + c->sector_size - jeb->free_size)) {
		uint32_t last_len = ref_totlen(c, jeb, jeb->last_node);

		JFFS2_ERROR("Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n",
			    ref, ref_offset(ref), ref_offset(ref)+len,
			    ref_offset(jeb->last_node), 
			    ref_offset(jeb->last_node)+last_len);
		BUG();
	}
	jeb->last_node = ref;

@@ -1130,12 +1133,13 @@ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
{
	if (!size)
		return 0;
	if (size > c->sector_size - jeb->used_size) {
		printk(KERN_CRIT "Dirty space 0x%x larger then used_size 0x%x (wasted 0x%x)\n",
		       size, jeb->used_size, jeb->wasted_size);
	if (unlikely(size > jeb->free_size)) {
		printk(KERN_CRIT "Dirty space 0x%x larger then free_size 0x%x (wasted 0x%x)\n",
		       size, jeb->free_size, jeb->wasted_size);
		BUG();
	}
	if (jeb->last_node && ref_obsolete(jeb->last_node)) {
	/* REF_EMPTY_NODE is !obsolete, so that works OK */
	if (ref_obsolete(jeb->last_node)) {
#ifdef TEST_TOTLEN
		jeb->last_node->__totlen += size;
#endif
@@ -1168,7 +1172,7 @@ static inline uint32_t __ref_totlen(struct jffs2_sb_info *c,
			jeb = &c->blocks[ref->flash_offset / c->sector_size];

		/* Last node in block. Use free_space */
		if (ref != jeb->last_node) {
		if (unlikely(ref != jeb->last_node)) {
			printk(KERN_CRIT "ref %p @0x%08x is not jeb->last_node (%p @0x%08x)\n",
			       ref, ref_offset(ref), jeb->last_node, jeb->last_node?ref_offset(jeb->last_node):0);
			BUG();
@@ -1183,17 +1187,13 @@ uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
{
	uint32_t ret;

#if CONFIG_JFFS2_FS_DEBUG > 0
	if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) {
		printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n",
		       jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref));
		BUG();
	}
#endif

	ret = __ref_totlen(c, jeb, ref);

#ifdef TEST_TOTLEN
	if (ret != ref->__totlen) {
	if (unlikely(ret != ref->__totlen)) {
		if (!jeb)
			jeb = &c->blocks[ref->flash_offset / c->sector_size];

		printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n",
		       ref, ref_offset(ref), ref_offset(ref)+ref->__totlen,
		       ret, ref->__totlen);
@@ -1204,13 +1204,14 @@ uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
			printk(KERN_CRIT "No next ref. jeb->last_node is %p\n", jeb->last_node);

		printk(KERN_CRIT "jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x\n", jeb->wasted_size, jeb->dirty_size, jeb->used_size, jeb->free_size);
		ret = ref->__totlen;
		if (!jeb)
			jeb = &c->blocks[ref->flash_offset / c->sector_size];

#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
		__jffs2_dbg_dump_node_refs_nolock(c, jeb);
#endif

		WARN_ON(1);

		ret = ref->__totlen;
	}
#endif /* TEST_TOTLEN */
	return ret;
+26 −5
Original line number Diff line number Diff line
@@ -80,7 +80,6 @@ struct jffs2_raw_node_ref
		for this object. If this _is_ the last, it points to the inode_cache,
		xattr_ref or xattr_datum instead. The common part of those structures
		has NULL in the first word. See jffs2_raw_ref_to_ic() below */
	struct jffs2_raw_node_ref *next_phys;
	uint32_t flash_offset;
#define TEST_TOTLEN
#ifdef TEST_TOTLEN
@@ -88,7 +87,29 @@ struct jffs2_raw_node_ref
#endif
};

#define ref_next(r) ((r)->next_phys)
#define REF_LINK_NODE ((int32_t)-1)
#define REF_EMPTY_NODE ((int32_t)-2)

/* Use blocks of about 256 bytes */
#define REFS_PER_BLOCK ((255/sizeof(struct jffs2_raw_node_ref))-1)

static inline struct jffs2_raw_node_ref *ref_next(struct jffs2_raw_node_ref *ref)
{
	ref++;

	/* Link to another block of refs */
	if (ref->flash_offset == REF_LINK_NODE) {
		ref = ref->next_in_ino;
		if (!ref)
			return ref;
	}

	/* End of chain */
	if (ref->flash_offset == REF_EMPTY_NODE)
		return NULL;

	return ref;
}

static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_node_ref *raw)
{
@@ -234,6 +255,7 @@ struct jffs2_eraseblock
	uint32_t wasted_size;
	uint32_t free_size;	/* Note that sector_size - free_size
				   is the address of the first free space */
	uint32_t allocated_refs;
	struct jffs2_raw_node_ref *first_node;
	struct jffs2_raw_node_ref *last_node;

@@ -380,8 +402,7 @@ struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void);
void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *);
int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c,
				 struct jffs2_eraseblock *jeb, int nr);
struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void);
void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *);
void jffs2_free_refblock(struct jffs2_raw_node_ref *);
struct jffs2_node_frag *jffs2_alloc_node_frag(void);
void jffs2_free_node_frag(struct jffs2_node_frag *);
struct jffs2_inode_cache *jffs2_alloc_inode_cache(void);
Loading