summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/jffs/intrep.c2
-rw-r--r--fs/jffs2/dir.c75
-rw-r--r--fs/jffs2/erase.c12
-rw-r--r--fs/jffs2/file.c13
-rw-r--r--fs/jffs2/gc.c13
-rw-r--r--fs/jffs2/malloc.c2
-rw-r--r--fs/jffs2/nodelist.c40
-rw-r--r--fs/jffs2/nodelist.h5
-rw-r--r--fs/jffs2/readinode.c34
-rw-r--r--fs/jffs2/scan.c62
-rw-r--r--fs/jffs2/super.c9
-rw-r--r--fs/jffs2/symlink.c11
-rw-r--r--include/linux/jffs2.h8
-rw-r--r--include/linux/jffs2_fs_sb.h3
14 files changed, 203 insertions, 86 deletions
diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c
index e1a0d5d9b833..b0df6fbaca37 100644
--- a/fs/jffs/intrep.c
+++ b/fs/jffs/intrep.c
@@ -2643,7 +2643,7 @@ jffs_print_tree(struct jffs_file *first_file, int indent)
void
jffs_print_memory_allocation_statistics(void)
{
- static long printout = 0;
+ static long printout;
printk("________ Memory printout #%ld ________\n", ++printout);
printk("no_jffs_file = %ld\n", no_jffs_file);
printk("no_jffs_node = %ld\n", no_jffs_node);
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index daadcf077ade..c505416ae609 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: dir.c,v 1.42 2001/05/24 22:24:39 dwmw2 Exp $
+ * $Id: dir.c,v 1.45.2.5 2002/02/23 14:31:09 dwmw2 Exp $
*
*/
@@ -39,6 +39,7 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/crc32.h>
+#include <linux/mtd/compatmac.h> /* For completion */
#include <linux/jffs2.h>
#include <linux/jffs2_fs_i.h>
#include <linux/jffs2_fs_sb.h>
@@ -181,11 +182,11 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
D2(printk(KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset, fd->name, fd->ino, fd->type));
if (filldir(dirent, fd->name, strlen(fd->name), offset, fd->ino, fd->type) < 0)
- goto out;
+ break;
offset++;
}
- out:
up(&f->sem);
+ out:
filp->f_pos = offset;
return 0;
}
@@ -305,7 +306,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode)
rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
rd->pino = dir_i->i_ino;
- rd->version = dir_f->highest_version++;
+ rd->version = ++dir_f->highest_version;
rd->ino = inode->i_ino;
rd->mctime = CURRENT_TIME;
rd->nsize = namelen;
@@ -316,17 +317,21 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode)
fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
jffs2_complete_reservation(c);
- jffs2_free_raw_dirent(rd);
-
+
if (IS_ERR(fd)) {
/* dirent failed to write. Delete the inode normally
as if it were the final unlink() */
+ jffs2_free_raw_dirent(rd);
up(&dir_f->sem);
jffs2_clear_inode(inode);
unlock_kernel();
return PTR_ERR(fd);
}
+ dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
+
+ jffs2_free_raw_dirent(rd);
+
/* Link the fd into the inode's list, obsoleting an old
one if necessary. */
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
@@ -373,7 +378,7 @@ static int jffs2_do_unlink(struct inode *dir_i, struct dentry *dentry, int renam
rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
rd->pino = dir_i->i_ino;
- rd->version = dir_f->highest_version++;
+ rd->version = ++dir_f->highest_version;
rd->ino = 0;
rd->mctime = CURRENT_TIME;
rd->nsize = dentry->d_name.len;
@@ -464,7 +469,7 @@ static int jffs2_do_link (struct dentry *old_dentry, struct inode *dir_i, struct
rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
rd->pino = dir_i->i_ino;
- rd->version = dir_f->highest_version++;
+ rd->version = ++dir_f->highest_version;
rd->ino = old_dentry->d_inode->i_ino;
rd->mctime = CURRENT_TIME;
rd->nsize = dentry->d_name.len;
@@ -503,6 +508,9 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
{
int ret;
+ if (S_ISDIR(old_dentry->d_inode->i_mode))
+ return -EPERM;
+
lock_kernel();
ret = jffs2_do_link(old_dentry, dir_i, dentry, 0);
if (!ret) {
@@ -567,7 +575,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
f = JFFS2_INODE_INFO(inode);
- ri->dsize = ri->csize = strlen(target);
+ 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);
@@ -628,7 +636,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
rd->pino = dir_i->i_ino;
- rd->version = dir_f->highest_version++;
+ rd->version = ++dir_f->highest_version;
rd->ino = inode->i_ino;
rd->mctime = CURRENT_TIME;
rd->nsize = namelen;
@@ -639,16 +647,19 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
jffs2_complete_reservation(c);
- jffs2_free_raw_dirent(rd);
if (IS_ERR(fd)) {
/* dirent failed to write. Delete the inode normally
as if it were the final unlink() */
+ jffs2_free_raw_dirent(rd);
up(&dir_f->sem);
jffs2_clear_inode(inode);
unlock_kernel();
return PTR_ERR(fd);
}
+ dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
+
+ jffs2_free_raw_dirent(rd);
/* Link the fd into the inode's list, obsoleting an old
one if necessary. */
@@ -768,7 +779,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
rd->pino = dir_i->i_ino;
- rd->version = dir_f->highest_version++;
+ rd->version = ++dir_f->highest_version;
rd->ino = inode->i_ino;
rd->mctime = CURRENT_TIME;
rd->nsize = namelen;
@@ -779,17 +790,21 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
jffs2_complete_reservation(c);
- jffs2_free_raw_dirent(rd);
if (IS_ERR(fd)) {
/* dirent failed to write. Delete the inode normally
as if it were the final unlink() */
+ jffs2_free_raw_dirent(rd);
up(&dir_f->sem);
jffs2_clear_inode(inode);
unlock_kernel();
return PTR_ERR(fd);
}
+ dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
+
+ jffs2_free_raw_dirent(rd);
+
/* Link the fd into the inode's list, obsoleting an old
one if necessary. */
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
@@ -841,8 +856,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
c = JFFS2_SB_INFO(dir_i->i_sb);
- if ((mode & S_IFMT) == S_IFBLK ||
- (mode & S_IFMT) == S_IFCHR) {
+ if (S_ISBLK(mode) || S_ISCHR(mode)) {
dev = (MAJOR(rdev) << 8) | MINOR(rdev);
devlen = sizeof(dev);
}
@@ -933,7 +947,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
rd->pino = dir_i->i_ino;
- rd->version = dir_f->highest_version++;
+ rd->version = ++dir_f->highest_version;
rd->ino = inode->i_ino;
rd->mctime = CURRENT_TIME;
rd->nsize = namelen;
@@ -947,17 +961,21 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
jffs2_complete_reservation(c);
- jffs2_free_raw_dirent(rd);
if (IS_ERR(fd)) {
/* dirent failed to write. Delete the inode normally
as if it were the final unlink() */
+ jffs2_free_raw_dirent(rd);
up(&dir_f->sem);
jffs2_clear_inode(inode);
unlock_kernel();
return PTR_ERR(fd);
}
+ dir_i->i_mtime = dir_i->i_ctime = rd->mctime;
+
+ jffs2_free_raw_dirent(rd);
+
/* Link the fd into the inode's list, obsoleting an old
one if necessary. */
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
@@ -965,6 +983,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
unlock_kernel();
d_instantiate(dentry, inode);
+
return 0;
}
@@ -989,20 +1008,16 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
ret = jffs2_do_unlink(old_dir_i, old_dentry, 1);
if (ret) {
- /* Try to delete the _new_ link to return a clean failure */
- int ret2 = jffs2_do_unlink(new_dir_i, new_dentry, 1);
- if (ret2) {
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
- down(&f->sem);
- old_dentry->d_inode->i_nlink = f->inocache->nlink++;
- up(&f->sem);
+ /* Oh shit. We really ought to make a single node which can do both atomically */
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
+ down(&f->sem);
+ old_dentry->d_inode->i_nlink = f->inocache->nlink++;
+ up(&f->sem);
- printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (old err %d, new err %d). You now have a hard link\n", ret, ret2);
- /* Might as well let the VFS know */
- d_instantiate(new_dentry, old_dentry->d_inode);
- atomic_inc(&old_dentry->d_inode->i_count);
- }
-
+ printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
+ /* Might as well let the VFS know */
+ d_instantiate(new_dentry, old_dentry->d_inode);
+ atomic_inc(&old_dentry->d_inode->i_count);
}
unlock_kernel();
return ret;
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index 2dc9b5f38294..be16d7cc263d 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: erase.c,v 1.23 2001/09/19 21:51:11 dwmw2 Exp $
+ * $Id: erase.c,v 1.24 2001/12/06 16:38:38 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
@@ -214,8 +214,8 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
D2({
int i=0;
- struct jffs2_raw_node_ref *this;
- printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG);
+ struct jffs2_raw_node_ref *this;
+ printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG);
this = ic->nodes;
@@ -262,7 +262,11 @@ void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
void jffs2_mark_erased_blocks(struct jffs2_sb_info *c)
{
- static struct jffs2_unknown_node marker = {JFFS2_MAGIC_BITMASK, JFFS2_NODETYPE_CLEANMARKER, sizeof(struct jffs2_unknown_node)};
+ static struct jffs2_unknown_node marker = {
+ magic: JFFS2_MAGIC_BITMASK,
+ nodetype: JFFS2_NODETYPE_CLEANMARKER,
+ totlen: sizeof(struct jffs2_unknown_node)
+ };
struct jffs2_eraseblock *jeb;
struct jffs2_raw_node_ref *marker_ref;
unsigned char *ebuf;
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index f0446acb9194..190a428acff8 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: file.c,v 1.58 2001/09/20 15:28:31 dwmw2 Exp $
+ * $Id: file.c,v 1.58.2.1 2002/02/23 14:25:36 dwmw2 Exp $
*
*/
@@ -102,15 +102,14 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
must read the original data associated with the node
(i.e. the device numbers or the target name) and write
it out again with the appropriate data attached */
- if ((inode->i_mode & S_IFMT) == S_IFBLK ||
- (inode->i_mode & S_IFMT) == S_IFCHR) {
+ if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
/* For these, we don't actually need to read the old node */
dev = (major(dentry->d_inode->i_rdev) << 8) |
minor(dentry->d_inode->i_rdev);
mdata = (char *)&dev;
mdatalen = sizeof(dev);
D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen));
- } else if ((inode->i_mode & S_IFMT) == S_IFLNK) {
+ } else if (S_ISLNK(inode->i_mode)) {
mdatalen = f->metadata->size;
mdata = kmalloc(f->metadata->size, GFP_USER);
if (!mdata)
@@ -125,7 +124,7 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
ri = jffs2_alloc_raw_inode();
if (!ri) {
- if ((inode->i_mode & S_IFMT) == S_IFLNK)
+ if (S_ISLNK(inode->i_mode))
kfree(mdata);
return -ENOMEM;
}
@@ -133,7 +132,7 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
if (ret) {
jffs2_free_raw_inode(ri);
- if ((inode->i_mode & S_IFMT) == S_IFLNK)
+ if (S_ISLNK(inode->i_mode))
kfree(mdata);
return ret;
}
@@ -177,7 +176,7 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
ri->data_crc = 0;
new_metadata = jffs2_write_dnode(inode, ri, mdata, mdatalen, phys_ofs, NULL);
- if ((inode->i_mode & S_IFMT) == S_IFLNK)
+ if (S_ISLNK(inode->i_mode))
kfree(mdata);
jffs2_complete_reservation(c);
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index fc4ab75ea921..f61cbf699414 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: gc.c,v 1.52 2001/09/19 21:53:47 dwmw2 Exp $
+ * $Id: gc.c,v 1.52.2.2 2002/02/23 14:25:36 dwmw2 Exp $
*
*/
@@ -266,15 +266,14 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
__u32 alloclen, phys_ofs;
int ret;
- if ((inode->i_mode & S_IFMT) == S_IFBLK ||
- (inode->i_mode & S_IFMT) == S_IFCHR) {
+ if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
/* For these, we don't actually need to read the old node */
dev = (major(inode->i_rdev) << 8) |
minor(inode->i_rdev);
mdata = (char *)&dev;
mdatalen = sizeof(dev);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen));
- } else if ((inode->i_mode & S_IFMT) == S_IFLNK) {
+ } else if (S_ISLNK(inode->i_mode)) {
mdatalen = fn->size;
mdata = kmalloc(fn->size, GFP_KERNEL);
if (!mdata) {
@@ -331,7 +330,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
jffs2_free_full_dnode(fn);
f->metadata = new_fn;
out:
- if ((inode->i_mode & S_IFMT) == S_IFLNK)
+ if (S_ISLNK(inode->i_mode))
kfree(mdata);
return ret;
}
@@ -466,8 +465,8 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
ri.ino = inode->i_ino;
ri.version = ++f->highest_version;
ri.offset = start;
- ri.csize = end - start;
- ri.dsize = 0;
+ ri.dsize = end - start;
+ ri.csize = 0;
ri.compr = JFFS2_COMPR_ZERO;
}
ri.mode = inode->i_mode;
diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
index 18874665d265..b43333100b19 100644
--- a/fs/jffs2/malloc.c
+++ b/fs/jffs2/malloc.c
@@ -139,7 +139,7 @@ int __init jffs2_create_slab_caches(void)
if (!jffs2_inode_cachep)
goto err;
- inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), 0, JFFS2_SLAB_POISON, NULL, NULL);
+ inode_cache_slab = kmem_cache_create("jffs2_inode", sizeof(struct jffs2_inode_cache), 0, JFFS2_SLAB_POISON, NULL, NULL);
if (inode_cache_slab)
return 0;
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index 27e90b8b366e..285971b48542 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.c
@@ -1,7 +1,7 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2001, 2002 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: nodelist.c,v 1.30 2001/11/14 10:35:21 dwmw2 Exp $
+ * $Id: nodelist.c,v 1.30.2.3 2002/02/23 14:04:44 dwmw2 Exp $
*
*/
@@ -94,7 +94,8 @@ void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnod
int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
- __u32 *highest_version)
+ __u32 *highest_version, __u32 *latest_mctime,
+ __u32 *mctime_ver)
{
struct jffs2_raw_node_ref *ref = f->inocache->nodes;
struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL;
@@ -104,6 +105,8 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
size_t retlen;
int err;
+ *mctime_ver = 0;
+
D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%lu\n", ino));
if (!f->inocache->nodes) {
printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", ino);
@@ -115,7 +118,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref->flash_offset &~3));
continue;
}
- err = c->mtd->read(c->mtd, (ref->flash_offset & ~3), sizeof(node), &retlen, (void *)&node);
+ err = c->mtd->read(c->mtd, (ref->flash_offset & ~3), 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);
goto free_out;
@@ -123,7 +126,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
/* Check we've managed to read at least the common node header */
- if (retlen < sizeof(node.u)) {
+ if (retlen < min(ref->totlen, sizeof(node.u))) {
printk(KERN_WARNING "short read in get_inode_nodes()\n");
err = -EIO;
goto free_out;
@@ -153,15 +156,22 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
fd->version = node.d.version;
fd->ino = node.d.ino;
fd->type = node.d.type;
- /* memcpy as much of the name as possible from the raw
- dirent we've already read from the flash
- */
+
+ /* Pick out the mctime of the latest dirent */
+ if(fd->version > *mctime_ver) {
+ *mctime_ver = fd->version;
+ *latest_mctime = node.d.mctime;
+ }
+
+ /* memcpy as much of the name as possible from the raw
+ dirent we've already read from the flash
+ */
if (retlen > sizeof(struct jffs2_raw_dirent))
memcpy(&fd->name[0], &node.d.name[0], min((__u32)node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
- /* Do we need to copy any more of the name directly
- from the flash?
- */
+ /* Do we need to copy any more of the name directly
+ from the flash?
+ */
if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) {
int already = retlen - sizeof(struct jffs2_raw_dirent);
@@ -217,7 +227,12 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
}
tn->version = node.i.version;
tn->fn->ofs = node.i.offset;
- tn->fn->size = node.i.dsize;
+ /* 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;
+ else // normal case...
+ tn->fn->size = 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));
jffs2_add_tn_to_list(tn, &ret_tn);
@@ -242,6 +257,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
}
*tnp = ret_tn;
*fdp = ret_fd;
+
return 0;
free_out:
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index 850817ef84b0..bec082a02fc8 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: nodelist.h,v 1.46 2001/09/18 23:43:05 dwmw2 Exp $
+ * $Id: nodelist.h,v 1.46.2.1 2002/02/23 14:04:44 dwmw2 Exp $
*
*/
@@ -248,7 +248,8 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new
void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list);
int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
- __u32 *highest_version);
+ __u32 *highest_version, __u32 *latest_mctime,
+ __u32 *mctime_ver);
struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, int ino);
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);
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 1824be09fcd9..d18ee615bca2 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: readinode.c,v 1.56 2001/07/26 20:32:39 dwmw2 Exp $
+ * $Id: readinode.c,v 1.58.2.2 2002/02/23 14:25:37 dwmw2 Exp $
*
*/
@@ -173,12 +173,12 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_
jffs2_free_node_frag(newfrag);
return -ENOMEM;
}
- printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size);
+ D1(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);
else
printk("hole\n");
-
+ )
newfrag2->ofs = fn->ofs + fn->size;
newfrag2->size = (this->ofs+this->size) - newfrag2->ofs;
newfrag2->next = this->next;
@@ -251,6 +251,7 @@ void jffs2_read_inode (struct inode *inode)
struct jffs2_full_dnode *fn = NULL;
struct jffs2_sb_info *c;
struct jffs2_raw_inode latest_node;
+ __u32 latest_mctime, mctime_ver;
int ret;
ssize_t retlen;
@@ -292,7 +293,7 @@ void jffs2_read_inode (struct inode *inode)
inode->i_nlink = f->inocache->nlink;
/* Grab all nodes relevant to this ino */
- ret = jffs2_get_inode_nodes(c, inode->i_ino, f, &tn_list, &fd_list, &f->highest_version);
+ ret = jffs2_get_inode_nodes(c, inode->i_ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);
if (ret) {
printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %lu returned %d\n", inode->i_ino, ret);
@@ -302,7 +303,7 @@ void jffs2_read_inode (struct inode *inode)
f->dents = fd_list;
while (tn_list) {
- static __u32 mdata_ver = 0;
+ static __u32 mdata_ver;
tn = tn_list;
@@ -339,6 +340,7 @@ void jffs2_read_inode (struct inode *inode)
printk(KERN_WARNING "jffs2_read_inode(): But it has children so we fake some modes for it\n");
}
inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO;
+ latest_node.version = 0;
inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
inode->i_nlink = f->inocache->nlink;
inode->i_size = 0;
@@ -366,7 +368,7 @@ void jffs2_read_inode (struct inode *inode)
inode->i_uid = latest_node.uid;
inode->i_gid = latest_node.gid;
inode->i_size = latest_node.isize;
- if ((inode->i_mode & S_IFMT) == S_IFREG)
+ if (S_ISREG(inode->i_mode))
jffs2_truncate_fraglist(c, &f->fraglist, latest_node.isize);
inode->i_atime = latest_node.atime;
inode->i_mtime = latest_node.mtime;
@@ -376,9 +378,8 @@ void jffs2_read_inode (struct inode *inode)
/* OK, now the special cases. Certain inode types should
have only one data node, and it's kept as the metadata
node */
- if ((inode->i_mode & S_IFMT) == S_IFBLK ||
- (inode->i_mode & S_IFMT) == S_IFCHR ||
- (inode->i_mode & S_IFMT) == S_IFLNK) {
+ if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)) {
if (f->metadata) {
printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had metadata node\n", inode->i_ino, inode->i_mode);
jffs2_clear_inode(inode);
@@ -393,7 +394,8 @@ void jffs2_read_inode (struct inode *inode)
}
/* ASSERT: f->fraglist != NULL */
if (f->fraglist->next) {
- printk(KERN_WARNING "Argh. Special inode #%lu had more than one node\n", inode->i_ino);
+ printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had more than one node\n", inode->i_ino, inode->i_mode);
+ /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */
jffs2_clear_inode(inode);
make_bad_inode(inode);
return;
@@ -412,9 +414,21 @@ void jffs2_read_inode (struct inode *inode)
case S_IFLNK:
inode->i_op = &jffs2_symlink_inode_operations;
+ /* Hack to work around broken isize in old symlink code.
+ Remove this when dwmw2 comes to his senses and stops
+ symlinks from being an entirely gratuitous special
+ case. */
+ if (!inode->i_size)
+ inode->i_size = latest_node.dsize;
break;
case S_IFDIR:
+ if (mctime_ver > latest_node.version) {
+ /* The times in the latest_node are actually older than
+ mctime in the latest dirent. Cheat. */
+ inode->i_mtime = inode->i_ctime = inode->i_atime =
+ latest_mctime;
+ }
inode->i_op = &jffs2_dir_inode_operations;
inode->i_fop = &jffs2_dir_operations;
break;
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index d1b870bd59df..f97cc6078040 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: scan.c,v 1.51 2001/09/19 00:06:35 dwmw2 Exp $
+ * $Id: scan.c,v 1.51.2.2 2002/02/23 13:34:31 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
@@ -62,6 +62,9 @@
} \
} while(0)
+static uint32_t pseudo_random;
+static void jffs2_rotate_lists(struct jffs2_sb_info *c);
+
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
/* These helper functions _must_ increase ofs and also do the dirty/used space accounting.
@@ -142,6 +145,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
c->nr_erasing_blocks++;
}
}
+ /* Rotate the lists by some number to ensure wear levelling */
+ jffs2_rotate_lists(c);
+
if (c->nr_erasing_blocks) {
if (!c->used_size && empty_blocks != c->nr_blocks) {
printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n");
@@ -444,6 +450,12 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
*ofs += 4;
return 0;
}
+ /* There was a bug where we wrote hole nodes out with csize/dsize
+ swapped. Deal with it */
+ if (ri.compr == JFFS2_COMPR_ZERO && !ri.dsize && ri.csize) {
+ ri.dsize = ri.csize;
+ ri.csize = 0;
+ }
if (ri.csize) {
/* Check data CRC too */
@@ -474,7 +486,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
*ofs, ri.data_crc, crc);
DIRTY_SPACE(PAD(ri.totlen));
*ofs += PAD(ri.totlen);
- return -0;
+ return 0;
}
}
@@ -518,6 +530,8 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
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;
@@ -613,6 +627,8 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
return 0;
}
+ pseudo_random += rd.version;
+
fd = jffs2_alloc_full_dirent(rd.nsize+1);
if (!fd) {
return -ENOMEM;
@@ -686,3 +702,45 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
*ofs += PAD(rd.totlen);
return 0;
}
+
+static int count_list(struct list_head *l)
+{
+ uint32_t count = 0;
+ struct list_head *tmp;
+
+ list_for_each(tmp, l) {
+ count++;
+ }
+ return count;
+}
+
+/* Note: This breaks if list_empty(head). I don't care. You
+ might, if you copy this code and use it elsewhere :) */
+static void rotate_list(struct list_head *head, uint32_t count)
+{
+ struct list_head *n = head->next;
+
+ list_del(head);
+ while(count--)
+ n = n->next;
+ list_add(head, n);
+}
+
+static void jffs2_rotate_lists(struct jffs2_sb_info *c)
+{
+ uint32_t x;
+
+ x = count_list(&c->clean_list);
+ if (x)
+ rotate_list((&c->clean_list), pseudo_random % x);
+
+ x = count_list(&c->dirty_list);
+ if (x)
+ rotate_list((&c->dirty_list), pseudo_random % x);
+
+ if (c->nr_erasing_blocks)
+ rotate_list((&c->erase_pending_list), pseudo_random % c->nr_erasing_blocks);
+
+ if (c->nr_free_blocks) /* Not that it should ever be zero */
+ rotate_list((&c->free_list), pseudo_random % c->nr_free_blocks);
+}
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 05f1185aa809..6c491da8d374 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: super.c,v 1.48 2001/10/02 09:16:23 dwmw2 Exp $
+ * $Id: super.c,v 1.48.2.1 2002/02/23 14:13:34 dwmw2 Exp $
*
*/
@@ -214,7 +214,7 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
c->mtd = get_mtd_device(NULL, minor(sb->s_dev));
if (!c->mtd) {
- D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev)));
+ D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", minor(sb->s_dev)));
return -EINVAL;
}
c->sector_size = c->mtd->erasesize;
@@ -249,10 +249,15 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
INIT_LIST_HEAD(&c->bad_used_list);
c->highest_ino = 1;
+ c->flags |= JFFS2_SB_FLAG_MOUNTING;
+
if (jffs2_build_filesystem(c)) {
D1(printk(KERN_DEBUG "build_fs failed\n"));
goto out_nodes;
}
+
+ c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
+
sb->s_op = &jffs2_super_operations;
D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
index c6746ed7c425..e1f7dec49f61 100644
--- a/fs/jffs2/symlink.c
+++ b/fs/jffs2/symlink.c
@@ -1,7 +1,7 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001 Red Hat, Inc.
+ * Copyright (C) 2001, 2002 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: symlink.c,v 1.5 2001/03/15 15:38:24 dwmw2 Exp $
+ * $Id: symlink.c,v 1.5.2.1 2002/01/15 10:39:06 dwmw2 Exp $
*
*/
@@ -58,16 +58,21 @@ static char *jffs2_getlink(struct dentry *dentry)
char *buf;
int ret;
+ down(&f->sem);
if (!f->metadata) {
+ up(&f->sem);
printk(KERN_NOTICE "No metadata for symlink inode #%lu\n", dentry->d_inode->i_ino);
return ERR_PTR(-EINVAL);
}
buf = kmalloc(f->metadata->size+1, GFP_USER);
- if (!buf)
+ if (!buf) {
+ up(&f->sem);
return ERR_PTR(-ENOMEM);
+ }
buf[f->metadata->size]=0;
ret = jffs2_read_dnode(JFFS2_SB_INFO(dentry->d_inode->i_sb), f->metadata, buf, 0, f->metadata->size);
+ up(&f->sem);
if (ret) {
kfree(buf);
return ERR_PTR(ret);
diff --git a/include/linux/jffs2.h b/include/linux/jffs2.h
index 37d3d931e416..9c67732fb12f 100644
--- a/include/linux/jffs2.h
+++ b/include/linux/jffs2.h
@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
- * $Id: jffs2.h,v 1.18 2001/03/25 22:36:12 dwmw2 Exp $
+ * $Id: jffs2.h,v 1.19 2001/10/09 13:20:23 dwmw2 Exp $
*
*/
@@ -103,7 +103,7 @@ struct jffs2_unknown_node
__u16 nodetype;
__u32 totlen; /* So we can skip over nodes we don't grok */
__u32 hdr_crc;
-};
+} __attribute__((packed));
struct jffs2_raw_dirent
{
@@ -121,7 +121,7 @@ struct jffs2_raw_dirent
__u32 node_crc;
__u32 name_crc;
__u8 name[0];
-};
+} __attribute__((packed));
/* The JFFS2 raw inode structure: Used for storage on physical media. */
/* The uid, gid, atime, mtime and ctime members could be longer, but
@@ -153,7 +153,7 @@ struct jffs2_raw_inode
__u32 data_crc; /* CRC for the (compressed) data. */
__u32 node_crc; /* CRC for the raw inode (excluding data) */
// __u8 data[dsize];
-};
+} __attribute__((packed));
union jffs2_node_union {
struct jffs2_raw_inode i;
diff --git a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h
index 2d9ad4e54f5f..626c8c57fb72 100644
--- a/include/linux/jffs2_fs_sb.h
+++ b/include/linux/jffs2_fs_sb.h
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_sb.h,v 1.16 2001/09/18 20:15:18 dwmw2 Exp $ */
+/* $Id: jffs2_fs_sb.h,v 1.16.2.1 2002/02/23 14:13:34 dwmw2 Exp $ */
#ifndef _JFFS2_FS_SB
#define _JFFS2_FS_SB
@@ -12,6 +12,7 @@
#define INOCACHE_HASHSIZE 1
#define JFFS2_SB_FLAG_RO 1
+#define JFFS2_SB_FLAG_MOUNTING 2
/* A struct for the overall file system control. Pointers to
jffs2_sb_info structs are named `c' in the source code.