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

Commit 2f785402 authored by David Woodhouse's avatar David Woodhouse
Browse files

[JFFS2] Reduce visibility of raw_node_ref to upper layers of JFFS2 code.



As the first step towards eliminating the ref->next_phys member and saving
memory by using an _array_ of struct jffs2_raw_node_ref per eraseblock,
stop the write functions from allocating their own refs; have them just
_reserve_ the appropriate number instead. Then jffs2_link_node_ref() can
just fill them in.

Use a linked list of pre-allocated refs in the superblock, for now. Once
we switch to an array, it'll just be a case of extending that array.

Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent 4cbb9b80
Loading
Loading
Loading
Loading
+4 −12
Original line number Diff line number Diff line
@@ -296,7 +296,7 @@ void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *
			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);
		__jffs2_free_raw_node_ref(ref);
	}
	jeb->last_node = NULL;
}
@@ -351,7 +351,6 @@ static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_erasebl

static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
	struct jffs2_raw_node_ref *marker_ref = NULL;
	size_t retlen;
	int ret;
	uint32_t bad_offset;
@@ -384,11 +383,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
			.totlen =	cpu_to_je32(c->cleanmarker_size)
		};

		marker_ref = jffs2_alloc_raw_node_ref();
		if (!marker_ref) {
			printk(KERN_WARNING "Failed to allocate raw node ref for clean marker. Refiling\n");
			goto refile;
		}
		jffs2_prealloc_raw_node_refs(c, 1);

		marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));

@@ -404,16 +399,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
				printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n",
				       jeb->offset, sizeof(marker), retlen);

			jffs2_free_raw_node_ref(marker_ref);
			goto filebad;
		}

		/* Everything else got zeroed before the erase */
		jeb->free_size = c->sector_size;

		marker_ref->flash_offset = jeb->offset | REF_NORMAL;

		jffs2_link_node_ref(c, jeb, marker_ref, c->cleanmarker_size, NULL);
		/* FIXME Special case for cleanmarker in empty block */
		jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, c->cleanmarker_size, NULL);
	}

	spin_lock(&c->erase_completion_lock);
+6 −19
Original line number Diff line number Diff line
@@ -528,7 +528,6 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
					  struct jffs2_raw_node_ref *raw)
{
	union jffs2_node_union *node;
	struct jffs2_raw_node_ref *nraw;
	size_t retlen;
	int ret;
	uint32_t phys_ofs, alloclen;
@@ -618,30 +617,21 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
		}
	}

	nraw = jffs2_alloc_raw_node_ref();
	if (!nraw) {
		ret = -ENOMEM;
		goto out_node;
	}

	/* OK, all the CRCs are good; this node can just be copied as-is. */
 retry:
	nraw->flash_offset = phys_ofs = write_ofs(c);
	phys_ofs = write_ofs(c);

	ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node);

	if (ret || (retlen != rawlen)) {
		printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",
                       rawlen, nraw->flash_offset, ret, retlen);
                       rawlen, phys_ofs, ret, retlen);
		if (retlen) {
			nraw->flash_offset |= REF_OBSOLETE;
			jffs2_add_physical_node_ref(c, nraw, rawlen, NULL);
			jffs2_mark_node_obsolete(c, nraw);
			jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL);
		} else {
			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset);
                        jffs2_free_raw_node_ref(nraw);
			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", phys_ofs);
		}
		if (!retried && (nraw = jffs2_alloc_raw_node_ref())) {
		if (!retried) {
			/* Try to reallocate space and retry */
			uint32_t dummy;
			struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size];
@@ -666,16 +656,13 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
				goto retry;
			}
			D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));
			jffs2_free_raw_node_ref(nraw);
		}

		jffs2_free_raw_node_ref(nraw);
		if (!ret)
			ret = -EIO;
		goto out_node;
	}
	nraw->flash_offset |= REF_PRISTINE;
	jffs2_add_physical_node_ref(c, nraw, rawlen, ic);
	jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, rawlen, ic);

	jffs2_mark_node_obsolete(c, raw);
	D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw)));
+3 −0
Original line number Diff line number Diff line
@@ -26,6 +26,9 @@ 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;

+24 −2
Original line number Diff line number Diff line
@@ -190,7 +190,29 @@ 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_raw_node_ref(void)
int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, int nr)
{
	struct jffs2_raw_node_ref *p = c->refs;

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

	while (nr && p) {
		p = p->next_in_ino;
		nr--;
	}
	while (nr) {
		p = __jffs2_alloc_raw_node_ref();
		if (!p)
			return -ENOMEM;
		p->next_in_ino = c->refs;
		c->refs = p;
		nr--;
	}
	c->reserved_refs = nr;
	return 0;
}

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);
@@ -198,7 +220,7 @@ struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void)
	return ret;
}

void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x)
void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x)
{
	dbg_memalloc("%p\n", x);
	kmem_cache_free(raw_node_ref_slab, x);
+33 −18
Original line number Diff line number Diff line
@@ -955,11 +955,17 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c)
		this = c->blocks[i].first_node;
		while (this) {
			next = this->next_phys;
			jffs2_free_raw_node_ref(this);
			__jffs2_free_raw_node_ref(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)
@@ -1047,10 +1053,27 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c)
	}
}

void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
			 struct jffs2_raw_node_ref *ref, uint32_t len,
struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c,
					       struct jffs2_eraseblock *jeb,
					       uint32_t ofs, uint32_t len,
					       struct jffs2_inode_cache *ic)
{
	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;
	}

	ref->next_phys = NULL;
	ref->flash_offset = ofs;

	if (!jeb->first_node)
		jeb->first_node = ref;
	if (jeb->last_node) {
@@ -1093,15 +1116,15 @@ void jffs2_link_node_ref(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
	c->free_size -= len;
	jeb->free_size -= len;

	ref->next_phys = NULL;
#ifdef TEST_TOTLEN
	/* Set (and test) __totlen field... for now */
	ref->__totlen = len;
	ref_totlen(c, jeb, ref);
#endif
	return ref;
}

/* No locking. Do not use on a live file system */
/* No locking, no reservation of 'ref'. Do not use on a live file system */
int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
			   uint32_t size)
{
@@ -1121,18 +1144,10 @@ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
		jeb->dirty_size += size;
		jeb->free_size -= size;
	} else {
		struct jffs2_raw_node_ref *ref;
		ref = jffs2_alloc_raw_node_ref();
		if (!ref)
			return -ENOMEM;

		ref->flash_offset = jeb->offset + c->sector_size - jeb->free_size;
		ref->flash_offset |= REF_OBSOLETE;
#ifdef TEST_TOTLEN
		ref->__totlen = size;
#endif
		uint32_t ofs = jeb->offset + c->sector_size - jeb->free_size;
		ofs |= REF_OBSOLETE;

		jffs2_link_node_ref(c, jeb, ref, size, NULL);
		jffs2_link_node_ref(c, jeb, ofs, size, NULL);
	}

	return 0;
Loading