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