Commit 20fed049 authored by David Woodhouse's avatar David Woodhouse

Merge [acm]time nanosecond support from 2.5.48.

parents 65b5db50 f662cf7a
...@@ -531,8 +531,8 @@ config JFFS2_FS ...@@ -531,8 +531,8 @@ config JFFS2_FS
levelling, compression and support for hard links. You cannot use levelling, compression and support for hard links. You cannot use
this on normal block devices, only on 'MTD' devices. this on normal block devices, only on 'MTD' devices.
Further information should be made available soon at Further information on the design and implementation of JFFS2 is
<http://sources.redhat.com/jffs2/>. available at <http://sources.redhat.com/jffs2/>.
config JFFS2_FS_DEBUG config JFFS2_FS_DEBUG
int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)" int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)"
...@@ -554,6 +554,19 @@ config JFFS2_FS_DEBUG ...@@ -554,6 +554,19 @@ config JFFS2_FS_DEBUG
config JFFS2_FS_NAND config JFFS2_FS_NAND
bool "JFFS2 support for NAND flash (EXPERIMENTAL)" bool "JFFS2 support for NAND flash (EXPERIMENTAL)"
depends on JFFS2_FS && EXPERIMENTAL depends on JFFS2_FS && EXPERIMENTAL
default n
---help---
This enables the experimental support for NAND flash in JFFS2. NAND
is a newer type of flash chip design than the traditional NOR flash,
with higher density but a handful of characteristics which make it
more interesting for the file system to use. Support for NAND flash
is not yet complete and may corrupt data. For further information,
including a link to the mailing list where details of the remaining
work to be completed for NAND flash support can be found, see the
JFFS2 web site at <http://sources.redhat.com/jffs2>.
Say 'N' unless you have NAND flash and you are willing to test and
develop JFFS2 support for it.
config CRAMFS config CRAMFS
tristate "Compressed ROM file system support" tristate "Compressed ROM file system support"
......
$Id: TODO,v 1.9 2002/07/11 10:39:04 dwmw2 Exp $ $Id: TODO,v 1.10 2002/09/09 16:31:21 dwmw2 Exp $
- disable compression in commit_write()? - disable compression in commit_write()?
- fine-tune the allocation / GC thresholds - fine-tune the allocation / GC thresholds
...@@ -23,22 +23,18 @@ $Id: TODO,v 1.9 2002/07/11 10:39:04 dwmw2 Exp $ ...@@ -23,22 +23,18 @@ $Id: TODO,v 1.9 2002/07/11 10:39:04 dwmw2 Exp $
- Optimisations: - Optimisations:
- Stop GC from decompressing and immediately recompressing nodes which could - Stop GC from decompressing and immediately recompressing nodes which could
just be copied intact. just be copied intact. (We now keep track of REF_PRISTINE flag. Easy now.)
- Furthermore, in the case where it could be copied intact we don't even need - Furthermore, in the case where it could be copied intact we don't even need
to call iget() for it -- if we use (raw_node_raw->flash_offset & 2) as a flag to call iget() for it -- if we use (raw_node_raw->flash_offset & 2) as a flag
to show a node can be copied intact and it's _not_ in icache, we could just do to show a node can be copied intact and it's _not_ in icache, we could just do
it, fix up the next_in_ino list and move on. We would need a way to find out it, fix up the next_in_ino list and move on. We would need a way to find out
_whether_ it's in icache though -- if it's in icache we also need to do the _whether_ it's in icache though -- if it's in icache we also need to do the
fragment lists, etc. P'raps a flag or pointer in the jffs2_inode_cache could fragment lists, etc. P'raps a flag or pointer in the jffs2_inode_cache could
help. help. (We have half of this now.)
- Stop keeping name in-core with struct jffs2_full_dirent. If we keep the hash in - Stop keeping name in-core with struct jffs2_full_dirent. If we keep the hash in
the full dirent, we only need to go to the flash in lookup() when we think we've the full dirent, we only need to go to the flash in lookup() when we think we've
got a match, and in readdir(). got a match, and in readdir().
- Doubly-linked next_in_ino list to allow us to free obsoleted raw_node_refs immediately? - Doubly-linked next_in_ino list to allow us to free obsoleted raw_node_refs immediately?
- Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into - Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into
jffs2_mark_node_obsolete(). Can all callers work it out? jffs2_mark_node_obsolete(). Can all callers work it out?
- Don't check data CRC on node scan during mount. We don't really need to know - Remove size from jffs2_raw_node_frag.
yet. This means we can't build up node fragment lists, and hence can't
build accurate clean/dirty information. But we don't _need_ that for reading,
only for writing. And in fact we don't even need it for writing until we
start to need GC.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: background.c,v 1.29 2002/06/07 10:04:28 dwmw2 Exp $ * $Id: background.c,v 1.33 2002/11/12 09:44:30 dwmw2 Exp $
* *
*/ */
...@@ -83,21 +83,22 @@ static int jffs2_garbage_collect_thread(void *_c) ...@@ -83,21 +83,22 @@ static int jffs2_garbage_collect_thread(void *_c)
struct jffs2_sb_info *c = _c; struct jffs2_sb_info *c = _c;
daemonize(); daemonize();
c->gc_task = current; c->gc_task = current;
up(&c->gc_thread_start); up(&c->gc_thread_start);
sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index); sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index);
set_user_nice(current, 10); set_user_nice(current, 10);
for (;;) { for (;;) {
spin_lock_irq(&current->sig->siglock); spin_lock_irq(&current_sig_lock);
siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sig->siglock); spin_unlock_irq(&current_sig_lock);
if (!thread_should_wake(c)) { if (!thread_should_wake(c)) {
set_current_state (TASK_INTERRUPTIBLE); set_current_state (TASK_INTERRUPTIBLE);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n"));
/* Yes, there's a race here; we checked thread_should_wake() before /* Yes, there's a race here; we checked thread_should_wake() before
setting current->state to TASK_INTERRUPTIBLE. But it doesn't setting current->state to TASK_INTERRUPTIBLE. But it doesn't
...@@ -105,30 +106,30 @@ static int jffs2_garbage_collect_thread(void *_c) ...@@ -105,30 +106,30 @@ static int jffs2_garbage_collect_thread(void *_c)
is only an optimisation anyway. */ is only an optimisation anyway. */
schedule(); schedule();
} }
cond_resched(); cond_resched();
/* Put_super will send a SIGKILL and then wait on the sem. /* Put_super will send a SIGKILL and then wait on the sem.
*/ */
while (signal_pending(current)) { while (signal_pending(current)) {
siginfo_t info; siginfo_t info;
unsigned long signr = 0 ; unsigned long signr;
spin_lock_irq(&current->sig->siglock); spin_lock_irq(&current_sig_lock);
signr = dequeue_signal(&current->blocked, &info); signr = dequeue_signal(&current->blocked, &info);
spin_unlock_irq(&current->sig->siglock); spin_unlock_irq(&current_sig_lock);
switch(signr) { switch(signr) {
case SIGSTOP: case SIGSTOP:
D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGSTOP received.\n")); D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGSTOP received.\n"));
set_current_state(TASK_STOPPED); set_current_state(TASK_STOPPED);
schedule(); schedule();
break; break;
case SIGKILL: case SIGKILL:
D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n")); D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n"));
spin_lock_bh(&c->erase_completion_lock); spin_lock_bh(&c->erase_completion_lock);
c->gc_task = NULL; c->gc_task = NULL;
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
complete_and_exit(&c->gc_thread_exit, 0); complete_and_exit(&c->gc_thread_exit, 0);
...@@ -137,14 +138,13 @@ static int jffs2_garbage_collect_thread(void *_c) ...@@ -137,14 +138,13 @@ static int jffs2_garbage_collect_thread(void *_c)
break; break;
default: default:
D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): signal %ld received\n", signr)); D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): signal %ld received\n", signr));
}
} }
}
/* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */ /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
spin_lock_irq(&current->sig->siglock); spin_lock_irq(&current_sig_lock);
siginitsetinv (&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); siginitsetinv (&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
recalc_sigpending(); recalc_sigpending();
spin_unlock_irq(&current->sig->siglock); spin_unlock_irq(&current_sig_lock);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n")); D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n"));
jffs2_garbage_collect_pass(c); jffs2_garbage_collect_pass(c);
...@@ -153,23 +153,20 @@ static int jffs2_garbage_collect_thread(void *_c) ...@@ -153,23 +153,20 @@ static int jffs2_garbage_collect_thread(void *_c)
static int thread_should_wake(struct jffs2_sb_info *c) static int thread_should_wake(struct jffs2_sb_info *c)
{ {
uint32_t gcnodeofs = 0; int ret = 0;
int ret;
/* Don't count any progress we've already made through the gcblock if (c->unchecked_size) {
as dirty space, for the purposes of this calculation */ D1(printk(KERN_DEBUG "thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
if (c->gcblock && c->gcblock->gc_node) c->unchecked_size, c->checked_ino));
gcnodeofs = c->gcblock->gc_node->flash_offset & ~3 & (c->sector_size-1); return 1;
}
if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER && if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER &&
(c->dirty_size - gcnodeofs) > c->sector_size) (c->dirty_size > c->sector_size))
ret = 1; ret = 1;
else
ret = 0;
D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x (mod 0x%x): %s\n", D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n",
c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no"));
c->dirty_size - gcnodeofs, ret?"yes":"no"));
return ret; return ret;
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: build.c,v 1.35 2002/05/20 14:56:37 dwmw2 Exp $ * $Id: build.c,v 1.42 2002/09/09 16:29:08 dwmw2 Exp $
* *
*/ */
...@@ -43,8 +43,9 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) ...@@ -43,8 +43,9 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
return ret; return ret;
D1(printk(KERN_DEBUG "Scanned flash completely\n")); D1(printk(KERN_DEBUG "Scanned flash completely\n"));
/* Now build the data map for each inode, marking obsoleted nodes D1(jffs2_dump_block_lists(c));
as such, and also increase nlink of any children. */
/* Now scan the directory tree, increasing nlink according to every dirent found. */
for_each_inode(i, c, ic) { for_each_inode(i, c, ic) {
D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino)); D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino));
ret = jffs2_build_inode_pass1(c, ic); ret = jffs2_build_inode_pass1(c, ic);
...@@ -52,8 +53,10 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) ...@@ -52,8 +53,10 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret)); D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret));
return ret; return ret;
} }
cond_resched();
} }
D1(printk(KERN_DEBUG "Pass 1 complete\n")); D1(printk(KERN_DEBUG "Pass 1 complete\n"));
D1(jffs2_dump_block_lists(c));
/* Next, scan for inodes with nlink == 0 and remove them. If /* Next, scan for inodes with nlink == 0 and remove them. If
they were directories, then decrement the nlink of their they were directories, then decrement the nlink of their
...@@ -68,6 +71,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) ...@@ -68,6 +71,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
if (ic->nlink) if (ic->nlink)
continue; continue;
/* XXX: Can get high latency here. Move the cond_resched() from the end of the loop? */
ret = jffs2_build_remove_unlinked_inode(c, ic); ret = jffs2_build_remove_unlinked_inode(c, ic);
if (ret) if (ret)
break; break;
...@@ -75,115 +80,52 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) ...@@ -75,115 +80,52 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
and furthermore that it had children and their nlink has now and furthermore that it had children and their nlink has now
gone to zero too. So we have to restart the scan. */ gone to zero too. So we have to restart the scan. */
} }
} while(ret == -EAGAIN); D1(jffs2_dump_block_lists(c));
cond_resched();
} while(ret == -EAGAIN);
D1(printk(KERN_DEBUG "Pass 2 complete\n")); D1(printk(KERN_DEBUG "Pass 2 complete\n"));
/* Finally, we can scan again and free the dirent nodes and scan_info structs */ /* Finally, we can scan again and free the dirent nodes and scan_info structs */
for_each_inode(i, c, ic) { for_each_inode(i, c, ic) {
struct jffs2_scan_info *scan = ic->scan;
struct jffs2_full_dirent *fd; struct jffs2_full_dirent *fd;
D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes)); D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
if (!scan) {
if (ic->nlink) { while(ic->scan_dents) {
D1(printk(KERN_WARNING "Why no scan struct for ino #%u which has nlink %d?\n", ic->ino, ic->nlink)); fd = ic->scan_dents;
} ic->scan_dents = fd->next;
continue;
}
ic->scan = NULL;
while(scan->dents) {
fd = scan->dents;
scan->dents = fd->next;
jffs2_free_full_dirent(fd); jffs2_free_full_dirent(fd);
} }
kfree(scan); ic->scan_dents = NULL;
cond_resched();
} }
D1(printk(KERN_DEBUG "Pass 3 complete\n")); D1(printk(KERN_DEBUG "Pass 3 complete\n"));
D1(jffs2_dump_block_lists(c));
/* Rotate the lists by some number to ensure wear levelling */ /* Rotate the lists by some number to ensure wear levelling */
jffs2_rotate_lists(c); jffs2_rotate_lists(c);
return ret; return ret;
} }
int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
{ {
struct jffs2_tmp_dnode_info *tn;
struct jffs2_full_dirent *fd; struct jffs2_full_dirent *fd;
struct jffs2_node_frag *fraglist = NULL;
struct jffs2_tmp_dnode_info *metadata = NULL;
D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino)); D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino));
if (ic->ino > c->highest_ino) if (ic->ino > c->highest_ino)
c->highest_ino = ic->ino; c->highest_ino = ic->ino;
if (!ic->scan->tmpnodes && ic->ino != 1) { /* For each child, increase nlink */
D1(printk(KERN_DEBUG "jffs2_build_inode: ino #%u has no data nodes!\n", ic->ino)); for(fd=ic->scan_dents; fd; fd = fd->next) {
}
/* Build the list to make sure any obsolete nodes are marked as such */
while(ic->scan->tmpnodes) {
tn = ic->scan->tmpnodes;
ic->scan->tmpnodes = tn->next;
if (metadata && tn->version > metadata->version) {
D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring old metadata at 0x%08x\n",
metadata->fn->raw->flash_offset &~3));
jffs2_mark_node_obsolete(c, metadata->fn->raw);
jffs2_free_full_dnode(metadata->fn);
jffs2_free_tmp_dnode_info(metadata);
metadata = NULL;
}
if (tn->fn->size) {
jffs2_add_full_dnode_to_fraglist (c, &fraglist, tn->fn);
jffs2_free_tmp_dnode_info(tn);
} else {
if (!metadata) {
metadata = tn;
} else {
/* This will only happen if it has the _same_ version
number as the existing metadata node. */
D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring new metadata at 0x%08x\n",
tn->fn->raw->flash_offset &~3));
jffs2_mark_node_obsolete(c, tn->fn->raw);
jffs2_free_full_dnode(tn->fn);
jffs2_free_tmp_dnode_info(tn);
}
}
}
if (ic->scan->version) {
/* It's a regular file, so truncate it to the last known
i_size, if necessary */
D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 truncating fraglist to 0x%08x\n", ic->scan->isize));
jffs2_truncate_fraglist(c, &fraglist, ic->scan->isize);
}
/* OK. Now clear up */
if (metadata) {
jffs2_free_full_dnode(metadata->fn);
jffs2_free_tmp_dnode_info(metadata);
}
metadata = NULL;
while (fraglist) {
struct jffs2_node_frag *frag;
frag = fraglist;
fraglist = fraglist->next;
if (frag->node && !(--frag->node->frags)) {
jffs2_free_full_dnode(frag->node);
}
jffs2_free_node_frag(frag);
}
/* Now for each child, increase nlink */
for(fd=ic->scan->dents; fd; fd = fd->next) {
struct jffs2_inode_cache *child_ic; struct jffs2_inode_cache *child_ic;
if (!fd->ino) if (!fd->ino)
continue; continue;
/* XXX: Can get high latency here with huge directories */
child_ic = jffs2_get_ino_cache(c, fd->ino); child_ic = jffs2_get_ino_cache(c, fd->ino);
if (!child_ic) { if (!child_ic) {
...@@ -212,26 +154,33 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod ...@@ -212,26 +154,33 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
struct jffs2_full_dirent *fd; struct jffs2_full_dirent *fd;
int ret = 0; int ret = 0;
if(!ic->scan) {
D1(printk(KERN_DEBUG "ino #%u was already removed\n", ic->ino));
return 0;
}
D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino)); D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) { for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) {
D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", raw->flash_offset&~3)); D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw)));
jffs2_mark_node_obsolete(c, raw); jffs2_mark_node_obsolete(c, raw);
} }
if (ic->scan->dents) { if (ic->scan_dents) {
printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino); int whinged = 0;
D1(printk(KERN_DEBUG "Inode #%u was a directory which may have children...\n", ic->ino));
while(ic->scan->dents) {
while(ic->scan_dents) {
struct jffs2_inode_cache *child_ic; struct jffs2_inode_cache *child_ic;
fd = ic->scan->dents; fd = ic->scan_dents;
ic->scan->dents = fd->next; ic->scan_dents = fd->next;
if (!fd->ino) {
/* It's a deletion dirent. Ignore it */
D1(printk(KERN_DEBUG "Child \"%s\" is a deletion dirent, skipping...\n", fd->name));
jffs2_free_full_dirent(fd);
continue;
}
if (!whinged) {
whinged = 1;
printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino);
}
D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n", D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n",
fd->name, fd->ino)); fd->name, fd->ino));
...@@ -239,6 +188,7 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod ...@@ -239,6 +188,7 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
child_ic = jffs2_get_ino_cache(c, fd->ino); child_ic = jffs2_get_ino_cache(c, fd->ino);
if (!child_ic) { if (!child_ic) {
printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino); printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino);
jffs2_free_full_dirent(fd);
continue; continue;
} }
jffs2_free_full_dirent(fd); jffs2_free_full_dirent(fd);
...@@ -246,8 +196,6 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod ...@@ -246,8 +196,6 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
} }
ret = -EAGAIN; ret = -EAGAIN;
} }
kfree(ic->scan);
ic->scan = NULL;
/* /*
We don't delete the inocache from the hash list and free it yet. We don't delete the inocache from the hash list and free it yet.
...@@ -271,6 +219,8 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c) ...@@ -271,6 +219,8 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
c->blocks[i].offset = i * c->sector_size; c->blocks[i].offset = i * c->sector_size;
c->blocks[i].free_size = c->sector_size; c->blocks[i].free_size = c->sector_size;
c->blocks[i].dirty_size = 0; 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].used_size = 0;
c->blocks[i].first_node = NULL; c->blocks[i].first_node = NULL;
c->blocks[i].last_node = NULL; c->blocks[i].last_node = NULL;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: dir.c,v 1.71 2002/07/23 17:00:45 dwmw2 Exp $ * $Id: dir.c,v 1.73 2002/08/26 15:00:51 dwmw2 Exp $
* *
*/ */
...@@ -211,7 +211,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -211,7 +211,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode)
return ret; return ret;
} }
dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = ri->ctime; dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(ri->ctime);
dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0; dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0;
jffs2_free_raw_inode(ri); jffs2_free_raw_inode(ri);
...@@ -234,7 +234,8 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) ...@@ -234,7 +234,8 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry)
ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
dentry->d_name.len, dead_f); dentry->d_name.len, dead_f);
dentry->d_inode->i_nlink = dead_f->inocache->nlink; if (dead_f->inocache)
dentry->d_inode->i_nlink = dead_f->inocache->nlink;
return ret; return ret;
} }
/***********************************************************************/ /***********************************************************************/
...@@ -248,6 +249,10 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de ...@@ -248,6 +249,10 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
int ret; int ret;
uint8_t type; uint8_t type;
/* Don't let people make hard links to bad inodes. */
if (!f->inocache)
return -EIO;
if (S_ISDIR(old_dentry->d_inode->i_mode)) if (S_ISDIR(old_dentry->d_inode->i_mode))
return -EPERM; return -EPERM;
...@@ -318,13 +323,14 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ...@@ -318,13 +323,14 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
f = JFFS2_INODE_INFO(inode); f = JFFS2_INODE_INFO(inode);
inode->i_size = ri->isize = ri->dsize = ri->csize = strlen(target); inode->i_size = strlen(target);
ri->totlen = sizeof(*ri) + ri->dsize; ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size);
ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
ri->compr = JFFS2_COMPR_NONE; ri->compr = JFFS2_COMPR_NONE;
ri->data_crc = crc32(0, target, strlen(target)); ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target)));
ri->node_crc = crc32(0, ri, sizeof(*ri)-8); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, &writtenlen); fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, &writtenlen);
...@@ -370,19 +376,19 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ...@@ -370,19 +376,19 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
dir_f = JFFS2_INODE_INFO(dir_i); dir_f = JFFS2_INODE_INFO(dir_i);
down(&dir_f->sem); down(&dir_f->sem);
rd->magic = JFFS2_MAGIC_BITMASK; rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
rd->totlen = sizeof(*rd) + namelen; rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
rd->pino = dir_i->i_ino; rd->pino = cpu_to_je32(dir_i->i_ino);
rd->version = ++dir_f->highest_version; rd->version = cpu_to_je32(++dir_f->highest_version);
rd->ino = inode->i_ino; rd->ino = cpu_to_je32(inode->i_ino);
rd->mctime = get_seconds(); rd->mctime = cpu_to_je32(get_seconds());
rd->nsize = namelen; rd->nsize = namelen;
rd->type = DT_LNK; rd->type = DT_LNK;
rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = crc32(0, dentry->d_name.name, namelen); rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
...@@ -396,7 +402,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ...@@ -396,7 +402,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
return PTR_ERR(fd); return PTR_ERR(fd);
} }
dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = rd->mctime; dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(rd->mctime);
dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0; dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0;
jffs2_free_raw_dirent(rd); jffs2_free_raw_dirent(rd);
...@@ -461,8 +467,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -461,8 +467,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
f = JFFS2_INODE_INFO(inode); f = JFFS2_INODE_INFO(inode);
ri->data_crc = 0; ri->data_crc = cpu_to_je32(0);
ri->node_crc = crc32(0, ri, sizeof(*ri)-8); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen); fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen);
...@@ -508,19 +514,19 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -508,19 +514,19 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
dir_f = JFFS2_INODE_INFO(dir_i); dir_f = JFFS2_INODE_INFO(dir_i);
down(&dir_f->sem); down(&dir_f->sem);
rd->magic = JFFS2_MAGIC_BITMASK; rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
rd->totlen = sizeof(*rd) + namelen; rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
rd->pino = dir_i->i_ino; rd->pino = cpu_to_je32(dir_i->i_ino);
rd->version = ++dir_f->highest_version; rd->version = cpu_to_je32(++dir_f->highest_version);
rd->ino = inode->i_ino; rd->ino = cpu_to_je32(inode->i_ino);
rd->mctime = get_seconds(); rd->mctime = cpu_to_je32(get_seconds());
rd->nsize = namelen; rd->nsize = namelen;
rd->type = DT_DIR; rd->type = DT_DIR;
rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = crc32(0, dentry->d_name.name, namelen); rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
...@@ -534,7 +540,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -534,7 +540,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
return PTR_ERR(fd); return PTR_ERR(fd);
} }
dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = rd->mctime; dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(rd->mctime);
dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0; dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0;
dir_i->i_nlink++; dir_i->i_nlink++;
...@@ -617,13 +623,13 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in ...@@ -617,13 +623,13 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
f = JFFS2_INODE_INFO(inode); f = JFFS2_INODE_INFO(inode);
ri->dsize = ri->csize = devlen; ri->dsize = ri->csize = cpu_to_je32(devlen);
ri->totlen = sizeof(*ri) + ri->csize; ri->totlen = cpu_to_je32(sizeof(*ri) + devlen);
ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
ri->compr = JFFS2_COMPR_NONE; ri->compr = JFFS2_COMPR_NONE;
ri->data_crc = crc32(0, &dev, devlen); ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen));
ri->node_crc = crc32(0, ri, sizeof(*ri)-8); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, &writtenlen); fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, &writtenlen);
...@@ -669,22 +675,22 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in ...@@ -669,22 +675,22 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
dir_f = JFFS2_INODE_INFO(dir_i); dir_f = JFFS2_INODE_INFO(dir_i);
down(&dir_f->sem); down(&dir_f->sem);
rd->magic = JFFS2_MAGIC_BITMASK; rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
rd->totlen = sizeof(*rd) + namelen; rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
rd->pino = dir_i->i_ino; rd->pino = cpu_to_je32(dir_i->i_ino);
rd->version = ++dir_f->highest_version; rd->version = cpu_to_je32(++dir_f->highest_version);
rd->ino = inode->i_ino; rd->ino = cpu_to_je32(inode->i_ino);
rd->mctime = get_seconds(); rd->mctime = cpu_to_je32(get_seconds());
rd->nsize = namelen; rd->nsize = namelen;
/* XXX: This is ugly. */ /* XXX: This is ugly. */
rd->type = (mode & S_IFMT) >> 12; rd->type = (mode & S_IFMT) >> 12;
rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = crc32(0, dentry->d_name.name, namelen); rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));
fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
...@@ -698,7 +704,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in ...@@ -698,7 +704,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
return PTR_ERR(fd); return PTR_ERR(fd);
} }
dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = rd->mctime; dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(rd->mctime);
dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0; dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0;
jffs2_free_raw_dirent(rd); jffs2_free_raw_dirent(rd);
...@@ -790,7 +796,8 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, ...@@ -790,7 +796,8 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
down(&f->sem); down(&f->sem);
old_dentry->d_inode->i_nlink++; old_dentry->d_inode->i_nlink++;
f->inocache->nlink++; if (f->inocache)
f->inocache->nlink++;
up(&f->sem); up(&f->sem);
printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: erase.c,v 1.39 2002/07/23 17:00:45 dwmw2 Exp $ * $Id: erase.c,v 1.45 2002/10/09 08:27:08 dwmw2 Exp $
* *
*/ */
...@@ -27,6 +27,7 @@ struct erase_priv_struct { ...@@ -27,6 +27,7 @@ struct erase_priv_struct {
static void jffs2_erase_callback(struct erase_info *); static void jffs2_erase_callback(struct erase_info *);
static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{ {
...@@ -81,12 +82,18 @@ void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) ...@@ -81,12 +82,18 @@ void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
else else
printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret); printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret);
/* Note: This is almost identical to jffs2_erase_failed() except
for the fact that we used spin_lock_bh() not spin_lock(). If
we could use spin_lock_bh() from a BH, we could merge them.
Or if we abandon the idea that MTD drivers may call the erase
callback from a BH, I suppose :)
*/
spin_lock_bh(&c->erase_completion_lock); spin_lock_bh(&c->erase_completion_lock);
c->erasing_size -= c->sector_size;
c->bad_size += c->sector_size;
list_del(&jeb->list); list_del(&jeb->list);
list_add(&jeb->list, &c->bad_list); list_add(&jeb->list, &c->bad_list);
c->nr_erasing_blocks--; c->nr_erasing_blocks--;
c->bad_size += c->sector_size;
c->erasing_size -= c->sector_size;
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
wake_up(&c->erase_wait); wake_up(&c->erase_wait);
} }
...@@ -98,36 +105,46 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c) ...@@ -98,36 +105,46 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
down(&c->erase_free_sem); down(&c->erase_free_sem);
spin_lock_bh(&c->erase_completion_lock); spin_lock_bh(&c->erase_completion_lock);
while (!list_empty(&c->erase_pending_list)) {
jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list);
D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset)); while (!list_empty(&c->erase_complete_list) ||
!list_empty(&c->erase_pending_list)) {
if (!list_empty(&c->erase_complete_list)) {
jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list);
list_del(&jeb->list);
spin_unlock_bh(&c->erase_completion_lock);
jffs2_mark_erased_block(c, jeb);
} else if (!list_empty(&c->erase_pending_list)) {
jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list);
D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset));
list_del(&jeb->list);
c->erasing_size += c->sector_size;
c->free_size -= jeb->free_size;
c->used_size -= jeb->used_size;
c->dirty_size -= jeb->dirty_size;
jeb->used_size = jeb->dirty_size = jeb->free_size = 0;
jffs2_free_all_node_refs(c, jeb);
list_add(&jeb->list, &c->erasing_list);
spin_unlock_bh(&c->erase_completion_lock);
jffs2_erase_block(c, jeb);
list_del(&jeb->list); } else {
c->erasing_size += c->sector_size; BUG();
c->free_size -= jeb->free_size; }
c->used_size -= jeb->used_size;
c->dirty_size -= jeb->dirty_size;
jeb->used_size = jeb->dirty_size = jeb->free_size = 0;
jffs2_free_all_node_refs(c, jeb);
list_add(&jeb->list, &c->erasing_list);
spin_unlock_bh(&c->erase_completion_lock);
jffs2_erase_block(c, jeb);
/* Be nice */ /* Be nice */
cond_resched(); cond_resched();
spin_lock_bh(&c->erase_completion_lock); spin_lock_bh(&c->erase_completion_lock);
} }
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n"));
up(&c->erase_free_sem); up(&c->erase_free_sem);
} }
static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{ {
D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset));
...@@ -135,6 +152,8 @@ static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -135,6 +152,8 @@ static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblo
list_del(&jeb->list); list_del(&jeb->list);
list_add_tail(&jeb->list, &c->erase_complete_list); list_add_tail(&jeb->list, &c->erase_complete_list);
spin_unlock(&c->erase_completion_lock); spin_unlock(&c->erase_completion_lock);
/* Ensure that kupdated calls us again to mark them clean */
jffs2_erase_pending_trigger(c);
} }
...@@ -160,8 +179,6 @@ static void jffs2_erase_callback(struct erase_info *instr) ...@@ -160,8 +179,6 @@ static void jffs2_erase_callback(struct erase_info *instr)
} else { } else {
jffs2_erase_succeeded(priv->c, priv->jeb); jffs2_erase_succeeded(priv->c, priv->jeb);
} }
/* Make sure someone picks up the block off the erase_complete list */
OFNI_BS_2SFFJ(priv->c)->s_dirt = 1;
kfree(instr); kfree(instr);
} }
...@@ -220,7 +237,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, ...@@ -220,7 +237,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
this = ic->nodes; this = ic->nodes;
while(this) { while(this) {
printk( "0x%08x(%d)->", this->flash_offset & ~3, this->flash_offset &3); printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this));
if (++i == 5) { if (++i == 5) {
printk("\n" KERN_DEBUG); printk("\n" KERN_DEBUG);
i=0; i=0;
...@@ -260,135 +277,133 @@ void jffs2_erase_pending_trigger(struct jffs2_sb_info *c) ...@@ -260,135 +277,133 @@ void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
OFNI_BS_2SFFJ(c)->s_dirt = 1; OFNI_BS_2SFFJ(c)->s_dirt = 1;
} }
void jffs2_mark_erased_blocks(struct jffs2_sb_info *c) static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{ {
struct jffs2_eraseblock *jeb;
struct jffs2_raw_node_ref *marker_ref = NULL; struct jffs2_raw_node_ref *marker_ref = NULL;
unsigned char *ebuf; unsigned char *ebuf;
size_t retlen; size_t retlen;
int ret; int ret;
spin_lock_bh(&c->erase_completion_lock); if (!jffs2_cleanmarker_oob(c)) {
while (!list_empty(&c->erase_complete_list)) { marker_ref = jffs2_alloc_raw_node_ref();
jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); if (!marker_ref) {
list_del(&jeb->list); printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n");
spin_unlock_bh(&c->erase_completion_lock); /* Stick it back on the list from whence it came and come back later */
jffs2_erase_pending_trigger(c);
if (!jffs2_cleanmarker_oob(c)) { spin_lock_bh(&c->erase_completion_lock);
marker_ref = jffs2_alloc_raw_node_ref(); list_add(&jeb->list, &c->erase_complete_list);
if (!marker_ref) { spin_unlock_bh(&c->erase_completion_lock);
printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); return;
/* Come back later */
jffs2_erase_pending_trigger(c);
return;
}
} }
ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); }
if (!ebuf) { ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Assuming it worked\n", jeb->offset); if (!ebuf) {
} else { printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Assuming it worked\n", jeb->offset);
uint32_t ofs = jeb->offset; } else {
uint32_t ofs = jeb->offset;
D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset)); D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset));
while(ofs < jeb->offset + c->sector_size) { while(ofs < jeb->offset + c->sector_size) {
uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs); uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
int i; int i;
ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf); ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
if (ret) { if (ret) {
printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
goto bad; goto bad;
} }
if (retlen != readlen) { if (retlen != readlen) {
printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %d\n", ofs, readlen, retlen); printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %d\n", ofs, readlen, retlen);
goto bad; goto bad;
} }
for (i=0; i<readlen; i += sizeof(unsigned long)) { for (i=0; i<readlen; i += sizeof(unsigned long)) {
/* It's OK. We know it's properly aligned */ /* It's OK. We know it's properly aligned */
unsigned long datum = *(unsigned long *)(&ebuf[i]); unsigned long datum = *(unsigned long *)(&ebuf[i]);
if (datum + 1) { if (datum + 1) {
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, ofs + i); printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, ofs + i);
bad: bad:
if (!jffs2_cleanmarker_oob(c)) if (!jffs2_cleanmarker_oob(c))
jffs2_free_raw_node_ref(marker_ref); jffs2_free_raw_node_ref(marker_ref);
else else
jffs2_write_nand_badblock( c ,jeb ); jffs2_write_nand_badblock( c ,jeb );
kfree(ebuf); kfree(ebuf);
bad2: bad2:
spin_lock_bh(&c->erase_completion_lock); spin_lock_bh(&c->erase_completion_lock);
c->erasing_size -= c->sector_size; c->erasing_size -= c->sector_size;
c->bad_size += c->sector_size; c->bad_size += c->sector_size;
list_add_tail(&jeb->list, &c->bad_list); list_add_tail(&jeb->list, &c->bad_list);
c->nr_erasing_blocks--; c->nr_erasing_blocks--;
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
wake_up(&c->erase_wait); wake_up(&c->erase_wait);
return; return;
}
} }
ofs += readlen;
cond_resched();
} }
kfree(ebuf); ofs += readlen;
cond_resched();
} }
kfree(ebuf);
}
/* Write the erase complete marker */ /* Write the erase complete marker */
D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset)); D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
if (jffs2_cleanmarker_oob(c)) { if (jffs2_cleanmarker_oob(c)) {
if (jffs2_write_nand_cleanmarker(c, jeb)) if (jffs2_write_nand_cleanmarker(c, jeb))
goto bad2; goto bad2;
jeb->first_node = jeb->last_node = NULL;
jeb->free_size = c->sector_size; jeb->first_node = jeb->last_node = NULL;
jeb->used_size = 0;
jeb->dirty_size = 0;
} else {
struct jffs2_unknown_node marker = {
.magic = JFFS2_MAGIC_BITMASK,
.nodetype = JFFS2_NODETYPE_CLEANMARKER,
.totlen = c->cleanmarker_size
};
marker.hdr_crc = crc32(0, &marker, marker.totlen - 4); jeb->free_size = c->sector_size;
jeb->used_size = 0;
jeb->dirty_size = 0;
jeb->wasted_size = 0;
} else {
struct jffs2_unknown_node marker = {
.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
.totlen = cpu_to_je32(c->cleanmarker_size)
};
marker.hdr_crc = cpu_to_je32(crc32(0, &marker, je32_to_cpu(marker.totlen) - 4));
ret = jffs2_flash_write(c, jeb->offset, je32_to_cpu(marker.totlen), &retlen, (char *)&marker);
if (ret) {
printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
jeb->offset, ret);
goto bad2;
}
if (retlen != je32_to_cpu(marker.totlen)) {
printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %d\n",
jeb->offset, je32_to_cpu(marker.totlen), retlen);
goto bad2;
}
ret = jffs2_flash_write(c, jeb->offset, marker.totlen, &retlen, (char *)&marker); marker_ref->next_in_ino = NULL;
if (ret) { marker_ref->next_phys = NULL;
printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n", marker_ref->flash_offset = jeb->offset | REF_NORMAL;
jeb->offset, ret); marker_ref->totlen = PAD(je32_to_cpu(marker.totlen));
goto bad2;
}
if (retlen != marker.totlen) {
printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %d\n",
jeb->offset, marker.totlen, retlen);
goto bad2;
}
marker_ref->next_in_ino = NULL; jeb->first_node = jeb->last_node = marker_ref;
marker_ref->next_phys = NULL;
marker_ref->flash_offset = jeb->offset;
marker_ref->totlen = PAD(marker.totlen);
jeb->first_node = jeb->last_node = marker_ref; jeb->free_size = c->sector_size - marker_ref->totlen;
jeb->used_size = marker_ref->totlen;
jeb->free_size = c->sector_size - marker_ref->totlen; jeb->dirty_size = 0;
jeb->used_size = marker_ref->totlen; jeb->wasted_size = 0;
jeb->dirty_size = 0; }
}
spin_lock_bh(&c->erase_completion_lock); spin_lock_bh(&c->erase_completion_lock);
c->erasing_size -= c->sector_size; c->erasing_size -= c->sector_size;
c->free_size += jeb->free_size; c->free_size += jeb->free_size;
c->used_size += jeb->used_size; c->used_size += jeb->used_size;
ACCT_SANITY_CHECK(c,jeb); ACCT_SANITY_CHECK(c,jeb);
ACCT_PARANOIA_CHECK(jeb); D1(ACCT_PARANOIA_CHECK(jeb));
list_add_tail(&jeb->list, &c->free_list); list_add_tail(&jeb->list, &c->free_list);
c->nr_erasing_blocks--; c->nr_erasing_blocks--;
c->nr_free_blocks++; c->nr_free_blocks++;
wake_up(&c->erase_wait);
}
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
wake_up(&c->erase_wait);
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: file.c,v 1.76 2002/07/29 08:25:35 dwmw2 Exp $ * $Id: file.c,v 1.81 2002/11/12 09:46:22 dwmw2 Exp $
* *
*/ */
...@@ -139,41 +139,43 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr) ...@@ -139,41 +139,43 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
down(&f->sem); down(&f->sem);
ivalid = iattr->ia_valid; ivalid = iattr->ia_valid;
ri->magic = JFFS2_MAGIC_BITMASK; ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
ri->nodetype = JFFS2_NODETYPE_INODE; ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
ri->totlen = sizeof(*ri) + mdatalen; ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen);
ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
ri->ino = inode->i_ino; ri->ino = cpu_to_je32(inode->i_ino);
ri->version = ++f->highest_version; ri->version = cpu_to_je32(++f->highest_version);
ri->mode = (ivalid & ATTR_MODE)?iattr->ia_mode:inode->i_mode; ri->uid = cpu_to_je16((ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid);
ri->uid = (ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid; ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid);
ri->gid = (ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid;
if (ivalid & ATTR_MODE)
if (ivalid & ATTR_MODE && ri->mode & S_ISGID && if (iattr->ia_mode & S_ISGID &&
!in_group_p(ri->gid) && !capable(CAP_FSETID)) !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID))
ri->mode &= ~S_ISGID; ri->mode = cpu_to_je32(iattr->ia_mode & ~S_ISGID);
else
ri->mode = cpu_to_je32(iattr->ia_mode);
else
ri->mode = cpu_to_je32(inode->i_mode);
ri->isize = (ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size;
ri->atime = (ivalid & ATTR_ATIME)?iattr->ia_atime.tv_sec:inode->i_atime.tv_sec;
ri->mtime = (ivalid & ATTR_MTIME)?iattr->ia_mtime.tv_sec:inode->i_mtime.tv_sec;
ri->ctime = (ivalid & ATTR_CTIME)?iattr->ia_ctime.tv_sec:inode->i_ctime.tv_sec;
ri->offset = 0; ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
ri->csize = ri->dsize = mdatalen; ri->atime = cpu_to_je32((ivalid & ATTR_ATIME)?iattr->ia_atime.tv_sec:inode->i_atime.tv_sec);
ri->mtime = cpu_to_je32((ivalid & ATTR_MTIME)?iattr->ia_mtime.tv_sec:inode->i_mtime.tv_sec);
ri->ctime = cpu_to_je32((ivalid & ATTR_CTIME)?iattr->ia_ctime.tv_sec:inode->i_ctime.tv_sec);
ri->compr = JFFS2_COMPR_NONE; ri->compr = JFFS2_COMPR_NONE;
if (inode->i_size < ri->isize) { if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
/* It's an extension. Make it a hole node */ /* It's an extension. Make it a hole node */
ri->compr = JFFS2_COMPR_ZERO; ri->compr = JFFS2_COMPR_ZERO;
ri->dsize = ri->isize - inode->i_size; ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size);
ri->offset = inode->i_size; ri->offset = cpu_to_je32(inode->i_size);
} }
ri->node_crc = crc32(0, ri, sizeof(*ri)-8); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
if (mdatalen) if (mdatalen)
ri->data_crc = crc32(0, mdata, mdatalen); ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
else else
ri->data_crc = 0; ri->data_crc = cpu_to_je32(0);
new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, NULL); new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, NULL);
if (S_ISLNK(inode->i_mode)) if (S_ISLNK(inode->i_mode))
...@@ -186,27 +188,27 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr) ...@@ -186,27 +188,27 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
return PTR_ERR(new_metadata); return PTR_ERR(new_metadata);
} }
/* It worked. Update the inode */ /* It worked. Update the inode */
inode->i_atime.tv_sec = ri->atime; inode->i_atime = je32_to_cpu(ri->atime.tv_sec);
inode->i_ctime.tv_sec = ri->ctime; inode->i_ctime = je32_to_cpu(ri->ctime.tv_sec);
inode->i_mtime.tv_sec = ri->mtime; inode->i_mtime = je32_to_cpu(ri->mtime.tv_sec);
inode->i_atime.tv_nsec = inode->i_atime.tv_nsec =
inode->i_ctime.tv_nsec = inode->i_ctime.tv_nsec =
inode->i_mtime.tv_nsec = 0; inode->i_mtime.tv_nsec = 0;
inode->i_mode = ri->mode; inode->i_mode = je32_to_cpu(ri->mode);
inode->i_uid = ri->uid; inode->i_uid = je16_to_cpu(ri->uid);
inode->i_gid = ri->gid; inode->i_gid = je16_to_cpu(ri->gid);
old_metadata = f->metadata; old_metadata = f->metadata;
if (inode->i_size > ri->isize) { if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
vmtruncate(inode, ri->isize); vmtruncate(inode, iattr->ia_size);
jffs2_truncate_fraglist (c, &f->fraglist, ri->isize); jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size);
} }
if (inode->i_size < ri->isize) { if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) {
jffs2_add_full_dnode_to_inode(c, f, new_metadata); jffs2_add_full_dnode_to_inode(c, f, new_metadata);
inode->i_size = ri->isize; inode->i_size = iattr->ia_size;
f->metadata = NULL; f->metadata = NULL;
} else { } else {
f->metadata = new_metadata; f->metadata = new_metadata;
...@@ -281,7 +283,6 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns ...@@ -281,7 +283,6 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
uint32_t pageofs = pg->index << PAGE_CACHE_SHIFT; uint32_t pageofs = pg->index << PAGE_CACHE_SHIFT;
int ret = 0; int ret = 0;
down(&f->sem);
D1(printk(KERN_DEBUG "jffs2_prepare_write()\n")); D1(printk(KERN_DEBUG "jffs2_prepare_write()\n"));
if (pageofs > inode->i_size) { if (pageofs > inode->i_size) {
...@@ -295,30 +296,30 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns ...@@ -295,30 +296,30 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
(unsigned int)inode->i_size, pageofs)); (unsigned int)inode->i_size, pageofs));
ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL); ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL);
if (ret) { if (ret)
up(&f->sem);
return ret; return ret;
}
down(&f->sem);
memset(&ri, 0, sizeof(ri)); memset(&ri, 0, sizeof(ri));
ri.magic = JFFS2_MAGIC_BITMASK; ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
ri.nodetype = JFFS2_NODETYPE_INODE; ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
ri.totlen = sizeof(ri); ri.totlen = cpu_to_je32(sizeof(ri));
ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
ri.ino = f->inocache->ino; ri.ino = cpu_to_je32(f->inocache->ino);
ri.version = ++f->highest_version; ri.version = cpu_to_je32(++f->highest_version);
ri.mode = inode->i_mode; ri.mode = cpu_to_je32(inode->i_mode);
ri.uid = inode->i_uid; ri.uid = cpu_to_je16(inode->i_uid);
ri.gid = inode->i_gid; ri.gid = cpu_to_je16(inode->i_gid);
ri.isize = max((uint32_t)inode->i_size, pageofs); ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs));
ri.atime = ri.ctime = ri.mtime = get_seconds(); ri.atime = ri.ctime = ri.mtime = cpu_to_je32(get_seconds());
ri.offset = inode->i_size; ri.offset = cpu_to_je32(inode->i_size);
ri.dsize = pageofs - inode->i_size; ri.dsize = cpu_to_je32(pageofs - inode->i_size);
ri.csize = 0; ri.csize = cpu_to_je32(0);
ri.compr = JFFS2_COMPR_ZERO; ri.compr = JFFS2_COMPR_ZERO;
ri.node_crc = crc32(0, &ri, sizeof(ri)-8); ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
ri.data_crc = 0; ri.data_crc = cpu_to_je32(0);
fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, NULL); fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, NULL);
...@@ -344,14 +345,16 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns ...@@ -344,14 +345,16 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
} }
jffs2_complete_reservation(c); jffs2_complete_reservation(c);
inode->i_size = pageofs; inode->i_size = pageofs;
up(&f->sem);
} }
/* Read in the page if it wasn't already present, unless it's a whole page */
/* Read in the page if it wasn't already present */ if (!PageUptodate(pg) && (start || end < PAGE_CACHE_SIZE)) {
if (!PageUptodate(pg) && (start || end < PAGE_SIZE)) down(&f->sem);
ret = jffs2_do_readpage_nolock(inode, pg); ret = jffs2_do_readpage_nolock(inode, pg);
D1(printk(KERN_DEBUG "end prepare_write()\n")); up(&f->sem);
up(&f->sem); }
D1(printk(KERN_DEBUG "end prepare_write(). pg->flags %lx\n", pg->flags));
return ret; return ret;
} }
...@@ -367,8 +370,16 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi ...@@ -367,8 +370,16 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
int ret = 0; int ret = 0;
uint32_t writtenlen = 0; uint32_t writtenlen = 0;
D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d\n", D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n",
inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end)); inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags));
if (!start && end == PAGE_CACHE_SIZE) {
/* We need to avoid deadlock with page_cache_read() in
jffs2_garbage_collect_pass(). So we have to mark the
page up to date, to prevent page_cache_read() from
trying to re-lock it. */
SetPageUptodate(pg);
}
ri = jffs2_alloc_raw_inode(); ri = jffs2_alloc_raw_inode();
...@@ -378,16 +389,21 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi ...@@ -378,16 +389,21 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
} }
/* Set the fields that the generic jffs2_write_inode_range() code can't find */ /* Set the fields that the generic jffs2_write_inode_range() code can't find */
ri->ino = inode->i_ino; ri->ino = cpu_to_je32(inode->i_ino);
ri->mode = inode->i_mode; ri->mode = cpu_to_je32(inode->i_mode);
ri->uid = inode->i_uid; ri->uid = cpu_to_je16(inode->i_uid);
ri->gid = inode->i_gid; ri->gid = cpu_to_je16(inode->i_gid);
ri->isize = (uint32_t)inode->i_size; ri->isize = cpu_to_je32((uint32_t)inode->i_size);
ri->atime = ri->ctime = ri->mtime = get_seconds(); ri->atime = ri->ctime = ri->mtime = cpu_to_je32(get_seconds());
/* In 2.4, it was already kmapped by generic_file_write(). Doesn't
hurt to do it again. The alternative is ifdefs, which are ugly. */
kmap(pg); kmap(pg);
ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + start, ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + start,
(pg->index << PAGE_CACHE_SHIFT) + start, end - start, &writtenlen); (pg->index << PAGE_CACHE_SHIFT) + start,
end - start, &writtenlen);
kunmap(pg); kunmap(pg);
if (ret) { if (ret) {
...@@ -400,7 +416,7 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi ...@@ -400,7 +416,7 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen; inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen;
inode->i_blocks = (inode->i_size + 511) >> 9; inode->i_blocks = (inode->i_size + 511) >> 9;
inode->i_ctime.tv_sec = inode->i_mtime.tv_sec = ri->ctime; inode->i_ctime.tv_sec = inode->i_mtime.tv_sec = je32_to_cpu(ri->ctime);
inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0; inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
} }
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: fs.c,v 1.13 2002/07/02 22:48:24 dwmw2 Exp $ * $Id: fs.c,v 1.19 2002/11/12 09:53:40 dwmw2 Exp $
* *
*/ */
...@@ -86,15 +86,15 @@ void jffs2_read_inode (struct inode *inode) ...@@ -86,15 +86,15 @@ void jffs2_read_inode (struct inode *inode)
up(&f->sem); up(&f->sem);
return; return;
} }
inode->i_mode = latest_node.mode; inode->i_mode = je32_to_cpu(latest_node.mode);
inode->i_uid = latest_node.uid; inode->i_uid = je16_to_cpu(latest_node.uid);
inode->i_gid = latest_node.gid; inode->i_gid = je16_to_cpu(latest_node.gid);
inode->i_size = latest_node.isize; inode->i_size = je32_to_cpu(latest_node.isize);
inode->i_atime.tv_sec = latest_node.atime; inode->i_atime = je32_to_cpu(latest_node.atime);
inode->i_mtime.tv_sec = latest_node.mtime; inode->i_mtime = je32_to_cpu(latest_node.mtime);
inode->i_ctime.tv_sec = latest_node.ctime; inode->i_ctime = je32_to_cpu(latest_node.ctime);
inode->i_atime.tv_nsec = inode->i_atime.tv_nsec =
inode->i_mtime.tv_nsec = inode->i_mtime.tv_nsec =
inode->i_ctime.tv_nsec = 0; inode->i_ctime.tv_nsec = 0;
inode->i_nlink = f->inocache->nlink; inode->i_nlink = f->inocache->nlink;
...@@ -192,19 +192,9 @@ void jffs2_write_super (struct super_block *sb) ...@@ -192,19 +192,9 @@ void jffs2_write_super (struct super_block *sb)
if (sb->s_flags & MS_RDONLY) if (sb->s_flags & MS_RDONLY)
return; return;
D1(printk(KERN_DEBUG "jffs2_write_super(): flush_wbuf before gc-trigger\n")); D1(printk(KERN_DEBUG "jffs2_write_super()\n"));
jffs2_garbage_collect_trigger(c); jffs2_garbage_collect_trigger(c);
jffs2_erase_pending_blocks(c); jffs2_erase_pending_blocks(c);
jffs2_mark_erased_blocks(c);
/* Eep. If we lock this here, we deadlock with jffs2_reserve_space() when
* it locks the alloc_sem and jffs2_do_reserve_space() waits for erases
* to happen. I think the erases and/or the flush_wbuf want doing from
*
*/
if (!down_trylock(&c->alloc_sem)) {
jffs2_flush_wbuf(c, 2);
up(&c->alloc_sem);
} // else it stays dirty. FIXME.
} }
...@@ -232,16 +222,16 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i ...@@ -232,16 +222,16 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
memset(ri, 0, sizeof(*ri)); memset(ri, 0, sizeof(*ri));
/* Set OS-specific defaults for new inodes */ /* Set OS-specific defaults for new inodes */
ri->uid = current->fsuid; ri->uid = cpu_to_je16(current->fsuid);
if (dir_i->i_mode & S_ISGID) { if (dir_i->i_mode & S_ISGID) {
ri->gid = dir_i->i_gid; ri->gid = cpu_to_je16(dir_i->i_gid);
if (S_ISDIR(mode)) if (S_ISDIR(mode))
ri->mode |= S_ISGID; mode |= S_ISGID;
} else { } else {
ri->gid = current->fsgid; ri->gid = cpu_to_je16(current->fsgid);
} }
ri->mode = mode; ri->mode = cpu_to_je32(mode);
ret = jffs2_do_new_inode (c, f, mode, ri); ret = jffs2_do_new_inode (c, f, mode, ri);
if (ret) { if (ret) {
make_bad_inode(inode); make_bad_inode(inode);
...@@ -249,12 +239,14 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i ...@@ -249,12 +239,14 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
return ERR_PTR(ret); return ERR_PTR(ret);
} }
inode->i_nlink = 1; inode->i_nlink = 1;
inode->i_ino = ri->ino; inode->i_ino = je32_to_cpu(ri->ino);
inode->i_mode = ri->mode; inode->i_mode = je32_to_cpu(ri->mode);
inode->i_gid = ri->gid; inode->i_gid = je16_to_cpu(ri->gid);
inode->i_uid = ri->uid; inode->i_uid = je16_to_cpu(ri->uid);
inode->i_atime = inode->i_ctime = inode->i_mtime = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
ri->atime = ri->mtime = ri->ctime = get_seconds(); inode->i_atime.tv_sec = inode->i_ctime.tv_sec = inode->i_mtime.tv_sec = get_seconds();
ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime.tv_sec);
inode->i_blksize = PAGE_SIZE; inode->i_blksize = PAGE_SIZE;
inode->i_blocks = 0; inode->i_blocks = 0;
inode->i_size = 0; inode->i_size = 0;
...@@ -305,9 +297,10 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) ...@@ -305,9 +297,10 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
if (!c->wbuf) if (!c->wbuf)
return -ENOMEM; return -ENOMEM;
/* Initialize process for timed wbuf flush */ /* Initialise process for timed wbuf flush */
INIT_WORK(&c->wbuf_task,(void*) jffs2_wbuf_process, (void *)c); INIT_WORK(&c->wbuf_task,(void*) jffs2_wbuf_process, (void *)c);
/* Initialize timer for timed wbuf flush */
/* Initialise timer for timed wbuf flush */
init_timer(&c->wbuf_timer); init_timer(&c->wbuf_timer);
c->wbuf_timer.function = jffs2_wbuf_timeout; c->wbuf_timer.function = jffs2_wbuf_timeout;
c->wbuf_timer.data = (unsigned long) c; c->wbuf_timer.data = (unsigned long) c;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: gc.c,v 1.74 2002/05/20 14:56:38 dwmw2 Exp $ * $Id: gc.c,v 1.88 2002/10/08 16:56:08 dwmw2 Exp $
* *
*/ */
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/compiler.h>
#include "nodelist.h" #include "nodelist.h"
static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
...@@ -86,6 +87,15 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) ...@@ -86,6 +87,15 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset); printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset);
BUG(); BUG();
} }
/* Have we accidentally picked a clean block with wasted space ? */
if (ret->wasted_size) {
D1(printk(KERN_DEBUG "Converting wasted_size %08x to dirty_size\n", ret->wasted_size));
ret->dirty_size += ret->wasted_size;
c->wasted_size -= ret->wasted_size;
c->dirty_size += ret->wasted_size;
ret->wasted_size = 0;
}
D1(jffs2_dump_block_lists(c)); D1(jffs2_dump_block_lists(c));
return ret; return ret;
...@@ -113,6 +123,49 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -113,6 +123,49 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
spin_lock_bh(&c->erase_completion_lock); spin_lock_bh(&c->erase_completion_lock);
while (c->unchecked_size) {
/* We can't start doing GC yet. We haven't finished checking
the node CRCs etc. Do it now and wait for it. */
struct jffs2_inode_cache *ic;
if (c->checked_ino > c->highest_ino) {
printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n",
c->unchecked_size);
D1(jffs2_dump_block_lists(c));
BUG();
}
ic = jffs2_get_ino_cache(c, c->checked_ino++);
if (!ic)
continue;
if (!ic->nlink) {
D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n",
ic->ino));
continue;
}
if (ic->state != INO_STATE_UNCHECKED) {
D1(printk(KERN_DEBUG "Skipping check of ino #%d already in state %d\n",
ic->ino, ic->state));
continue;
}
spin_unlock_bh(&c->erase_completion_lock);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%d\n", ic->ino));
{
/* XXX: This wants doing more sensibly -- split the core of jffs2_do_read_inode up */
struct inode *i = iget(OFNI_BS_2SFFJ(c), ic->ino);
if (is_bad_inode(i)) {
printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", ic->ino);
ret = -EIO;
}
iput(i);
}
up(&c->alloc_sem);
return ret;
}
/* First, work out which block we're garbage-collecting */ /* First, work out which block we're garbage-collecting */
jeb = c->gcblock; jeb = c->gcblock;
...@@ -128,15 +181,17 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -128,15 +181,17 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
D1(printk(KERN_DEBUG "GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size)); D1(printk(KERN_DEBUG "GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size));
D1(if (c->nextblock) D1(if (c->nextblock)
printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->free_size)); printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size));
if (!jeb->used_size) if (!jeb->used_size) {
up(&c->alloc_sem);
goto eraseit; goto eraseit;
}
raw = jeb->gc_node; raw = jeb->gc_node;
while(raw->flash_offset & 1) { while(ref_obsolete(raw)) {
D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", raw->flash_offset &~3)); D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw)));
jeb->gc_node = raw = raw->next_phys; jeb->gc_node = raw = raw->next_phys;
if (!raw) { if (!raw) {
printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n"); printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n");
...@@ -147,13 +202,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -147,13 +202,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
BUG(); BUG();
} }
} }
D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", raw->flash_offset &~3)); D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", ref_offset(raw)));
if (!raw->next_in_ino) { if (!raw->next_in_ino) {
/* Inode-less node. Clean marker, snapshot or something like that */ /* Inode-less node. Clean marker, snapshot or something like that */
/* FIXME: If it's something that needs to be copied, including something /* FIXME: If it's something that needs to be copied, including something
we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */ we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
jffs2_mark_node_obsolete(c, raw); jffs2_mark_node_obsolete(c, raw);
up(&c->alloc_sem);
goto eraseit_lock; goto eraseit_lock;
} }
...@@ -162,14 +218,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -162,14 +218,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x, ino #%u\n", jeb->offset, raw->flash_offset&~3, inum)); D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x, ino #%u\n", jeb->offset, ref_offset(raw), inum));
inode = iget(OFNI_BS_2SFFJ(c), inum); inode = iget(OFNI_BS_2SFFJ(c), inum);
if (is_bad_inode(inode)) { if (is_bad_inode(inode)) {
printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", inum); printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", inum);
/* NB. This will happen again. We need to do something appropriate here. */ /* NB. This will happen again. We need to do something appropriate here. */
iput(inode);
up(&c->alloc_sem); up(&c->alloc_sem);
iput(inode);
return -EIO; return -EIO;
} }
...@@ -179,7 +235,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -179,7 +235,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
/* Now we have the lock for this inode. Check that it's still the one at the head /* Now we have the lock for this inode. Check that it's still the one at the head
of the list. */ of the list. */
if (raw->flash_offset & 1) { if (ref_obsolete(raw)) {
D1(printk(KERN_DEBUG "node to be GC'd was obsoleted in the meantime.\n")); D1(printk(KERN_DEBUG "node to be GC'd was obsoleted in the meantime.\n"));
/* They'll call again */ /* They'll call again */
goto upnout; goto upnout;
...@@ -190,11 +246,26 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -190,11 +246,26 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
ret = jffs2_garbage_collect_metadata(c, jeb, f, fn); ret = jffs2_garbage_collect_metadata(c, jeb, f, fn);
goto upnout; goto upnout;
} }
for (frag = f->fraglist; frag; frag = frag->next) { /* FIXME. Read node and do lookup? */
for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {
if (frag->node && frag->node->raw == raw) { if (frag->node && frag->node->raw == raw) {
fn = frag->node; fn = frag->node;
end = frag->ofs + frag->size; end = frag->ofs + frag->size;
#if 1 /* Temporary debugging sanity checks, till we're ready to _trust_ the REF_PRISTINE flag stuff */
if (!nrfrags && ref_flags(fn->raw) == REF_PRISTINE) {
if (fn->frags > 1)
printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(raw), fn->frags);
if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->node)
printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n",
ref_offset(raw));
if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->node)
printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n",
ref_offset(raw), frag->ofs, frag->ofs+frag->size);
}
#endif
if (!nrfrags++) if (!nrfrags++)
start = frag->ofs; start = frag->ofs;
if (nrfrags == frag->node->frags) if (nrfrags == frag->node->frags)
...@@ -225,8 +296,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -225,8 +296,8 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
ret = jffs2_garbage_collect_deletion_dirent(c, jeb, f, fd); ret = jffs2_garbage_collect_deletion_dirent(c, jeb, f, fd);
} else { } else {
printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%u\n", printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%u\n",
raw->flash_offset&~3, f->inocache->ino); ref_offset(raw), f->inocache->ino);
if (raw->flash_offset & 1) { if (ref_obsolete(raw)) {
printk(KERN_WARNING "But it's obsolete so we don't mind too much\n"); printk(KERN_WARNING "But it's obsolete so we don't mind too much\n");
} else { } else {
ret = -EIO; ret = -EIO;
...@@ -234,6 +305,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -234,6 +305,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
} }
upnout: upnout:
up(&f->sem); up(&f->sem);
up(&c->alloc_sem);
iput(inode); iput(inode);
eraseit_lock: eraseit_lock:
...@@ -250,7 +322,6 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) ...@@ -250,7 +322,6 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
jffs2_erase_pending_trigger(c); jffs2_erase_pending_trigger(c);
} }
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
up(&c->alloc_sem);
return ret; return ret;
} }
...@@ -299,26 +370,26 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ ...@@ -299,26 +370,26 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
} }
memset(&ri, 0, sizeof(ri)); memset(&ri, 0, sizeof(ri));
ri.magic = JFFS2_MAGIC_BITMASK; ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
ri.nodetype = JFFS2_NODETYPE_INODE; ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
ri.totlen = sizeof(ri) + mdatalen; ri.totlen = cpu_to_je32(sizeof(ri) + mdatalen);
ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
ri.ino = f->inocache->ino; ri.ino = cpu_to_je32(f->inocache->ino);
ri.version = ++f->highest_version; ri.version = cpu_to_je32(++f->highest_version);
ri.mode = JFFS2_F_I_MODE(f); ri.mode = cpu_to_je32(JFFS2_F_I_MODE(f));
ri.uid = JFFS2_F_I_UID(f); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
ri.gid = JFFS2_F_I_GID(f); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
ri.isize = JFFS2_F_I_SIZE(f); ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
ri.atime = JFFS2_F_I_ATIME(f); ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
ri.ctime = JFFS2_F_I_CTIME(f); ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
ri.mtime = JFFS2_F_I_MTIME(f); ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
ri.offset = 0; ri.offset = cpu_to_je32(0);
ri.csize = mdatalen; ri.csize = cpu_to_je32(mdatalen);
ri.dsize = mdatalen; ri.dsize = cpu_to_je32(mdatalen);
ri.compr = JFFS2_COMPR_NONE; ri.compr = JFFS2_COMPR_NONE;
ri.node_crc = crc32(0, &ri, sizeof(ri)-8); ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
ri.data_crc = crc32(0, mdata, mdatalen); ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));
new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, phys_ofs, NULL); new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, phys_ofs, NULL);
...@@ -344,19 +415,19 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er ...@@ -344,19 +415,19 @@ static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_er
uint32_t alloclen, phys_ofs; uint32_t alloclen, phys_ofs;
int ret; int ret;
rd.magic = JFFS2_MAGIC_BITMASK; rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
rd.nodetype = JFFS2_NODETYPE_DIRENT; rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
rd.nsize = strlen(fd->name); rd.nsize = strlen(fd->name);
rd.totlen = sizeof(rd) + rd.nsize; rd.totlen = cpu_to_je32(sizeof(rd) + rd.nsize);
rd.hdr_crc = crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4); rd.hdr_crc = cpu_to_je32(crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4));
rd.pino = f->inocache->ino; rd.pino = cpu_to_je32(f->inocache->ino);
rd.version = ++f->highest_version; rd.version = cpu_to_je32(++f->highest_version);
rd.ino = fd->ino; rd.ino = cpu_to_je32(fd->ino);
rd.mctime = max(JFFS2_F_I_MTIME(f), JFFS2_F_I_CTIME(f)); rd.mctime = cpu_to_je32(max(JFFS2_F_I_MTIME(f), JFFS2_F_I_CTIME(f)));
rd.type = fd->type; rd.type = fd->type;
rd.node_crc = crc32(0, &rd, sizeof(rd)-8); rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8));
rd.name_crc = crc32(0, fd->name, rd.nsize); rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize));
ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen); ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen);
if (ret) { if (ret) {
...@@ -401,7 +472,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct ...@@ -401,7 +472,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) { for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) {
/* We only care about obsolete ones */ /* We only care about obsolete ones */
if (!(raw->flash_offset & 1)) if (!(ref_obsolete(raw)))
continue; continue;
/* Doesn't matter if there's one in the same erase block. We're going to /* Doesn't matter if there's one in the same erase block. We're going to
...@@ -411,40 +482,40 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct ...@@ -411,40 +482,40 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
continue; continue;
/* This is an obsolete node belonging to the same directory */ /* This is an obsolete node belonging to the same directory */
ret = jffs2_flash_read(c, raw->flash_offset & ~3, sizeof(struct jffs2_unknown_node), &retlen, (char *)&rd); ret = jffs2_flash_read(c, ref_offset(raw), sizeof(struct jffs2_unknown_node), &retlen, (char *)&rd);
if (ret) { if (ret) {
printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading header from obsolete node at %08x\n", ret, raw->flash_offset & ~3); printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading header from obsolete node at %08x\n", ret, ref_offset(raw));
/* If we can't read it, we don't need to continune to obsolete it. Continue */ /* If we can't read it, we don't need to continue to obsolete it. Continue */
continue; continue;
} }
if (retlen != sizeof(struct jffs2_unknown_node)) { if (retlen != sizeof(struct jffs2_unknown_node)) {
printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading header from obsolete node at %08x\n", printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading header from obsolete node at %08x\n",
retlen, sizeof(struct jffs2_unknown_node), raw->flash_offset & ~3); retlen, sizeof(struct jffs2_unknown_node), ref_offset(raw));
continue; continue;
} }
if (rd.nodetype != JFFS2_NODETYPE_DIRENT || if (je16_to_cpu(rd.nodetype) != JFFS2_NODETYPE_DIRENT ||
PAD(rd.totlen) != PAD(sizeof(rd) + name_len)) PAD(je32_to_cpu(rd.totlen)) != PAD(sizeof(rd) + name_len))
continue; continue;
/* OK, it's a dirent node, it's the right length. We have to take a /* OK, it's a dirent node, it's the right length. We have to take a
closer look at it... */ closer look at it... */
ret = jffs2_flash_read(c, raw->flash_offset & ~3, sizeof(rd), &retlen, (char *)&rd); ret = jffs2_flash_read(c, ref_offset(raw), sizeof(rd), &retlen, (char *)&rd);
if (ret) { if (ret) {
printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading from obsolete node at %08x\n", ret, raw->flash_offset & ~3); printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading from obsolete node at %08x\n", ret, ref_offset(raw));
/* If we can't read it, we don't need to continune to obsolete it. Continue */ /* If we can't read it, we don't need to continune to obsolete it. Continue */
continue; continue;
} }
if (retlen != sizeof(struct jffs2_unknown_node)) { if (retlen != sizeof(rd)) {
printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading from obsolete node at %08x\n", printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading from obsolete node at %08x\n",
retlen, sizeof(struct jffs2_unknown_node), raw->flash_offset & ~3); retlen, sizeof(rd), ref_offset(raw));
continue; continue;
} }
/* If the name CRC doesn't match, skip */ /* If the name CRC doesn't match, skip */
if (rd.name_crc != name_crc) if (je32_to_cpu(rd.name_crc) != name_crc)
continue; continue;
/* If the name length doesn't match, or it's another deletion dirent, skip */ /* If the name length doesn't match, or it's another deletion dirent, skip */
if (rd.nsize != name_len || !rd.ino) if (rd.nsize != name_len || !je32_to_cpu(rd.ino))
continue; continue;
/* OK, check the actual name now */ /* OK, check the actual name now */
...@@ -456,15 +527,15 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct ...@@ -456,15 +527,15 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
} }
} }
/* We read the extra byte before it so it's a word-aligned read */ /* We read the extra byte before it so it's a word-aligned read */
ret = jffs2_flash_read(c, (raw->flash_offset & ~3)+sizeof(rd)-1, name_len+1, &retlen, namebuf); ret = jffs2_flash_read(c, (ref_offset(raw))+sizeof(rd)-1, name_len+1, &retlen, namebuf);
if (ret) { if (ret) {
printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading name from obsolete node at %08x\n", ret, raw->flash_offset & ~3); printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading name from obsolete node at %08x\n", ret, ref_offset(raw));
/* If we can't read it, we don't need to continune to obsolete it. Continue */ /* If we can't read it, we don't need to continune to obsolete it. Continue */
continue; continue;
} }
if (retlen != sizeof(rd)) { if (retlen != name_len+1) {
printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading name from obsolete node at %08x\n", printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading name from obsolete node at %08x\n",
retlen, name_len, raw->flash_offset & ~3); retlen, name_len+1, ref_offset(raw));
continue; continue;
} }
if (memcmp(namebuf+1, fd->name, name_len)) if (memcmp(namebuf+1, fd->name, name_len))
...@@ -524,59 +595,62 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -524,59 +595,62 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
uint32_t crc; uint32_t crc;
/* It's partially obsoleted by a later write. So we have to /* It's partially obsoleted by a later write. So we have to
write it out again with the _same_ version as before */ write it out again with the _same_ version as before */
ret = jffs2_flash_read(c, fn->raw->flash_offset & ~3, sizeof(ri), &readlen, (char *)&ri); ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri);
if (readlen != sizeof(ri) || ret) { if (readlen != sizeof(ri) || ret) {
printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hold node\n", ret, readlen); printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hole node\n", ret, readlen);
goto fill; goto fill;
} }
if (ri.nodetype != JFFS2_NODETYPE_INODE) { if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) {
printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n", printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n",
fn->raw->flash_offset & ~3, ri.nodetype, JFFS2_NODETYPE_INODE); ref_offset(fn->raw),
je16_to_cpu(ri.nodetype), JFFS2_NODETYPE_INODE);
return -EIO; return -EIO;
} }
if (ri.totlen != sizeof(ri)) { if (je32_to_cpu(ri.totlen) != sizeof(ri)) {
printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x\n", printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x\n",
fn->raw->flash_offset & ~3, ri.totlen, sizeof(ri)); ref_offset(fn->raw),
je32_to_cpu(ri.totlen), sizeof(ri));
return -EIO; return -EIO;
} }
crc = crc32(0, &ri, sizeof(ri)-8); crc = crc32(0, &ri, sizeof(ri)-8);
if (crc != ri.node_crc) { if (crc != je32_to_cpu(ri.node_crc)) {
printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n", printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n",
fn->raw->flash_offset & ~3, ri.node_crc, crc); ref_offset(fn->raw),
je32_to_cpu(ri.node_crc), crc);
/* FIXME: We could possibly deal with this by writing new holes for each frag */ /* FIXME: We could possibly deal with this by writing new holes for each frag */
printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",
start, end, f->inocache->ino); start, end, f->inocache->ino);
goto fill; goto fill;
} }
if (ri.compr != JFFS2_COMPR_ZERO) { if (ri.compr != JFFS2_COMPR_ZERO) {
printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", fn->raw->flash_offset & ~3); printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", ref_offset(fn->raw));
printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",
start, end, f->inocache->ino); start, end, f->inocache->ino);
goto fill; goto fill;
} }
} else { } else {
fill: fill:
ri.magic = JFFS2_MAGIC_BITMASK; ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
ri.nodetype = JFFS2_NODETYPE_INODE; ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
ri.totlen = sizeof(ri); ri.totlen = cpu_to_je32(sizeof(ri));
ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
ri.ino = f->inocache->ino; ri.ino = cpu_to_je32(f->inocache->ino);
ri.version = ++f->highest_version; ri.version = cpu_to_je32(++f->highest_version);
ri.offset = start; ri.offset = cpu_to_je32(start);
ri.dsize = end - start; ri.dsize = cpu_to_je32(end - start);
ri.csize = 0; ri.csize = cpu_to_je32(0);
ri.compr = JFFS2_COMPR_ZERO; ri.compr = JFFS2_COMPR_ZERO;
} }
ri.mode = JFFS2_F_I_MODE(f); ri.mode = cpu_to_je32(JFFS2_F_I_MODE(f));
ri.uid = JFFS2_F_I_UID(f); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
ri.gid = JFFS2_F_I_GID(f); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
ri.isize = JFFS2_F_I_SIZE(f); ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
ri.atime = JFFS2_F_I_ATIME(f); ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
ri.ctime = JFFS2_F_I_CTIME(f); ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
ri.mtime = JFFS2_F_I_MTIME(f); ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
ri.data_crc = 0; ri.data_crc = cpu_to_je32(0);
ri.node_crc = crc32(0, &ri, sizeof(ri)-8); ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen); ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen);
if (ret) { if (ret) {
...@@ -590,7 +664,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -590,7 +664,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
printk(KERN_WARNING "Error writing new hole node: %ld\n", PTR_ERR(new_fn)); printk(KERN_WARNING "Error writing new hole node: %ld\n", PTR_ERR(new_fn));
return PTR_ERR(new_fn); return PTR_ERR(new_fn);
} }
if (ri.version == f->highest_version) { if (je32_to_cpu(ri.version) == f->highest_version) {
jffs2_add_full_dnode_to_inode(c, f, new_fn); jffs2_add_full_dnode_to_inode(c, f, new_fn);
if (f->metadata) { if (f->metadata) {
jffs2_mark_node_obsolete(c, f->metadata->raw); jffs2_mark_node_obsolete(c, f->metadata->raw);
...@@ -608,10 +682,12 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -608,10 +682,12 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
*/ */
D1(if(unlikely(fn->frags <= 1)) { D1(if(unlikely(fn->frags <= 1)) {
printk(KERN_WARNING "jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n", printk(KERN_WARNING "jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n",
fn->frags, ri.version, f->highest_version, ri.ino); fn->frags, je32_to_cpu(ri.version), f->highest_version,
je32_to_cpu(ri.ino));
}); });
for (frag = f->fraglist; frag; frag = frag->next) { for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs);
frag; frag = frag_next(frag)) {
if (frag->ofs > fn->size + fn->ofs) if (frag->ofs > fn->size + fn->ofs)
break; break;
if (frag->node == fn) { if (frag->node == fn) {
...@@ -655,7 +731,6 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era ...@@ -655,7 +731,6 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
orig_end = end; orig_end = end;
/* If we're looking at the last node in the block we're /* If we're looking at the last node in the block we're
garbage-collecting, we allow ourselves to merge as if the garbage-collecting, we allow ourselves to merge as if the
block was already erasing. We're likely to be GC'ing a block was already erasing. We're likely to be GC'ing a
...@@ -722,26 +797,26 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era ...@@ -722,26 +797,26 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
} else { } else {
datalen = cdatalen; datalen = cdatalen;
} }
ri.magic = JFFS2_MAGIC_BITMASK; ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
ri.nodetype = JFFS2_NODETYPE_INODE; ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
ri.totlen = sizeof(ri) + cdatalen; ri.totlen = cpu_to_je32(sizeof(ri) + cdatalen);
ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
ri.ino = f->inocache->ino; ri.ino = cpu_to_je32(f->inocache->ino);
ri.version = ++f->highest_version; ri.version = cpu_to_je32(++f->highest_version);
ri.mode = JFFS2_F_I_MODE(f); ri.mode = cpu_to_je32(JFFS2_F_I_MODE(f));
ri.uid = JFFS2_F_I_UID(f); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
ri.gid = JFFS2_F_I_GID(f); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
ri.isize = JFFS2_F_I_SIZE(f); ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
ri.atime = JFFS2_F_I_ATIME(f); ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
ri.ctime = JFFS2_F_I_CTIME(f); ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
ri.mtime = JFFS2_F_I_MTIME(f); ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
ri.offset = offset; ri.offset = cpu_to_je32(offset);
ri.csize = cdatalen; ri.csize = cpu_to_je32(cdatalen);
ri.dsize = datalen; ri.dsize = cpu_to_je32(datalen);
ri.compr = comprtype; ri.compr = comprtype;
ri.node_crc = crc32(0, &ri, sizeof(ri)-8); ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
ri.data_crc = crc32(0, writebuf, cdatalen); ri.data_crc = cpu_to_je32(crc32(0, writebuf, cdatalen));
new_fn = jffs2_write_dnode(c, f, &ri, writebuf, cdatalen, phys_ofs, NULL); new_fn = jffs2_write_dnode(c, f, &ri, writebuf, cdatalen, phys_ofs, NULL);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: nodelist.c,v 1.47 2002/06/26 01:25:30 dwmw2 Exp $ * $Id: nodelist.c,v 1.65 2002/11/12 09:50:13 dwmw2 Exp $
* *
*/ */
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/rbtree.h>
#include <linux/crc32.h>
#include <linux/slab.h>
#include "nodelist.h" #include "nodelist.h"
void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list) void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list)
...@@ -116,9 +119,9 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode ...@@ -116,9 +119,9 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
for (ref = f->inocache->nodes; ref && ref->next_in_ino; ref = ref->next_in_ino) { for (ref = f->inocache->nodes; ref && ref->next_in_ino; ref = ref->next_in_ino) {
/* Work out whether it's a data node or a dirent node */ /* Work out whether it's a data node or a dirent node */
if (ref->flash_offset & 1) { if (ref_obsolete(ref)) {
/* FIXME: On NAND flash we may need to read these */ /* FIXME: On NAND flash we may need to read these */
D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref->flash_offset &~3)); D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref)));
continue; continue;
} }
/* We can hold a pointer to a non-obsolete node without the spinlock, /* We can hold a pointer to a non-obsolete node without the spinlock,
...@@ -126,9 +129,12 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode ...@@ -126,9 +129,12 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
they're in gets erased */ they're in gets erased */
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
err = jffs2_flash_read(c, (ref->flash_offset & ~3), min(ref->totlen, sizeof(node)), &retlen, (void *)&node); cond_resched();
/* FIXME: point() */
err = jffs2_flash_read(c, (ref_offset(ref)), min(ref->totlen, sizeof(node)), &retlen, (void *)&node);
if (err) { if (err) {
printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, (ref->flash_offset) & ~3); printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref));
goto free_out; goto free_out;
} }
...@@ -140,20 +146,24 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode ...@@ -140,20 +146,24 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
goto free_out; goto free_out;
} }
switch (node.u.nodetype) { switch (je16_to_cpu(node.u.nodetype)) {
case JFFS2_NODETYPE_DIRENT: case JFFS2_NODETYPE_DIRENT:
D1(printk(KERN_DEBUG "Node at %08x is a dirent node\n", ref->flash_offset &~3)); D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref)));
if (ref_flags(ref) == REF_UNCHECKED) {
printk(KERN_WARNING "BUG: Dirent node at 0x%08x never got checked? How?\n", ref_offset(ref));
BUG();
}
if (retlen < sizeof(node.d)) { if (retlen < sizeof(node.d)) {
printk(KERN_WARNING "short read in get_inode_nodes()\n"); printk(KERN_WARNING "short read in get_inode_nodes()\n");
err = -EIO; err = -EIO;
goto free_out; goto free_out;
} }
if (node.d.version > *highest_version) if (je32_to_cpu(node.d.version) > *highest_version)
*highest_version = node.d.version; *highest_version = je32_to_cpu(node.d.version);
if (ref->flash_offset & 1) { if (ref_obsolete(ref)) {
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n", printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n",
ref->flash_offset & ~3); ref_offset(ref));
BUG(); BUG();
} }
fd = jffs2_alloc_full_dirent(node.d.nsize+1); fd = jffs2_alloc_full_dirent(node.d.nsize+1);
...@@ -163,14 +173,14 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode ...@@ -163,14 +173,14 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
} }
memset(fd,0,sizeof(struct jffs2_full_dirent) + node.d.nsize+1); memset(fd,0,sizeof(struct jffs2_full_dirent) + node.d.nsize+1);
fd->raw = ref; fd->raw = ref;
fd->version = node.d.version; fd->version = je32_to_cpu(node.d.version);
fd->ino = node.d.ino; fd->ino = je32_to_cpu(node.d.ino);
fd->type = node.d.type; fd->type = node.d.type;
/* Pick out the mctime of the latest dirent */ /* Pick out the mctime of the latest dirent */
if(fd->version > *mctime_ver) { if(fd->version > *mctime_ver) {
*mctime_ver = fd->version; *mctime_ver = fd->version;
*latest_mctime = node.d.mctime; *latest_mctime = je32_to_cpu(node.d.mctime);
} }
/* memcpy as much of the name as possible from the raw /* memcpy as much of the name as possible from the raw
...@@ -183,9 +193,10 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode ...@@ -183,9 +193,10 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
from the flash? from the flash?
*/ */
if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) { if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) {
/* FIXME: point() */
int already = retlen - sizeof(struct jffs2_raw_dirent); int already = retlen - sizeof(struct jffs2_raw_dirent);
err = jffs2_flash_read(c, (ref->flash_offset & ~3) + retlen, err = jffs2_flash_read(c, (ref_offset(ref)) + retlen,
node.d.nsize - already, &retlen, &fd->name[already]); node.d.nsize - already, &retlen, &fd->name[already]);
if (!err && retlen != node.d.nsize - already) if (!err && retlen != node.d.nsize - already)
err = -EIO; err = -EIO;
...@@ -206,22 +217,75 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode ...@@ -206,22 +217,75 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
break; break;
case JFFS2_NODETYPE_INODE: case JFFS2_NODETYPE_INODE:
D1(printk(KERN_DEBUG "Node at %08x is a data node\n", ref->flash_offset &~3)); D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref)));
if (retlen < sizeof(node.i)) { if (retlen < sizeof(node.i)) {
printk(KERN_WARNING "read too short for dnode\n"); printk(KERN_WARNING "read too short for dnode\n");
err = -EIO; err = -EIO;
goto free_out; goto free_out;
} }
if (node.d.version > *highest_version) if (je32_to_cpu(node.i.version) > *highest_version)
*highest_version = node.i.version; *highest_version = je32_to_cpu(node.i.version);
D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", node.d.version, *highest_version)); D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", je32_to_cpu(node.i.version), *highest_version));
if (ref->flash_offset & 1) { if (ref_obsolete(ref)) {
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n", printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n",
ref->flash_offset & ~3); ref_offset(ref));
BUG(); BUG();
} }
/* If we've never checked the CRCs on this node, check them now. */
if (ref_flags(ref) == REF_UNCHECKED) {
uint32_t crc;
struct jffs2_eraseblock *jeb;
crc = crc32(0, &node, sizeof(node.i)-8);
if (crc != je32_to_cpu(node.i.node_crc)) {
printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
ref_offset(ref), je32_to_cpu(node.i.node_crc), crc);
jffs2_mark_node_obsolete(c, ref);
spin_lock_bh(&c->erase_completion_lock);
continue;
}
if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) {
/* FIXME: point() */
char *buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL);
if (!buf)
return -ENOMEM;
err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
&retlen, buf);
if (!err && retlen != je32_to_cpu(node.i.csize))
err = -EIO;
if (err) {
kfree(buf);
return err;
}
crc = crc32(0, buf, je32_to_cpu(node.i.csize));
kfree(buf);
if (crc != je32_to_cpu(node.i.data_crc)) {
printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
ref_offset(ref), je32_to_cpu(node.i.data_crc), crc);
jffs2_mark_node_obsolete(c, ref);
spin_lock_bh(&c->erase_completion_lock);
continue;
}
}
/* Mark the node as having been checked and fix the accounting accordingly */
jeb = &c->blocks[ref->flash_offset / c->sector_size];
jeb->used_size += ref->totlen;
jeb->unchecked_size -= ref->totlen;
c->used_size += ref->totlen;
c->unchecked_size -= ref->totlen;
mark_ref_normal(ref);
}
tn = jffs2_alloc_tmp_dnode_info(); tn = jffs2_alloc_tmp_dnode_info();
if (!tn) { if (!tn) {
D1(printk(KERN_DEBUG "alloc tn failed\n")); D1(printk(KERN_DEBUG "alloc tn failed\n"));
...@@ -236,34 +300,66 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode ...@@ -236,34 +300,66 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
jffs2_free_tmp_dnode_info(tn); jffs2_free_tmp_dnode_info(tn);
goto free_out; goto free_out;
} }
tn->version = node.i.version; tn->version = je32_to_cpu(node.i.version);
tn->fn->ofs = node.i.offset; tn->fn->ofs = je32_to_cpu(node.i.offset);
/* There was a bug where we wrote hole nodes out with /* There was a bug where we wrote hole nodes out with
csize/dsize swapped. Deal with it */ csize/dsize swapped. Deal with it */
if (node.i.compr == JFFS2_COMPR_ZERO && !node.i.dsize && node.i.csize) if (node.i.compr == JFFS2_COMPR_ZERO && !je32_to_cpu(node.i.dsize) && je32_to_cpu(node.i.csize))
tn->fn->size = node.i.csize; tn->fn->size = je32_to_cpu(node.i.csize);
else // normal case... else // normal case...
tn->fn->size = node.i.dsize; tn->fn->size = je32_to_cpu(node.i.dsize);
tn->fn->raw = ref; tn->fn->raw = ref;
D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n", ref->flash_offset &~3, node.i.version, node.i.offset, node.i.dsize)); D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n",
ref_offset(ref), je32_to_cpu(node.i.version),
je32_to_cpu(node.i.offset), je32_to_cpu(node.i.dsize)));
jffs2_add_tn_to_list(tn, &ret_tn); jffs2_add_tn_to_list(tn, &ret_tn);
break; break;
default: default:
switch(node.u.nodetype & JFFS2_COMPAT_MASK) { if (ref_flags(ref) == REF_UNCHECKED) {
struct jffs2_eraseblock *jeb;
printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n",
je16_to_cpu(node.u.nodetype), ref_offset(ref));
/* Mark the node as having been checked and fix the accounting accordingly */
jeb = &c->blocks[ref->flash_offset / c->sector_size];
jeb->used_size += ref->totlen;
jeb->unchecked_size -= ref->totlen;
c->used_size += ref->totlen;
c->unchecked_size -= ref->totlen;
mark_ref_normal(ref);
}
node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype));
if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) {
/* Hmmm. This should have been caught at scan time. */
printk(KERN_ERR "Node header CRC failed at %08x. But it must have been OK earlier.\n",
ref_offset(ref));
printk(KERN_ERR "Node was: { %04x, %04x, %08x, %08x }\n",
je16_to_cpu(node.u.magic), je16_to_cpu(node.u.nodetype), je32_to_cpu(node.u.totlen),
je32_to_cpu(node.u.hdr_crc));
jffs2_mark_node_obsolete(c, ref);
} else switch(je16_to_cpu(node.u.nodetype) & JFFS2_COMPAT_MASK) {
case JFFS2_FEATURE_INCOMPAT: case JFFS2_FEATURE_INCOMPAT:
printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3); printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
/* EEP */
BUG();
break; break;
case JFFS2_FEATURE_ROCOMPAT: case JFFS2_FEATURE_ROCOMPAT:
printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3); printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
if (!(c->flags & JFFS2_SB_FLAG_RO))
BUG();
break; break;
case JFFS2_FEATURE_RWCOMPAT_COPY: case JFFS2_FEATURE_RWCOMPAT_COPY:
printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3); printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
break; break;
case JFFS2_FEATURE_RWCOMPAT_DELETE: case JFFS2_FEATURE_RWCOMPAT_DELETE:
printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3); printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
jffs2_mark_node_obsolete(c, ref);
break; break;
} }
} }
spin_lock_bh(&c->erase_completion_lock); spin_lock_bh(&c->erase_completion_lock);
...@@ -369,3 +465,126 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c) ...@@ -369,3 +465,126 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c)
} }
} }
struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset)
{
/* The common case in lookup is that there will be a node
which precisely matches. So we go looking for that first */
struct rb_node *next;
struct jffs2_node_frag *prev = NULL;
struct jffs2_node_frag *frag = NULL;
D2(printk(KERN_DEBUG "jffs2_lookup_node_frag(%p, %d)\n", fragtree, offset));
next = fragtree->rb_node;
while(next) {
frag = rb_entry(next, struct jffs2_node_frag, rb);
D2(printk(KERN_DEBUG "Considering frag %d-%d (%p). left %p, right %p\n",
frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right));
if (frag->ofs + frag->size <= offset) {
D2(printk(KERN_DEBUG "Going right from frag %d-%d, before the region we care about\n",
frag->ofs, frag->ofs+frag->size));
/* Remember the closest smaller match on the way down */
if (!prev || frag->ofs > prev->ofs)
prev = frag;
next = frag->rb.rb_right;
} else if (frag->ofs > offset) {
D2(printk(KERN_DEBUG "Going left from frag %d-%d, after the region we care about\n",
frag->ofs, frag->ofs+frag->size));
next = frag->rb.rb_left;
} else {
D2(printk(KERN_DEBUG "Returning frag %d,%d, matched\n",
frag->ofs, frag->ofs+frag->size));
return frag;
}
}
/* Exact match not found. Go back up looking at each parent,
and return the closest smaller one */
if (prev)
D2(printk(KERN_DEBUG "No match. Returning frag %d,%d, closest previous\n",
prev->ofs, prev->ofs+prev->size));
else
D2(printk(KERN_DEBUG "Returning NULL, empty fragtree\n"));
return prev;
}
/* Pass 'c' argument to indicate that nodes should be marked obsolete as
they're killed. */
void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c)
{
struct jffs2_node_frag *frag;
struct jffs2_node_frag *parent;
if (!root->rb_node)
return;
frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb));
while(frag) {
if (frag->rb.rb_left) {
D2(printk(KERN_DEBUG "Going left from frag (%p) %d-%d\n",
frag, frag->ofs, frag->ofs+frag->size));
frag = frag_left(frag);
continue;
}
if (frag->rb.rb_right) {
D2(printk(KERN_DEBUG "Going right from frag (%p) %d-%d\n",
frag, frag->ofs, frag->ofs+frag->size));
frag = frag_right(frag);
continue;
}
D2(printk(KERN_DEBUG "jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--\n",
frag->ofs, frag->ofs+frag->size, frag->node,
frag->node?frag->node->frags:0));
if (frag->node && !(--frag->node->frags)) {
/* Not a hole, and it's the final remaining frag
of this node. Free the node */
if (c)
jffs2_mark_node_obsolete(c, frag->node->raw);
jffs2_free_full_dnode(frag->node);
}
parent = frag_parent(frag);
if (parent) {
if (frag_left(parent) == frag)
parent->rb.rb_left = NULL;
else
parent->rb.rb_right = NULL;
}
jffs2_free_node_frag(frag);
frag = parent;
}
}
void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base)
{
struct rb_node *parent = &base->rb;
struct rb_node **link = &parent;
D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag,
newfrag->ofs, newfrag->ofs+newfrag->size, base));
while (*link) {
parent = *link;
base = rb_entry(parent, struct jffs2_node_frag, rb);
D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs));
if (newfrag->ofs > base->ofs)
link = &base->rb.rb_right;
else if (newfrag->ofs < base->ofs)
link = &base->rb.rb_left;
else {
printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base);
BUG();
}
}
rb_link_node(&newfrag->rb, &base->rb, link);
}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: nodelist.h,v 1.74 2002/06/26 01:20:43 dwmw2 Exp $ * $Id: nodelist.h,v 1.87 2002/11/12 13:36:18 dwmw2 Exp $
* *
*/ */
...@@ -53,16 +53,22 @@ struct jffs2_raw_node_ref ...@@ -53,16 +53,22 @@ struct jffs2_raw_node_ref
for this inode instead. The inode_cache will have NULL in the first for this inode instead. The inode_cache will have NULL in the first
word so you know when you've got there :) */ word so you know when you've got there :) */
struct jffs2_raw_node_ref *next_phys; struct jffs2_raw_node_ref *next_phys;
// uint32_t ino;
uint32_t flash_offset; uint32_t flash_offset;
uint32_t totlen; uint32_t totlen;
// uint16_t nodetype;
/* flash_offset & 3 always has to be zero, because nodes are /* flash_offset & 3 always has to be zero, because nodes are
always aligned at 4 bytes. So we have a couple of extra bits always aligned at 4 bytes. So we have a couple of extra bits
to play with. So we set the least significant bit to 1 to to play with. So we set the least significant bit to 1 to
signify that the node is obsoleted by later nodes. signify that the node is obsoleted by later nodes.
*/ */
#define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */
#define REF_OBSOLETE 1 /* Obsolete, can be completely ignored */
#define REF_PRISTINE 2 /* Completely clean. GC without looking */
#define REF_NORMAL 3 /* Possibly overlapped. Read the page and write again on GC */
#define ref_flags(ref) ((ref)->flash_offset & 3)
#define ref_offset(ref) ((ref)->flash_offset & ~3)
#define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE)
#define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
}; };
/* /*
...@@ -83,14 +89,20 @@ struct jffs2_raw_node_ref_list { ...@@ -83,14 +89,20 @@ struct jffs2_raw_node_ref_list {
a pointer to the first physical node which is part of this inode, too. a pointer to the first physical node which is part of this inode, too.
*/ */
struct jffs2_inode_cache { struct jffs2_inode_cache {
struct jffs2_scan_info *scan; /* Used during scan to hold struct jffs2_full_dirent *scan_dents; /* Used during scan to hold
temporary lists of nodes, and later must be set to temporary lists of dirents, and later must be set to
NULL to mark the end of the raw_node_ref->next_in_ino NULL to mark the end of the raw_node_ref->next_in_ino
chain. */ chain. */
struct jffs2_inode_cache *next; struct jffs2_inode_cache *next;
struct jffs2_raw_node_ref *nodes; struct jffs2_raw_node_ref *nodes;
uint32_t ino; uint32_t ino;
int nlink; int nlink;
int state;
#define INO_STATE_UNCHECKED 0
#define INO_STATE_CHECKING 1
#define INO_STATE_CHECKEDABSENT 2
#define INO_STATE_READINGINODE 3
#define INO_STATE_PRESENT 5
}; };
#define INOCACHE_HASHSIZE 128 #define INOCACHE_HASHSIZE 128
...@@ -146,7 +158,7 @@ struct jffs2_full_dirent ...@@ -146,7 +158,7 @@ struct jffs2_full_dirent
*/ */
struct jffs2_node_frag struct jffs2_node_frag
{ {
struct jffs2_node_frag *next; struct rb_node rb;
struct jffs2_full_dnode *node; /* NULL for holes */ struct jffs2_full_dnode *node; /* NULL for holes */
uint32_t size; uint32_t size;
uint32_t ofs; /* Don't really need this, but optimisation */ uint32_t ofs; /* Don't really need this, but optimisation */
...@@ -158,8 +170,10 @@ struct jffs2_eraseblock ...@@ -158,8 +170,10 @@ struct jffs2_eraseblock
int bad_count; int bad_count;
uint32_t offset; /* of this block in the MTD */ uint32_t offset; /* of this block in the MTD */
uint32_t unchecked_size;
uint32_t used_size; uint32_t used_size;
uint32_t dirty_size; uint32_t dirty_size;
uint32_t wasted_size;
uint32_t free_size; /* Note that sector_size - free_size uint32_t free_size; /* Note that sector_size - free_size
is the address of the first free space */ is the address of the first free space */
struct jffs2_raw_node_ref *first_node; struct jffs2_raw_node_ref *first_node;
...@@ -177,25 +191,28 @@ struct jffs2_eraseblock ...@@ -177,25 +191,28 @@ struct jffs2_eraseblock
}; };
#define ACCT_SANITY_CHECK(c, jeb) do { \ #define ACCT_SANITY_CHECK(c, jeb) do { \
if (jeb->used_size + jeb->dirty_size + jeb->free_size != c->sector_size) { \ if (jeb->used_size + jeb->dirty_size + jeb->free_size + jeb->wasted_size + jeb->unchecked_size != c->sector_size) { \
printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", jeb->offset); \ printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", jeb->offset); \
printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x != total %08x\n", \ printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + wasted %08x + unchecked %08x != total %08x\n", \
jeb->free_size, jeb->dirty_size, jeb->used_size, c->sector_size); \ jeb->free_size, jeb->dirty_size, jeb->used_size, jeb->wasted_size, jeb->unchecked_size, c->sector_size); \
BUG(); \ BUG(); \
} \ } \
if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size != c->flash_size) { \ if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size + c->wasted_size + c->unchecked_size != c->flash_size) { \
printk(KERN_NOTICE "Eeep. Space accounting superblock info is screwed\n"); \ printk(KERN_NOTICE "Eeep. Space accounting superblock info is screwed\n"); \
printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x != total %08x\n", \ printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x + wasted %08x + unchecked %08x != total %08x\n", \
c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->flash_size); \ c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->wasted_size, c->unchecked_size, c->flash_size); \
BUG(); \ BUG(); \
} \ } \
} while(0) } while(0)
#define ACCT_PARANOIA_CHECK(jeb) do { \ #define ACCT_PARANOIA_CHECK(jeb) do { \
uint32_t my_used_size = 0; \ uint32_t my_used_size = 0; \
uint32_t my_unchecked_size = 0; \
struct jffs2_raw_node_ref *ref2 = jeb->first_node; \ struct jffs2_raw_node_ref *ref2 = jeb->first_node; \
while (ref2) { \ while (ref2) { \
if (!(ref2->flash_offset & 1)) \ if (ref_flags(ref2) == REF_UNCHECKED) \
my_unchecked_size += ref2->totlen; \
else if (!ref_obsolete(ref2)) \
my_used_size += ref2->totlen; \ my_used_size += ref2->totlen; \
ref2 = ref2->next_phys; \ ref2 = ref2->next_phys; \
} \ } \
...@@ -203,6 +220,10 @@ struct jffs2_eraseblock ...@@ -203,6 +220,10 @@ struct jffs2_eraseblock
printk(KERN_NOTICE "Calculated used size %08x != stored used size %08x\n", my_used_size, jeb->used_size); \ printk(KERN_NOTICE "Calculated used size %08x != stored used size %08x\n", my_used_size, jeb->used_size); \
BUG(); \ BUG(); \
} \ } \
if (my_unchecked_size != jeb->unchecked_size) { \
printk(KERN_NOTICE "Calculated unchecked size %08x != stored unchecked size %08x\n", my_unchecked_size, jeb->unchecked_size); \
BUG(); \
} \
} while(0) } while(0)
#define ALLOC_NORMAL 0 /* Normal allocation */ #define ALLOC_NORMAL 0 /* Normal allocation */
...@@ -211,7 +232,7 @@ struct jffs2_eraseblock ...@@ -211,7 +232,7 @@ struct jffs2_eraseblock
#define JFFS2_RESERVED_BLOCKS_BASE 3 /* Number of free blocks there must be before we... */ #define JFFS2_RESERVED_BLOCKS_BASE 3 /* Number of free blocks there must be before we... */
#define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 2) /* ... allow a normal filesystem write */ #define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 2) /* ... allow a normal filesystem write */
#define JFFS2_RESERVED_BLOCKS_DELETION (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... allow a normal filesystem deletion */ #define JFFS2_RESERVED_BLOCKS_DELETION (JFFS2_RESERVED_BLOCKS_BASE) /* ... allow a normal filesystem deletion */
#define JFFS2_RESERVED_BLOCKS_GCTRIGGER (JFFS2_RESERVED_BLOCKS_BASE + 3) /* ... wake up the GC thread */ #define JFFS2_RESERVED_BLOCKS_GCTRIGGER (JFFS2_RESERVED_BLOCKS_BASE + 3) /* ... wake up the GC thread */
#define JFFS2_RESERVED_BLOCKS_GCBAD (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... pick a block from the bad_list to GC */ #define JFFS2_RESERVED_BLOCKS_GCBAD (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... pick a block from the bad_list to GC */
#define JFFS2_RESERVED_BLOCKS_GCMERGE (JFFS2_RESERVED_BLOCKS_BASE) /* ... merge pages when garbage collecting */ #define JFFS2_RESERVED_BLOCKS_GCMERGE (JFFS2_RESERVED_BLOCKS_BASE) /* ... merge pages when garbage collecting */
...@@ -220,6 +241,9 @@ struct jffs2_eraseblock ...@@ -220,6 +241,9 @@ struct jffs2_eraseblock
/* How much dirty space before it goes on the very_dirty_list */ /* How much dirty space before it goes on the very_dirty_list */
#define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2)) #define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2))
/* check if dirty space is more than 255 Byte */
#define ISDIRTY(size) ((size) > sizeof (struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN)
#define PAD(x) (((x)+3)&~3) #define PAD(x) (((x)+3)&~3)
static inline int jffs2_raw_ref_to_inum(struct jffs2_raw_node_ref *raw) static inline int jffs2_raw_ref_to_inum(struct jffs2_raw_node_ref *raw)
...@@ -231,6 +255,24 @@ static inline int jffs2_raw_ref_to_inum(struct jffs2_raw_node_ref *raw) ...@@ -231,6 +255,24 @@ static inline int jffs2_raw_ref_to_inum(struct jffs2_raw_node_ref *raw)
return ((struct jffs2_inode_cache *)raw)->ino; return ((struct jffs2_inode_cache *)raw)->ino;
} }
static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
{
struct rb_node *node = root->rb_node;
if (!node)
return NULL;
while(node->rb_left)
node = node->rb_left;
return rb_entry(node, struct jffs2_node_frag, rb);
}
#define rb_parent(rb) ((rb)->rb_parent)
#define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb)
#define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb)
#define frag_parent(frag) rb_entry(rb_parent(&(frag)->rb), struct jffs2_node_frag, rb)
#define frag_left(frag) rb_entry((frag)->rb.rb_left, struct jffs2_node_frag, rb)
#define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb)
#define frag_erase(frag, list) rb_erase(&frag->rb, list);
/* nodelist.c */ /* nodelist.c */
D1(void jffs2_print_frag_list(struct jffs2_inode_info *f)); D1(void jffs2_print_frag_list(struct jffs2_inode_info *f));
void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
...@@ -244,11 +286,17 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new ...@@ -244,11 +286,17 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new
void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old); void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old);
void jffs2_free_ino_caches(struct jffs2_sb_info *c); void jffs2_free_ino_caches(struct jffs2_sb_info *c);
void jffs2_free_raw_node_refs(struct jffs2_sb_info *c); void jffs2_free_raw_node_refs(struct jffs2_sb_info *c);
struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset);
void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c_delete);
void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base);
struct rb_node *rb_next(struct rb_node *);
struct rb_node *rb_prev(struct rb_node *);
void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root);
/* nodemgmt.c */ /* nodemgmt.c */
int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio); int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio);
int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len);
int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, uint32_t len, int dirty); int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new);
void jffs2_complete_reservation(struct jffs2_sb_info *c); void jffs2_complete_reservation(struct jffs2_sb_info *c);
void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw); void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw);
void jffs2_dump_block_lists(struct jffs2_sb_info *c); void jffs2_dump_block_lists(struct jffs2_sb_info *c);
...@@ -266,8 +314,8 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint ...@@ -266,8 +314,8 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
/* readinode.c */ /* readinode.c */
void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, uint32_t size); void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size);
int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn); int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_full_dnode *fn);
int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn);
int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
uint32_t ino, struct jffs2_raw_inode *latest_node); uint32_t ino, struct jffs2_raw_inode *latest_node);
...@@ -320,7 +368,6 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c); ...@@ -320,7 +368,6 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c);
/* erase.c */ /* erase.c */
void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
void jffs2_erase_pending_blocks(struct jffs2_sb_info *c); void jffs2_erase_pending_blocks(struct jffs2_sb_info *c);
void jffs2_mark_erased_blocks(struct jffs2_sb_info *c);
void jffs2_erase_pending_trigger(struct jffs2_sb_info *c); void jffs2_erase_pending_trigger(struct jffs2_sb_info *c);
#ifdef CONFIG_JFFS2_FS_NAND #ifdef CONFIG_JFFS2_FS_NAND
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: nodemgmt.c,v 1.70 2002/07/02 22:48:24 dwmw2 Exp $ * $Id: nodemgmt.c,v 1.84 2002/11/12 11:17:29 dwmw2 Exp $
* *
*/ */
...@@ -62,14 +62,17 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs ...@@ -62,14 +62,17 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
int ret; int ret;
up(&c->alloc_sem); up(&c->alloc_sem);
if (c->dirty_size < c->sector_size) {
D1(printk(KERN_DEBUG "Short on space, but total dirty size 0x%08x < sector size 0x%08x, so -ENOSPC\n", c->dirty_size, c->sector_size)); if (c->dirty_size + c->unchecked_size < c->sector_size) {
D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < sector size 0x%08x, returning -ENOSPC\n",
c->dirty_size, c->unchecked_size, c->sector_size));
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
return -ENOSPC; return -ENOSPC;
} }
D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
c->free_size + c->dirty_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size)); c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size,
c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
ret = jffs2_garbage_collect_pass(c); ret = jffs2_garbage_collect_pass(c);
...@@ -130,18 +133,30 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui ...@@ -130,18 +133,30 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
spin_lock_bh(&c->erase_completion_lock); spin_lock_bh(&c->erase_completion_lock);
/* We know nobody's going to have changed nextblock. Just continue */ /* We know nobody's going to have changed nextblock. Just continue */
} }
c->dirty_size += jeb->free_size; c->wasted_size += jeb->free_size;
c->free_size -= jeb->free_size; c->free_size -= jeb->free_size;
jeb->dirty_size += jeb->free_size; jeb->wasted_size += jeb->free_size;
jeb->free_size = 0; jeb->free_size = 0;
if (VERYDIRTY(c, jeb->dirty_size)) {
D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", /* Check, if we have a dirty block now, or if it was dirty already */
jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
list_add_tail(&jeb->list, &c->very_dirty_list); c->dirty_size += jeb->wasted_size;
} else { c->wasted_size -= jeb->wasted_size;
D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->dirty_size += jeb->wasted_size;
jeb->wasted_size = 0;
if (VERYDIRTY(c, jeb->dirty_size)) {
D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
list_add_tail(&jeb->list, &c->very_dirty_list);
} else {
D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
list_add_tail(&jeb->list, &c->dirty_list);
}
} else {
D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
list_add_tail(&jeb->list, &c->dirty_list); list_add_tail(&jeb->list, &c->clean_list);
} }
c->nextblock = jeb = NULL; c->nextblock = jeb = NULL;
} }
...@@ -225,7 +240,7 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui ...@@ -225,7 +240,7 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
*ofs = jeb->offset + (c->sector_size - jeb->free_size); *ofs = jeb->offset + (c->sector_size - jeb->free_size);
*len = jeb->free_size; *len = jeb->free_size;
if (jeb->used_size == PAD(sizeof(struct jffs2_unknown_node)) && if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
!jeb->first_node->next_in_ino) { !jeb->first_node->next_in_ino) {
/* Only node in it beforehand was a CLEANMARKER node (we think). /* Only node in it beforehand was a CLEANMARKER node (we think).
So mark it obsolete now that there's going to be another node So mark it obsolete now that there's going to be another node
...@@ -255,15 +270,15 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui ...@@ -255,15 +270,15 @@ static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, ui
* Must be called with the alloc_sem held. * Must be called with the alloc_sem held.
*/ */
int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, uint32_t len, int dirty) int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new)
{ {
struct jffs2_eraseblock *jeb; struct jffs2_eraseblock *jeb;
uint32_t len = new->totlen;
len = PAD(len);
jeb = &c->blocks[new->flash_offset / c->sector_size]; jeb = &c->blocks[new->flash_offset / c->sector_size];
D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x\n", new->flash_offset & ~3, len)); D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x\n", ref_offset(new), len));
#if 1 #if 1
if (jeb != c->nextblock || (new->flash_offset & ~3) != jeb->offset + (c->sector_size - jeb->free_size)) { if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) {
printk(KERN_WARNING "argh. node added in wrong place\n"); printk(KERN_WARNING "argh. node added in wrong place\n");
jffs2_free_raw_node_ref(new); jffs2_free_raw_node_ref(new);
return -EINVAL; return -EINVAL;
...@@ -279,8 +294,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r ...@@ -279,8 +294,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
jeb->free_size -= len; jeb->free_size -= len;
c->free_size -= len; c->free_size -= len;
if (dirty) { if (ref_obsolete(new)) {
new->flash_offset |= 1;
jeb->dirty_size += len; jeb->dirty_size += len;
c->dirty_size += len; c->dirty_size += len;
} else { } else {
...@@ -303,7 +317,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r ...@@ -303,7 +317,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
c->nextblock = NULL; c->nextblock = NULL;
} }
ACCT_SANITY_CHECK(c,jeb); ACCT_SANITY_CHECK(c,jeb);
ACCT_PARANOIA_CHECK(jeb); D1(ACCT_PARANOIA_CHECK(jeb));
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
...@@ -330,8 +344,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref ...@@ -330,8 +344,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n");
return; return;
} }
if (ref->flash_offset & 1) { if (ref_obsolete(ref)) {
D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref->flash_offset &~3)); D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref_offset(ref)));
return; return;
} }
blocknr = ref->flash_offset / c->sector_size; blocknr = ref->flash_offset / c->sector_size;
...@@ -340,22 +354,45 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref ...@@ -340,22 +354,45 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
BUG(); BUG();
} }
jeb = &c->blocks[blocknr]; jeb = &c->blocks[blocknr];
if (jeb->used_size < ref->totlen) {
printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n",
ref->totlen, blocknr, ref->flash_offset, jeb->used_size);
BUG();
}
spin_lock_bh(&c->erase_completion_lock); spin_lock_bh(&c->erase_completion_lock);
jeb->used_size -= ref->totlen;
jeb->dirty_size += ref->totlen; if (ref_flags(ref) == REF_UNCHECKED) {
c->used_size -= ref->totlen; D1(if (unlikely(jeb->unchecked_size < ref->totlen)) {
c->dirty_size += ref->totlen; printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n",
ref->flash_offset |= 1; ref->totlen, blocknr, ref->flash_offset, jeb->used_size);
BUG();
})
D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), ref->totlen));
jeb->unchecked_size -= ref->totlen;
c->unchecked_size -= ref->totlen;
} else {
D1(if (unlikely(jeb->used_size < ref->totlen)) {
printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n",
ref->totlen, blocknr, ref->flash_offset, jeb->used_size);
BUG();
})
D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %x: ", ref_offset(ref), ref->totlen));
jeb->used_size -= ref->totlen;
c->used_size -= ref->totlen;
}
if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref->totlen)) && jeb != c->nextblock) {
D1(printk("Dirtying\n"));
jeb->dirty_size += ref->totlen + jeb->wasted_size;
c->dirty_size += ref->totlen + jeb->wasted_size;
c->wasted_size -= jeb->wasted_size;
jeb->wasted_size = 0;
} else {
D1(printk("Wasting\n"));
jeb->wasted_size += ref->totlen;
c->wasted_size += ref->totlen;
}
ref->flash_offset = ref_offset(ref) | REF_OBSOLETE;
ACCT_SANITY_CHECK(c, jeb); ACCT_SANITY_CHECK(c, jeb);
ACCT_PARANOIA_CHECK(jeb); D1(ACCT_PARANOIA_CHECK(jeb));
if (c->flags & JFFS2_SB_FLAG_MOUNTING) { if (c->flags & JFFS2_SB_FLAG_MOUNTING) {
/* Mount in progress. Don't muck about with the block /* Mount in progress. Don't muck about with the block
...@@ -369,7 +406,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref ...@@ -369,7 +406,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
if (jeb == c->nextblock) { if (jeb == c->nextblock) {
D2(printk(KERN_DEBUG "Not moving nextblock 0x%08x to dirty/erase_pending list\n", jeb->offset)); D2(printk(KERN_DEBUG "Not moving nextblock 0x%08x to dirty/erase_pending list\n", jeb->offset));
} else if (!jeb->used_size) { } else if (!jeb->used_size && !jeb->unchecked_size) {
if (jeb == c->gcblock) { if (jeb == c->gcblock) {
D1(printk(KERN_DEBUG "gcblock at 0x%08x completely dirtied. Clearing gcblock...\n", jeb->offset)); D1(printk(KERN_DEBUG "gcblock at 0x%08x completely dirtied. Clearing gcblock...\n", jeb->offset));
c->gcblock = NULL; c->gcblock = NULL;
...@@ -417,7 +454,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref ...@@ -417,7 +454,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
D1(printk(KERN_DEBUG "Done OK\n")); D1(printk(KERN_DEBUG "Done OK\n"));
} else if (jeb == c->gcblock) { } else if (jeb == c->gcblock) {
D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty_list\n", jeb->offset)); D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty_list\n", jeb->offset));
} else if (jeb->dirty_size == ref->totlen) { } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - ref->totlen)) {
D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset)); D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset));
list_del(&jeb->list); list_del(&jeb->list);
D1(printk(KERN_DEBUG "...and adding to dirty_list\n")); D1(printk(KERN_DEBUG "...and adding to dirty_list\n"));
...@@ -428,7 +465,10 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref ...@@ -428,7 +465,10 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
list_del(&jeb->list); list_del(&jeb->list);
D1(printk(KERN_DEBUG "...and adding to very_dirty_list\n")); D1(printk(KERN_DEBUG "...and adding to very_dirty_list\n"));
list_add_tail(&jeb->list, &c->very_dirty_list); list_add_tail(&jeb->list, &c->very_dirty_list);
} } else {
D1(printk(KERN_DEBUG "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n",
jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
}
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
...@@ -437,32 +477,33 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref ...@@ -437,32 +477,33 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
if (jffs2_is_readonly(c)) if (jffs2_is_readonly(c))
return; return;
D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref->flash_offset &~3)); D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref)));
ret = jffs2_flash_read(c, ref->flash_offset &~3, sizeof(n), &retlen, (char *)&n); ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n);
if (ret) { if (ret) {
printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret); printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret);
return; return;
} }
if (retlen != sizeof(n)) { if (retlen != sizeof(n)) {
printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen); printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %d\n", ref_offset(ref), retlen);
return; return;
} }
if (PAD(n.totlen) != PAD(ref->totlen)) { if (PAD(je32_to_cpu(n.totlen)) != PAD(ref->totlen)) {
printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen in node ref (0x%08x)\n", n.totlen, ref->totlen); printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen in node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref->totlen);
return; return;
} }
if (!(n.nodetype & JFFS2_NODE_ACCURATE)) { if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) {
D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x\n", ref->flash_offset &~3, n.nodetype)); D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x\n", ref_offset(ref), je16_to_cpu(n.nodetype)));
return; return;
} }
n.nodetype &= ~JFFS2_NODE_ACCURATE; /* XXX FIXME: This is ugly now */
ret = jffs2_flash_write(c, ref->flash_offset&~3, sizeof(n), &retlen, (char *)&n); n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE);
ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n);
if (ret) { if (ret) {
printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret); printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret);
return; return;
} }
if (retlen != sizeof(n)) { if (retlen != sizeof(n)) {
printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen); printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), retlen);
return; return;
} }
} }
...@@ -470,10 +511,14 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref ...@@ -470,10 +511,14 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
#if CONFIG_JFFS2_FS_DEBUG > 0 #if CONFIG_JFFS2_FS_DEBUG > 0
void jffs2_dump_block_lists(struct jffs2_sb_info *c) void jffs2_dump_block_lists(struct jffs2_sb_info *c)
{ {
printk(KERN_DEBUG "jffs2_dump_block_lists:\n"); printk(KERN_DEBUG "jffs2_dump_block_lists:\n");
printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size); printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size);
printk(KERN_DEBUG "used_size: %08x\n", c->used_size); printk(KERN_DEBUG "used_size: %08x\n", c->used_size);
printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size); printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size);
printk(KERN_DEBUG "wasted_size: %08x\n", c->wasted_size);
printk(KERN_DEBUG "unchecked_size: %08x\n", c->unchecked_size);
printk(KERN_DEBUG "free_size: %08x\n", c->free_size); printk(KERN_DEBUG "free_size: %08x\n", c->free_size);
printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size); printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size);
printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size); printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size);
...@@ -481,12 +526,14 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c) ...@@ -481,12 +526,14 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE); printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE);
if (c->nextblock) { if (c->nextblock) {
printk(KERN_DEBUG "nextblock: %08x (used %08x, dirty %08x, free %08x)\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->free_size); printk(KERN_DEBUG "nextblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->unchecked_size, c->nextblock->free_size);
} else { } else {
printk(KERN_DEBUG "nextblock: NULL\n"); printk(KERN_DEBUG "nextblock: NULL\n");
} }
if (c->gcblock) { if (c->gcblock) {
printk(KERN_DEBUG "gcblock: %08x (used %08x, dirty %08x, free %08x)\n", c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, c->gcblock->free_size); printk(KERN_DEBUG "gcblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size);
} else { } else {
printk(KERN_DEBUG "gcblock: NULL\n"); printk(KERN_DEBUG "gcblock: NULL\n");
} }
...@@ -494,31 +541,50 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c) ...@@ -494,31 +541,50 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
printk(KERN_DEBUG "clean_list: empty\n"); printk(KERN_DEBUG "clean_list: empty\n");
} else { } else {
struct list_head *this; struct list_head *this;
int numblocks = 0;
uint32_t dirty = 0;
list_for_each(this, &c->clean_list) { list_for_each(this, &c->clean_list) {
struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
printk(KERN_DEBUG "clean_list: %08x (used %08x, dirty %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); numblocks ++;
dirty += jeb->wasted_size;
printk(KERN_DEBUG "clean_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
} }
printk (KERN_DEBUG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", numblocks, dirty, dirty / numblocks);
} }
if (list_empty(&c->very_dirty_list)) { if (list_empty(&c->very_dirty_list)) {
printk(KERN_DEBUG "very_dirty_list: empty\n"); printk(KERN_DEBUG "very_dirty_list: empty\n");
} else { } else {
struct list_head *this; struct list_head *this;
int numblocks = 0;
uint32_t dirty = 0;
list_for_each(this, &c->very_dirty_list) { list_for_each(this, &c->very_dirty_list) {
struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
printk(KERN_DEBUG "very_dirty_list: %08x (used %08x, dirty %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); numblocks ++;
dirty += jeb->dirty_size;
printk(KERN_DEBUG "very_dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
} }
printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
numblocks, dirty, dirty / numblocks);
} }
if (list_empty(&c->dirty_list)) { if (list_empty(&c->dirty_list)) {
printk(KERN_DEBUG "dirty_list: empty\n"); printk(KERN_DEBUG "dirty_list: empty\n");
} else { } else {
struct list_head *this; struct list_head *this;
int numblocks = 0;
uint32_t dirty = 0;
list_for_each(this, &c->dirty_list) { list_for_each(this, &c->dirty_list) {
struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
printk(KERN_DEBUG "dirty_list: %08x (used %08x, dirty %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); numblocks ++;
dirty += jeb->dirty_size;
printk(KERN_DEBUG "dirty_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
} }
printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n",
numblocks, dirty, dirty / numblocks);
} }
if (list_empty(&c->erasable_list)) { if (list_empty(&c->erasable_list)) {
printk(KERN_DEBUG "erasable_list: empty\n"); printk(KERN_DEBUG "erasable_list: empty\n");
...@@ -527,7 +593,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c) ...@@ -527,7 +593,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each(this, &c->erasable_list) { list_for_each(this, &c->erasable_list) {
struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
printk(KERN_DEBUG "erasable_list: %08x (used %08x, dirty %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); printk(KERN_DEBUG "erasable_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
} }
} }
if (list_empty(&c->erasing_list)) { if (list_empty(&c->erasing_list)) {
...@@ -537,7 +604,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c) ...@@ -537,7 +604,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each(this, &c->erasing_list) { list_for_each(this, &c->erasing_list) {
struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
printk(KERN_DEBUG "erasing_list: %08x (used %08x, dirty %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); printk(KERN_DEBUG "erasing_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
} }
} }
if (list_empty(&c->erase_pending_list)) { if (list_empty(&c->erase_pending_list)) {
...@@ -547,7 +615,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c) ...@@ -547,7 +615,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each(this, &c->erase_pending_list) { list_for_each(this, &c->erase_pending_list) {
struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
printk(KERN_DEBUG "erase_pending_list: %08x (used %08x, dirty %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); printk(KERN_DEBUG "erase_pending_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
} }
} }
if (list_empty(&c->erasable_pending_wbuf_list)) { if (list_empty(&c->erasable_pending_wbuf_list)) {
...@@ -557,7 +626,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c) ...@@ -557,7 +626,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each(this, &c->erasable_pending_wbuf_list) { list_for_each(this, &c->erasable_pending_wbuf_list) {
struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
printk(KERN_DEBUG "erase_pending_wbuf_list: %08x (used %08x, dirty %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); printk(KERN_DEBUG "erase_pending_wbuf_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
} }
} }
if (list_empty(&c->free_list)) { if (list_empty(&c->free_list)) {
...@@ -567,7 +637,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c) ...@@ -567,7 +637,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each(this, &c->free_list) { list_for_each(this, &c->free_list) {
struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
printk(KERN_DEBUG "free_list: %08x (used %08x, dirty %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); printk(KERN_DEBUG "free_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
} }
} }
if (list_empty(&c->bad_list)) { if (list_empty(&c->bad_list)) {
...@@ -577,7 +648,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c) ...@@ -577,7 +648,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each(this, &c->bad_list) { list_for_each(this, &c->bad_list) {
struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
printk(KERN_DEBUG "bad_list: %08x (used %08x, dirty %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); printk(KERN_DEBUG "bad_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
} }
} }
if (list_empty(&c->bad_used_list)) { if (list_empty(&c->bad_used_list)) {
...@@ -587,7 +659,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c) ...@@ -587,7 +659,8 @@ void jffs2_dump_block_lists(struct jffs2_sb_info *c)
list_for_each(this, &c->bad_used_list) { list_for_each(this, &c->bad_used_list) {
struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list);
printk(KERN_DEBUG "bad_used_list: %08x (used %08x, dirty %08x, free %08x)\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size); printk(KERN_DEBUG "bad_used_list: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n",
jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
} }
} }
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: os-linux.h,v 1.19 2002/05/20 14:56:38 dwmw2 Exp $ * $Id: os-linux.h,v 1.21 2002/11/12 09:44:30 dwmw2 Exp $
* *
*/ */
...@@ -49,11 +49,19 @@ ...@@ -49,11 +49,19 @@
#define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev))) #define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
#endif #endif
/* Hmmm. P'raps generic code should only ever see versions of signal
functions which do the locking automatically? */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40)
#define current_sig_lock current->sigmask_lock
#else
#define current_sig_lock current->sig->siglock
#endif
static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
{ {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
f->highest_version = 0; f->highest_version = 0;
f->fraglist = NULL; f->fragtree = RB_ROOT;
f->metadata = NULL; f->metadata = NULL;
f->dents = NULL; f->dents = NULL;
f->flags = 0; f->flags = 0;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: read.c,v 1.23 2002/05/20 14:56:38 dwmw2 Exp $ * $Id: read.c,v 1.29 2002/11/12 09:51:22 dwmw2 Exp $
* *
*/ */
...@@ -31,35 +31,41 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig ...@@ -31,35 +31,41 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
if (!ri) if (!ri)
return -ENOMEM; return -ENOMEM;
ret = jffs2_flash_read(c, fd->raw->flash_offset & ~3, sizeof(*ri), &readlen, (char *)ri); ret = jffs2_flash_read(c, ref_offset(fd->raw), sizeof(*ri), &readlen, (char *)ri);
if (ret) { if (ret) {
jffs2_free_raw_inode(ri); jffs2_free_raw_inode(ri);
printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", fd->raw->flash_offset & ~3, ret); printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", ref_offset(fd->raw), ret);
return ret; return ret;
} }
if (readlen != sizeof(*ri)) { if (readlen != sizeof(*ri)) {
jffs2_free_raw_inode(ri); jffs2_free_raw_inode(ri);
printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%x bytes, got 0x%x\n", printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%x bytes, got 0x%x\n",
fd->raw->flash_offset & ~3, sizeof(*ri), readlen); ref_offset(fd->raw), sizeof(*ri), readlen);
return -EIO; return -EIO;
} }
crc = crc32(0, ri, sizeof(*ri)-8); crc = crc32(0, ri, sizeof(*ri)-8);
D1(printk(KERN_DEBUG "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n", fd->raw->flash_offset & ~3, ri->node_crc, crc, ri->dsize, ri->csize, ri->offset, buf)); D1(printk(KERN_DEBUG "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n",
if (crc != ri->node_crc) { ref_offset(fd->raw), je32_to_cpu(ri->node_crc),
printk(KERN_WARNING "Node CRC %08x != calculated CRC %08x for node at %08x\n", ri->node_crc, crc, fd->raw->flash_offset & ~3); crc, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize),
je32_to_cpu(ri->offset), buf));
if (crc != je32_to_cpu(ri->node_crc)) {
printk(KERN_WARNING "Node CRC %08x != calculated CRC %08x for node at %08x\n",
je32_to_cpu(ri->node_crc), crc, ref_offset(fd->raw));
ret = -EIO; ret = -EIO;
goto out_ri; goto out_ri;
} }
/* There was a bug where we wrote hole nodes out with csize/dsize /* There was a bug where we wrote hole nodes out with csize/dsize
swapped. Deal with it */ swapped. Deal with it */
if (ri->compr == JFFS2_COMPR_ZERO && !ri->dsize && ri->csize) { if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) &&
je32_to_cpu(ri->csize)) {
ri->dsize = ri->csize; ri->dsize = ri->csize;
ri->csize = 0; ri->csize = cpu_to_je32(0);
} }
D1(if(ofs + len > ri->dsize) { D1(if(ofs + len > je32_to_cpu(ri->dsize)) {
printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n", len, ofs, ri->dsize); printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n",
len, ofs, je32_to_cpu(ri->dsize));
ret = -EINVAL; ret = -EINVAL;
goto out_ri; goto out_ri;
}); });
...@@ -76,18 +82,18 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig ...@@ -76,18 +82,18 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy
Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy
*/ */
if (ri->compr == JFFS2_COMPR_NONE && len == ri->dsize) { if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) {
readbuf = buf; readbuf = buf;
} else { } else {
readbuf = kmalloc(ri->csize, GFP_KERNEL); readbuf = kmalloc(je32_to_cpu(ri->csize), GFP_KERNEL);
if (!readbuf) { if (!readbuf) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_ri; goto out_ri;
} }
} }
if (ri->compr != JFFS2_COMPR_NONE) { if (ri->compr != JFFS2_COMPR_NONE) {
if (len < ri->dsize) { if (len < je32_to_cpu(ri->dsize)) {
decomprbuf = kmalloc(ri->dsize, GFP_KERNEL); decomprbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL);
if (!decomprbuf) { if (!decomprbuf) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_readbuf; goto out_readbuf;
...@@ -99,31 +105,35 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig ...@@ -99,31 +105,35 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
decomprbuf = readbuf; decomprbuf = readbuf;
} }
D2(printk(KERN_DEBUG "Read %d bytes to %p\n", ri->csize, readbuf)); D2(printk(KERN_DEBUG "Read %d bytes to %p\n", je32_to_cpu(ri->csize),
ret = jffs2_flash_read(c, (fd->raw->flash_offset &~3) + sizeof(*ri), ri->csize, &readlen, readbuf); readbuf));
ret = jffs2_flash_read(c, (ref_offset(fd->raw)) + sizeof(*ri),
je32_to_cpu(ri->csize), &readlen, readbuf);
if (!ret && readlen != ri->csize) if (!ret && readlen != je32_to_cpu(ri->csize))
ret = -EIO; ret = -EIO;
if (ret) if (ret)
goto out_decomprbuf; goto out_decomprbuf;
crc = crc32(0, readbuf, ri->csize); crc = crc32(0, readbuf, je32_to_cpu(ri->csize));
if (crc != ri->data_crc) { if (crc != je32_to_cpu(ri->data_crc)) {
printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n", ri->data_crc, crc, fd->raw->flash_offset & ~3); printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n",
je32_to_cpu(ri->data_crc), crc, ref_offset(fd->raw));
ret = -EIO; ret = -EIO;
goto out_decomprbuf; goto out_decomprbuf;
} }
D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc)); D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc));
if (ri->compr != JFFS2_COMPR_NONE) { if (ri->compr != JFFS2_COMPR_NONE) {
D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", ri->csize, readbuf, ri->dsize, decomprbuf)); D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n",
ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, ri->csize, ri->dsize); je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf));
ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize));
if (ret) { if (ret) {
printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret); printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret);
goto out_decomprbuf; goto out_decomprbuf;
} }
} }
if (len < ri->dsize) { if (len < je32_to_cpu(ri->dsize)) {
memcpy(buf, decomprbuf+ofs, len); memcpy(buf, decomprbuf+ofs, len);
} }
out_decomprbuf: out_decomprbuf:
...@@ -142,16 +152,14 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, ...@@ -142,16 +152,14 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
unsigned char *buf, uint32_t offset, uint32_t len) unsigned char *buf, uint32_t offset, uint32_t len)
{ {
uint32_t end = offset + len; uint32_t end = offset + len;
struct jffs2_node_frag *frag = f->fraglist; struct jffs2_node_frag *frag;
int ret; int ret;
D1(printk(KERN_DEBUG "jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x\n", D1(printk(KERN_DEBUG "jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x\n",
f->inocache->ino, offset, offset+len)); f->inocache->ino, offset, offset+len));
while(frag && frag->ofs + frag->size <= offset) { frag = jffs2_lookup_node_frag(&f->fragtree, offset);
D2(printk(KERN_DEBUG "skipping frag %d-%d; before the region we care about\n", frag->ofs, frag->ofs + frag->size));
frag = frag->next;
}
/* XXX FIXME: Where a single physical node actually shows up in two /* XXX FIXME: Where a single physical node actually shows up in two
frags, we read it twice. Don't do that. */ frags, we read it twice. Don't do that. */
/* Now we're pointing at the first frag which overlaps our page */ /* Now we're pointing at the first frag which overlaps our page */
...@@ -181,24 +189,28 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, ...@@ -181,24 +189,28 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
memset(buf, 0, holeend - offset); memset(buf, 0, holeend - offset);
buf += holeend - offset; buf += holeend - offset;
offset = holeend; offset = holeend;
frag = frag->next; frag = frag_next(frag);
continue; continue;
} else { } else {
uint32_t readlen; uint32_t readlen;
readlen = min(frag->size, end - offset); uint32_t fragofs; /* offset within the frag to start reading */
D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%x\n", frag->ofs, frag->ofs+readlen, frag->node->raw->flash_offset & ~3));
ret = jffs2_read_dnode(c, frag->node, buf, frag->ofs - frag->node->ofs, readlen); fragofs = offset - frag->ofs;
readlen = min(frag->size - fragofs, end - offset);
D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%x\n", frag->ofs+fragofs, frag->ofs+fragofs+readlen,
ref_offset(frag->node->raw)));
ret = jffs2_read_dnode(c, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen);
D2(printk(KERN_DEBUG "node read done\n")); D2(printk(KERN_DEBUG "node read done\n"));
if (ret) { if (ret) {
D1(printk(KERN_DEBUG"jffs2_read_inode_range error %d\n",ret)); D1(printk(KERN_DEBUG"jffs2_read_inode_range error %d\n",ret));
memset(buf, 0, frag->size); memset(buf, 0, readlen);
return ret; return ret;
} }
buf += readlen;
offset += readlen;
frag = frag_next(frag);
D2(printk(KERN_DEBUG "node read was OK. Looping\n"));
} }
buf += frag->size;
offset += frag->size;
frag = frag->next;
D2(printk(KERN_DEBUG "node read was OK. Looping\n"));
} }
return 0; return 0;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: readinode.c,v 1.73 2002/05/20 14:56:38 dwmw2 Exp $ * $Id: readinode.c,v 1.95 2002/11/12 11:17:29 dwmw2 Exp $
* *
*/ */
...@@ -15,24 +15,43 @@ ...@@ -15,24 +15,43 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include "nodelist.h" #include "nodelist.h"
D1(void jffs2_print_frag_list(struct jffs2_inode_info *f) D1(static void jffs2_print_fragtree(struct rb_root *list, int permitbug)
{ {
struct jffs2_node_frag *this = f->fraglist; struct jffs2_node_frag *this = frag_first(list);
uint32_t lastofs = 0;
int buggy = 0;
while(this) { while(this) {
if (this->node) if (this->node)
printk(KERN_DEBUG "frag %04x-%04x: 0x%08x on flash (*%p->%p)\n", this->ofs, this->ofs+this->size, this->node->raw->flash_offset &~3, this, this->next); printk(KERN_DEBUG "frag %04x-%04x: 0x%08x(%d) on flash (*%p). left (%p), right (%p), parent (%p)\n",
this->ofs, this->ofs+this->size, ref_offset(this->node->raw), ref_flags(this->node->raw),
this, frag_left(this), frag_right(this), frag_parent(this));
else else
printk(KERN_DEBUG "frag %04x-%04x: hole (*%p->%p)\n", this->ofs, this->ofs+this->size, this, this->next); printk(KERN_DEBUG "frag %04x-%04x: hole (*%p). left (%p} right (%p), parent (%p)\n", this->ofs,
this = this->next; this->ofs+this->size, this, frag_left(this), frag_right(this), frag_parent(this));
if (this->ofs != lastofs)
buggy = 1;
lastofs = this->ofs+this->size;
this = frag_next(this);
}
if (buggy && !permitbug) {
printk(KERN_CRIT "Frag tree got a hole in it\n");
BUG();
} }
})
D1(void jffs2_print_frag_list(struct jffs2_inode_info *f)
{
jffs2_print_fragtree(&f->fragtree, 0);
if (f->metadata) { if (f->metadata) {
printk(KERN_DEBUG "metadata at 0x%08x\n", f->metadata->raw->flash_offset &~3); printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw));
} }
}) })
...@@ -45,7 +64,7 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in ...@@ -45,7 +64,7 @@ int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_in
int ret; int ret;
D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn));
ret = jffs2_add_full_dnode_to_fraglist(c, &f->fraglist, fn); ret = jffs2_add_full_dnode_to_fraglist(c, &f->fragtree, fn);
D2(jffs2_print_frag_list(f)); D2(jffs2_print_frag_list(f));
return ret; return ret;
...@@ -58,13 +77,14 @@ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_ ...@@ -58,13 +77,14 @@ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_
if (!this->node->frags) { if (!this->node->frags) {
/* The node has no valid frags left. It's totally obsoleted */ /* The node has no valid frags left. It's totally obsoleted */
D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) obsolete\n", D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) obsolete\n",
this->node->raw->flash_offset &~3, this->node->ofs, this->node->ofs+this->node->size)); ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size));
jffs2_mark_node_obsolete(c, this->node->raw); jffs2_mark_node_obsolete(c, this->node->raw);
jffs2_free_full_dnode(this->node); jffs2_free_full_dnode(this->node);
} else { } else {
D2(printk(KERN_DEBUG "Not marking old node @0x%08x (0x%04x-0x%04x) obsolete. frags is %d\n", D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n",
this->node->raw->flash_offset &~3, this->node->ofs, this->node->ofs+this->node->size, ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size,
this->node->frags)); this->node->frags));
mark_ref_normal(this->node->raw);
} }
} }
...@@ -72,27 +92,24 @@ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_ ...@@ -72,27 +92,24 @@ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_
} }
/* Doesn't set inode->i_size */ /* Doesn't set inode->i_size */
int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn) int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_full_dnode *fn)
{ {
struct jffs2_node_frag *this;
struct jffs2_node_frag *this, **prev, *old; struct jffs2_node_frag *newfrag;
struct jffs2_node_frag *newfrag, *newfrag2; uint32_t lastend;
uint32_t lastend = 0;
newfrag = jffs2_alloc_node_frag(); newfrag = jffs2_alloc_node_frag();
if (!newfrag) { if (!newfrag) {
return -ENOMEM; return -ENOMEM;
} }
D2(if (fn->raw) if (!fn->raw) {
printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, fn->raw->flash_offset &~3, newfrag); printk(KERN_WARNING "dwmw2 is stupid. j_a_f_d_t_f should never happen with ->raw == NULL\n");
else BUG();
printk(KERN_DEBUG "adding hole node %04x-%04x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, newfrag)); }
prev = list;
this = *list;
D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag));
if (!fn->size) { if (!fn->size) {
jffs2_free_node_frag(newfrag); jffs2_free_node_frag(newfrag);
return 0; return 0;
...@@ -102,21 +119,33 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_ ...@@ -102,21 +119,33 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_
newfrag->size = fn->size; newfrag->size = fn->size;
newfrag->node = fn; newfrag->node = fn;
newfrag->node->frags = 1; newfrag->node->frags = 1;
newfrag->next = (void *)0xdeadbeef;
/* Skip all the nodes which are completed before this one starts */ /* Skip all the nodes which are completed before this one starts */
while(this && fn->ofs >= this->ofs+this->size) { this = jffs2_lookup_node_frag(list, fn->ofs);
lastend = this->ofs + this->size;
D2(printk(KERN_DEBUG "j_a_f_d_t_f: skipping frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)\n", if (this) {
this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this, this->next)); D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n",
prev = &this->next; this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this));
this = this->next; lastend = this->ofs + this->size;
} else {
D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave no frag\n"));
lastend = 0;
} }
/* See if we ran off the end of the list */ /* See if we ran off the end of the list */
if (!this) { if (lastend <= newfrag->ofs) {
/* We did */ /* We did */
/* Check if 'this' node was on the same page as the new node.
If so, both 'this' and the new node get marked REF_NORMAL so
the GC can take a look.
*/
if ((lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) {
if (this->node)
mark_ref_normal(this->node->raw);
mark_ref_normal(fn->raw);
}
if (lastend < fn->ofs) { if (lastend < fn->ofs) {
/* ... and we need to put a hole in before the new node */ /* ... and we need to put a hole in before the new node */
struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag(); struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag();
...@@ -124,96 +153,162 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_ ...@@ -124,96 +153,162 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_
return -ENOMEM; return -ENOMEM;
holefrag->ofs = lastend; holefrag->ofs = lastend;
holefrag->size = fn->ofs - lastend; holefrag->size = fn->ofs - lastend;
holefrag->next = NULL;
holefrag->node = NULL; holefrag->node = NULL;
*prev = holefrag; if (this) {
prev = &holefrag->next; /* By definition, the 'this' node has no right-hand child,
because there are no frags with offset greater than it.
So that's where we want to put the hole */
D2(printk(KERN_DEBUG "Adding hole frag (%p) on right of node at (%p)\n", holefrag, this));
rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right);
} else {
D2(printk(KERN_DEBUG "Adding hole frag (%p) at root of tree\n", holefrag));
rb_link_node(&holefrag->rb, NULL, &list->rb_node);
}
rb_insert_color(&holefrag->rb, list);
this = holefrag;
}
if (this) {
/* By definition, the 'this' node has no right-hand child,
because there are no frags with offset greater than it.
So that's where we want to put the hole */
D2(printk(KERN_DEBUG "Adding new frag (%p) on right of node at (%p)\n", newfrag, this));
rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right);
} else {
D2(printk(KERN_DEBUG "Adding new frag (%p) at root of tree\n", newfrag));
rb_link_node(&newfrag->rb, NULL, &list->rb_node);
} }
newfrag->next = NULL; rb_insert_color(&newfrag->rb, list);
*prev = newfrag;
return 0; return 0;
} }
D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)\n", D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n",
this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this, this->next)); this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this));
/* OK. 'this' is pointing at the first frag that fn->ofs at least partially obsoletes, /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes,
* - i.e. fn->ofs < this->ofs+this->size && fn->ofs >= this->ofs * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs
*/ */
if (fn->ofs > this->ofs) { if (newfrag->ofs > this->ofs) {
/* This node isn't completely obsoleted. The start of it remains valid */ /* This node isn't completely obsoleted. The start of it remains valid */
if (this->ofs + this->size > fn->ofs + fn->size) {
/* Mark the new node and the partially covered node REF_NORMAL -- let
the GC take a look at them */
mark_ref_normal(fn->raw);
if (this->node)
mark_ref_normal(this->node->raw);
if (this->ofs + this->size > newfrag->ofs + newfrag->size) {
/* The new node splits 'this' frag into two */ /* The new node splits 'this' frag into two */
newfrag2 = jffs2_alloc_node_frag(); struct jffs2_node_frag *newfrag2 = jffs2_alloc_node_frag();
if (!newfrag2) { if (!newfrag2) {
jffs2_free_node_frag(newfrag); jffs2_free_node_frag(newfrag);
return -ENOMEM; return -ENOMEM;
} }
D1(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size); D2(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size);
if (this->node) if (this->node)
printk("phys 0x%08x\n", this->node->raw->flash_offset &~3); printk("phys 0x%08x\n", ref_offset(this->node->raw));
else else
printk("hole\n"); printk("hole\n");
) )
newfrag2->ofs = fn->ofs + fn->size;
/* New second frag pointing to this's node */
newfrag2->ofs = newfrag->ofs + newfrag->size;
newfrag2->size = (this->ofs+this->size) - newfrag2->ofs; newfrag2->size = (this->ofs+this->size) - newfrag2->ofs;
newfrag2->next = this->next;
newfrag2->node = this->node; newfrag2->node = this->node;
if (this->node) if (this->node)
this->node->frags++; this->node->frags++;
newfrag->next = newfrag2;
this->next = newfrag; /* Adjust size of original 'this' */
this->size = newfrag->ofs - this->ofs; this->size = newfrag->ofs - this->ofs;
/* Now, we know there's no node with offset
greater than this->ofs but smaller than
newfrag2->ofs or newfrag->ofs, for obvious
reasons. So we can do a tree insert from
'this' to insert newfrag, and a tree insert
from newfrag to insert newfrag2. */
jffs2_fragtree_insert(newfrag, this);
rb_insert_color(&newfrag->rb, list);
jffs2_fragtree_insert(newfrag2, newfrag);
rb_insert_color(&newfrag2->rb, list);
return 0; return 0;
} }
/* New node just reduces 'this' frag in size, doesn't split it */ /* New node just reduces 'this' frag in size, doesn't split it */
this->size = fn->ofs - this->ofs; this->size = newfrag->ofs - this->ofs;
newfrag->next = this->next;
this->next = newfrag; /* Again, we know it lives down here in the tree */
this = newfrag->next; jffs2_fragtree_insert(newfrag, this);
rb_insert_color(&newfrag->rb, list);
} else { } else {
D2(printk(KERN_DEBUG "Inserting newfrag (*%p) in before 'this' (*%p)\n", newfrag, this)); /* New frag starts at the same point as 'this' used to. Replace
*prev = newfrag; it in the tree without doing a delete and insertion */
newfrag->next = this; D2(printk(KERN_DEBUG "Inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n",
newfrag, newfrag->ofs, newfrag->ofs+newfrag->size,
this, this->ofs, this->ofs+this->size));
rb_replace_node(&this->rb, &newfrag->rb, list);
if (newfrag->ofs + newfrag->size >= this->ofs+this->size) {
D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size));
jffs2_obsolete_node_frag(c, this);
} else {
this->ofs += newfrag->size;
this->size -= newfrag->size;
jffs2_fragtree_insert(this, newfrag);
rb_insert_color(&this->rb, list);
return 0;
}
} }
/* OK, now we have newfrag added in the correct place in the list, but /* OK, now we have newfrag added in the correct place in the tree, but
newfrag->next points to a fragment which may be overlapping it frag_next(newfrag) may be a fragment which is overlapped by it
*/ */
while (this && newfrag->ofs + newfrag->size >= this->ofs + this->size) { while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) {
/* 'this' frag is obsoleted. */ /* 'this' frag is obsoleted completely. */
old = this; D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x) and removing from tree\n", this, this->ofs, this->ofs+this->size));
this = old->next; rb_erase(&this->rb, list);
jffs2_obsolete_node_frag(c, old); jffs2_obsolete_node_frag(c, this);
} }
/* Now we're pointing at the first frag which isn't totally obsoleted by /* Now we're pointing at the first frag which isn't totally obsoleted by
the new frag */ the new frag */
newfrag->next = this;
if (!this || newfrag->ofs + newfrag->size == this->ofs) { if (!this || newfrag->ofs + newfrag->size == this->ofs) {
return 0; return 0;
} }
/* Still some overlap */ /* Still some overlap but we don't need to move it in the tree */
this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size); this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size);
this->ofs = newfrag->ofs + newfrag->size; this->ofs = newfrag->ofs + newfrag->size;
/* And mark them REF_NORMAL so the GC takes a look at them */
if (this->node)
mark_ref_normal(this->node->raw);
mark_ref_normal(fn->raw);
return 0; return 0;
} }
void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, uint32_t size) void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size)
{ {
struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size);
D1(printk(KERN_DEBUG "Truncating fraglist to 0x%08x bytes\n", size)); D1(printk(KERN_DEBUG "Truncating fraglist to 0x%08x bytes\n", size));
while (*list) { /* We know frag->ofs <= size. That's what lookup does for us */
if ((*list)->ofs >= size) { if (frag && frag->ofs != size) {
struct jffs2_node_frag *this = *list; if (frag->ofs+frag->size >= size) {
*list = this->next; D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size));
D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", this->ofs, this->ofs+this->size)); frag->size = size - frag->ofs;
jffs2_obsolete_node_frag(c, this);
continue;
} else if ((*list)->ofs + (*list)->size > size) {
D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", (*list)->ofs, (*list)->ofs + (*list)->size));
(*list)->size = size - (*list)->ofs;
} }
list = &(*list)->next; frag = frag_next(frag);
}
while (frag && frag->ofs >= size) {
struct jffs2_node_frag *next = frag_next(frag);
D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size));
frag_erase(frag, list);
jffs2_obsolete_node_frag(c, frag);
frag = next;
} }
} }
...@@ -271,7 +366,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, ...@@ -271,7 +366,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
fn = tn->fn; fn = tn->fn;
if (f->metadata && tn->version > mdata_ver) { if (f->metadata && tn->version > mdata_ver) {
D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", f->metadata->raw->flash_offset &~3)); D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw)));
jffs2_mark_node_obsolete(c, f->metadata->raw); jffs2_mark_node_obsolete(c, f->metadata->raw);
jffs2_free_full_dnode(f->metadata); jffs2_free_full_dnode(f->metadata);
f->metadata = NULL; f->metadata = NULL;
...@@ -283,7 +378,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, ...@@ -283,7 +378,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
jffs2_add_full_dnode_to_inode(c, f, fn); jffs2_add_full_dnode_to_inode(c, f, fn);
} else { } else {
/* Zero-sized node at end of version list. Just a metadata update */ /* Zero-sized node at end of version list. Just a metadata update */
D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", fn->raw->flash_offset &~3, tn->version)); D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", ref_offset(fn->raw), tn->version));
f->metadata = fn; f->metadata = fn;
mdata_ver = tn->version; mdata_ver = tn->version;
} }
...@@ -299,16 +394,16 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, ...@@ -299,16 +394,16 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
} }
printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n"); printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n");
} }
latest_node->mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO; latest_node->mode = cpu_to_je32(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO);
latest_node->version = 0; latest_node->version = cpu_to_je32(0);
latest_node->atime = latest_node->ctime = latest_node->mtime = 0; latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0);
latest_node->isize = 0; latest_node->isize = cpu_to_je32(0);
latest_node->gid = 0; latest_node->gid = cpu_to_je16(0);
latest_node->uid = 0; latest_node->uid = cpu_to_je16(0);
return 0; return 0;
} }
ret = jffs2_flash_read(c, fn->raw->flash_offset & ~3, sizeof(*latest_node), &retlen, (void *)latest_node); ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node);
if (ret || retlen != sizeof(*latest_node)) { if (ret || retlen != sizeof(*latest_node)) {
printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %ld of %d bytes read\n", printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %ld of %d bytes read\n",
ret, (long)retlen, sizeof(*latest_node)); ret, (long)retlen, sizeof(*latest_node));
...@@ -319,26 +414,26 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, ...@@ -319,26 +414,26 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
} }
crc = crc32(0, latest_node, sizeof(*latest_node)-8); crc = crc32(0, latest_node, sizeof(*latest_node)-8);
if (crc != latest_node->node_crc) { if (crc != je32_to_cpu(latest_node->node_crc)) {
printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", ino, fn->raw->flash_offset & ~3); printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", ino, ref_offset(fn->raw));
up(&f->sem); up(&f->sem);
jffs2_do_clear_inode(c, f); jffs2_do_clear_inode(c, f);
return -EIO; return -EIO;
} }
switch(latest_node->mode & S_IFMT) { switch(je32_to_cpu(latest_node->mode) & S_IFMT) {
case S_IFDIR: case S_IFDIR:
if (mctime_ver > latest_node->version) { if (mctime_ver > je32_to_cpu(latest_node->version)) {
/* The times in the latest_node are actually older than /* The times in the latest_node are actually older than
mctime in the latest dirent. Cheat. */ mctime in the latest dirent. Cheat. */
latest_node->ctime = latest_node->mtime = latest_mctime; latest_node->ctime = latest_node->mtime = cpu_to_je32(latest_mctime);
} }
break; break;
case S_IFREG: case S_IFREG:
/* If it was a regular file, truncate it to the latest node's isize */ /* If it was a regular file, truncate it to the latest node's isize */
jffs2_truncate_fraglist(c, &f->fraglist, latest_node->isize); jffs2_truncate_fraglist(c, &f->fragtree, je32_to_cpu(latest_node->isize));
break; break;
case S_IFLNK: case S_IFLNK:
...@@ -346,7 +441,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, ...@@ -346,7 +441,7 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
Remove this when dwmw2 comes to his senses and stops Remove this when dwmw2 comes to his senses and stops
symlinks from being an entirely gratuitous special symlinks from being an entirely gratuitous special
case. */ case. */
if (!latest_node->isize) if (!je32_to_cpu(latest_node->isize))
latest_node->isize = latest_node->dsize; latest_node->isize = latest_node->dsize;
/* fall through... */ /* fall through... */
...@@ -355,82 +450,79 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, ...@@ -355,82 +450,79 @@ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
/* Xertain inode types should have only one data node, and it's /* Xertain inode types should have only one data node, and it's
kept as the metadata node */ kept as the metadata node */
if (f->metadata) { if (f->metadata) {
printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n", ino, latest_node->mode); printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n", ino, je32_to_cpu(latest_node->mode));
up(&f->sem); up(&f->sem);
jffs2_do_clear_inode(c, f); jffs2_do_clear_inode(c, f);
return -EIO; return -EIO;
} }
if (!f->fraglist) { if (!frag_first(&f->fragtree)) {
printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", ino, latest_node->mode); printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", ino, je32_to_cpu(latest_node->mode));
up(&f->sem); up(&f->sem);
jffs2_do_clear_inode(c, f); jffs2_do_clear_inode(c, f);
return -EIO; return -EIO;
} }
/* ASSERT: f->fraglist != NULL */ /* ASSERT: f->fraglist != NULL */
if (f->fraglist->next) { if (frag_next(frag_first(&f->fragtree))) {
printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had more than one node\n", ino, latest_node->mode); printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had more than one node\n", ino, je32_to_cpu(latest_node->mode));
/* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
up(&f->sem); up(&f->sem);
jffs2_do_clear_inode(c, f); jffs2_do_clear_inode(c, f);
return -EIO; return -EIO;
} }
/* OK. We're happy */ /* OK. We're happy */
f->metadata = f->fraglist->node; f->metadata = frag_first(&f->fragtree)->node;
jffs2_free_node_frag(f->fraglist); jffs2_free_node_frag(frag_first(&f->fragtree));
f->fraglist = NULL; f->fragtree = RB_ROOT;
break; break;
} }
f->inocache->state = INO_STATE_PRESENT;
return 0; return 0;
} }
void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
{ {
struct jffs2_node_frag *frag, *frags;
struct jffs2_full_dirent *fd, *fds; struct jffs2_full_dirent *fd, *fds;
/* I don't think we care about the potential race due to reading this
/* If it's a deleted inode, grab the alloc_sem to keep the without f->sem. It can never get undeleted. */
(maybe temporary) BUG() in jffs2_mark_node_obsolete() int deleted = f->inocache && !f->inocache->nlink;
from triggering */
if(!f->inocache->nlink) /* If it's a deleted inode, grab the alloc_sem. This prevents
jffs2_garbage_collect_pass() from deciding that it wants to
garbage collect one of the nodes we're just about to mark
obsolete -- by the time we drop alloc_sem and return, all
the nodes are marked obsolete, and jffs2_g_c_pass() won't
call iget() for the inode in question.
We also do this to keep the (maybe temporary) BUG() in
jffs2_mark_node_obsolete() from triggering.
*/
if(deleted)
down(&c->alloc_sem); down(&c->alloc_sem);
down(&f->sem); down(&f->sem);
frags = f->fraglist;
fds = f->dents;
if (f->metadata) { if (f->metadata) {
if (!f->inocache->nlink) if (deleted)
jffs2_mark_node_obsolete(c, f->metadata->raw); jffs2_mark_node_obsolete(c, f->metadata->raw);
jffs2_free_full_dnode(f->metadata); jffs2_free_full_dnode(f->metadata);
} }
while (frags) { jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
frag = frags;
frags = frag->next;
D2(printk(KERN_DEBUG "jffs2_do_clear_inode: frag at 0x%x-0x%x: node %p, frags %d--\n", frag->ofs, frag->ofs+frag->size, frag->node, frag->node?frag->node->frags:0));
if (frag->node && !(--frag->node->frags)) { fds = f->dents;
/* Not a hole, and it's the final remaining frag of this node. Free the node */
if (!f->inocache->nlink)
jffs2_mark_node_obsolete(c, frag->node->raw);
jffs2_free_full_dnode(frag->node);
}
jffs2_free_node_frag(frag);
}
while(fds) { while(fds) {
fd = fds; fd = fds;
fds = fd->next; fds = fd->next;
jffs2_free_full_dirent(fd); jffs2_free_full_dirent(fd);
} }
/* Urgh. Is there a nicer way to do this? */ if (f->inocache)
if(!f->inocache->nlink) { f->inocache->state = INO_STATE_CHECKEDABSENT;
up(&f->sem);
up(&f->sem);
if(deleted)
up(&c->alloc_sem); up(&c->alloc_sem);
} else {
up(&f->sem);
}
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: scan.c,v 1.79 2002/07/25 20:48:51 dwmw2 Exp $ * $Id: scan.c,v 1.92 2002/09/09 16:29:08 dwmw2 Exp $
* *
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -15,8 +15,10 @@ ...@@ -15,8 +15,10 @@
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/compiler.h>
#include "nodelist.h" #include "nodelist.h"
#define EMPTY_SCAN_SIZE 1024
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->dirty_size += _x; \ c->free_size -= _x; c->dirty_size += _x; \
...@@ -26,6 +28,10 @@ ...@@ -26,6 +28,10 @@
c->free_size -= _x; c->used_size += _x; \ c->free_size -= _x; c->used_size += _x; \
jeb->free_size -= _x ; jeb->used_size += _x; \ jeb->free_size -= _x ; jeb->used_size += _x; \
}while(0) }while(0)
#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->unchecked_size += _x; \
jeb->free_size -= _x ; jeb->unchecked_size += _x; \
}while(0)
#define noisy_printk(noise, args...) do { \ #define noisy_printk(noise, args...) do { \
if (*(noise)) { \ if (*(noise)) { \
...@@ -39,15 +45,17 @@ ...@@ -39,15 +45,17 @@
static uint32_t pseudo_random; static uint32_t pseudo_random;
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
unsigned char *buf, uint32_t buf_size);
/* These helper functions _must_ increase ofs and also do the dirty/used space accounting. /* These helper functions _must_ increase ofs and also do the dirty/used space accounting.
* Returning an error will abort the mount - bad checksums etc. should just mark the space * Returning an error will abort the mount - bad checksums etc. should just mark the space
* as dirty. * as dirty.
*/ */
static int jffs2_scan_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *ofs, int *noise); static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *ofs); struct jffs2_raw_inode *ri, uint32_t ofs);
static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *ofs); static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
struct jffs2_raw_dirent *rd, uint32_t ofs);
#define BLK_STATE_ALLFF 0 #define BLK_STATE_ALLFF 0
#define BLK_STATE_CLEAN 1 #define BLK_STATE_CLEAN 1
...@@ -60,15 +68,44 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -60,15 +68,44 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
{ {
int i, ret; int i, ret;
uint32_t empty_blocks = 0, bad_blocks = 0; uint32_t empty_blocks = 0, bad_blocks = 0;
unsigned char *flashbuf = NULL;
uint32_t buf_size = 0;
size_t pointlen;
if (!c->blocks) { if (!c->blocks) {
printk(KERN_WARNING "EEEK! c->blocks is NULL!\n"); printk(KERN_WARNING "EEEK! c->blocks is NULL!\n");
return -EINVAL; return -EINVAL;
} }
if (c->mtd->point) {
ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf);
if (!ret && pointlen < c->mtd->size) {
/* Don't muck about if it won't let us point to the whole flash */
D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%x\n", pointlen));
c->mtd->unpoint(c->mtd, flashbuf);
flashbuf = NULL;
}
if (ret)
D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
}
if (!flashbuf) {
/* For NAND it's quicker to read a whole eraseblock at a time,
apparently */
if (jffs2_cleanmarker_oob(c))
buf_size = c->sector_size;
else
buf_size = PAGE_SIZE;
D1(printk(KERN_DEBUG "Allocating readbuf of %d bytes\n", buf_size));
flashbuf = kmalloc(buf_size, GFP_KERNEL);
if (!flashbuf)
return -ENOMEM;
}
for (i=0; i<c->nr_blocks; i++) { for (i=0; i<c->nr_blocks; i++) {
struct jffs2_eraseblock *jeb = &c->blocks[i]; struct jffs2_eraseblock *jeb = &c->blocks[i];
ret = jffs2_scan_eraseblock(c, jeb); ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -120,6 +157,11 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -120,6 +157,11 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
(!c->nextblock || c->nextblock->free_size < jeb->free_size)) { (!c->nextblock || c->nextblock->free_size < jeb->free_size)) {
/* Better candidate for the next writes to go to */ /* Better candidate for the next writes to go to */
if (c->nextblock) { if (c->nextblock) {
c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size;
c->free_size -= c->nextblock->free_size;
c->wasted_size -= c->nextblock->wasted_size;
c->nextblock->free_size = c->nextblock->wasted_size = 0;
if (VERYDIRTY(c, c->nextblock->dirty_size)) { if (VERYDIRTY(c, c->nextblock->dirty_size)) {
list_add(&c->nextblock->list, &c->very_dirty_list); list_add(&c->nextblock->list, &c->very_dirty_list);
} else { } else {
...@@ -128,6 +170,11 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -128,6 +170,11 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
} }
c->nextblock = jeb; c->nextblock = jeb;
} else { } else {
jeb->dirty_size += jeb->free_size + jeb->wasted_size;
c->dirty_size += jeb->free_size + jeb->wasted_size;
c->free_size -= jeb->free_size;
c->wasted_size -= jeb->wasted_size;
jeb->free_size = jeb->wasted_size = 0;
if (VERYDIRTY(c, jeb->dirty_size)) { if (VERYDIRTY(c, jeb->dirty_size)) {
list_add(&jeb->list, &c->very_dirty_list); list_add(&jeb->list, &c->very_dirty_list);
} else { } else {
...@@ -156,6 +203,14 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -156,6 +203,14 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
BUG(); BUG();
} }
} }
/* Nextblock dirty is always seen as wasted, because we cannot recycle it now */
if (c->nextblock && (c->nextblock->dirty_size)) {
c->nextblock->wasted_size += c->nextblock->dirty_size;
c->wasted_size += c->nextblock->dirty_size;
c->dirty_size -= c->nextblock->dirty_size;
c->nextblock->dirty_size = 0;
}
if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) {
/* If we're going to start writing into a block which already /* If we're going to start writing into a block which already
...@@ -166,8 +221,8 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -166,8 +221,8 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n", D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n",
skip)); skip));
c->nextblock->dirty_size += skip; c->nextblock->wasted_size += skip;
c->dirty_size += skip; c->wasted_size += skip;
c->nextblock->free_size -= skip; c->nextblock->free_size -= skip;
c->free_size -= skip; c->free_size -= skip;
...@@ -180,17 +235,47 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) ...@@ -180,17 +235,47 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
} }
jffs2_erase_pending_trigger(c); jffs2_erase_pending_trigger(c);
} }
if (buf_size)
kfree(flashbuf);
else
c->mtd->unpoint(c->mtd, flashbuf);
return 0; return 0;
} }
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf,
struct jffs2_unknown_node node; uint32_t ofs, uint32_t len)
{
int ret;
size_t retlen;
ret = jffs2_flash_read(c, ofs, len, &retlen, buf);
if (ret) {
D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", len, ofs, ret));
return ret;
}
if (retlen < len) {
D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%x bytes\n", ofs, retlen));
return -EIO;
}
D2(printk(KERN_DEBUG "Read 0x%x bytes from 0x%08x into buf\n", len, ofs));
D2(printk(KERN_DEBUG "000: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]));
return 0;
}
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
unsigned char *buf, uint32_t buf_size) {
struct jffs2_unknown_node *node;
struct jffs2_unknown_node crcnode;
uint32_t ofs, prevofs; uint32_t ofs, prevofs;
uint32_t hdr_crc, nodetype; uint32_t hdr_crc, buf_ofs, buf_len;
int err; int err;
int noise = 0; int noise = 0;
int wasempty = 0;
uint32_t empty_start = 0;
#ifdef CONFIG_JFFS2_FS_NAND #ifdef CONFIG_JFFS2_FS_NAND
int cleanmarkerfound=0; int cleanmarkerfound = 0;
#endif #endif
ofs = jeb->offset; ofs = jeb->offset;
...@@ -214,16 +299,30 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -214,16 +299,30 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
} }
} }
#endif #endif
err = jffs2_scan_empty(c, jeb, &ofs, &noise); buf_ofs = jeb->offset;
if (err)
return err;
if (ofs == jeb->offset + c->sector_size) { if (!buf_size) {
buf_len = c->sector_size;
} else {
buf_len = EMPTY_SCAN_SIZE;
err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
if (err)
return err;
}
/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
ofs = 0;
/* Scan only 4KiB of 0xFF before declaring it's empty */
while(ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
ofs += 4;
if (ofs == EMPTY_SCAN_SIZE) {
#ifdef CONFIG_JFFS2_FS_NAND #ifdef CONFIG_JFFS2_FS_NAND
if (jffs2_cleanmarker_oob(c)) { if (jffs2_cleanmarker_oob(c)) {
/* scan oob, take care of cleanmarker */ /* scan oob, take care of cleanmarker */
int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound); int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
D2(printk(KERN_NOTICE "jffs_check_oob_empty returned %d\n",ret)); D2(printk(KERN_NOTICE "jffs2_check_oob_empty returned %d\n",ret));
switch (ret) { switch (ret) {
case 0: return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF; case 0: return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
case 1: return BLK_STATE_ALLDIRTY; case 1: return BLK_STATE_ALLDIRTY;
...@@ -236,12 +335,20 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -236,12 +335,20 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset)); D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */
} }
if (ofs) {
D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
jeb->offset + ofs));
DIRTY_SPACE(ofs);
}
/* Now ofs is a complete physical flash offset as it always was... */
ofs += jeb->offset;
noise = 10; noise = 10;
while(ofs < jeb->offset + c->sector_size) { while(ofs < jeb->offset + c->sector_size) {
size_t retlen;
ACCT_PARANOIA_CHECK(jeb); D1(ACCT_PARANOIA_CHECK(jeb));
cond_resched(); cond_resched();
...@@ -257,110 +364,174 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -257,110 +364,174 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
continue; continue;
} }
prevofs = ofs; prevofs = ofs;
if (jeb->offset + c->sector_size < ofs + sizeof(node)) { if (jeb->offset + c->sector_size < ofs + sizeof(*node)) {
D1(printk(KERN_DEBUG "Fewer than %d bytes left to end of block. Not reading\n", sizeof(struct jffs2_unknown_node))); D1(printk(KERN_DEBUG "Fewer than %d bytes left to end of block. (%x+%x<%x+%x) Not reading\n", sizeof(struct jffs2_unknown_node),
jeb->offset, c->sector_size, ofs, sizeof(*node)));
DIRTY_SPACE((jeb->offset + c->sector_size)-ofs); DIRTY_SPACE((jeb->offset + c->sector_size)-ofs);
break; break;
} }
err = jffs2_flash_read(c, ofs, sizeof(node), &retlen, (char *)&node); if (buf_ofs + buf_len < ofs + sizeof(*node)) {
if (err) { buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", sizeof(node), ofs, err)); D1(printk(KERN_DEBUG "Fewer than %d bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n",
return err; sizeof(struct jffs2_unknown_node), buf_len, ofs));
} err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
if (retlen < sizeof(node)) { if (err)
D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%x bytes\n", ofs, retlen)); return err;
DIRTY_SPACE(retlen); buf_ofs = ofs;
ofs += retlen;
continue;
} }
if (node.magic == JFFS2_EMPTY_BITMASK && node.nodetype == JFFS2_EMPTY_BITMASK) { node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];
D1(printk(KERN_DEBUG "Found empty flash at 0x%x\n", ofs));
err = jffs2_scan_empty(c, jeb, &ofs, &noise); if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
if (err) return err; uint32_t inbuf_ofs = ofs - buf_ofs + 4;
uint32_t scanend;
empty_start = ofs;
ofs += 4;
/* If scanning empty space after only a cleanmarker, don't
bother scanning the whole block */
if (unlikely(empty_start == jeb->offset + c->cleanmarker_size &&
jeb->offset + EMPTY_SCAN_SIZE < buf_ofs + buf_len))
scanend = jeb->offset + EMPTY_SCAN_SIZE - buf_ofs;
else
scanend = buf_len;
D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
while (inbuf_ofs < scanend) {
if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff)
goto emptyends;
inbuf_ofs+=4;
ofs += 4;
}
/* Ran off end. */
D1(printk(KERN_DEBUG "Empty flash ends normally at 0x%08x\n", ofs));
if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
!jeb->first_node->next_in_ino && !jeb->dirty_size)
return BLK_STATE_CLEANMARKER;
wasempty = 1;
continue;
} else if (wasempty) {
emptyends:
printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n", empty_start, ofs);
DIRTY_SPACE(ofs-empty_start);
wasempty = 0;
continue; continue;
} }
if (ofs == jeb->offset && node.magic == KSAMTIB_CIGAM_2SFFJ) { if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs); printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs);
DIRTY_SPACE(4); DIRTY_SPACE(4);
ofs += 4; ofs += 4;
continue; continue;
} }
if (node.magic == JFFS2_DIRTY_BITMASK) { if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) {
D1(printk(KERN_DEBUG "Empty bitmask at 0x%08x\n", ofs)); D1(printk(KERN_DEBUG "Empty bitmask at 0x%08x\n", ofs));
DIRTY_SPACE(4); DIRTY_SPACE(4);
ofs += 4; ofs += 4;
continue; continue;
} }
if (node.magic == JFFS2_OLD_MAGIC_BITMASK) { if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) {
printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs); printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs);
printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n"); printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n");
DIRTY_SPACE(4); DIRTY_SPACE(4);
ofs += 4; ofs += 4;
continue; continue;
} }
if (node.magic != JFFS2_MAGIC_BITMASK) { if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) {
/* OK. We're out of possibilities. Whinge and move on */ /* OK. We're out of possibilities. Whinge and move on */
noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", JFFS2_MAGIC_BITMASK, ofs, node.magic); noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n",
JFFS2_MAGIC_BITMASK, ofs,
je16_to_cpu(node->magic));
DIRTY_SPACE(4); DIRTY_SPACE(4);
ofs += 4; ofs += 4;
continue; continue;
} }
/* We seem to have a node of sorts. Check the CRC */ /* We seem to have a node of sorts. Check the CRC */
nodetype = node.nodetype; crcnode.magic = node->magic;
node.nodetype |= JFFS2_NODE_ACCURATE; crcnode.nodetype = cpu_to_je16( je16_to_cpu(node->nodetype) | JFFS2_NODE_ACCURATE);
hdr_crc = crc32(0, &node, sizeof(node)-4); crcnode.totlen = node->totlen;
node.nodetype = nodetype; hdr_crc = crc32(0, &crcnode, sizeof(crcnode)-4);
if (hdr_crc != node.hdr_crc) {
if (hdr_crc != je32_to_cpu(node->hdr_crc)) {
noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n", noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n",
ofs, node.magic, node.nodetype, node.totlen, node.hdr_crc, hdr_crc); ofs, je16_to_cpu(node->magic),
je16_to_cpu(node->nodetype),
je32_to_cpu(node->totlen),
je32_to_cpu(node->hdr_crc),
hdr_crc);
DIRTY_SPACE(4); DIRTY_SPACE(4);
ofs += 4; ofs += 4;
continue; continue;
} }
if (ofs + node.totlen > jeb->offset + c->sector_size) { if (ofs + je32_to_cpu(node->totlen) >
jeb->offset + c->sector_size) {
/* Eep. Node goes over the end of the erase block. */ /* Eep. Node goes over the end of the erase block. */
printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n", printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
ofs, node.totlen); ofs, je32_to_cpu(node->totlen));
printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n"); printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n");
DIRTY_SPACE(4); DIRTY_SPACE(4);
ofs += 4; ofs += 4;
continue; continue;
} }
if (!(node.nodetype & JFFS2_NODE_ACCURATE)) { if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) {
/* Wheee. This is an obsoleted node */ /* Wheee. This is an obsoleted node */
D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs)); D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs));
DIRTY_SPACE(PAD(node.totlen)); DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
ofs += PAD(node.totlen); ofs += PAD(je32_to_cpu(node->totlen));
continue; continue;
} }
switch(node.nodetype) { switch(je16_to_cpu(node->nodetype)) {
case JFFS2_NODETYPE_INODE: case JFFS2_NODETYPE_INODE:
err = jffs2_scan_inode_node(c, jeb, &ofs); if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) {
buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
D1(printk(KERN_DEBUG "Fewer than %d bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
sizeof(struct jffs2_raw_inode), buf_len, ofs));
err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
if (err)
return err;
buf_ofs = ofs;
node = (void *)buf;
}
err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs);
if (err) return err; if (err) return err;
ofs += PAD(je32_to_cpu(node->totlen));
break; break;
case JFFS2_NODETYPE_DIRENT: case JFFS2_NODETYPE_DIRENT:
err = jffs2_scan_dirent_node(c, jeb, &ofs); if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
D1(printk(KERN_DEBUG "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n",
je32_to_cpu(node->totlen), buf_len, ofs));
err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
if (err)
return err;
buf_ofs = ofs;
node = (void *)buf;
}
err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs);
if (err) return err; if (err) return err;
ofs += PAD(je32_to_cpu(node->totlen));
break; break;
case JFFS2_NODETYPE_CLEANMARKER: case JFFS2_NODETYPE_CLEANMARKER:
if (node.totlen != c->cleanmarker_size) { D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n", printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n",
ofs, node.totlen, c->cleanmarker_size); ofs, je32_to_cpu(node->totlen), c->cleanmarker_size);
DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node))); DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
ofs += PAD(sizeof(struct jffs2_unknown_node));
} else if (jeb->first_node) { } else if (jeb->first_node) {
printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset); printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset);
DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node))); DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
ofs += PAD(sizeof(struct jffs2_unknown_node)); ofs += PAD(sizeof(struct jffs2_unknown_node));
continue;
} else { } else {
struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
if (!marker_ref) { if (!marker_ref) {
...@@ -369,45 +540,45 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -369,45 +540,45 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
} }
marker_ref->next_in_ino = NULL; marker_ref->next_in_ino = NULL;
marker_ref->next_phys = NULL; marker_ref->next_phys = NULL;
marker_ref->flash_offset = ofs; marker_ref->flash_offset = ofs | REF_NORMAL;
marker_ref->totlen = sizeof(struct jffs2_unknown_node); marker_ref->totlen = c->cleanmarker_size;
jeb->first_node = jeb->last_node = marker_ref; jeb->first_node = jeb->last_node = marker_ref;
USED_SPACE(PAD(sizeof(struct jffs2_unknown_node))); USED_SPACE(PAD(c->cleanmarker_size));
ofs += PAD(c->cleanmarker_size);
} }
ofs += PAD(sizeof(struct jffs2_unknown_node));
break; break;
case JFFS2_NODETYPE_PADDING: case JFFS2_NODETYPE_PADDING:
DIRTY_SPACE(PAD(node.totlen)); DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
ofs += PAD(node.totlen); ofs += PAD(je32_to_cpu(node->totlen));
break; break;
default: default:
switch (node.nodetype & JFFS2_COMPAT_MASK) { switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) {
case JFFS2_FEATURE_ROCOMPAT: case JFFS2_FEATURE_ROCOMPAT:
printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs); printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
c->flags |= JFFS2_SB_FLAG_RO; c->flags |= JFFS2_SB_FLAG_RO;
if (!(jffs2_is_readonly(c))) if (!(jffs2_is_readonly(c)))
return -EROFS; return -EROFS;
DIRTY_SPACE(PAD(node.totlen)); DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
ofs += PAD(node.totlen); ofs += PAD(je32_to_cpu(node->totlen));
break; break;
case JFFS2_FEATURE_INCOMPAT: case JFFS2_FEATURE_INCOMPAT:
printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs); printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
return -EINVAL; return -EINVAL;
case JFFS2_FEATURE_RWCOMPAT_DELETE: case JFFS2_FEATURE_RWCOMPAT_DELETE:
D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs)); D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
DIRTY_SPACE(PAD(node.totlen)); DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
ofs += PAD(node.totlen); ofs += PAD(je32_to_cpu(node->totlen));
break; break;
case JFFS2_FEATURE_RWCOMPAT_COPY: case JFFS2_FEATURE_RWCOMPAT_COPY:
D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs)); D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
USED_SPACE(PAD(node.totlen)); USED_SPACE(PAD(je32_to_cpu(node->totlen)));
ofs += PAD(node.totlen); ofs += PAD(je32_to_cpu(node->totlen));
break; break;
} }
} }
...@@ -417,64 +588,30 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -417,64 +588,30 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset, D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset,
jeb->free_size, jeb->dirty_size, jeb->used_size)); jeb->free_size, jeb->dirty_size, jeb->used_size));
if (jeb->used_size == PAD(sizeof(struct jffs2_unknown_node)) && /* mark_node_obsolete can add to wasted !! */
if (jeb->wasted_size) {
jeb->dirty_size += jeb->wasted_size;
c->dirty_size += jeb->wasted_size;
c->wasted_size -= jeb->wasted_size;
jeb->wasted_size = 0;
}
if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) &&
!jeb->first_node->next_in_ino && !jeb->dirty_size) !jeb->first_node->next_in_ino && !jeb->dirty_size)
return BLK_STATE_CLEANMARKER; return BLK_STATE_CLEANMARKER;
else if (jeb->used_size > c->sector_size - (2*sizeof(struct jffs2_raw_inode))) /* move blocks with max 4 byte dirty space to cleanlist */
else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
c->dirty_size -= jeb->dirty_size;
c->wasted_size += jeb->dirty_size;
jeb->wasted_size += jeb->dirty_size;
jeb->dirty_size = 0;
return BLK_STATE_CLEAN; return BLK_STATE_CLEAN;
else if (jeb->used_size) } else if (jeb->used_size || jeb->unchecked_size)
return BLK_STATE_PARTDIRTY; return BLK_STATE_PARTDIRTY;
else else
return BLK_STATE_ALLDIRTY; return BLK_STATE_ALLDIRTY;
} }
/* We're pointing at the first empty word on the flash. Scan and account for the whole dirty region */
static int jffs2_scan_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *startofs, int *noise)
{
uint32_t *buf;
uint32_t scanlen = (jeb->offset + c->sector_size) - *startofs;
uint32_t curofs = *startofs;
buf = kmalloc(min((uint32_t)PAGE_SIZE, scanlen), GFP_KERNEL);
if (!buf) {
printk(KERN_WARNING "Scan buffer allocation failed\n");
return -ENOMEM;
}
while(scanlen) {
size_t retlen;
int ret, i;
ret = jffs2_flash_read(c, curofs, min((uint32_t)PAGE_SIZE, scanlen), &retlen, (char *)buf);
if (ret) {
D1(printk(KERN_WARNING "jffs2_scan_empty(): Read 0x%x bytes at 0x%08x returned %d\n", min((uint32_t)PAGE_SIZE, scanlen), curofs, ret));
kfree(buf);
return ret;
}
if (retlen < 4) {
D1(printk(KERN_WARNING "Eep. too few bytes read in scan_empty()\n"));
kfree(buf);
return -EIO;
}
for (i=0; i<(retlen / 4); i++) {
if (buf[i] != 0xffffffff) {
curofs += i*4;
noisy_printk(noise, "jffs2_scan_empty(): Empty block at 0x%08x ends at 0x%08x (with 0x%08x)! Marking dirty\n", *startofs, curofs, buf[i]);
DIRTY_SPACE(curofs - (*startofs));
*startofs = curofs;
kfree(buf);
return 0;
}
}
scanlen -= retlen&~3;
curofs += retlen&~3;
}
D1(printk(KERN_DEBUG "Empty flash detected from 0x%08x to 0x%08x\n", *startofs, curofs));
kfree(buf);
*startofs = curofs;
return 0;
}
static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino) static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino)
{ {
struct jffs2_inode_cache *ic; struct jffs2_inode_cache *ic;
...@@ -489,13 +626,7 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info ...@@ -489,13 +626,7 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info
return NULL; return NULL;
} }
memset(ic, 0, sizeof(*ic)); memset(ic, 0, sizeof(*ic));
ic->scan = kmalloc(sizeof(struct jffs2_scan_info), GFP_KERNEL);
if (!ic->scan) {
printk(KERN_NOTICE "jffs2_scan_make_inode_cache(): allocation of scan info for inode cache failed\n");
jffs2_free_inode_cache(ic);
return NULL;
}
memset(ic->scan, 0, sizeof(*ic->scan));
ic->ino = ino; ic->ino = ino;
ic->nodes = (void *)ic; ic->nodes = (void *)ic;
jffs2_add_ino_cache(c, ic); jffs2_add_ino_cache(c, ic);
...@@ -504,116 +635,58 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info ...@@ -504,116 +635,58 @@ static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info
return ic; return ic;
} }
static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *ofs) static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
struct jffs2_raw_inode *ri, uint32_t ofs)
{ {
struct jffs2_raw_node_ref *raw; struct jffs2_raw_node_ref *raw;
struct jffs2_full_dnode *fn;
struct jffs2_tmp_dnode_info *tn, **tn_list;
struct jffs2_inode_cache *ic; struct jffs2_inode_cache *ic;
struct jffs2_raw_inode ri; uint32_t ino = je32_to_cpu(ri->ino);
uint32_t crc;
uint16_t oldnodetype;
int ret;
size_t retlen;
D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", *ofs));
ret = jffs2_flash_read(c, *ofs, sizeof(ri), &retlen, (char *)&ri);
if (ret) {
printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs, ret);
return ret;
}
if (retlen != sizeof(ri)) {
printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n",
retlen, *ofs, sizeof(ri));
return -EIO;
}
/* We sort of assume that the node was accurate when it was D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs));
first written to the medium :) */
oldnodetype = ri.nodetype;
ri.nodetype |= JFFS2_NODE_ACCURATE;
crc = crc32(0, &ri, sizeof(ri)-8);
ri.nodetype = oldnodetype;
if(crc != ri.node_crc) {
printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
*ofs, ri.node_crc, crc);
/* FIXME: Why do we believe totlen? */
DIRTY_SPACE(4);
*ofs += 4;
return 0;
}
/* There was a bug where we wrote hole nodes out with csize/dsize
swapped. Deal with it */
if (ri.compr == JFFS2_COMPR_ZERO && !ri.dsize && ri.csize) {
ri.dsize = ri.csize;
ri.csize = 0;
}
if (ri.csize) { /* We do very little here now. Just check the ino# to which we should attribute
/* Check data CRC too */ this node; we can do all the CRC checking etc. later. There's a tradeoff here --
unsigned char *dbuf; we used to scan the flash once only, reading everything we want from it into
uint32_t crc; memory, then building all our in-core data structures and freeing the extra
information. Now we allow the first part of the mount to complete a lot quicker,
but we have to go _back_ to the flash in order to finish the CRC checking, etc.
Which means that the _full_ amount of time to get to proper write mode with GC
operational may actually be _longer_ than before. Sucks to be me. */
dbuf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
if (!dbuf) {
printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of temporary data buffer for CRC check failed\n");
return -ENOMEM;
}
ret = jffs2_flash_read(c, *ofs+sizeof(ri), ri.csize, &retlen, dbuf);
if (ret) {
printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs+sizeof(ri), ret);
kfree(dbuf);
return ret;
}
if (retlen != ri.csize) {
printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n",
retlen, *ofs+ sizeof(ri), ri.csize);
kfree(dbuf);
return -EIO;
}
crc = crc32(0, dbuf, ri.csize);
kfree(dbuf);
if (crc != ri.data_crc) {
printk(KERN_NOTICE "jffs2_scan_inode_node(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
*ofs, ri.data_crc, crc);
DIRTY_SPACE(PAD(ri.totlen));
*ofs += PAD(ri.totlen);
return 0;
}
}
/* Wheee. It worked */
raw = jffs2_alloc_raw_node_ref(); raw = jffs2_alloc_raw_node_ref();
if (!raw) { if (!raw) {
printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of node reference failed\n"); printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of node reference failed\n");
return -ENOMEM; return -ENOMEM;
} }
tn = jffs2_alloc_tmp_dnode_info();
if (!tn) { ic = jffs2_get_ino_cache(c, ino);
jffs2_free_raw_node_ref(raw);
return -ENOMEM;
}
fn = jffs2_alloc_full_dnode();
if (!fn) {
jffs2_free_tmp_dnode_info(tn);
jffs2_free_raw_node_ref(raw);
return -ENOMEM;
}
ic = jffs2_scan_make_ino_cache(c, ri.ino);
if (!ic) { if (!ic) {
jffs2_free_full_dnode(fn); /* Inocache get failed. Either we read a bogus ino# or it's just genuinely the
jffs2_free_tmp_dnode_info(tn); first node we found for this inode. Do a CRC check to protect against the former
jffs2_free_raw_node_ref(raw); case */
return -ENOMEM; uint32_t crc = crc32(0, ri, sizeof(*ri)-8);
if (crc != je32_to_cpu(ri->node_crc)) {
printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
ofs, je32_to_cpu(ri->node_crc), crc);
/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
DIRTY_SPACE(PAD(je32_to_cpu(ri->totlen)));
return 0;
}
ic = jffs2_scan_make_ino_cache(c, ino);
if (!ic) {
jffs2_free_raw_node_ref(raw);
return -ENOMEM;
}
} }
/* Build the data structures and file them for later */ /* Wheee. It worked */
raw->flash_offset = *ofs;
raw->totlen = PAD(ri.totlen); raw->flash_offset = ofs | REF_UNCHECKED;
raw->totlen = PAD(je32_to_cpu(ri->totlen));
raw->next_phys = NULL; raw->next_phys = NULL;
raw->next_in_ino = ic->nodes; raw->next_in_ino = ic->nodes;
ic->nodes = raw; ic->nodes = raw;
if (!jeb->first_node) if (!jeb->first_node)
jeb->first_node = raw; jeb->first_node = raw;
...@@ -622,146 +695,56 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc ...@@ -622,146 +695,56 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
jeb->last_node = raw; jeb->last_node = raw;
D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n",
ri.ino, ri.version, ri.offset, ri.offset+ri.dsize)); je32_to_cpu(ri->ino), je32_to_cpu(ri->version),
je32_to_cpu(ri->offset),
pseudo_random += ri.version; je32_to_cpu(ri->offset)+je32_to_cpu(ri->dsize)));
for (tn_list = &ic->scan->tmpnodes; *tn_list; tn_list = &((*tn_list)->next)) {
if ((*tn_list)->version < ri.version)
continue;
if ((*tn_list)->version > ri.version)
break;
/* Wheee. We've found another instance of the same version number.
We should obsolete one of them.
*/
D1(printk(KERN_DEBUG "Duplicate version %d found in ino #%u. Previous one is at 0x%08x\n", ri.version, ic->ino, (*tn_list)->fn->raw->flash_offset &~3));
if (!jeb->used_size) {
D1(printk(KERN_DEBUG "No valid nodes yet found in this eraseblock 0x%08x, so obsoleting the new instance at 0x%08x\n",
jeb->offset, raw->flash_offset & ~3));
ri.nodetype &= ~JFFS2_NODE_ACCURATE;
/* Perhaps we could also mark it as such on the medium. Maybe later */
}
break;
}
if (ri.nodetype & JFFS2_NODE_ACCURATE) {
/* Only do fraglist truncation in pass1 for S_IFREG inodes */
if (S_ISREG(ri.mode) && ic->scan->version < ri.version) {
ic->scan->version = ri.version;
ic->scan->isize = ri.isize;
}
memset(fn,0,sizeof(*fn)); pseudo_random += je32_to_cpu(ri->version);
fn->ofs = ri.offset; UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen)));
fn->size = ri.dsize;
fn->frags = 0;
fn->raw = raw;
tn->next = NULL;
tn->fn = fn;
tn->version = ri.version;
USED_SPACE(PAD(ri.totlen));
/* No need to scan from the beginning of the list again.
We can start from tn_list instead (Thanks Jocke) */
jffs2_add_tn_to_list(tn, tn_list);
/* Make sure the one we just added is the _last_ in the list
with this version number, so the older ones get obsoleted */
while (tn->next && tn->next->version == tn->version) {
D1(printk(KERN_DEBUG "Shifting new node at 0x%08x after other node at 0x%08x for version %d in list\n",
fn->raw->flash_offset&~3, tn->next->fn->raw->flash_offset &~3, ri.version));
if(tn->fn != fn)
BUG();
tn->fn = tn->next->fn;
tn->next->fn = fn;
tn = tn->next;
}
} else {
jffs2_free_full_dnode(fn);
jffs2_free_tmp_dnode_info(tn);
raw->flash_offset |= 1;
DIRTY_SPACE(PAD(ri.totlen));
}
*ofs += PAD(ri.totlen);
return 0; return 0;
} }
static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *ofs) static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
struct jffs2_raw_dirent *rd, uint32_t ofs)
{ {
struct jffs2_raw_node_ref *raw; struct jffs2_raw_node_ref *raw;
struct jffs2_full_dirent *fd; struct jffs2_full_dirent *fd;
struct jffs2_inode_cache *ic; struct jffs2_inode_cache *ic;
struct jffs2_raw_dirent rd;
uint16_t oldnodetype;
int ret;
uint32_t crc; uint32_t crc;
size_t retlen;
D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", *ofs)); D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", ofs));
ret = jffs2_flash_read(c, *ofs, sizeof(rd), &retlen, (char *)&rd); /* We don't get here unless the node is still valid, so we don't have to
if (ret) { mask in the ACCURATE bit any more. */
printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n", *ofs, ret); crc = crc32(0, rd, sizeof(*rd)-8);
return ret;
}
if (retlen != sizeof(rd)) {
printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n",
retlen, *ofs, sizeof(rd));
return -EIO;
}
/* We sort of assume that the node was accurate when it was
first written to the medium :) */
oldnodetype = rd.nodetype;
rd.nodetype |= JFFS2_NODE_ACCURATE;
crc = crc32(0, &rd, sizeof(rd)-8);
rd.nodetype = oldnodetype;
if (crc != rd.node_crc) { if (crc != je32_to_cpu(rd->node_crc)) {
printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
*ofs, rd.node_crc, crc); ofs, je32_to_cpu(rd->node_crc), crc);
/* FIXME: Why do we believe totlen? */ /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
DIRTY_SPACE(4); DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen)));
*ofs += 4;
return 0; return 0;
} }
pseudo_random += rd.version; pseudo_random += je32_to_cpu(rd->version);
fd = jffs2_alloc_full_dirent(rd.nsize+1); fd = jffs2_alloc_full_dirent(rd->nsize+1);
if (!fd) { if (!fd) {
return -ENOMEM; return -ENOMEM;
} }
ret = jffs2_flash_read(c, *ofs + sizeof(rd), rd.nsize, &retlen, &fd->name[0]); memcpy(&fd->name, rd->name, rd->nsize);
if (ret) { fd->name[rd->nsize] = 0;
jffs2_free_full_dirent(fd);
printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n",
*ofs + sizeof(rd), ret);
return ret;
}
if (retlen != rd.nsize) {
jffs2_free_full_dirent(fd);
printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n",
retlen, *ofs + sizeof(rd), rd.nsize);
return -EIO;
}
crc = crc32(0, fd->name, rd.nsize); crc = crc32(0, fd->name, rd->nsize);
if (crc != rd.name_crc) { if (crc != je32_to_cpu(rd->name_crc)) {
printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
*ofs, rd.name_crc, crc); ofs, je32_to_cpu(rd->name_crc), crc);
fd->name[rd.nsize]=0; D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino)));
D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, rd.ino));
jffs2_free_full_dirent(fd); jffs2_free_full_dirent(fd);
/* FIXME: Why do we believe totlen? */ /* FIXME: Why do we believe totlen? */
DIRTY_SPACE(PAD(rd.totlen)); /* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */
*ofs += PAD(rd.totlen); DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen)));
return 0; return 0;
} }
raw = jffs2_alloc_raw_node_ref(); raw = jffs2_alloc_raw_node_ref();
...@@ -770,15 +753,15 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -770,15 +753,15 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n"); printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n");
return -ENOMEM; return -ENOMEM;
} }
ic = jffs2_scan_make_ino_cache(c, rd.pino); ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino));
if (!ic) { if (!ic) {
jffs2_free_full_dirent(fd); jffs2_free_full_dirent(fd);
jffs2_free_raw_node_ref(raw); jffs2_free_raw_node_ref(raw);
return -ENOMEM; return -ENOMEM;
} }
raw->totlen = PAD(rd.totlen); raw->totlen = PAD(je32_to_cpu(rd->totlen));
raw->flash_offset = *ofs; raw->flash_offset = ofs | REF_PRISTINE;
raw->next_phys = NULL; raw->next_phys = NULL;
raw->next_in_ino = ic->nodes; raw->next_in_ino = ic->nodes;
ic->nodes = raw; ic->nodes = raw;
...@@ -788,22 +771,15 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -788,22 +771,15 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
jeb->last_node->next_phys = raw; jeb->last_node->next_phys = raw;
jeb->last_node = raw; jeb->last_node = raw;
if (rd.nodetype & JFFS2_NODE_ACCURATE) { fd->raw = raw;
fd->raw = raw; fd->next = NULL;
fd->next = NULL; fd->version = je32_to_cpu(rd->version);
fd->version = rd.version; fd->ino = je32_to_cpu(rd->ino);
fd->ino = rd.ino; fd->nhash = full_name_hash(fd->name, rd->nsize);
fd->name[rd.nsize]=0; fd->type = rd->type;
fd->nhash = full_name_hash(fd->name, rd.nsize); USED_SPACE(PAD(je32_to_cpu(rd->totlen)));
fd->type = rd.type; jffs2_add_fd_to_list(c, fd, &ic->scan_dents);
USED_SPACE(PAD(rd.totlen));
jffs2_add_fd_to_list(c, fd, &ic->scan->dents);
} else {
raw->flash_offset |= 1;
jffs2_free_full_dirent(fd);
DIRTY_SPACE(PAD(rd.totlen));
}
*ofs += PAD(rd.totlen);
return 0; return 0;
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: super.c,v 1.73 2002/07/23 17:00:45 dwmw2 Exp $ * $Id: super.c,v 1.74 2002/11/12 09:37:39 dwmw2 Exp $
* *
*/ */
......
...@@ -7,8 +7,9 @@ ...@@ -7,8 +7,9 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: wbuf.c,v 1.12 2002/05/20 14:56:39 dwmw2 Exp $ * $Id: wbuf.c,v 1.20 2002/11/12 11:33:02 dwmw2 Exp $
* -- with the NAND definitions added back pending MTD update for 2.5. * + some of the dependencies on later MTD NAND code temporarily reverted.
*
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -16,17 +17,22 @@ ...@@ -16,17 +17,22 @@
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/mtd/nand.h>
#include "nodelist.h" #include "nodelist.h"
/* FIXME duplicated defines in wbuf.c and nand.c /* FIXME duplicated defines in wbuf.c and nand.c
* Constants for out of band layout * Constants for out of band layout
*/ */
#ifndef NAND_BADBLOCK_POS
#define NAND_BADBLOCK_POS 5
#endif
#ifndef NAND_JFFS2_OOB_BADBPOS
#define NAND_JFFS2_OOB_BADBPOS 5 #define NAND_JFFS2_OOB_BADBPOS 5
#define NAND_JFFS2_OOB8_FSDAPOS 6 #define NAND_JFFS2_OOB8_FSDAPOS 6
#define NAND_JFFS2_OOB16_FSDAPOS 8 #define NAND_JFFS2_OOB16_FSDAPOS 8
#define NAND_JFFS2_OOB8_FSDALEN 2 #define NAND_JFFS2_OOB8_FSDALEN 2
#define NAND_JFFS2_OOB16_FSDALEN 8 #define NAND_JFFS2_OOB16_FSDALEN 8
#endif
/* max. erase failures before we mark a block bad */ /* max. erase failures before we mark a block bad */
#define MAX_ERASE_FAILURES 5 #define MAX_ERASE_FAILURES 5
...@@ -88,18 +94,40 @@ void jffs2_wbuf_process (void *data) ...@@ -88,18 +94,40 @@ void jffs2_wbuf_process (void *data)
struct jffs2_sb_info *c = (struct jffs2_sb_info *) data; struct jffs2_sb_info *c = (struct jffs2_sb_info *) data;
D1(printk(KERN_DEBUG "jffs2_wbuf_process() entered\n")); D1(printk(KERN_DEBUG "jffs2_wbuf_process() entered\n"));
if (!down_trylock(&c->alloc_sem)) {
D1(printk (KERN_DEBUG "jffs2_wbuf_process() alloc_sem got\n"));
if(!c->nextblock || (c->nextblock->free_size < (c->wbuf_pagesize - c->wbuf_len))) /* Check, if the timer is active again */
jffs2_flush_wbuf(c, 1); /* pad only */ if (timer_pending (&c->wbuf_timer)) {
else D1(printk (KERN_DEBUG "Nothing to do, timer is active again\n"));
jffs2_flush_wbuf(c, 2); /* pad and adjust nextblock */ return;
up(&c->alloc_sem); }
} else {
if (down_trylock(&c->alloc_sem)) {
/* If someone else has the alloc_sem, they're about to
write anyway. So no need to waste space by
padding */
D1(printk (KERN_DEBUG "jffs2_wbuf_process() alloc_sem already occupied\n")); D1(printk (KERN_DEBUG "jffs2_wbuf_process() alloc_sem already occupied\n"));
return;
} }
D1(printk (KERN_DEBUG "jffs2_wbuf_process() alloc_sem got\n"));
if (!c->nextblock) {
D1(printk(KERN_DEBUG "jffs2_wbuf_process(): nextblock NULL, nothing to do\n"));
if (c->wbuf_len) {
printk(KERN_WARNING "jffs2_wbuf_process(): c->wbuf_len is 0x%03x but nextblock is NULL!\n", c->wbuf_len);
up(&c->alloc_sem);
BUG();
}
return;
}
/* if !c->nextblock then the tail will have got flushed from
jffs2_do_reserve_space() anyway. */
if(c->nextblock)
jffs2_flush_wbuf(c, 2); /* pad and adjust nextblock */
up(&c->alloc_sem);
} }
...@@ -112,7 +140,12 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) ...@@ -112,7 +140,12 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
{ {
int ret; int ret;
size_t retlen; size_t retlen;
/* Nothing to do if not NAND flash. In particular, we shouldn't
del_timer() the timer we never initialised. */
if (jffs2_can_mark_obsolete(c))
return 0;
if (!down_trylock(&c->alloc_sem)) { if (!down_trylock(&c->alloc_sem)) {
up(&c->alloc_sem); up(&c->alloc_sem);
printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n"); printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n");
...@@ -136,10 +169,10 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) ...@@ -136,10 +169,10 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) { if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) {
struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len); struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len);
padnode->magic = JFFS2_MAGIC_BITMASK; padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
padnode->nodetype = JFFS2_NODETYPE_PADDING; padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING);
padnode->totlen = c->wbuf_pagesize - c->wbuf_len; padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len);
padnode->hdr_crc = crc32(0, padnode, sizeof(*padnode)-4); padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4));
} }
} }
/* else jffs2_flash_writev has actually filled in the rest of the /* else jffs2_flash_writev has actually filled in the rest of the
...@@ -175,10 +208,20 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) ...@@ -175,10 +208,20 @@ int jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
spin_lock_bh(&c->erase_completion_lock); spin_lock_bh(&c->erase_completion_lock);
if (!c->nextblock) if (!c->nextblock)
BUG(); BUG();
if (c->nextblock->free_size < (c->wbuf_pagesize - c->wbuf_len)) /* wbuf_pagesize - wbuf_len is the amount of space that's to be
padded. If there is less free space in the block than that,
something screwed up */
if (c->nextblock->free_size < (c->wbuf_pagesize - c->wbuf_len)) {
printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
c->wbuf_ofs, c->wbuf_len, c->wbuf_pagesize-c->wbuf_len);
printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
c->nextblock->offset, c->nextblock->free_size);
BUG(); BUG();
}
c->nextblock->free_size -= (c->wbuf_pagesize - c->wbuf_len); c->nextblock->free_size -= (c->wbuf_pagesize - c->wbuf_len);
c->nextblock->dirty_size += (c->wbuf_pagesize - c->wbuf_len); c->free_size -= (c->wbuf_pagesize - c->wbuf_len);
c->nextblock->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
c->wasted_size += (c->wbuf_pagesize - c->wbuf_len);
spin_unlock_bh(&c->erase_completion_lock); spin_unlock_bh(&c->erase_completion_lock);
} }
...@@ -415,28 +458,30 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re ...@@ -415,28 +458,30 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
int ret; int ret;
/* Read flash */ /* Read flash */
ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); if (!jffs2_can_mark_obsolete(c)) {
ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
if (!jffs2_can_mark_obsolete(c) && (ret == -EIO) && (*retlen == len) ) {
printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%llx) returned ECC error\n", len, ofs); if ( (ret == -EIO) && (*retlen == len) ) {
/* printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%llx) returned ECC error\n", len, ofs);
* We have the raw data without ECC correction in the buffer, maybe /*
* we are lucky and all data or parts are correct. We check the node. * We have the raw data without ECC correction in the buffer, maybe
* If data are corrupted node check will sort it out. * we are lucky and all data or parts are correct. We check the node.
* We keep this block, it will fail on write or erase and the we * If data are corrupted node check will sort it out.
* mark it bad. Or should we do that now? But we should give him a chance. * We keep this block, it will fail on write or erase and the we
* Maybe we had a system crash or power loss before the ecc write or * mark it bad. Or should we do that now? But we should give him a chance.
* a erase was completed. * Maybe we had a system crash or power loss before the ecc write or
* So we return success. :) * a erase was completed.
*/ * So we return success. :)
ret = 0; */
} ret = 0;
}
} else
return c->mtd->read(c->mtd, ofs, len, retlen, buf);
/* if no writebuffer available or write buffer empty, return */ /* if no writebuffer available or write buffer empty, return */
if (!c->wbuf_pagesize || !c->wbuf_len) if (!c->wbuf_pagesize || !c->wbuf_len)
return ret; return ret;
/* if we read in a different block, return */ /* if we read in a different block, return */
if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) )
return ret; return ret;
...@@ -478,7 +523,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb ...@@ -478,7 +523,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
switch(c->mtd->ecctype) { switch(c->mtd->ecctype) {
case MTD_ECC_SW: case MTD_ECC_SW:
fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS; fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS;
badblock_pos = NAND_JFFS2_OOB_BADBPOS; badblock_pos = NAND_BADBLOCK_POS;
break; break;
default: default:
D1(printk(KERN_WARNING "jffs2_write_oob_empty(): Invalid ECC type\n")); D1(printk(KERN_WARNING "jffs2_write_oob_empty(): Invalid ECC type\n"));
...@@ -486,7 +531,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb ...@@ -486,7 +531,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
} }
/* allocate a buffer for all oob data in this sector */ /* allocate a buffer for all oob data in this sector */
len = oob_size * (c->sector_size/c->mtd->oobblock); len = 4 * oob_size;
buf = kmalloc(len, GFP_KERNEL); buf = kmalloc(len, GFP_KERNEL);
if (!buf) { if (!buf) {
printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n"); printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n");
...@@ -510,7 +555,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb ...@@ -510,7 +555,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
} }
/* Special check for first two pages */ /* Special check for first two pages */
for (page = 0; page < 2; page += oob_size) { for (page = 0; page < 2 * oob_size; page += oob_size) {
/* Check for bad block marker */ /* Check for bad block marker */
if (buf[page+badblock_pos] != 0xff) { if (buf[page+badblock_pos] != 0xff) {
D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Bad or failed block at %08x\n",jeb->offset)); D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Bad or failed block at %08x\n",jeb->offset));
...@@ -563,7 +608,7 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc ...@@ -563,7 +608,7 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
case MTD_ECC_SW: case MTD_ECC_SW:
fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS; fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS;
fsdata_len = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDALEN : NAND_JFFS2_OOB16_FSDALEN; fsdata_len = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDALEN : NAND_JFFS2_OOB16_FSDALEN;
badblock_pos = NAND_JFFS2_OOB_BADBPOS; badblock_pos = NAND_BADBLOCK_POS;
break; break;
default: default:
D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Invalid ECC type\n")); D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Invalid ECC type\n"));
...@@ -598,9 +643,9 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc ...@@ -598,9 +643,9 @@ int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
return 3; return 3;
} }
n.magic = JFFS2_MAGIC_BITMASK; n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
n.nodetype = JFFS2_NODETYPE_CLEANMARKER; n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
n.totlen = 8; n.totlen = cpu_to_je32(8);
p = (unsigned char *) &n; p = (unsigned char *) &n;
for (i = 0; i < fsdata_len; i++) { for (i = 0; i < fsdata_len; i++) {
...@@ -630,9 +675,9 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc ...@@ -630,9 +675,9 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
return -EINVAL; return -EINVAL;
} }
n.magic = JFFS2_MAGIC_BITMASK; n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
n.nodetype = JFFS2_NODETYPE_CLEANMARKER; n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
n.totlen = 8; n.totlen = cpu_to_je32(8);
ret = jffs2_flash_write_oob(c, jeb->offset + fsdata_pos, fsdata_len, &retlen, (unsigned char *)&n); ret = jffs2_flash_write_oob(c, jeb->offset + fsdata_pos, fsdata_len, &retlen, (unsigned char *)&n);
...@@ -661,7 +706,7 @@ int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *je ...@@ -661,7 +706,7 @@ int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
switch(c->mtd->ecctype) { switch(c->mtd->ecctype) {
case MTD_ECC_SW: case MTD_ECC_SW:
badblock_pos = NAND_JFFS2_OOB_BADBPOS; badblock_pos = NAND_BADBLOCK_POS;
break; break;
default: default:
D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Invalid ECC type\n")); D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Invalid ECC type\n"));
...@@ -702,7 +747,7 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock * ...@@ -702,7 +747,7 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *
switch(c->mtd->ecctype) { switch(c->mtd->ecctype) {
case MTD_ECC_SW: case MTD_ECC_SW:
pos = NAND_JFFS2_OOB_BADBPOS; pos = NAND_BADBLOCK_POS;
break; break;
default: default:
D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Invalid ECC type\n")); D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Invalid ECC type\n"));
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: write.c,v 1.56 2002/07/10 14:05:16 dwmw2 Exp $ * $Id: write.c,v 1.60 2002/09/09 16:29:08 dwmw2 Exp $
* *
*/ */
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include "nodelist.h" #include "nodelist.h"
...@@ -34,16 +35,22 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint ...@@ -34,16 +35,22 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
f->inocache = ic; f->inocache = ic;
f->inocache->nlink = 1; f->inocache->nlink = 1;
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
f->inocache->ino = ri->ino = ++c->highest_ino; f->inocache->ino = ++c->highest_ino;
D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", ri->ino)); f->inocache->state = INO_STATE_PRESENT;
ri->ino = cpu_to_je32(f->inocache->ino);
D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
jffs2_add_ino_cache(c, f->inocache); jffs2_add_ino_cache(c, f->inocache);
ri->magic = JFFS2_MAGIC_BITMASK; ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
ri->nodetype = JFFS2_NODETYPE_INODE; ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
ri->totlen = PAD(sizeof(*ri)); ri->totlen = cpu_to_je32(PAD(sizeof(*ri)));
ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
ri->mode = mode; ri->mode = cpu_to_je32(mode);
f->highest_version = ri->version = 1;
f->highest_version = 1;
ri->version = cpu_to_je32(f->highest_version);
return 0; return 0;
} }
...@@ -88,7 +95,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 ...@@ -88,7 +95,7 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
int ret; int ret;
unsigned long cnt = 2; unsigned long cnt = 2;
D1(if(ri->hdr_crc != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) { D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) {
printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode()\n"); printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode()\n");
BUG(); BUG();
} }
...@@ -100,8 +107,8 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 ...@@ -100,8 +107,8 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
writecheck(c, flash_ofs); writecheck(c, flash_ofs);
if (ri->totlen != sizeof(*ri) + datalen) { if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) {
printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)\n", ri->totlen, sizeof(*ri), datalen); printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen);
} }
raw = jffs2_alloc_raw_node_ref(); raw = jffs2_alloc_raw_node_ref();
if (!raw) if (!raw)
...@@ -113,11 +120,11 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 ...@@ -113,11 +120,11 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
raw->flash_offset = flash_ofs; raw->flash_offset = flash_ofs;
raw->totlen = PAD(ri->totlen); raw->totlen = PAD(sizeof(*ri)+datalen);
raw->next_phys = NULL; raw->next_phys = NULL;
fn->ofs = ri->offset; fn->ofs = je32_to_cpu(ri->offset);
fn->size = ri->dsize; fn->size = je32_to_cpu(ri->dsize);
fn->frags = 0; fn->frags = 0;
fn->raw = raw; fn->raw = raw;
...@@ -140,7 +147,8 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 ...@@ -140,7 +147,8 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
seem corrupted, in which case the scan would skip over seem corrupted, in which case the scan would skip over
any node we write before the original intended end of any node we write before the original intended end of
this node */ this node */
jffs2_add_physical_node_ref(c, raw, sizeof(*ri)+datalen, 1); raw->flash_offset |= REF_OBSOLETE;
jffs2_add_physical_node_ref(c, raw);
jffs2_mark_node_obsolete(c, raw); jffs2_mark_node_obsolete(c, raw);
} else { } else {
printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
...@@ -154,13 +162,20 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 ...@@ -154,13 +162,20 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
return ERR_PTR(ret?ret:-EIO); return ERR_PTR(ret?ret:-EIO);
} }
/* Mark the space used */ /* Mark the space used */
jffs2_add_physical_node_ref(c, raw, retlen, 0); if (datalen == PAGE_CACHE_SIZE)
raw->flash_offset |= REF_PRISTINE;
else
raw->flash_offset |= REF_NORMAL;
jffs2_add_physical_node_ref(c, raw);
/* Link into per-inode list */ /* Link into per-inode list */
raw->next_in_ino = f->inocache->nodes; raw->next_in_ino = f->inocache->nodes;
f->inocache->nodes = raw; f->inocache->nodes = raw;
D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", flash_ofs, ri->dsize, ri->csize, ri->node_crc, ri->data_crc, ri->totlen)); D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n",
flash_ofs, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize),
je32_to_cpu(ri->node_crc), je32_to_cpu(ri->data_crc),
je32_to_cpu(ri->totlen)));
if (writelen) if (writelen)
*writelen = retlen; *writelen = retlen;
...@@ -176,10 +191,12 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff ...@@ -176,10 +191,12 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
struct iovec vecs[2]; struct iovec vecs[2];
int ret; int ret;
D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", rd->pino, name, name, rd->ino, rd->name_crc)); D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n",
je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino),
je32_to_cpu(rd->name_crc)));
writecheck(c, flash_ofs); writecheck(c, flash_ofs);
D1(if(rd->hdr_crc != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) {
printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n"); printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n");
BUG(); BUG();
} }
...@@ -201,13 +218,13 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff ...@@ -201,13 +218,13 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
raw->flash_offset = flash_ofs; raw->flash_offset = flash_ofs;
raw->totlen = PAD(rd->totlen); raw->totlen = PAD(sizeof(*rd)+namelen);
raw->next_in_ino = f->inocache->nodes; raw->next_in_ino = f->inocache->nodes;
f->inocache->nodes = raw; f->inocache->nodes = raw;
raw->next_phys = NULL; raw->next_phys = NULL;
fd->version = rd->version; fd->version = je32_to_cpu(rd->version);
fd->ino = rd->ino; fd->ino = je32_to_cpu(rd->ino);
fd->nhash = full_name_hash(name, strlen(name)); fd->nhash = full_name_hash(name, strlen(name));
fd->type = rd->type; fd->type = rd->type;
memcpy(fd->name, name, namelen); memcpy(fd->name, name, namelen);
...@@ -220,7 +237,8 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff ...@@ -220,7 +237,8 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
sizeof(*rd)+namelen, flash_ofs, ret, retlen); sizeof(*rd)+namelen, flash_ofs, ret, retlen);
/* Mark the space as dirtied */ /* Mark the space as dirtied */
if (retlen) { if (retlen) {
jffs2_add_physical_node_ref(c, raw, sizeof(*rd)+namelen, 1); raw->flash_offset |= REF_OBSOLETE;
jffs2_add_physical_node_ref(c, raw);
jffs2_mark_node_obsolete(c, raw); jffs2_mark_node_obsolete(c, raw);
} else { } else {
printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset);
...@@ -234,7 +252,8 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff ...@@ -234,7 +252,8 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
return ERR_PTR(ret?ret:-EIO); return ERR_PTR(ret?ret:-EIO);
} }
/* Mark the space used */ /* Mark the space used */
jffs2_add_physical_node_ref(c, raw, retlen, 0); raw->flash_offset |= REF_PRISTINE;
jffs2_add_physical_node_ref(c, raw);
if (writelen) if (writelen)
*writelen = retlen; *writelen = retlen;
...@@ -289,20 +308,20 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, ...@@ -289,20 +308,20 @@ int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
that the comprbuf doesn't need to be kfree()d. that the comprbuf doesn't need to be kfree()d.
*/ */
ri->magic = JFFS2_MAGIC_BITMASK; ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
ri->nodetype = JFFS2_NODETYPE_INODE; ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
ri->totlen = sizeof(*ri) + cdatalen; ri->totlen = cpu_to_je32(sizeof(*ri) + cdatalen);
ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
ri->ino = f->inocache->ino; ri->ino = cpu_to_je32(f->inocache->ino);
ri->version = ++f->highest_version; ri->version = cpu_to_je32(++f->highest_version);
ri->isize = max(ri->isize, offset + datalen); ri->isize = cpu_to_je32(max(je32_to_cpu(ri->isize), offset + datalen));
ri->offset = offset; ri->offset = cpu_to_je32(offset);
ri->csize = cdatalen; ri->csize = cpu_to_je32(cdatalen);
ri->dsize = datalen; ri->dsize = cpu_to_je32(datalen);
ri->compr = comprtype; ri->compr = comprtype;
ri->node_crc = crc32(0, ri, sizeof(*ri)-8); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
ri->data_crc = crc32(0, comprbuf, cdatalen); ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, NULL); fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, NULL);
...@@ -367,12 +386,13 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str ...@@ -367,12 +386,13 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
return ret; return ret;
} }
ri->data_crc = 0; ri->data_crc = cpu_to_je32(0);
ri->node_crc = crc32(0, ri, sizeof(*ri)-8); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen); fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen);
D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n", ri->mode)); D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n",
je32_to_cpu(ri->mode)));
if (IS_ERR(fn)) { if (IS_ERR(fn)) {
D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n"));
...@@ -413,19 +433,19 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str ...@@ -413,19 +433,19 @@ int jffs2_do_create(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, str
down(&dir_f->sem); down(&dir_f->sem);
rd->magic = JFFS2_MAGIC_BITMASK; rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
rd->totlen = sizeof(*rd) + namelen; rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
rd->pino = dir_f->inocache->ino; rd->pino = cpu_to_je32(dir_f->inocache->ino);
rd->version = ++dir_f->highest_version; rd->version = cpu_to_je32(++dir_f->highest_version);
rd->ino = ri->ino; rd->ino = ri->ino;
rd->mctime = ri->ctime; rd->mctime = ri->ctime;
rd->nsize = namelen; rd->nsize = namelen;
rd->type = DT_REG; rd->type = DT_REG;
rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = crc32(0, name, namelen); rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, &writtenlen); fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, &writtenlen);
...@@ -471,19 +491,19 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, ...@@ -471,19 +491,19 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
down(&dir_f->sem); down(&dir_f->sem);
/* Build a deletion node */ /* Build a deletion node */
rd->magic = JFFS2_MAGIC_BITMASK; rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
rd->totlen = sizeof(*rd) + namelen; rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
rd->pino = dir_f->inocache->ino; rd->pino = cpu_to_je32(dir_f->inocache->ino);
rd->version = ++dir_f->highest_version; rd->version = cpu_to_je32(++dir_f->highest_version);
rd->ino = 0; rd->ino = cpu_to_je32(0);
rd->mctime = get_seconds(); rd->mctime = cpu_to_je32(get_seconds());
rd->nsize = namelen; rd->nsize = namelen;
rd->type = DT_UNKNOWN; rd->type = DT_UNKNOWN;
rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = crc32(0, name, namelen); rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, NULL); fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, NULL);
...@@ -498,7 +518,6 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, ...@@ -498,7 +518,6 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
/* File it. This will mark the old one obsolete. */ /* File it. This will mark the old one obsolete. */
jffs2_add_fd_to_list(c, fd, &dir_f->dents); jffs2_add_fd_to_list(c, fd, &dir_f->dents);
jffs2_complete_reservation(c);
up(&dir_f->sem); up(&dir_f->sem);
/* dead_f is NULL if this was a rename not a real unlink */ /* dead_f is NULL if this was a rename not a real unlink */
...@@ -529,6 +548,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, ...@@ -529,6 +548,8 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
up(&dead_f->sem); up(&dead_f->sem);
} }
jffs2_complete_reservation(c);
return 0; return 0;
} }
...@@ -553,21 +574,21 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint ...@@ -553,21 +574,21 @@ int jffs2_do_link (struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, uint
down(&dir_f->sem); down(&dir_f->sem);
/* Build a deletion node */ /* Build a deletion node */
rd->magic = JFFS2_MAGIC_BITMASK; rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
rd->nodetype = JFFS2_NODETYPE_DIRENT; rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
rd->totlen = sizeof(*rd) + namelen; rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));
rd->pino = dir_f->inocache->ino; rd->pino = cpu_to_je32(dir_f->inocache->ino);
rd->version = ++dir_f->highest_version; rd->version = cpu_to_je32(++dir_f->highest_version);
rd->ino = ino; rd->ino = cpu_to_je32(ino);
rd->mctime = get_seconds(); rd->mctime = cpu_to_je32(get_seconds());
rd->nsize = namelen; rd->nsize = namelen;
rd->type = type; rd->type = type;
rd->node_crc = crc32(0, rd, sizeof(*rd)-8); rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
rd->name_crc = crc32(0, name, namelen); rd->name_crc = cpu_to_je32(crc32(0, name, namelen));
fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, NULL); fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, NULL);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* For licensing information, see the file 'LICENCE' in this directory. * For licensing information, see the file 'LICENCE' in this directory.
* *
* $Id: writev.c,v 1.2 2002/05/20 14:56:39 dwmw2 Exp $ * $Id: writev.c,v 1.3 2002/08/08 08:35:21 dwmw2 Exp $
* *
*/ */
...@@ -28,7 +28,7 @@ static inline int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs ...@@ -28,7 +28,7 @@ static inline int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs
for (i=0; i<count; i++) { for (i=0; i<count; i++) {
if (!vecs[i].iov_len) if (!vecs[i].iov_len)
continue; continue;
mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base); ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
totlen += thislen; totlen += thislen;
if (ret || thislen != vecs[i].iov_len) if (ret || thislen != vecs[i].iov_len)
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* For licensing information, see the file 'LICENCE' in the * For licensing information, see the file 'LICENCE' in the
* jffs2 directory. * jffs2 directory.
* *
* $Id: jffs2.h,v 1.24 2002/05/20 14:56:37 dwmw2 Exp $ * $Id: jffs2.h,v 1.25 2002/08/20 21:37:27 dwmw2 Exp $
* *
*/ */
...@@ -68,30 +68,65 @@ ...@@ -68,30 +68,65 @@
compression type */ compression type */
/* These can go once we've made sure we've caught all uses without
byteswapping */
typedef struct {
uint32_t v32;
} __attribute__((packed)) jint32_t;
typedef struct {
uint16_t v16;
} __attribute__((packed)) jint16_t;
#define JFFS2_NATIVE_ENDIAN
#if defined(JFFS2_NATIVE_ENDIAN)
#define cpu_to_je16(x) ((jint16_t){x})
#define cpu_to_je32(x) ((jint32_t){x})
#define je16_to_cpu(x) ((x).v16)
#define je32_to_cpu(x) ((x).v32)
#elif defined(JFFS2_BIG_ENDIAN)
#define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)})
#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)})
#define je16_to_cpu(x) (be16_to_cpu(x.v16))
#define je32_to_cpu(x) (be32_to_cpu(x.v32))
#elif defined(JFFS2_LITTLE_ENDIAN)
#define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)})
#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)})
#define je16_to_cpu(x) (le16_to_cpu(x.v16))
#define je32_to_cpu(x) (le32_to_cpu(x.v32))
#else
#error wibble
#endif
struct jffs2_unknown_node struct jffs2_unknown_node
{ {
/* All start like this */ /* All start like this */
uint16_t magic; jint16_t magic;
uint16_t nodetype; jint16_t nodetype;
uint32_t totlen; /* So we can skip over nodes we don't grok */ jint32_t totlen; /* So we can skip over nodes we don't grok */
uint32_t hdr_crc; jint32_t hdr_crc;
} __attribute__((packed)); } __attribute__((packed));
struct jffs2_raw_dirent struct jffs2_raw_dirent
{ {
uint16_t magic; jint16_t magic;
uint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
uint32_t totlen; jint32_t totlen;
uint32_t hdr_crc; jint32_t hdr_crc;
uint32_t pino; jint32_t pino;
uint32_t version; jint32_t version;
uint32_t ino; /* == zero for unlink */ jint32_t ino; /* == zero for unlink */
uint32_t mctime; jint32_t mctime;
uint8_t nsize; uint8_t nsize;
uint8_t type; uint8_t type;
uint8_t unused[2]; uint8_t unused[2];
uint32_t node_crc; jint32_t node_crc;
uint32_t name_crc; jint32_t name_crc;
uint8_t name[0]; uint8_t name[0];
} __attribute__((packed)); } __attribute__((packed));
...@@ -103,27 +138,27 @@ struct jffs2_raw_dirent ...@@ -103,27 +138,27 @@ struct jffs2_raw_dirent
*/ */
struct jffs2_raw_inode struct jffs2_raw_inode
{ {
uint16_t magic; /* A constant magic number. */ jint16_t magic; /* A constant magic number. */
uint16_t nodetype; /* == JFFS_NODETYPE_INODE */ jint16_t nodetype; /* == JFFS_NODETYPE_INODE */
uint32_t totlen; /* Total length of this node (inc data, etc.) */ jint32_t totlen; /* Total length of this node (inc data, etc.) */
uint32_t hdr_crc; jint32_t hdr_crc;
uint32_t ino; /* Inode number. */ jint32_t ino; /* Inode number. */
uint32_t version; /* Version number. */ jint32_t version; /* Version number. */
uint32_t mode; /* The file's type or mode. */ jint32_t mode; /* The file's type or mode. */
uint16_t uid; /* The file's owner. */ jint16_t uid; /* The file's owner. */
uint16_t gid; /* The file's group. */ jint16_t gid; /* The file's group. */
uint32_t isize; /* Total resultant size of this inode (used for truncations) */ jint32_t isize; /* Total resultant size of this inode (used for truncations) */
uint32_t atime; /* Last access time. */ jint32_t atime; /* Last access time. */
uint32_t mtime; /* Last modification time. */ jint32_t mtime; /* Last modification time. */
uint32_t ctime; /* Change time. */ jint32_t ctime; /* Change time. */
uint32_t offset; /* Where to begin to write. */ jint32_t offset; /* Where to begin to write. */
uint32_t csize; /* (Compressed) data size */ jint32_t csize; /* (Compressed) data size */
uint32_t dsize; /* Size of the node's data. (after decompression) */ jint32_t dsize; /* Size of the node's data. (after decompression) */
uint8_t compr; /* Compression algorithm used */ uint8_t compr; /* Compression algorithm used */
uint8_t usercompr; /* Compression algorithm requested by the user */ uint8_t usercompr; /* Compression algorithm requested by the user */
uint16_t flags; /* See JFFS2_INO_FLAG_* */ jint16_t flags; /* See JFFS2_INO_FLAG_* */
uint32_t data_crc; /* CRC for the (compressed) data. */ jint32_t data_crc; /* CRC for the (compressed) data. */
uint32_t node_crc; /* CRC for the raw inode (excluding data) */ jint32_t node_crc; /* CRC for the raw inode (excluding data) */
// uint8_t data[dsize]; // uint8_t data[dsize];
} __attribute__((packed)); } __attribute__((packed));
......
/* $Id: jffs2_fs_i.h,v 1.12 2002/03/06 13:59:21 dwmw2 Exp $ */ /* $Id: jffs2_fs_i.h,v 1.15 2002/11/12 09:42:49 dwmw2 Exp $ */
#ifndef _JFFS2_FS_I #ifndef _JFFS2_FS_I
#define _JFFS2_FS_I #define _JFFS2_FS_I
#include <linux/version.h> #include <linux/version.h>
#include <linux/rbtree.h>
struct jffs2_inode_info { struct jffs2_inode_info {
/* We need an internal semaphore similar to inode->i_sem. /* We need an internal semaphore similar to inode->i_sem.
...@@ -18,7 +19,7 @@ struct jffs2_inode_info { ...@@ -18,7 +19,7 @@ struct jffs2_inode_info {
uint32_t highest_version; uint32_t highest_version;
/* List of data fragments which make up the file */ /* List of data fragments which make up the file */
struct jffs2_node_frag *fraglist; struct rb_root fragtree;
/* There may be one datanode which isn't referenced by any of the /* There may be one datanode which isn't referenced by any of the
above fragments, if it contains a metadata update but no actual above fragments, if it contains a metadata update but no actual
......
/* $Id: jffs2_fs_sb.h,v 1.32 2002/07/23 14:35:34 dwmw2 Exp $ */ /* $Id: jffs2_fs_sb.h,v 1.35 2002/11/12 09:42:18 dwmw2 Exp $ */
#ifndef _JFFS2_FS_SB #ifndef _JFFS2_FS_SB
#define _JFFS2_FS_SB #define _JFFS2_FS_SB
...@@ -21,6 +21,8 @@ struct jffs2_sb_info { ...@@ -21,6 +21,8 @@ struct jffs2_sb_info {
struct mtd_info *mtd; struct mtd_info *mtd;
uint32_t highest_ino; uint32_t highest_ino;
uint32_t checked_ino;
unsigned int flags; unsigned int flags;
struct task_struct *gc_task; /* GC task struct */ struct task_struct *gc_task; /* GC task struct */
...@@ -38,10 +40,12 @@ struct jffs2_sb_info { ...@@ -38,10 +40,12 @@ struct jffs2_sb_info {
uint32_t flash_size; uint32_t flash_size;
uint32_t used_size; uint32_t used_size;
uint32_t dirty_size; uint32_t dirty_size;
uint32_t wasted_size;
uint32_t free_size; uint32_t free_size;
uint32_t erasing_size; uint32_t erasing_size;
uint32_t bad_size; uint32_t bad_size;
uint32_t sector_size; uint32_t sector_size;
uint32_t unchecked_size;
uint32_t nr_free_blocks; uint32_t nr_free_blocks;
uint32_t nr_erasing_blocks; uint32_t nr_erasing_blocks;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment