/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001-2003 Red Hat, Inc.
+ * Copyright © 2001-2007 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: gc.c,v 1.155 2005/11/07 11:14:39 gleixner Exp $
- *
*/
#include <linux/kernel.h>
struct jffs2_inode_cache *ic;
struct jffs2_eraseblock *jeb;
struct jffs2_raw_node_ref *raw;
+ uint32_t gcblock_dirty;
int ret = 0, inum, nlink;
int xattr = 0;
c->unchecked_size);
jffs2_dbg_dump_block_lists_nolock(c);
spin_unlock(&c->erase_completion_lock);
- BUG();
+ up(&c->alloc_sem);
+ return -ENOSPC;
}
spin_unlock(&c->erase_completion_lock);
D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n",
ic->ino));
spin_unlock(&c->inocache_lock);
+ jffs2_xattr_delete_inode(c, ic);
continue;
}
switch(ic->state) {
}
raw = jeb->gc_node;
+ gcblock_dirty = jeb->dirty_size;
while(ref_obsolete(raw)) {
D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw)));
- raw = raw->next_phys;
+ raw = ref_next(raw);
if (unlikely(!raw)) {
printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n");
printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n",
* We can decide whether this node is inode or xattr by ic->class. */
if (ic->class == RAWNODE_CLASS_XATTR_DATUM
|| ic->class == RAWNODE_CLASS_XATTR_REF) {
- BUG_ON(raw->next_in_ino != (void *)ic);
spin_unlock(&c->erase_completion_lock);
if (ic->class == RAWNODE_CLASS_XATTR_DATUM) {
- ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic);
+ ret = jffs2_garbage_collect_xattr_datum(c, (struct jffs2_xattr_datum *)ic, raw);
} else {
- ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic);
+ ret = jffs2_garbage_collect_xattr_ref(c, (struct jffs2_xattr_ref *)ic, raw);
}
- goto release_sem;
+ goto test_gcnode;
}
#endif
if (ret != -EBADFD) {
spin_unlock(&c->inocache_lock);
- goto release_sem;
+ goto test_gcnode;
}
/* Fall through if it wanted us to, with inocache_lock held */
jffs2_gc_release_inode(c, f);
+ test_gcnode:
+ if (jeb->dirty_size == gcblock_dirty && !ref_obsolete(jeb->gc_node)) {
+ /* Eep. This really should never happen. GC is broken */
+ printk(KERN_ERR "Error garbage collecting node at %08x!\n", ref_offset(jeb->gc_node));
+ ret = -ENOSPC;
+ }
release_sem:
up(&c->alloc_sem);
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;
node = kmalloc(rawlen, GFP_KERNEL);
if (!node)
- return -ENOMEM;
+ return -ENOMEM;
ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node);
if (!ret && retlen != rawlen)
goto bail;
}
+ if (strnlen(node->d.name, node->d.nsize) != node->d.nsize) {
+ printk(KERN_WARNING "Name in dirent node at 0x%08x contains zeroes\n", ref_offset(raw));
+ goto bail;
+ }
+
if (node->d.nsize) {
crc = crc32(0, node->d.name, node->d.nsize);
if (je32_to_cpu(node->d.name_crc) != crc) {
- printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
+ printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
ref_offset(raw), je32_to_cpu(node->d.name_crc), crc);
goto bail;
}
}
}
- 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];
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)));
for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) {
+ cond_resched();
+
/* We only care about obsolete ones */
if (!(ref_obsolete(raw)))
continue;