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) ...@@ -2643,7 +2643,7 @@ jffs_print_tree(struct jffs_file *first_file, int indent)
void void
jffs_print_memory_allocation_statistics(void) jffs_print_memory_allocation_statistics(void)
{ {
static long printout = 0; static long printout;
printk("________ Memory printout #%ld ________\n", ++printout); printk("________ Memory printout #%ld ________\n", ++printout);
printk("no_jffs_file = %ld\n", no_jffs_file); printk("no_jffs_file = %ld\n", no_jffs_file);
printk("no_jffs_node = %ld\n", no_jffs_node); printk("no_jffs_node = %ld\n", no_jffs_node);
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL. * 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 @@ ...@@ -39,6 +39,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/mtd/compatmac.h> /* For completion */
#include <linux/jffs2.h> #include <linux/jffs2.h>
#include <linux/jffs2_fs_i.h> #include <linux/jffs2_fs_i.h>
#include <linux/jffs2_fs_sb.h> #include <linux/jffs2_fs_sb.h>
...@@ -181,11 +182,11 @@ static int jffs2_readdir(struct file *filp, void *dirent, filldir_t filldir) ...@@ -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)); 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) if (filldir(dirent, fd->name, strlen(fd->name), offset, fd->ino, fd->type) < 0)
goto out; break;
offset++; offset++;
} }
out:
up(&f->sem); up(&f->sem);
out:
filp->f_pos = offset; filp->f_pos = offset;
return 0; return 0;
} }
...@@ -305,7 +306,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -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->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
rd->pino = dir_i->i_ino; rd->pino = dir_i->i_ino;
rd->version = dir_f->highest_version++; rd->version = ++dir_f->highest_version;
rd->ino = inode->i_ino; rd->ino = inode->i_ino;
rd->mctime = CURRENT_TIME; rd->mctime = CURRENT_TIME;
rd->nsize = namelen; rd->nsize = namelen;
...@@ -316,17 +317,21 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -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); fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
jffs2_complete_reservation(c); jffs2_complete_reservation(c);
jffs2_free_raw_dirent(rd);
if (IS_ERR(fd)) { if (IS_ERR(fd)) {
/* dirent failed to write. Delete the inode normally /* dirent failed to write. Delete the inode normally
as if it were the final unlink() */ as if it were the final unlink() */
jffs2_free_raw_dirent(rd);
up(&dir_f->sem); up(&dir_f->sem);
jffs2_clear_inode(inode); jffs2_clear_inode(inode);
unlock_kernel(); unlock_kernel();
return PTR_ERR(fd); 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 /* Link the fd into the inode's list, obsoleting an old
one if necessary. */ one if necessary. */
jffs2_add_fd_to_list(c, fd, &dir_f->dents); 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 ...@@ -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->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
rd->pino = dir_i->i_ino; rd->pino = dir_i->i_ino;
rd->version = dir_f->highest_version++; rd->version = ++dir_f->highest_version;
rd->ino = 0; rd->ino = 0;
rd->mctime = CURRENT_TIME; rd->mctime = CURRENT_TIME;
rd->nsize = dentry->d_name.len; rd->nsize = dentry->d_name.len;
...@@ -464,7 +469,7 @@ static int jffs2_do_link (struct dentry *old_dentry, struct inode *dir_i, struct ...@@ -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->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
rd->pino = dir_i->i_ino; 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->ino = old_dentry->d_inode->i_ino;
rd->mctime = CURRENT_TIME; rd->mctime = CURRENT_TIME;
rd->nsize = dentry->d_name.len; rd->nsize = dentry->d_name.len;
...@@ -503,6 +508,9 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de ...@@ -503,6 +508,9 @@ static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct de
{ {
int ret; int ret;
if (S_ISDIR(old_dentry->d_inode->i_mode))
return -EPERM;
lock_kernel(); lock_kernel();
ret = jffs2_do_link(old_dentry, dir_i, dentry, 0); ret = jffs2_do_link(old_dentry, dir_i, dentry, 0);
if (!ret) { if (!ret) {
...@@ -567,7 +575,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ...@@ -567,7 +575,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
f = JFFS2_INODE_INFO(inode); 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->totlen = sizeof(*ri) + ri->dsize;
ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); 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 ...@@ -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->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
rd->pino = dir_i->i_ino; rd->pino = dir_i->i_ino;
rd->version = dir_f->highest_version++; rd->version = ++dir_f->highest_version;
rd->ino = inode->i_ino; rd->ino = inode->i_ino;
rd->mctime = CURRENT_TIME; rd->mctime = CURRENT_TIME;
rd->nsize = namelen; rd->nsize = namelen;
...@@ -639,16 +647,19 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char ...@@ -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); fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
jffs2_complete_reservation(c); jffs2_complete_reservation(c);
jffs2_free_raw_dirent(rd);
if (IS_ERR(fd)) { if (IS_ERR(fd)) {
/* dirent failed to write. Delete the inode normally /* dirent failed to write. Delete the inode normally
as if it were the final unlink() */ as if it were the final unlink() */
jffs2_free_raw_dirent(rd);
up(&dir_f->sem); up(&dir_f->sem);
jffs2_clear_inode(inode); jffs2_clear_inode(inode);
unlock_kernel(); unlock_kernel();
return PTR_ERR(fd); 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 /* Link the fd into the inode's list, obsoleting an old
one if necessary. */ one if necessary. */
...@@ -768,7 +779,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -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->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
rd->pino = dir_i->i_ino; rd->pino = dir_i->i_ino;
rd->version = dir_f->highest_version++; rd->version = ++dir_f->highest_version;
rd->ino = inode->i_ino; rd->ino = inode->i_ino;
rd->mctime = CURRENT_TIME; rd->mctime = CURRENT_TIME;
rd->nsize = namelen; rd->nsize = namelen;
...@@ -779,17 +790,21 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) ...@@ -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); fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
jffs2_complete_reservation(c); jffs2_complete_reservation(c);
jffs2_free_raw_dirent(rd);
if (IS_ERR(fd)) { if (IS_ERR(fd)) {
/* dirent failed to write. Delete the inode normally /* dirent failed to write. Delete the inode normally
as if it were the final unlink() */ as if it were the final unlink() */
jffs2_free_raw_dirent(rd);
up(&dir_f->sem); up(&dir_f->sem);
jffs2_clear_inode(inode); jffs2_clear_inode(inode);
unlock_kernel(); unlock_kernel();
return PTR_ERR(fd); 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 /* Link the fd into the inode's list, obsoleting an old
one if necessary. */ one if necessary. */
jffs2_add_fd_to_list(c, fd, &dir_f->dents); 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 ...@@ -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); c = JFFS2_SB_INFO(dir_i->i_sb);
if ((mode & S_IFMT) == S_IFBLK || if (S_ISBLK(mode) || S_ISCHR(mode)) {
(mode & S_IFMT) == S_IFCHR) {
dev = (MAJOR(rdev) << 8) | MINOR(rdev); dev = (MAJOR(rdev) << 8) | MINOR(rdev);
devlen = sizeof(dev); devlen = sizeof(dev);
} }
...@@ -933,7 +947,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in ...@@ -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->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);
rd->pino = dir_i->i_ino; rd->pino = dir_i->i_ino;
rd->version = dir_f->highest_version++; rd->version = ++dir_f->highest_version;
rd->ino = inode->i_ino; rd->ino = inode->i_ino;
rd->mctime = CURRENT_TIME; rd->mctime = CURRENT_TIME;
rd->nsize = namelen; rd->nsize = namelen;
...@@ -947,17 +961,21 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in ...@@ -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); fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
jffs2_complete_reservation(c); jffs2_complete_reservation(c);
jffs2_free_raw_dirent(rd);
if (IS_ERR(fd)) { if (IS_ERR(fd)) {
/* dirent failed to write. Delete the inode normally /* dirent failed to write. Delete the inode normally
as if it were the final unlink() */ as if it were the final unlink() */
jffs2_free_raw_dirent(rd);
up(&dir_f->sem); up(&dir_f->sem);
jffs2_clear_inode(inode); jffs2_clear_inode(inode);
unlock_kernel(); unlock_kernel();
return PTR_ERR(fd); 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 /* Link the fd into the inode's list, obsoleting an old
one if necessary. */ one if necessary. */
jffs2_add_fd_to_list(c, fd, &dir_f->dents); 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 ...@@ -965,6 +983,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, in
unlock_kernel(); unlock_kernel();
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
return 0; return 0;
} }
...@@ -989,20 +1008,16 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry, ...@@ -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); ret = jffs2_do_unlink(old_dir_i, old_dentry, 1);
if (ret) { if (ret) {
/* Try to delete the _new_ link to return a clean failure */ /* Oh shit. We really ought to make a single node which can do both atomically */
int ret2 = jffs2_do_unlink(new_dir_i, new_dentry, 1); struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
if (ret2) { down(&f->sem);
struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); old_dentry->d_inode->i_nlink = f->inocache->nlink++;
down(&f->sem); up(&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 */ /* Might as well let the VFS know */
d_instantiate(new_dentry, old_dentry->d_inode); d_instantiate(new_dentry, old_dentry->d_inode);
atomic_inc(&old_dentry->d_inode->i_count); atomic_inc(&old_dentry->d_inode->i_count);
}
} }
unlock_kernel(); unlock_kernel();
return ret; return ret;
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL. * 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> #include <linux/kernel.h>
...@@ -214,8 +214,8 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, ...@@ -214,8 +214,8 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
D2({ D2({
int i=0; int i=0;
struct jffs2_raw_node_ref *this; struct jffs2_raw_node_ref *this;
printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG); printk(KERN_DEBUG "After remove_node_refs_from_ino_list: \n" KERN_DEBUG);
this = ic->nodes; this = ic->nodes;
...@@ -262,7 +262,11 @@ void jffs2_erase_pending_trigger(struct jffs2_sb_info *c) ...@@ -262,7 +262,11 @@ void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
void jffs2_mark_erased_blocks(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_eraseblock *jeb;
struct jffs2_raw_node_ref *marker_ref; struct jffs2_raw_node_ref *marker_ref;
unsigned char *ebuf; unsigned char *ebuf;
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL. * 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) ...@@ -102,15 +102,14 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
must read the original data associated with the node must read the original data associated with the node
(i.e. the device numbers or the target name) and write (i.e. the device numbers or the target name) and write
it out again with the appropriate data attached */ it out again with the appropriate data attached */
if ((inode->i_mode & S_IFMT) == S_IFBLK || if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
(inode->i_mode & S_IFMT) == S_IFCHR) {
/* For these, we don't actually need to read the old node */ /* For these, we don't actually need to read the old node */
dev = (major(dentry->d_inode->i_rdev) << 8) | dev = (major(dentry->d_inode->i_rdev) << 8) |
minor(dentry->d_inode->i_rdev); minor(dentry->d_inode->i_rdev);
mdata = (char *)&dev; mdata = (char *)&dev;
mdatalen = sizeof(dev); mdatalen = sizeof(dev);
D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen)); 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; mdatalen = f->metadata->size;
mdata = kmalloc(f->metadata->size, GFP_USER); mdata = kmalloc(f->metadata->size, GFP_USER);
if (!mdata) if (!mdata)
...@@ -125,7 +124,7 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr) ...@@ -125,7 +124,7 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
ri = jffs2_alloc_raw_inode(); ri = jffs2_alloc_raw_inode();
if (!ri) { if (!ri) {
if ((inode->i_mode & S_IFMT) == S_IFLNK) if (S_ISLNK(inode->i_mode))
kfree(mdata); kfree(mdata);
return -ENOMEM; return -ENOMEM;
} }
...@@ -133,7 +132,7 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr) ...@@ -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); ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL);
if (ret) { if (ret) {
jffs2_free_raw_inode(ri); jffs2_free_raw_inode(ri);
if ((inode->i_mode & S_IFMT) == S_IFLNK) if (S_ISLNK(inode->i_mode))
kfree(mdata); kfree(mdata);
return ret; return ret;
} }
...@@ -177,7 +176,7 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr) ...@@ -177,7 +176,7 @@ int jffs2_setattr (struct dentry *dentry, struct iattr *iattr)
ri->data_crc = 0; ri->data_crc = 0;
new_metadata = jffs2_write_dnode(inode, ri, mdata, mdatalen, phys_ofs, NULL); 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); kfree(mdata);
jffs2_complete_reservation(c); jffs2_complete_reservation(c);
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL. * 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_ ...@@ -266,15 +266,14 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
__u32 alloclen, phys_ofs; __u32 alloclen, phys_ofs;
int ret; int ret;
if ((inode->i_mode & S_IFMT) == S_IFBLK || if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
(inode->i_mode & S_IFMT) == S_IFCHR) {
/* For these, we don't actually need to read the old node */ /* For these, we don't actually need to read the old node */
dev = (major(inode->i_rdev) << 8) | dev = (major(inode->i_rdev) << 8) |
minor(inode->i_rdev); minor(inode->i_rdev);
mdata = (char *)&dev; mdata = (char *)&dev;
mdatalen = sizeof(dev); mdatalen = sizeof(dev);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen)); 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; mdatalen = fn->size;
mdata = kmalloc(fn->size, GFP_KERNEL); mdata = kmalloc(fn->size, GFP_KERNEL);
if (!mdata) { if (!mdata) {
...@@ -331,7 +330,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ ...@@ -331,7 +330,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
jffs2_free_full_dnode(fn); jffs2_free_full_dnode(fn);
f->metadata = new_fn; f->metadata = new_fn;
out: out:
if ((inode->i_mode & S_IFMT) == S_IFLNK) if (S_ISLNK(inode->i_mode))
kfree(mdata); kfree(mdata);
return ret; return ret;
} }
...@@ -466,8 +465,8 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -466,8 +465,8 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
ri.ino = inode->i_ino; ri.ino = inode->i_ino;
ri.version = ++f->highest_version; ri.version = ++f->highest_version;
ri.offset = start; ri.offset = start;
ri.csize = end - start; ri.dsize = end - start;
ri.dsize = 0; ri.csize = 0;
ri.compr = JFFS2_COMPR_ZERO; ri.compr = JFFS2_COMPR_ZERO;
} }
ri.mode = inode->i_mode; ri.mode = inode->i_mode;
......
...@@ -139,7 +139,7 @@ int __init jffs2_create_slab_caches(void) ...@@ -139,7 +139,7 @@ int __init jffs2_create_slab_caches(void)
if (!jffs2_inode_cachep) if (!jffs2_inode_cachep)
goto err; 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) if (inode_cache_slab)
return 0; return 0;
......
/* /*
* JFFS2 -- Journalling Flash File System, Version 2. * 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> * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
* *
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL. * 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 ...@@ -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, 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, 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_raw_node_ref *ref = f->inocache->nodes;
struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL; 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 ...@@ -104,6 +105,8 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
size_t retlen; size_t retlen;
int err; int err;
*mctime_ver = 0;
D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%lu\n", ino)); D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%lu\n", ino));
if (!f->inocache->nodes) { if (!f->inocache->nodes) {
printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", ino); 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 ...@@ -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)); D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref->flash_offset &~3));
continue; 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) { if (err) {
printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, (ref->flash_offset) & ~3); printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, (ref->flash_offset) & ~3);
goto free_out; goto free_out;
...@@ -123,7 +126,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode ...@@ -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 */ /* 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"); printk(KERN_WARNING "short read in get_inode_nodes()\n");
err = -EIO; err = -EIO;
goto free_out; goto free_out;
...@@ -153,15 +156,22 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode ...@@ -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->version = node.d.version;
fd->ino = node.d.ino; fd->ino = node.d.ino;
fd->type = node.d.type; 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)) 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)))); 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 /* Do we need to copy any more of the name directly
from the flash? from the flash?
*/ */
if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) { if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) {
int already = retlen - sizeof(struct jffs2_raw_dirent); 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 ...@@ -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->version = node.i.version;
tn->fn->ofs = node.i.offset; 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; tn->fn->raw = ref;
D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n", ref->flash_offset &~3, node.i.version, node.i.offset, node.i.dsize)); D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n", ref->flash_offset &~3, node.i.version, node.i.offset, node.i.dsize));
jffs2_add_tn_to_list(tn, &ret_tn); 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 ...@@ -242,6 +257,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
} }
*tnp = ret_tn; *tnp = ret_tn;
*fdp = ret_fd; *fdp = ret_fd;
return 0; return 0;
free_out: free_out:
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL. * 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 ...@@ -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); 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, 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, 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); 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_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new);
void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old); void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old);
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL. * 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_ ...@@ -173,12 +173,12 @@ int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_
jffs2_free_node_frag(newfrag); jffs2_free_node_frag(newfrag);
return -ENOMEM; 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) if (this->node)
printk("phys 0x%08x\n", this->node->raw->flash_offset &~3); printk("phys 0x%08x\n", this->node->raw->flash_offset &~3);
else else
printk("hole\n"); printk("hole\n");
)
newfrag2->ofs = fn->ofs + fn->size; newfrag2->ofs = fn->ofs + fn->size;
newfrag2->size = (this->ofs+this->size) - newfrag2->ofs; newfrag2->size = (this->ofs+this->size) - newfrag2->ofs;
newfrag2->next = this->next; newfrag2->next = this->next;
...@@ -251,6 +251,7 @@ void jffs2_read_inode (struct inode *inode) ...@@ -251,6 +251,7 @@ void jffs2_read_inode (struct inode *inode)
struct jffs2_full_dnode *fn = NULL; struct jffs2_full_dnode *fn = NULL;
struct jffs2_sb_info *c; struct jffs2_sb_info *c;
struct jffs2_raw_inode latest_node; struct jffs2_raw_inode latest_node;
__u32 latest_mctime, mctime_ver;
int ret; int ret;
ssize_t retlen; ssize_t retlen;
...@@ -292,7 +293,7 @@ void jffs2_read_inode (struct inode *inode) ...@@ -292,7 +293,7 @@ void jffs2_read_inode (struct inode *inode)
inode->i_nlink = f->inocache->nlink; inode->i_nlink = f->inocache->nlink;
/* Grab all nodes relevant to this ino */ /* 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) { if (ret) {
printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %lu returned %d\n", inode->i_ino, 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) ...@@ -302,7 +303,7 @@ void jffs2_read_inode (struct inode *inode)
f->dents = fd_list; f->dents = fd_list;
while (tn_list) { while (tn_list) {
static __u32 mdata_ver = 0; static __u32 mdata_ver;
tn = tn_list; tn = tn_list;
...@@ -339,6 +340,7 @@ void jffs2_read_inode (struct inode *inode) ...@@ -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"); 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; 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_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
inode->i_nlink = f->inocache->nlink; inode->i_nlink = f->inocache->nlink;
inode->i_size = 0; inode->i_size = 0;
...@@ -366,7 +368,7 @@ void jffs2_read_inode (struct inode *inode) ...@@ -366,7 +368,7 @@ void jffs2_read_inode (struct inode *inode)
inode->i_uid = latest_node.uid; inode->i_uid = latest_node.uid;
inode->i_gid = latest_node.gid; inode->i_gid = latest_node.gid;
inode->i_size = latest_node.isize; 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); jffs2_truncate_fraglist(c, &f->fraglist, latest_node.isize);
inode->i_atime = latest_node.atime; inode->i_atime = latest_node.atime;
inode->i_mtime = latest_node.mtime; inode->i_mtime = latest_node.mtime;
...@@ -376,9 +378,8 @@ void jffs2_read_inode (struct inode *inode) ...@@ -376,9 +378,8 @@ void jffs2_read_inode (struct inode *inode)
/* OK, now the special cases. Certain inode types should /* OK, now the special cases. Certain inode types should
have only one data node, and it's kept as the metadata have only one data node, and it's kept as the metadata
node */ node */
if ((inode->i_mode & S_IFMT) == S_IFBLK || if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode) ||
(inode->i_mode & S_IFMT) == S_IFCHR || S_ISLNK(inode->i_mode)) {
(inode->i_mode & S_IFMT) == S_IFLNK) {
if (f->metadata) { if (f->metadata) {
printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had metadata node\n", inode->i_ino, inode->i_mode); 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); jffs2_clear_inode(inode);
...@@ -393,7 +394,8 @@ void jffs2_read_inode (struct inode *inode) ...@@ -393,7 +394,8 @@ void jffs2_read_inode (struct inode *inode)
} }
/* ASSERT: f->fraglist != NULL */ /* ASSERT: f->fraglist != NULL */
if (f->fraglist->next) { 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); jffs2_clear_inode(inode);
make_bad_inode(inode); make_bad_inode(inode);
return; return;
...@@ -412,9 +414,21 @@ void jffs2_read_inode (struct inode *inode) ...@@ -412,9 +414,21 @@ void jffs2_read_inode (struct inode *inode)
case S_IFLNK: case S_IFLNK:
inode->i_op = &jffs2_symlink_inode_operations; 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; break;
case S_IFDIR: 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_op = &jffs2_dir_inode_operations;
inode->i_fop = &jffs2_dir_operations; inode->i_fop = &jffs2_dir_operations;
break; break;
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL. * 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> #include <linux/kernel.h>
...@@ -62,6 +62,9 @@ ...@@ -62,6 +62,9 @@
} \ } \
} while(0) } 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); 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. /* 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) ...@@ -142,6 +145,9 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
c->nr_erasing_blocks++; 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->nr_erasing_blocks) {
if (!c->used_size && empty_blocks != c->nr_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"); 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 ...@@ -444,6 +450,12 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
*ofs += 4; *ofs += 4;
return 0; 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) { if (ri.csize) {
/* Check data CRC too */ /* Check data CRC too */
...@@ -474,7 +486,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc ...@@ -474,7 +486,7 @@ static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_erasebloc
*ofs, ri.data_crc, crc); *ofs, ri.data_crc, crc);
DIRTY_SPACE(PAD(ri.totlen)); DIRTY_SPACE(PAD(ri.totlen));
*ofs += 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 ...@@ -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", 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)); 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)) { for (tn_list = &ic->scan->tmpnodes; *tn_list; tn_list = &((*tn_list)->next)) {
if ((*tn_list)->version < ri.version) if ((*tn_list)->version < ri.version)
continue; continue;
...@@ -613,6 +627,8 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -613,6 +627,8 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
return 0; return 0;
} }
pseudo_random += rd.version;
fd = jffs2_alloc_full_dirent(rd.nsize+1); fd = jffs2_alloc_full_dirent(rd.nsize+1);
if (!fd) { if (!fd) {
return -ENOMEM; return -ENOMEM;
...@@ -686,3 +702,45 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -686,3 +702,45 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
*ofs += PAD(rd.totlen); *ofs += PAD(rd.totlen);
return 0; 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 @@ ...@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL. * 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) ...@@ -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)); c->mtd = get_mtd_device(NULL, minor(sb->s_dev));
if (!c->mtd) { 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; return -EINVAL;
} }
c->sector_size = c->mtd->erasesize; c->sector_size = c->mtd->erasesize;
...@@ -249,10 +249,15 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -249,10 +249,15 @@ static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
INIT_LIST_HEAD(&c->bad_used_list); INIT_LIST_HEAD(&c->bad_used_list);
c->highest_ino = 1; c->highest_ino = 1;
c->flags |= JFFS2_SB_FLAG_MOUNTING;
if (jffs2_build_filesystem(c)) { if (jffs2_build_filesystem(c)) {
D1(printk(KERN_DEBUG "build_fs failed\n")); D1(printk(KERN_DEBUG "build_fs failed\n"));
goto out_nodes; goto out_nodes;
} }
c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
sb->s_op = &jffs2_super_operations; sb->s_op = &jffs2_super_operations;
D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n")); D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
......
/* /*
* JFFS2 -- Journalling Flash File System, Version 2. * 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> * Created by David Woodhouse <dwmw2@cambridge.redhat.com>
* *
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL. * 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) ...@@ -58,16 +58,21 @@ static char *jffs2_getlink(struct dentry *dentry)
char *buf; char *buf;
int ret; int ret;
down(&f->sem);
if (!f->metadata) { if (!f->metadata) {
up(&f->sem);
printk(KERN_NOTICE "No metadata for symlink inode #%lu\n", dentry->d_inode->i_ino); printk(KERN_NOTICE "No metadata for symlink inode #%lu\n", dentry->d_inode->i_ino);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
buf = kmalloc(f->metadata->size+1, GFP_USER); buf = kmalloc(f->metadata->size+1, GFP_USER);
if (!buf) if (!buf) {
up(&f->sem);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
buf[f->metadata->size]=0; buf[f->metadata->size]=0;
ret = jffs2_read_dnode(JFFS2_SB_INFO(dentry->d_inode->i_sb), f->metadata, buf, 0, f->metadata->size); ret = jffs2_read_dnode(JFFS2_SB_INFO(dentry->d_inode->i_sb), f->metadata, buf, 0, f->metadata->size);
up(&f->sem);
if (ret) { if (ret) {
kfree(buf); kfree(buf);
return ERR_PTR(ret); return ERR_PTR(ret);
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file * provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL. * 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 ...@@ -103,7 +103,7 @@ struct jffs2_unknown_node
__u16 nodetype; __u16 nodetype;
__u32 totlen; /* So we can skip over nodes we don't grok */ __u32 totlen; /* So we can skip over nodes we don't grok */
__u32 hdr_crc; __u32 hdr_crc;
}; } __attribute__((packed));
struct jffs2_raw_dirent struct jffs2_raw_dirent
{ {
...@@ -121,7 +121,7 @@ struct jffs2_raw_dirent ...@@ -121,7 +121,7 @@ struct jffs2_raw_dirent
__u32 node_crc; __u32 node_crc;
__u32 name_crc; __u32 name_crc;
__u8 name[0]; __u8 name[0];
}; } __attribute__((packed));
/* The JFFS2 raw inode structure: Used for storage on physical media. */ /* The JFFS2 raw inode structure: Used for storage on physical media. */
/* The uid, gid, atime, mtime and ctime members could be longer, but /* The uid, gid, atime, mtime and ctime members could be longer, but
...@@ -153,7 +153,7 @@ struct jffs2_raw_inode ...@@ -153,7 +153,7 @@ struct jffs2_raw_inode
__u32 data_crc; /* CRC for the (compressed) data. */ __u32 data_crc; /* CRC for the (compressed) data. */
__u32 node_crc; /* CRC for the raw inode (excluding data) */ __u32 node_crc; /* CRC for the raw inode (excluding data) */
// __u8 data[dsize]; // __u8 data[dsize];
}; } __attribute__((packed));
union jffs2_node_union { union jffs2_node_union {
struct jffs2_raw_inode i; 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 #ifndef _JFFS2_FS_SB
#define _JFFS2_FS_SB #define _JFFS2_FS_SB
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#define INOCACHE_HASHSIZE 1 #define INOCACHE_HASHSIZE 1
#define JFFS2_SB_FLAG_RO 1 #define JFFS2_SB_FLAG_RO 1
#define JFFS2_SB_FLAG_MOUNTING 2
/* A struct for the overall file system control. Pointers to /* A struct for the overall file system control. Pointers to
jffs2_sb_info structs are named `c' in the source code. 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