#include <linux/pagemap.h>
#include "nodelist.h"
+static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c,
+ struct jffs2_node_frag *this);
+
void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list)
{
struct jffs2_full_dirent **prev = list;
}
}
-void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this)
+static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c,
+ struct jffs2_node_frag *this)
{
if (this->node) {
this->node->frags--;
{
struct jffs2_inode_cache **prev;
+#ifdef CONFIG_JFFS2_FS_XATTR
+ BUG_ON(old->xref);
+#endif
dbg_inocache("del %p (ino #%u)\n", old, old->ino);
spin_lock(&c->inocache_lock);
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);
+ while (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;
}
}
-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_inode_cache *ic)
+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)
{
- if (!jeb->first_node)
+ struct jffs2_raw_node_ref *ref;
+
+ 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++;
+ }
+
+ 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) {
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;
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)
{
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();
}
+ /* REF_EMPTY_NODE is !obsolete, so that works OK */
if (jeb->last_node && ref_obsolete(jeb->last_node)) {
#ifdef TEST_TOTLEN
jeb->last_node->__totlen += size;
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;
+ uint32_t ofs = jeb->offset + c->sector_size - jeb->free_size;
+ ofs |= REF_OBSOLETE;
- ref->flash_offset = jeb->offset + c->sector_size - jeb->free_size;
- ref->flash_offset |= REF_OBSOLETE;
-#ifdef TEST_TOTLEN
- ref->__totlen = size;
-#endif
-
- jffs2_link_node_ref(c, jeb, ref, size, NULL);
+ jffs2_link_node_ref(c, jeb, ofs, size, NULL);
}
return 0;
struct jffs2_raw_node_ref *ref)
{
uint32_t ref_end;
+ struct jffs2_raw_node_ref *next_ref = ref_next(ref);
- if (ref->next_phys)
- ref_end = ref_offset(ref->next_phys);
+ if (next_ref)
+ ref_end = ref_offset(next_ref);
else {
if (!jeb)
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();
{
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);
- if (ref->next_phys) {
- printk(KERN_CRIT "next_phys %p (0x%08x-0x%08x)\n", ref->next_phys, ref_offset(ref->next_phys),
- ref_offset(ref->next_phys)+ref->__totlen);
+ if (ref_next(ref)) {
+ printk(KERN_CRIT "next %p (0x%08x-0x%08x)\n", ref_next(ref), ref_offset(ref_next(ref)),
+ ref_offset(ref_next(ref))+ref->__totlen);
} else
- printk(KERN_CRIT "No next_phys. jeb->last_node is %p\n", jeb->last_node);
+ 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;