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,6 +83,7 @@ static int jffs2_garbage_collect_thread(void *_c)
struct jffs2_sb_info *c = _c;
daemonize();
c->gc_task = current;
up(&c->gc_thread_start);
......@@ -91,10 +92,10 @@ static int jffs2_garbage_collect_thread(void *_c)
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);
......@@ -112,11 +113,11 @@ static int jffs2_garbage_collect_thread(void *_c)
*/
while (signal_pending(current)) {
siginfo_t info;
unsigned long signr = 0 ;
unsigned long signr;
spin_lock_irq(&current->sig->siglock);
spin_lock_irq(&current_sig_lock);
signr = dequeue_signal(&current->blocked, &info);
spin_unlock_irq(&current->sig->siglock);
spin_unlock_irq(&current_sig_lock);
switch(signr) {
case SIGSTOP:
......@@ -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)
(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,30 +80,29 @@ 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. */
}
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);
......@@ -108,83 +112,21 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
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) {
printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
......@@ -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);
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) {
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,6 +233,7 @@ 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);
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,6 +792,7 @@ 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++;
if (f->inocache)
f->inocache->nlink++;
up(&f->sem);
......
......@@ -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,12 +105,19 @@ 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);
while (!list_empty(&c->erase_complete_list) ||
!list_empty(&c->erase_pending_list)) {
D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset));
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;
......@@ -116,18 +130,21 @@ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c)
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,26 +277,22 @@ 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 */
/* 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;
}
}
......@@ -344,37 +357,39 @@ void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
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 = JFFS2_MAGIC_BITMASK,
.nodetype = JFFS2_NODETYPE_CLEANMARKER,
.totlen = c->cleanmarker_size
.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
.totlen = cpu_to_je32(c->cleanmarker_size)
};
marker.hdr_crc = crc32(0, &marker, marker.totlen - 4);
marker.hdr_crc = cpu_to_je32(crc32(0, &marker, je32_to_cpu(marker.totlen) - 4));
ret = jffs2_flash_write(c, jeb->offset, marker.totlen, &retlen, (char *)&marker);
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 != marker.totlen) {
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, marker.totlen, retlen);
jeb->offset, je32_to_cpu(marker.totlen), retlen);
goto bad2;
}
marker_ref->next_in_ino = NULL;
marker_ref->next_phys = NULL;
marker_ref->flash_offset = jeb->offset;
marker_ref->totlen = PAD(marker.totlen);
marker_ref->flash_offset = jeb->offset | REF_NORMAL;
marker_ref->totlen = PAD(je32_to_cpu(marker.totlen));
jeb->first_node = jeb->last_node = marker_ref;
jeb->free_size = c->sector_size - marker_ref->totlen;
jeb->used_size = marker_ref->totlen;
jeb->dirty_size = 0;
jeb->wasted_size = 0;
}
spin_lock_bh(&c->erase_completion_lock);
......@@ -383,12 +398,12 @@ void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
c->used_size += jeb->used_size;
ACCT_SANITY_CHECK(c,jeb);
ACCT_PARANOIA_CHECK(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);
}
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->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 = inode->i_ino;
ri->version = ++f->highest_version;
ri->ino = cpu_to_je32(inode->i_ino);
ri->version = cpu_to_je32(++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->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);
}
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;
......
This diff is collapsed.
This diff is collapsed.
......@@ -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
......
This diff is collapsed.
......@@ -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,25 +189,29 @@ 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 += frag->size;
offset += frag->size;
frag = frag->next;
buf += readlen;
offset += readlen;
frag = frag_next(frag);
D2(printk(KERN_DEBUG "node read was OK. Looping\n"));
}
}
return 0;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -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
......@@ -89,17 +95,39 @@ void jffs2_wbuf_process (void *data)
D1(printk(KERN_DEBUG "jffs2_wbuf_process() entered\n"));
if (!down_trylock(&c->alloc_sem)) {
/* 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 || (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 */
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);
} else {
D1(printk (KERN_DEBUG "jffs2_wbuf_process() alloc_sem already occupied\n"));
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);
}
......@@ -113,6 +141,11 @@ 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,9 +458,10 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
int ret;
/* Read flash */
if (!jffs2_can_mark_obsolete(c)) {
ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
if (!jffs2_can_mark_obsolete(c) && (ret == -EIO) && (*retlen == len) ) {
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
......@@ -431,12 +475,13 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
*/
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"));
......
This diff is collapsed.
......@@ -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;
......
This diff is collapsed.
/* $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