Commit 34a7eea9 authored by Dave Jones's avatar Dave Jones Committed by Linus Torvalds

[PATCH] updates.

Forward ports from 2.4, Various janitor bits, and some fixes by me to
make the thing work again in 2.5.  I munged the MTDRAM driver to work
also (seperate patch to follow), and it seems to work.

David Woodhouse gave this the once over, and approved the changes.
Complete changelog below:

o   Don't create two slabcaches with the same name.
o   Don't corrupt eraseblock lists on mount
o   Don't mark nodes obsolete during mount
o   __attribute__((packed)) on the node definitions.
o   Fix up() without down() in jffs2_readdir().
o   Fix duplicate version number usage - s/highest_version++/++highest_version/
o   Fix (i.e. implement) mtime/ctime on directories.
    maybe too busy with the bk stuff
o   Don't allow hardlinks of directories.
o   s/(mode&S_IFMT)==S_IFLNK/S_ISLNK(mode)/ et al to keep Al happy.
o   Fix for garbage-collection of holes, where we used to write nodes out
    with csize/dsize swapped. Workarounds for existing such brokenness.
o   Improve wear levelling by rotating node lists on mount, to avoid starting
     at one end of the flash every time.
o   Remember to get internal inode-semaphore on symlink operations.
parent efc9d68f
......@@ -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);
......
......@@ -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,21 +1008,17 @@ 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) {
/* 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);
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;
}
......
......@@ -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>
......@@ -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;
......
......@@ -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);
......
......@@ -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;
......
......@@ -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;
......
/*
* 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,6 +156,13 @@ 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;
/* 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
*/
......@@ -217,6 +227,11 @@ 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;
/* 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));
......@@ -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:
......
......@@ -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);
......
......@@ -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;
......
......@@ -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);
}
......@@ -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"));
......
/*
* 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);
......
......@@ -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;
......
/* $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.
......
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