Commit f662cf7a authored by David Woodhouse's avatar David Woodhouse

JFFS2 update.

Various bugfixes
 -- deadlock in prepare_write() on extension of file fixed.
 -- corruption when reading a page where a multi-page hole ends fixed.
 -- oops on unlink of bad inodes fixed.
 -- allow bi-endian operation; mounting of non-host-endian file system is now possible.

Optimisations
 -- switch to rbtrees for the inode fragment list. O(log n) insertion and lookup now.
 -- avoid checking all data crcs and building fragment trees at scan time. Do it later in GC.
 -- use 'point' method if available to use a pointer directly into the flash chip during
	scan, rather than always using memcpy into RAM first.
 -- start to track node 'pristine' status, for later use in GC optimisation -- we'll be
	able to copy those nodes intact without having to read them, decompress and 
	recompress their payload, etc. Or indeed having to read_inode() their inode. 
 -- fix ordering of work done from kupdated. We now erase a block, mark it free and stick 
	it on the appropriate list, and go on to the next one. Before, we erased _all_ the
	pending blocks before marking any of them free, while everyone waited for us.
parent a375720f
...@@ -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 = dir_i->i_ctime = ri->ctime; dir_i->i_mtime = dir_i->i_ctime = je32_to_cpu(ri->ctime);
jffs2_free_raw_inode(ri); jffs2_free_raw_inode(ri);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
...@@ -233,7 +233,8 @@ static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) ...@@ -233,7 +233,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;
} }
/***********************************************************************/ /***********************************************************************/
...@@ -247,6 +248,10 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de ...@@ -247,6 +248,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;
...@@ -317,13 +322,14 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ...@@ -317,13 +322,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);
...@@ -369,19 +375,19 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ...@@ -369,19 +375,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 = CURRENT_TIME; rd->mctime = cpu_to_je32(CURRENT_TIME);
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);
...@@ -395,7 +401,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ...@@ -395,7 +401,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 = dir_i->i_ctime = rd->mctime; dir_i->i_mtime = dir_i->i_ctime = je32_to_cpu(rd->mctime);
jffs2_free_raw_dirent(rd); jffs2_free_raw_dirent(rd);
...@@ -459,8 +465,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -459,8 +465,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);
...@@ -506,19 +512,19 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -506,19 +512,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 = CURRENT_TIME; rd->mctime = cpu_to_je32(CURRENT_TIME);
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);
...@@ -532,7 +538,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -532,7 +538,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 = dir_i->i_ctime = rd->mctime; dir_i->i_mtime = dir_i->i_ctime = je32_to_cpu(rd->mctime);
dir_i->i_nlink++; dir_i->i_nlink++;
jffs2_free_raw_dirent(rd); jffs2_free_raw_dirent(rd);
...@@ -614,13 +620,13 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in ...@@ -614,13 +620,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);
...@@ -666,22 +672,22 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in ...@@ -666,22 +672,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 = CURRENT_TIME; rd->mctime = cpu_to_je32(CURRENT_TIME);
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);
...@@ -695,7 +701,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in ...@@ -695,7 +701,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 = dir_i->i_ctime = rd->mctime; dir_i->i_mtime = dir_i->i_ctime = je32_to_cpu(rd->mctime);
jffs2_free_raw_dirent(rd); jffs2_free_raw_dirent(rd);
...@@ -786,7 +792,8 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, ...@@ -786,7 +792,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);
......
This diff is collapsed.
...@@ -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,46 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr) ...@@ -139,41 +139,46 @@ 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 (iattr->ia_mode & S_ISGID &&
!in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID))
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);
if (ivalid & ATTR_MODE && ri->mode & S_ISGID &&
!in_group_p(ri->gid) && !capable(CAP_FSETID))
ri->mode &= ~S_ISGID;
ri->isize = (ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size; ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size);
ri->atime = (ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime; ri->atime = cpu_to_je32((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime);
ri->mtime = (ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime; ri->mtime = cpu_to_je32((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime);
ri->ctime = (ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime; ri->ctime = cpu_to_je32((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime);
ri->offset = 0; ri->offset = cpu_to_je32(0);
ri->csize = ri->dsize = mdatalen; ri->csize = ri->dsize = cpu_to_je32(mdatalen);
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,24 +191,24 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr) ...@@ -186,24 +191,24 @@ 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 = ri->atime; inode->i_atime = je32_to_cpu(ri->atime);
inode->i_ctime = ri->ctime; inode->i_ctime = je32_to_cpu(ri->ctime);
inode->i_mtime = ri->mtime; inode->i_mtime = je32_to_cpu(ri->mtime);
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;
...@@ -278,7 +283,6 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns ...@@ -278,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) {
...@@ -292,30 +296,30 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns ...@@ -292,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 = CURRENT_TIME; ri.atime = ri.ctime = ri.mtime = cpu_to_je32(CURRENT_TIME);
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);
...@@ -341,14 +345,16 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns ...@@ -341,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;
} }
...@@ -364,8 +370,16 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi ...@@ -364,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();
...@@ -375,16 +389,21 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi ...@@ -375,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 = CURRENT_TIME; ri->atime = ri->ctime = ri->mtime = cpu_to_je32(CURRENT_TIME);
/* 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) {
...@@ -397,7 +416,7 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi ...@@ -397,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 = inode->i_mtime = ri->ctime; inode->i_ctime = inode->i_mtime = je32_to_cpu(ri->ctime);
} }
} }
......
...@@ -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,13 +86,13 @@ void jffs2_read_inode (struct inode *inode) ...@@ -86,13 +86,13 @@ 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 = latest_node.atime; inode->i_atime = je32_to_cpu(latest_node.atime);
inode->i_mtime = latest_node.mtime; inode->i_mtime = je32_to_cpu(latest_node.mtime);
inode->i_ctime = latest_node.ctime; inode->i_ctime = je32_to_cpu(latest_node.ctime);
inode->i_nlink = f->inocache->nlink; inode->i_nlink = f->inocache->nlink;
...@@ -189,19 +189,9 @@ void jffs2_write_super (struct super_block *sb) ...@@ -189,19 +189,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.
} }
...@@ -229,16 +219,16 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i ...@@ -229,16 +219,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);
...@@ -246,12 +236,13 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i ...@@ -246,12 +236,13 @@ 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 = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
ri->atime = ri->mtime = ri->ctime = CURRENT_TIME; ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime);
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;
...@@ -302,9 +293,10 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) ...@@ -302,9 +293,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;
......
This diff is collapsed.
This diff is collapsed.
...@@ -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
......
This diff is collapsed.
...@@ -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;
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -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"));
......
This diff is collapsed.
...@@ -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));
......
This diff is collapsed.
This diff is collapsed.
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