This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
Latest JFFS2
- From: Gary Thomas <gary at mlbassoc dot com>
- To: eCos patches <ecos-patches at ecos dot sourceware dot org>
- Date: 11 Dec 2003 16:40:19 -0700
- Subject: Latest JFFS2
- Organization: MLB Associates
... imported without prejudice from MTD :-)
--
Gary Thomas <gary@mlbassoc.com>
MLB Associates
Index: fs/jffs2/current/ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/ChangeLog,v
retrieving revision 1.21
diff -u -5 -p -r1.21 ChangeLog
--- fs/jffs2/current/ChangeLog 25 Nov 2003 16:41:08 -0000 1.21
+++ fs/jffs2/current/ChangeLog 11 Dec 2003 23:28:09 -0000
@@ -1,5 +1,20 @@
+2003-11-26 David Woodhouse <dwmw2@redhat.com>
+
+ JFFS2 cleanup and import of newer code. Remove last vestiges of
+ Linuxisms such as 'struct inode' from the core code, leaving eCos
+ with no excuse, and renaming the eCos 'struct inode' to make that
+ point. Fix i_count handling throughout. Clean up remaining Linuxisms
+ such as 'struct qstr' to the point where jffs2port.h can be removed.
+ Add skeleton for background garbage-collect thread. Fix compression
+ so that it's actually called, and even with the right pointers. Turn
+ on -Werror again. Zero tolerance is a good thing. Make the i_mode
+ conversion functions non-inline to avoid warnings. Fix namespace
+ pollution (of all but ^jffs2_* at least). Move physical flash I/O
+ functions into separate file flashio.c for relatively easy
+ substitution. Various other cruftectomy.
+
2003-11-25 Andrew Lunn <andrew.lunn@ascom.ch>
* src/fs-ecos.c: ARM gcc 3.2.3 is also broken. Complain with any
ARM gcc 3.2 compiler.
Index: fs/jffs2/current/cdl/jffs2.cdl
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/cdl/jffs2.cdl,v
retrieving revision 1.12
diff -u -5 -p -r1.12 jffs2.cdl
--- fs/jffs2/current/cdl/jffs2.cdl 21 Nov 2003 19:05:24 -0000 1.12
+++ fs/jffs2/current/cdl/jffs2.cdl 11 Dec 2003 23:28:08 -0000
@@ -2,11 +2,11 @@
#
# jffs2.cdl
#
# JFFS2 Filesystem configuration data
#
-# $Id: jffs2.cdl,v 1.6 2003/11/20 16:41:57 dwmw2 Exp $
+# $Id: jffs2.cdl,v 1.13 2003/11/29 00:30:30 dwmw2 Exp $
#
# ====================================================================
#####ECOSGPLCOPYRIGHTBEGIN####
## -------------------------------------------
## This file is part of eCos, the Embedded Configurable Operating System.
@@ -70,11 +70,34 @@ cdl_package CYGPKG_FS_JFFS2 {
requires CYGPKG_CRC
implements CYGINT_IO_FILEIO_FS
compile -library=libextras.a fs-ecos.c
- compile build.c scan.c malloc-ecos.c nodelist.c nodemgmt.c readinode.c erase.c dir-ecos.c write.c gc.c read.c compr.c file-ecos.c
+ compile build.c scan.c malloc-ecos.c nodelist.c nodemgmt.c readinode.c dir-ecos.c read.c compr.c
+ # This could be overridden by an alternative direct I/O method.
+ compile flashio.c
+
+ cdl_option CYGOPT_FS_JFFS2_GCTHREAD {
+ display "Support garbage-collection background thread"
+ flavor bool
+ compile gcthread.c
+# Leave this off till it's been implemented. And don't implement it till
+# icache locking has been made thread-safe.
+ requires CYGPKG_KERNEL && 0
+ description "
+ Enable background garbage collection thread, for making
+ free space ahead of time."
+ }
+
+ cdl_option CYGOPT_FS_JFFS2_WRITE {
+ display "Include write support for JFFS2"
+ flavor bool
+ compile gc.c write.c erase.c
+ default_value 1
+ description "
+ Enable writing to JFFS2 file systems; not only reading."
+ }
cdl_option CYGOPT_FS_JFFS2_NAND {
display "Support for NAND flash"
flavor bool
define CONFIG_JFFS2_FS_NAND
@@ -164,32 +187,19 @@ cdl_package CYGPKG_FS_JFFS2 {
cdl_option CYGPKG_FS_JFFS2_CFLAGS_ADD {
display "Additional compiler flags"
flavor data
no_define
- # We add -D__ECOS to trigger eCos-specific code in places.
- # We add -Werror because I find it useful.
+ # We add '-D__ECOS' to trigger eCos-specific code in places.
+ # We add '-nostdinc -iwithprefix include' to avoid picking up
+ # native <linux/*.h> include files when building on Linux.
default_value { "-D__ECOS -nostdinc -iwithprefix include" }
description "
This option modifies the set of compiler flags for
building the JFFS2 package.
These flags are used in addition
to the set of global flags."
- }
-
- cdl_option CYGPKG_FS_JFFS2_CFLAGS_REMOVE {
- display "Suppressed compiler flags"
- flavor data
- no_define
- # We remove -Wpointer-arith so that some of the hacky Linux-compat code
- # (in file.c) compiled. We can probably remove it when that's replaced
- # properly.
- default_value { "-Wpointer-arith" }
- description "
- This option modifies the set of compiler flags for
- building the JFFS2 package. These flags are removed from
- the set of global flags if present."
}
# ----------------------------------------------------------------
# Tests
Index: fs/jffs2/current/src/compr.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/compr.c,v
retrieving revision 1.4
diff -u -5 -p -r1.4 compr.c
--- fs/jffs2/current/src/compr.c 20 Nov 2003 16:52:36 -0000 1.4
+++ fs/jffs2/current/src/compr.c 11 Dec 2003 23:28:08 -0000
@@ -5,20 +5,21 @@
*
* Created by Arjan van de Ven <arjanv@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: compr.c,v 1.29 2003/11/20 16:40:35 dwmw2 Exp $
+ * $Id: compr.c,v 1.33 2003/11/28 17:22:54 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/jffs2.h>
+#include "nodelist.h"
int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
@@ -52,46 +53,47 @@ unsigned char jffs2_compress(unsigned ch
int ret;
*cpage_out = kmalloc(*cdatalen, GFP_KERNEL);
if (!*cpage_out) {
printk(KERN_WARNING "No memory for compressor allocation. Compression failed\n");
- return JFFS2_COMPR_NONE;
+ goto out;
}
#ifdef JFFS2_USE_ZLIB
- ret = jffs2_zlib_compress(data_in, cpage_out, datalen, cdatalen);
+ ret = jffs2_zlib_compress(data_in, *cpage_out, datalen, cdatalen);
if (!ret) {
return JFFS2_COMPR_ZLIB;
}
#endif
#ifdef JFFS2_USE_DYNRUBIN
- ret = jffs2_dynrubin_compress(data_in, cpage_out, datalen, cdatalen);
+ ret = jffs2_dynrubin_compress(data_in, *cpage_out, datalen, cdatalen);
if (!ret) {
return JFFS2_COMPR_DYNRUBIN;
}
#endif
#ifdef JFFS2_USE_RUBINMIPS
- ret = jffs2_rubinmips_compress(data_in, cpage_out, datalen, cdatalen);
+ ret = jffs2_rubinmips_compress(data_in, *cpage_out, datalen, cdatalen);
if (!ret) {
return JFFS2_COMPR_RUBINMIPS;
}
#endif
#ifdef JFFS2_USE_RTIME
/* rtime does manage to recompress already-compressed data */
- ret = jffs2_rtime_compress(data_in, cpage_out, datalen, cdatalen);
+ ret = jffs2_rtime_compress(data_in, *cpage_out, datalen, cdatalen);
if (!ret) {
return JFFS2_COMPR_RTIME;
}
#endif
kfree(*cpage_out);
#endif /* Compression */
+ out:
*cpage_out = data_in;
*datalen = *cdatalen;
return JFFS2_COMPR_NONE; /* We failed to compress */
}
-void jffs2_free_comprbuf(unsigned char *orig, unsigned char *comprbuf)
+void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig)
{
if (orig != comprbuf)
kfree(comprbuf);
}
Index: fs/jffs2/current/src/compr_zlib.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/compr_zlib.c,v
retrieving revision 1.5
diff -u -5 -p -r1.5 compr_zlib.c
--- fs/jffs2/current/src/compr_zlib.c 20 Nov 2003 16:52:36 -0000 1.5
+++ fs/jffs2/current/src/compr_zlib.c 11 Dec 2003 23:28:08 -0000
@@ -5,22 +5,20 @@
*
* Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: compr_zlib.c,v 1.24 2003/10/04 08:33:06 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.25 2003/12/03 09:25:43 dwmw2 Exp $
*
*/
#if !defined(__KERNEL__) && !defined(__ECOS)
#error "The userspace support got too messy and was removed. Update your mkfs.jffs2"
#endif
#include <linux/config.h>
#include <linux/kernel.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
#include <linux/slab.h>
#include <linux/zlib.h>
#include <linux/zutil.h>
#include <asm/semaphore.h>
#include "nodelist.h"
@@ -37,10 +35,13 @@
static DECLARE_MUTEX(deflate_sem);
static DECLARE_MUTEX(inflate_sem);
static z_stream inf_strm, def_strm;
#ifdef __KERNEL__ /* Linux-only */
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+
int __init jffs2_zlib_init(void)
{
def_strm.workspace = vmalloc(zlib_deflate_workspacesize());
if (!def_strm.workspace) {
printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize());
Index: fs/jffs2/current/src/dir-ecos.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/dir-ecos.c,v
retrieving revision 1.4
diff -u -5 -p -r1.4 dir-ecos.c
--- fs/jffs2/current/src/dir-ecos.c 20 Nov 2003 16:52:36 -0000 1.4
+++ fs/jffs2/current/src/dir-ecos.c 11 Dec 2003 23:28:08 -0000
@@ -1,60 +1,57 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: dir-ecos.c,v 1.4 2003/11/20 16:41:58 dwmw2 Exp $
+ * $Id: dir-ecos.c,v 1.10 2003/11/26 15:55:35 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
#include <linux/crc32.h>
#include "nodelist.h"
/***********************************************************************/
-
-/* We keep the dirent list sorted in increasing order of name hash,
- and we use the same hash function as the dentries. Makes this
- nice and simple
-*/
-struct inode *jffs2_lookup(struct inode *dir_i, struct qstr *d_name)
+/* Takes length argument because it can be either NUL-terminated or '/'-terminated */
+struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *d_name, int namelen)
{
struct jffs2_inode_info *dir_f;
struct jffs2_sb_info *c;
struct jffs2_full_dirent *fd = NULL, *fd_list;
uint32_t ino = 0;
- struct inode *inode = NULL;
+ uint32_t hash = full_name_hash(d_name, namelen);
+ struct _inode *inode = NULL;
D1(printk("jffs2_lookup()\n"));
dir_f = JFFS2_INODE_INFO(dir_i);
c = JFFS2_SB_INFO(dir_i->i_sb);
down(&dir_f->sem);
/* NB: The 2.2 backport will need to explicitly check for '.' and '..' here */
- for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= d_name->hash; fd_list = fd_list->next) {
- if (fd_list->nhash == d_name->hash &&
+ for (fd_list = dir_f->dents; fd_list && fd_list->nhash <= hash; fd_list = fd_list->next) {
+ if (fd_list->nhash == hash &&
(!fd || fd_list->version > fd->version) &&
- strlen(fd_list->name) == d_name->len &&
- !strncmp(fd_list->name, d_name->name, d_name->len)) {
+ strlen(fd_list->name) == namelen &&
+ !strncmp(fd_list->name, d_name, namelen)) {
fd = fd_list;
}
}
if (fd)
ino = fd->ino;
up(&dir_f->sem);
if (ino) {
- inode = iget(dir_i->i_sb, ino);
+ inode = jffs2_iget(dir_i->i_sb, ino);
if (!inode) {
- printk("iget() failed for ino #%u\n", ino);
+ printk("jffs2_iget() failed for ino #%u\n", ino);
return (ERR_PTR(-EIO));
}
}
return inode;
@@ -62,17 +59,17 @@ struct inode *jffs2_lookup(struct inode
/***********************************************************************/
-int jffs2_create(struct inode *dir_i, struct qstr *d_name, int mode,
- struct inode **new_i)
+int jffs2_create(struct _inode *dir_i, const unsigned char *d_name, int mode,
+ struct _inode **new_i)
{
struct jffs2_raw_inode *ri;
struct jffs2_inode_info *f, *dir_f;
struct jffs2_sb_info *c;
- struct inode *inode;
+ struct _inode *inode;
int ret;
ri = jffs2_alloc_raw_inode();
if (!ri)
return -ENOMEM;
@@ -91,16 +88,15 @@ int jffs2_create(struct inode *dir_i, st
f = JFFS2_INODE_INFO(inode);
dir_f = JFFS2_INODE_INFO(dir_i);
ret = jffs2_do_create(c, dir_f, f, ri,
- d_name->name, d_name->len);
+ d_name, strlen(d_name));
if (ret) {
- jffs2_clear_inode(inode);
- make_bad_inode(inode);
- iput(inode);
+ inode->i_nlink = 0;
+ jffs2_iput(inode);
jffs2_free_raw_inode(ri);
return ret;
}
jffs2_free_raw_inode(ri);
@@ -112,52 +108,52 @@ int jffs2_create(struct inode *dir_i, st
}
/***********************************************************************/
-int jffs2_unlink(struct inode *dir_i, struct inode *d_inode, struct qstr *d_name)
+int jffs2_unlink(struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name)
{
struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(d_inode);
int ret;
- ret = jffs2_do_unlink(c, dir_f, d_name->name,
- d_name->len, dead_f);
+ ret = jffs2_do_unlink(c, dir_f, d_name,
+ strlen(d_name), dead_f);
if (dead_f->inocache)
d_inode->i_nlink = dead_f->inocache->nlink;
return ret;
}
/***********************************************************************/
-int jffs2_link (struct inode *old_d_inode, struct inode *dir_i, struct qstr *d_name)
+int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned char *d_name)
{
struct jffs2_sb_info *c = JFFS2_SB_INFO(old_d_inode->i_sb);
struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_d_inode);
struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
int ret;
/* XXX: This is ugly */
uint8_t type = (old_d_inode->i_mode & S_IFMT) >> 12;
if (!type) type = DT_REG;
- ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, d_name->name, d_name->len);
+ ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, d_name, strlen(d_name));
if (!ret) {
down(&f->sem);
old_d_inode->i_nlink = ++f->inocache->nlink;
up(&f->sem);
}
return ret;
}
-int jffs2_mkdir (struct inode *dir_i, struct qstr *d_name, int mode, struct inode **new_i)
+int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode)
{
struct jffs2_inode_info *f, *dir_f;
struct jffs2_sb_info *c;
- struct inode *inode;
+ struct _inode *inode;
struct jffs2_raw_inode *ri;
struct jffs2_raw_dirent *rd;
struct jffs2_full_dnode *fn;
struct jffs2_full_dirent *fd;
int namelen;
@@ -173,11 +169,11 @@ int jffs2_mkdir (struct inode *dir_i, st
c = JFFS2_SB_INFO(dir_i->i_sb);
/* Try to reserve enough space for both node and dirent.
* Just the node will do for now, though
*/
- namelen = d_name->len;
+ namelen = strlen(d_name);
ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
if (ret) {
jffs2_free_raw_inode(ri);
return ret;
@@ -202,11 +198,12 @@ int jffs2_mkdir (struct inode *dir_i, st
if (IS_ERR(fn)) {
/* Eeek. Wave bye bye */
up(&f->sem);
jffs2_complete_reservation(c);
- jffs2_clear_inode(inode);
+ inode->i_nlink = 0;
+ jffs2_iput(inode);
return PTR_ERR(fn);
}
/* No data here. Only a metadata node, which will be
obsoleted by the first data write
*/
@@ -215,19 +212,21 @@ int jffs2_mkdir (struct inode *dir_i, st
jffs2_complete_reservation(c);
ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
if (ret) {
/* Eep. */
- jffs2_clear_inode(inode);
+ inode->i_nlink = 0;
+ jffs2_iput(inode);
return ret;
}
rd = jffs2_alloc_raw_dirent();
if (!rd) {
/* Argh. Now we treat it like a normal delete */
jffs2_complete_reservation(c);
- jffs2_clear_inode(inode);
+ inode->i_nlink = 0;
+ jffs2_iput(inode);
return -ENOMEM;
}
dir_f = JFFS2_INODE_INFO(dir_i);
down(&dir_f->sem);
@@ -242,35 +241,36 @@ int jffs2_mkdir (struct inode *dir_i, st
rd->ino = cpu_to_je32(inode->i_ino);
rd->mctime = cpu_to_je32(cyg_timestamp());
rd->nsize = namelen;
rd->type = DT_DIR;
rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
- rd->name_crc = cpu_to_je32(crc32(0, d_name->name, namelen));
+ rd->name_crc = cpu_to_je32(crc32(0, d_name, namelen));
- fd = jffs2_write_dirent(c, dir_f, rd, d_name->name, namelen, phys_ofs, ALLOC_NORMAL);
+ fd = jffs2_write_dirent(c, dir_f, rd, d_name, namelen, phys_ofs, ALLOC_NORMAL);
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() */
up(&dir_f->sem);
- jffs2_clear_inode(inode);
+ inode->i_nlink = 0;
+ jffs2_iput(inode);
return PTR_ERR(fd);
}
/* Link the fd into the inode's list, obsoleting an old
one if necessary. */
jffs2_add_fd_to_list(c, fd, &dir_f->dents);
up(&dir_f->sem);
- *new_i = inode;
+ jffs2_iput(inode);
return 0;
}
-int jffs2_rmdir (struct inode *dir_i, struct inode *d_inode, struct qstr *d_name)
+int jffs2_rmdir (struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name)
{
struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode);
struct jffs2_full_dirent *fd;
for (fd = f->dents ; fd; fd = fd->next) {
@@ -278,12 +278,12 @@ int jffs2_rmdir (struct inode *dir_i, st
return EPERM; //-ENOTEMPTY;
}
return jffs2_unlink(dir_i, d_inode, d_name);
}
-int jffs2_rename (struct inode *old_dir_i, struct inode *d_inode, struct qstr *old_d_name,
- struct inode *new_dir_i, struct qstr *new_d_name)
+int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsigned char *old_d_name,
+ struct _inode *new_dir_i, const unsigned char *new_d_name)
{
int ret;
struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
struct jffs2_inode_info *victim_f = NULL;
uint8_t type;
@@ -329,11 +329,11 @@ int jffs2_rename (struct inode *old_dir_
type = (d_inode->i_mode & S_IFMT) >> 12;
if (!type) type = DT_REG;
ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i),
d_inode->i_ino, type,
- new_d_name->name, new_d_name->len);
+ new_d_name, strlen(new_d_name));
if (ret)
return ret;
if (victim_f) {
@@ -347,11 +347,11 @@ int jffs2_rename (struct inode *old_dir_
}
}
/* Unlink the original */
ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
- old_d_name->name, old_d_name->len, NULL);
+ old_d_name, strlen(old_d_name), NULL);
if (ret) {
/* Oh shit. We really ought to make a single node which can do both atomically */
struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode);
down(&f->sem);
Index: fs/jffs2/current/src/erase.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/erase.c,v
retrieving revision 1.5
diff -u -5 -p -r1.5 erase.c
--- fs/jffs2/current/src/erase.c 20 Nov 2003 16:52:36 -0000 1.5
+++ fs/jffs2/current/src/erase.c 11 Dec 2003 23:28:08 -0000
@@ -5,11 +5,11 @@
*
* Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: erase.c,v 1.57 2003/11/04 14:46:13 dwmw2 Exp $
+ * $Id: erase.c,v 1.58 2003/11/26 13:02:46 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -279,15 +279,10 @@ static void jffs2_free_all_node_refs(str
/* else it was a non-inode node or already removed, so don't bother */
jffs2_free_raw_node_ref(ref);
}
jeb->last_node = NULL;
-}
-
-void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
-{
- OFNI_BS_2SFFJ(c)->s_dirt = 1;
}
static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{
struct jffs2_raw_node_ref *marker_ref = NULL;
Index: fs/jffs2/current/src/fs-ecos.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/fs-ecos.c,v
retrieving revision 1.15
diff -u -5 -p -r1.15 fs-ecos.c
--- fs/jffs2/current/src/fs-ecos.c 25 Nov 2003 16:41:08 -0000 1.15
+++ fs/jffs2/current/src/fs-ecos.c 11 Dec 2003 23:28:08 -0000
@@ -1,34 +1,33 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by Dominic Ostrowski <dominic.ostrowski@3glab.com>
* Contributors: David Woodhouse, Nick Garnett, Richard Panton.
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: fs-ecos.c,v 1.11 2003/11/20 16:41:58 dwmw2 Exp $
+ * $Id: fs-ecos.c,v 1.33 2003/12/02 10:43:03 dwmw2 Exp $
*
*/
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/kernel.h>
-#include "jffs2port.h"
#include <linux/jffs2.h>
#include <linux/jffs2_fs_sb.h>
#include <linux/jffs2_fs_i.h>
#include <linux/pagemap.h>
+#include <linux/crc32.h>
#include "nodelist.h"
#include <errno.h>
#include <string.h>
#include <cyg/io/io.h>
#include <cyg/io/config_keys.h>
-#include <cyg/io/flash.h>
#if (__GNUC__ == 3) && (__GNUC_MINOR__ == 2) && defined (__ARM_ARCH_4__)
#error This compiler is known to be broken. Please see:
#error http://ecos.sourceware.org/ml/ecos-patches/2003-08/msg00006.html
#endif
@@ -38,396 +37,399 @@
// Filesystem operations
static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte);
static int jffs2_umount(cyg_mtab_entry * mte);
static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
- int mode, cyg_file * fte);
+ int mode, cyg_file * fte);
+#ifdef CYGOPT_FS_JFFS2_WRITE
static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir,
- const char *name);
+ const char *name);
static int jffs2_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name);
static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name);
static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1,
- const char *name1, cyg_dir dir2, const char *name2);
+ const char *name1, cyg_dir dir2, const char *name2);
static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1,
- cyg_dir dir2, const char *name2, int type);
+ cyg_dir dir2, const char *name2, int type);
+#endif
static int jffs2_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
- cyg_file * fte);
+ cyg_file * fte);
static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
- cyg_dir * dir_out);
+ cyg_dir * dir_out);
static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
- struct stat *buf);
+ struct stat *buf);
static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
- int key, void *buf, int len);
+ int key, void *buf, int len);
static int jffs2_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
- int key, void *buf, int len);
+ int key, void *buf, int len);
// File operations
static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
+#ifdef CYGOPT_FS_JFFS2_WRITE
static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
+#endif
static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence);
static int jffs2_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
- CYG_ADDRWORD data);
+ CYG_ADDRWORD data);
static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode);
static int jffs2_fo_close(struct CYG_FILE_TAG *fp);
static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf);
static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
- int len);
+ int len);
static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
- int len);
+ int len);
// Directory operations
static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence);
+
+static int jffs2_read_inode (struct _inode *inode);
+static void jffs2_clear_inode (struct _inode *inode);
+
//==========================================================================
// Filesystem table entries
// -------------------------------------------------------------------------
// Fstab entry.
// This defines the entry in the filesystem table.
// For simplicity we use _FILESYSTEM synchronization for all accesses since
// we should never block in any filesystem operations.
+#ifdef CYGOPT_FS_JFFS2_WRITE
+FSTAB_ENTRY(jffs2_fste, "jffs2", 0,
+ CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILE,
+ jffs2_mount,
+ jffs2_umount,
+ jffs2_open,
+ jffs2_ops_unlink,
+ jffs2_ops_mkdir,
+ jffs2_ops_rmdir,
+ jffs2_ops_rename,
+ jffs2_ops_link,
+ jffs2_opendir,
+ jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo);
+#else
FSTAB_ENTRY(jffs2_fste, "jffs2", 0,
- CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILESYSTEM,
- jffs2_mount,
- jffs2_umount,
- jffs2_open,
- jffs2_ops_unlink,
- jffs2_ops_mkdir,
- jffs2_ops_rmdir,
- jffs2_ops_rename,
- jffs2_ops_link,
- jffs2_opendir,
- jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo);
+ CYG_SYNCMODE_FILE_FILESYSTEM | CYG_SYNCMODE_IO_FILE,
+ jffs2_mount,
+ jffs2_umount,
+ jffs2_open,
+ (cyg_fsop_unlink *)cyg_fileio_erofs,
+ (cyg_fsop_mkdir *)cyg_fileio_erofs,
+ (cyg_fsop_rmdir *)cyg_fileio_erofs,
+ (cyg_fsop_rename *)cyg_fileio_erofs,
+ (cyg_fsop_link *)cyg_fileio_erofs,
+ jffs2_opendir,
+ jffs2_chdir, jffs2_stat, jffs2_getinfo, jffs2_setinfo);
+#endif
// -------------------------------------------------------------------------
// File operations.
// This set of file operations are used for normal open files.
static cyg_fileops jffs2_fileops = {
- jffs2_fo_read,
- jffs2_fo_write,
- jffs2_fo_lseek,
- jffs2_fo_ioctl,
- cyg_fileio_seltrue,
- jffs2_fo_fsync,
- jffs2_fo_close,
- jffs2_fo_fstat,
- jffs2_fo_getinfo,
- jffs2_fo_setinfo
+ jffs2_fo_read,
+#ifdef CYGOPT_FS_JFFS2_WRITE
+ jffs2_fo_write,
+#else
+ (cyg_fileop_write *) cyg_fileio_erofs,
+#endif
+ jffs2_fo_lseek,
+ jffs2_fo_ioctl,
+ cyg_fileio_seltrue,
+ jffs2_fo_fsync,
+ jffs2_fo_close,
+ jffs2_fo_fstat,
+ jffs2_fo_getinfo,
+ jffs2_fo_setinfo
};
// -------------------------------------------------------------------------
// Directory file operations.
// This set of operations are used for open directories. Most entries
// point to error-returning stub functions. Only the read, lseek and
// close entries are functional.
static cyg_fileops jffs2_dirops = {
- jffs2_fo_dirread,
- (cyg_fileop_write *) cyg_fileio_enosys,
- jffs2_fo_dirlseek,
- (cyg_fileop_ioctl *) cyg_fileio_enosys,
- cyg_fileio_seltrue,
- (cyg_fileop_fsync *) cyg_fileio_enosys,
- jffs2_fo_close,
- (cyg_fileop_fstat *) cyg_fileio_enosys,
- (cyg_fileop_getinfo *) cyg_fileio_enosys,
- (cyg_fileop_setinfo *) cyg_fileio_enosys
+ jffs2_fo_dirread,
+ (cyg_fileop_write *) cyg_fileio_enosys,
+ jffs2_fo_dirlseek,
+ (cyg_fileop_ioctl *) cyg_fileio_enosys,
+ cyg_fileio_seltrue,
+ (cyg_fileop_fsync *) cyg_fileio_enosys,
+ jffs2_fo_close,
+ (cyg_fileop_fstat *) cyg_fileio_enosys,
+ (cyg_fileop_getinfo *) cyg_fileio_enosys,
+ (cyg_fileop_setinfo *) cyg_fileio_enosys
};
//==========================================================================
// STATIC VARIABLES !!!
-static char read_write_buffer[PAGE_CACHE_SIZE]; //avoids malloc when user may be under memory pressure
-static char gc_buffer[PAGE_CACHE_SIZE]; //avoids malloc when user may be under memory pressure
+static unsigned char gc_buffer[PAGE_CACHE_SIZE]; //avoids malloc when user may be under memory pressure
static unsigned char n_fs_mounted = 0; // a counter to track the number of jffs2 instances mounted
//==========================================================================
// Directory operations
struct jffs2_dirsearch {
- struct inode *dir; // directory to search
- const char *path; // path to follow
- struct inode *node; // Node found
- const char *name; // last name fragment used
- int namelen; // name fragment length
- cyg_bool last; // last name in path?
+ struct _inode *dir; // directory to search
+ const char *path; // path to follow
+ struct _inode *node; // Node found
+ const char *name; // last name fragment used
+ int namelen; // name fragment length
+ cyg_bool last; // last name in path?
};
typedef struct jffs2_dirsearch jffs2_dirsearch;
//==========================================================================
// Ref count and nlink management
-// -------------------------------------------------------------------------
-// dec_refcnt()
-// Decrment the reference count on an inode. If this makes the ref count
-// zero, then this inode can be freed.
-
-static int dec_refcnt(struct inode *node)
-{
- int err = ENOERR;
- node->i_count--;
-
- // In JFFS2 inode's are temporary in ram structures that are free'd when the usage i_count drops to 0
- // The i_nlink however is managed by JFFS2 and is unrelated to usage
- if (node->i_count == 0) {
- // This inode is not in use, so delete it.
- iput(node);
- }
-
- return err;
-}
// FIXME: This seems like real cruft. Wouldn't it be better just to do the
// right thing?
-static void icache_evict(struct inode *root_i, struct inode *i)
+static void icache_evict(struct _inode *root_i, struct _inode *i)
{
- struct inode *cached_inode;
- struct inode *next_inode;
+ struct _inode *this = root_i, *next;
- D2(printf("icache_evict\n"));
- // If this is an absolute search path from the root,
- // remove all cached inodes with i_count of zero (these are only
- // held where needed for dotdot filepaths)
- if (i == root_i) {
- for (cached_inode = root_i; cached_inode != NULL;
- cached_inode = next_inode) {
- next_inode = cached_inode->i_cache_next;
- if (cached_inode->i_count == 0) {
- cached_inode->i_cache_prev->i_cache_next = cached_inode->i_cache_next; // Previous entry points ahead of us
- if (cached_inode->i_cache_next != NULL)
- cached_inode->i_cache_next->i_cache_prev = cached_inode->i_cache_prev; // Next entry points behind us
- jffs2_clear_inode(cached_inode);
- D2(printf
- ("free icache_evict inode %x $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n",
- cached_inode));
- free(cached_inode);
- }
- }
- }
+ restart:
+ D2(printf("icache_evict\n"));
+ // If this is an absolute search path from the root,
+ // remove all cached inodes with i_count of zero (these are only
+ // held where needed for dotdot filepaths)
+ while (this) {
+ next = this->i_cache_next;
+ if (this != i && this->i_count == 0) {
+ struct _inode *parent = this->i_parent;
+ if (this->i_cache_next)
+ this->i_cache_next->i_cache_prev = this->i_cache_prev;
+ if (this->i_cache_prev)
+ this->i_cache_prev->i_cache_next = this->i_cache_next;
+ jffs2_clear_inode(this);
+ memset(this, 0x5a, sizeof(*this));
+ free(this);
+ if (parent && parent != this) {
+ parent->i_count--;
+ this = root_i;
+ goto restart;
+ }
+ }
+ this = next;
+ }
}
//==========================================================================
// Directory search
// -------------------------------------------------------------------------
// init_dirsearch()
// Initialize a dirsearch object to start a search
static void init_dirsearch(jffs2_dirsearch * ds,
- struct inode *dir, const char *name)
+ struct _inode *dir, const char *name)
{
- D2(printf("init_dirsearch name = %s\n", name));
- D2(printf("init_dirsearch dir = %x\n", dir));
- ds->dir = dir;
- ds->path = name;
- ds->node = dir;
- ds->name = name;
- ds->namelen = 0;
- ds->last = false;
+ D2(printf("init_dirsearch name = %s\n", name));
+ D2(printf("init_dirsearch dir = %x\n", dir));
+
+ dir->i_count++;
+ ds->dir = dir;
+ ds->path = name;
+ ds->node = dir;
+ ds->name = name;
+ ds->namelen = 0;
+ ds->last = false;
}
// -------------------------------------------------------------------------
// find_entry()
// Search a single directory for the next name in a path and update the
// dirsearch object appropriately.
static int find_entry(jffs2_dirsearch * ds)
{
- unsigned long hash;
- struct qstr this;
- unsigned int c;
- const char *hashname;
-
- struct inode *dir = ds->dir;
- const char *name = ds->path;
- const char *n = name;
- char namelen = 0;
- struct inode *d;
-
- D2(printf("find_entry\n"));
-
- // check that we really have a directory
- if (!S_ISDIR(dir->i_mode))
- return ENOTDIR;
-
- // Isolate the next element of the path name.
- while (*n != '\0' && *n != '/')
- n++, namelen++;
-
- // If we terminated on a NUL, set last flag.
- if (*n == '\0')
- ds->last = true;
-
- // update name in dirsearch object
- ds->name = name;
- ds->namelen = namelen;
-
- if (name[0] == '.')
- switch (namelen) {
- default:
- break;
- case 2:
- // Dot followed by not Dot, treat as any other name
- if (name[1] != '.')
- break;
- // Dot Dot
- // Move back up the search path
- D2(printf("find_entry found ..\n"));
- ds->node = ds->dir->i_parent;
- if (ds->dir->i_count == 0) {
- iput(ds->dir); // This inode may be evicted
- ds->dir = NULL;
- }
- return ENOERR;
- case 1:
- // Dot is consumed
- D2(printf("find_entry found .\n"));
- ds->node = ds->dir;
- return ENOERR;
- }
- // Here we have the name and its length set up.
- // Search the directory for a matching entry
-
- hashname = name;
- this.name = hashname;
- c = *(const unsigned char *) hashname;
-
- hash = init_name_hash();
- do {
- hashname++;
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *) hashname;
- } while (c && (c != '/'));
- this.len = hashname - (const char *) this.name;
- this.hash = end_name_hash(hash);
-
- D2(printf("find_entry for name = %s\n", ds->path));
- d = jffs2_lookup(dir, &this);
- D2(printf("find_entry got dir = %x\n", d));
-
- if (d == NULL)
- return ENOENT;
-
- // The back path for dotdot to follow
- d->i_parent = dir;
- // pass back the node we have found
- ds->node = d;
-
- return ENOERR;
+ struct _inode *dir = ds->dir;
+ const char *name = ds->path;
+ const char *n = name;
+ char namelen = 0;
+ struct _inode *d;
+
+ D2(printf("find_entry\n"));
+
+ // check that we really have a directory
+ if (!S_ISDIR(dir->i_mode))
+ return ENOTDIR;
+
+ // Isolate the next element of the path name.
+ while (*n != '\0' && *n != '/')
+ n++, namelen++;
+
+ // If we terminated on a NUL, set last flag.
+ if (*n == '\0')
+ ds->last = true;
+
+ // update name in dirsearch object
+ ds->name = name;
+ ds->namelen = namelen;
+
+ if (name[0] == '.')
+ switch (namelen) {
+ default:
+ break;
+ case 2:
+ // Dot followed by not Dot, treat as any other name
+ if (name[1] != '.')
+ break;
+ // Dot Dot
+ // Move back up the search path
+ D2(printf("find_entry found ..\n"));
+ ds->dir = ds->node;
+ ds->node = ds->dir->i_parent;
+ ds->node->i_count++;
+ return ENOERR;
+ case 1:
+ // Dot is consumed
+ D2(printf("find_entry found .\n"));
+ ds->node = ds->dir;
+ ds->dir->i_count++;
+ return ENOERR;
+ }
+
+ // Here we have the name and its length set up.
+ // Search the directory for a matching entry
+
+ D2(printf("find_entry for name = %s\n", ds->path));
+ d = jffs2_lookup(dir, name, namelen);
+ D2(printf("find_entry got dir = %x\n", d));
+
+ if (d == NULL)
+ return ENOENT;
+
+ // If it's a new directory inode, increase refcount on its parent
+ if (S_ISDIR(d->i_mode) && !d->i_parent) {
+ d->i_parent = dir;
+ dir->i_count++;
+ }
+
+ // pass back the node we have found
+ ds->node = d;
+ return ENOERR;
}
// -------------------------------------------------------------------------
// jffs2_find()
// Main interface to directory search code. This is used in all file
// level operations to locate the object named by the pathname.
+// Returns with use count incremented on both the sought object and
+// the directory it was found in
static int jffs2_find(jffs2_dirsearch * d)
{
- int err;
+ int err;
- D2(printf("jffs2_find for path =%s\n", d->path));
- // Short circuit empty paths
- if (*(d->path) == '\0')
- return ENOERR;
-
- // iterate down directory tree until we find the object
- // we want.
- for (;;) {
- err = find_entry(d);
-
- if (err != ENOERR)
- return err;
-
- if (d->last)
- return ENOERR;
-
- // every inode traversed in the find is temporary and should be free'd
- //iput(d->dir);
-
- // Update dirsearch object to search next directory.
- d->dir = d->node;
- d->path += d->namelen;
- if (*(d->path) == '/')
- d->path++; // skip dirname separators
- }
+ D2(printf("jffs2_find for path =%s\n", d->path));
+
+ // Short circuit empty paths
+ if (*(d->path) == '\0') {
+ d->node->i_count++;
+ return ENOERR;
+ }
+
+ // iterate down directory tree until we find the object
+ // we want.
+ for (;;) {
+ err = find_entry(d);
+
+ if (err != ENOERR)
+ return err;
+
+ if (d->last)
+ return ENOERR;
+
+ /* We're done with it, although it we found a subdir that
+ will have caused the refcount to have been increased */
+ jffs2_iput(d->dir);
+
+ // Update dirsearch object to search next directory.
+ d->dir = d->node;
+ d->path += d->namelen;
+ if (*(d->path) == '/')
+ d->path++; // skip dirname separators
+ }
}
//==========================================================================
// Pathconf support
// This function provides support for pathconf() and fpathconf().
-static int jffs2_pathconf(struct inode *node, struct cyg_pathconf_info *info)
+static int jffs2_pathconf(struct _inode *node, struct cyg_pathconf_info *info)
{
- int err = ENOERR;
- D2(printf("jffs2_pathconf\n"));
+ int err = ENOERR;
+ D2(printf("jffs2_pathconf\n"));
- switch (info->name) {
- case _PC_LINK_MAX:
- info->value = LINK_MAX;
- break;
-
- case _PC_MAX_CANON:
- info->value = -1; // not supported
- err = EINVAL;
- break;
-
- case _PC_MAX_INPUT:
- info->value = -1; // not supported
- err = EINVAL;
- break;
-
- case _PC_NAME_MAX:
- info->value = NAME_MAX;
- break;
-
- case _PC_PATH_MAX:
- info->value = PATH_MAX;
- break;
-
- case _PC_PIPE_BUF:
- info->value = -1; // not supported
- err = EINVAL;
- break;
-
- case _PC_ASYNC_IO:
- info->value = -1; // not supported
- err = EINVAL;
- break;
-
- case _PC_CHOWN_RESTRICTED:
- info->value = -1; // not supported
- err = EINVAL;
- break;
-
- case _PC_NO_TRUNC:
- info->value = 0;
- break;
-
- case _PC_PRIO_IO:
- info->value = 0;
- break;
-
- case _PC_SYNC_IO:
- info->value = 0;
- break;
-
- case _PC_VDISABLE:
- info->value = -1; // not supported
- err = EINVAL;
- break;
-
- default:
- err = EINVAL;
- break;
- }
+ switch (info->name) {
+ case _PC_LINK_MAX:
+ info->value = LINK_MAX;
+ break;
+
+ case _PC_MAX_CANON:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_MAX_INPUT:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_NAME_MAX:
+ info->value = NAME_MAX;
+ break;
+
+ case _PC_PATH_MAX:
+ info->value = PATH_MAX;
+ break;
+
+ case _PC_PIPE_BUF:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_ASYNC_IO:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_CHOWN_RESTRICTED:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_NO_TRUNC:
+ info->value = 0;
+ break;
+
+ case _PC_PRIO_IO:
+ info->value = 0;
+ break;
+
+ case _PC_SYNC_IO:
+ info->value = 0;
+ break;
+
+ case _PC_VDISABLE:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ default:
+ err = EINVAL;
+ break;
+ }
- return err;
+ return err;
}
//==========================================================================
// Filesystem operations
@@ -435,787 +437,756 @@ static int jffs2_pathconf(struct inode *
// jffs2_mount()
// Process a mount request. This mainly creates a root for the
// filesystem.
static int jffs2_read_super(struct super_block *sb)
{
- struct jffs2_sb_info *c;
- struct inode *root_i;
- Cyg_ErrNo err;
- cyg_uint32 len;
- cyg_io_flash_getconfig_devsize_t ds;
- cyg_io_flash_getconfig_blocksize_t bs;
-
- D1(printk(KERN_DEBUG "jffs2: read_super\n"));
-
- c = JFFS2_SB_INFO(sb);
-
- len = sizeof (ds);
- err = cyg_io_get_config(sb->s_dev,
- CYG_IO_GET_CONFIG_FLASH_DEVSIZE, &ds, &len);
- if (err != ENOERR) {
- D1(printf
- ("jffs2: cyg_io_get_config failed to get dev size: %d\n",
- err));
- return err;
- }
- len = sizeof (bs);
- bs.offset = 0;
- err = cyg_io_get_config(sb->s_dev,
- CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE, &bs, &len);
- if (err != ENOERR) {
- D1(printf
- ("jffs2: cyg_io_get_config failed to get block size: %d\n",
- err));
- return err;
- }
+ struct jffs2_sb_info *c;
+ Cyg_ErrNo err;
+ cyg_uint32 len;
+ cyg_io_flash_getconfig_devsize_t ds;
+ cyg_io_flash_getconfig_blocksize_t bs;
+
+ D1(printk(KERN_DEBUG "jffs2: read_super\n"));
+
+ c = JFFS2_SB_INFO(sb);
+
+ len = sizeof (ds);
+ err = cyg_io_get_config(sb->s_dev,
+ CYG_IO_GET_CONFIG_FLASH_DEVSIZE, &ds, &len);
+ if (err != ENOERR) {
+ D1(printf
+ ("jffs2: cyg_io_get_config failed to get dev size: %d\n",
+ err));
+ return err;
+ }
+ len = sizeof (bs);
+ bs.offset = 0;
+ err = cyg_io_get_config(sb->s_dev,
+ CYG_IO_GET_CONFIG_FLASH_BLOCKSIZE, &bs, &len);
+ if (err != ENOERR) {
+ D1(printf
+ ("jffs2: cyg_io_get_config failed to get block size: %d\n",
+ err));
+ return err;
+ }
+
+ c->sector_size = bs.block_size;
+ c->flash_size = ds.dev_size;
+ c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
+
+ err = jffs2_do_mount_fs(c);
+ if (err)
+ return -err;
+
+ D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
+ sb->s_root = jffs2_iget(sb, 1);
+ if (IS_ERR(sb->s_root)) {
+ D1(printk(KERN_WARNING "get root inode failed\n"));
+ err = PTR_ERR(sb->s_root);
+ sb->s_root = NULL;
+ goto out_nodes;
+ }
- c->sector_size = bs.block_size;
- c->flash_size = ds.dev_size;
- c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
-
- err = jffs2_do_mount_fs(c);
- if (err)
- return -err;
-
- D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n"));
- root_i = iget(sb, 1);
- if (is_bad_inode(root_i)) {
- D1(printk(KERN_WARNING "get root inode failed\n"));
- err = EIO;
- goto out_nodes;
- }
+ return 0;
- D1(printk(KERN_DEBUG "jffs2_read_super(): d_alloc_root()\n"));
- sb->s_root = d_alloc_root(root_i);
- if (!sb->s_root) {
- err = ENOMEM;
- goto out_root_i;
- }
- sb->s_blocksize = PAGE_CACHE_SIZE;
- sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
- sb->s_magic = JFFS2_SUPER_MAGIC;
-
- return 0;
-
- out_root_i:
- iput(root_i);
out_nodes:
- jffs2_free_ino_caches(c);
- jffs2_free_raw_node_refs(c);
- free(c->blocks);
+ jffs2_free_ino_caches(c);
+ jffs2_free_raw_node_refs(c);
+ free(c->blocks);
- return err;
+ return err;
}
static int jffs2_mount(cyg_fstab_entry * fste, cyg_mtab_entry * mte)
{
- extern cyg_mtab_entry cyg_mtab[], cyg_mtab_end;
- struct super_block *jffs2_sb = NULL;
- struct jffs2_sb_info *c;
- cyg_mtab_entry *m;
- cyg_io_handle_t t;
- Cyg_ErrNo err;
-
- D2(printf("jffs2_mount\n"));
-
- err = cyg_io_lookup(mte->devname, &t);
- if (err != ENOERR)
- return -err;
-
- // Iterate through the mount table to see if we're mounted
- // FIXME: this should be done better - perhaps if the superblock
- // can be stored as an inode in the icache.
- for (m = &cyg_mtab[0]; m != &cyg_mtab_end; m++) {
- // stop if there are more than the configured maximum
- if (m - &cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX) {
- m = &cyg_mtab_end;
- break;
- }
- if (m->valid && strcmp(m->fsname, "jffs2") == 0 &&
- strcmp(m->devname, mte->devname) == 0) {
- jffs2_sb = (struct super_block *) m->data;
- }
- }
-
- if (jffs2_sb == NULL) {
- jffs2_sb = malloc(sizeof (struct super_block));
-
- if (jffs2_sb == NULL)
- return ENOMEM;
-
- c = JFFS2_SB_INFO(jffs2_sb);
- memset(jffs2_sb, 0, sizeof (struct super_block));
- jffs2_sb->s_dev = t;
-
- c->inocache_list = malloc(sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE);
- if (!c->inocache_list) {
- free(jffs2_sb);
- return ENOMEM;
- }
- memset(c->inocache_list, 0, sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE);
+ extern cyg_mtab_entry cyg_mtab[], cyg_mtab_end;
+ struct super_block *jffs2_sb = NULL;
+ struct jffs2_sb_info *c;
+ cyg_mtab_entry *m;
+ cyg_io_handle_t t;
+ Cyg_ErrNo err;
+
+ D2(printf("jffs2_mount\n"));
+
+ err = cyg_io_lookup(mte->devname, &t);
+ if (err != ENOERR)
+ return -err;
+
+ // Iterate through the mount table to see if we're mounted
+ // FIXME: this should be done better - perhaps if the superblock
+ // can be stored as an inode in the icache.
+ for (m = &cyg_mtab[0]; m != &cyg_mtab_end; m++) {
+ // stop if there are more than the configured maximum
+ if (m - &cyg_mtab[0] >= CYGNUM_FILEIO_MTAB_MAX) {
+ m = &cyg_mtab_end;
+ break;
+ }
+ if (m->valid && strcmp(m->fsname, "jffs2") == 0 &&
+ strcmp(m->devname, mte->devname) == 0) {
+ jffs2_sb = (struct super_block *) m->data;
+ }
+ }
+
+ if (jffs2_sb == NULL) {
+ jffs2_sb = malloc(sizeof (struct super_block));
+
+ if (jffs2_sb == NULL)
+ return ENOMEM;
+
+ c = JFFS2_SB_INFO(jffs2_sb);
+ memset(jffs2_sb, 0, sizeof (struct super_block));
+ jffs2_sb->s_dev = t;
+
+ c->inocache_list = malloc(sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE);
+ if (!c->inocache_list) {
+ free(jffs2_sb);
+ return ENOMEM;
+ }
+ memset(c->inocache_list, 0, sizeof(struct jffs2_inode_cache *) * INOCACHE_HASHSIZE);
if (n_fs_mounted++ == 0)
jffs2_create_slab_caches(); // No error check, cannot fail
- err = jffs2_read_super(jffs2_sb);
+ err = jffs2_read_super(jffs2_sb);
- if (err) {
+ if (err) {
if (--n_fs_mounted == 0)
jffs2_destroy_slab_caches();
- free(jffs2_sb);
- free(c->inocache_list);
- return err;
- }
-
- jffs2_sb->s_root->i_parent = jffs2_sb->s_root; // points to itself, no dotdot paths above mountpoint
- jffs2_sb->s_root->i_cache_prev = NULL; // root inode, so always null
- jffs2_sb->s_root->i_cache_next = NULL;
- jffs2_sb->s_root->i_count = 1; // Ensures the root inode is always in ram until umount
-
- D2(printf("jffs2_mount erasing pending blocks\n"));
- jffs2_erase_pending_blocks(c,0);
- }
- mte->data = (CYG_ADDRWORD) jffs2_sb;
+ free(jffs2_sb);
+ free(c->inocache_list);
+ return err;
+ }
+
+ jffs2_sb->s_root->i_parent = jffs2_sb->s_root; // points to itself, no dotdot paths above mountpoint
+ jffs2_sb->s_root->i_cache_prev = NULL; // root inode, so always null
+ jffs2_sb->s_root->i_cache_next = NULL;
+ jffs2_sb->s_root->i_count = 1; // Ensures the root inode is always in ram until umount
+
+ D2(printf("jffs2_mount erasing pending blocks\n"));
+#ifdef CYGOPT_FS_JFFS2_WRITE
+ if (!jffs2_is_readonly(c))
+ jffs2_erase_pending_blocks(c,0);
+#endif
+#ifdef CYGOPT_FS_JFFS2_GCTHREAD
+ jffs2_start_garbage_collect_thread(c);
+#endif
+ }
+ mte->data = (CYG_ADDRWORD) jffs2_sb;
- jffs2_sb->s_mount_count++;
- mte->root = (cyg_dir) jffs2_sb->s_root;
- D2(printf("jffs2_mounted superblock at %x\n", mte->root));
+ jffs2_sb->s_mount_count++;
+ mte->root = (cyg_dir) jffs2_sb->s_root;
+ D2(printf("jffs2_mounted superblock at %x\n", mte->root));
- return ENOERR;
+ return ENOERR;
}
+extern cyg_dir cyg_cdir_dir;
+extern cyg_mtab_entry *cyg_cdir_mtab_entry;
+
// -------------------------------------------------------------------------
// jffs2_umount()
// Unmount the filesystem.
static int jffs2_umount(cyg_mtab_entry * mte)
{
- struct inode *root = (struct inode *) mte->root;
- struct super_block *jffs2_sb = root->i_sb;
- struct jffs2_sb_info *c = JFFS2_SB_INFO(jffs2_sb);
-
- D2(printf("jffs2_umount\n"));
-
- // Only really umount if this is the only mount
- if (jffs2_sb->s_mount_count == 1) {
-
- if (root->i_cache_next != NULL) // root icount was set to 1 on mount
- return EBUSY;
-
- dec_refcnt(root); // Time to free the root inode
-
- //Clear root inode
- //root_i = NULL;
-
- // Clean up the super block and root inode
- jffs2_free_ino_caches(c);
- jffs2_free_raw_node_refs(c);
- free(c->blocks);
- free(c->inocache_list);
- free(jffs2_sb);
- // Clear superblock & root pointer
- mte->root = CYG_DIR_NULL;
+ struct _inode *root = (struct _inode *) mte->root;
+ struct super_block *jffs2_sb = root->i_sb;
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(jffs2_sb);
+
+ D2(printf("jffs2_umount\n"));
+
+ // Only really umount if this is the only mount
+ if (jffs2_sb->s_mount_count == 1) {
+ icache_evict(root, NULL);
+ if (root->i_cache_next != NULL) {
+ struct _inode *inode = root;
+ printf("Refuse to unmount.\n");
+ while (inode) {
+ printf("Ino #%u has use count %d\n",
+ inode->i_ino, inode->i_count);
+ inode = inode->i_cache_next;
+ }
+ // root icount was set to 1 on mount
+ return EBUSY;
+ }
+ if (root->i_count == 2 &&
+ cyg_cdir_mtab_entry == mte &&
+ cyg_cdir_dir == (cyg_dir)root &&
+ !strcmp(mte->name, "/")) {
+ /* If we were mounted on root, there's no
+ way for the cwd to change out and free
+ the file system for unmounting. So we hack
+ it -- if cwd is '/' we unset it. Perhaps
+ we should allow chdir(NULL) to unset
+ cyg_cdir_dir? */
+ cyg_cdir_dir = CYG_DIR_NULL;
+ jffs2_iput(root);
+ }
+ /* Argh. The fileio code sets this; never clears it */
+ if (cyg_cdir_mtab_entry == mte)
+ cyg_cdir_mtab_entry = NULL;
+
+ if (root->i_count != 1) {
+ printf("Ino #1 has use count %d\n",
+ root->i_count);
+ return EBUSY;
+ }
+#ifdef CYGOPT_FS_JFFS2_GCTHREAD
+ jffs2_stop_garbage_collect_thread(c);
+#endif
+ jffs2_iput(root); // Time to free the root inode
+ free(root);
+ //Clear root inode
+ //root_i = NULL;
+
+ // Clean up the super block and root inode
+ jffs2_free_ino_caches(c);
+ jffs2_free_raw_node_refs(c);
+ free(c->blocks);
+ free(c->inocache_list);
+ free(jffs2_sb);
+ // Clear superblock & root pointer
+ mte->root = CYG_DIR_NULL;
mte->data = 0;
- mte->fs->data = 0; // fstab entry, visible to all mounts. No current mount
- // That's all folks.
- D2(printf("jffs2_umount No current mounts\n"));
- } else {
- jffs2_sb->s_mount_count--;
+ mte->fs->data = 0; // fstab entry, visible to all mounts. No current mount
+ // That's all folks.
+ D2(printf("jffs2_umount No current mounts\n"));
+ } else {
+ jffs2_sb->s_mount_count--;
}
if (--n_fs_mounted == 0)
jffs2_destroy_slab_caches();
- return ENOERR;
+ return ENOERR;
}
// -------------------------------------------------------------------------
// jffs2_open()
// Open a file for reading or writing.
static int jffs2_open(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
- int mode, cyg_file * file)
+ int mode, cyg_file * file)
{
- jffs2_dirsearch ds;
- struct inode *node = NULL;
- int err;
-
- D2(printf("jffs2_open\n"));
-
- icache_evict((struct inode *) mte->root, (struct inode *) dir);
-
- init_dirsearch(&ds, (struct inode *) dir, name);
-
- err = jffs2_find(&ds);
+ jffs2_dirsearch ds;
+ struct _inode *node = NULL;
+ int err;
- if (err == ENOENT) {
- if (ds.last && (mode & O_CREAT)) {
- unsigned long hash;
- struct qstr this;
- unsigned int c;
- const char *hashname;
+ D2(printf("jffs2_open\n"));
- // No node there, if the O_CREAT bit is set then we must
- // create a new one. The dir and name fields of the dirsearch
- // object will have been updated so we know where to put it.
+ /* If no chdir has been called and we were the first file system
+ mounted, we get called with dir == NULL. Deal with it */
+ if (!dir)
+ dir = mte->root;
- hashname = ds.name;
- this.name = hashname;
- c = *(const unsigned char *) hashname;
-
- hash = init_name_hash();
- do {
- hashname++;
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *) hashname;
- } while (c && (c != '/'));
- this.len = hashname - (const char *) this.name;
- this.hash = end_name_hash(hash);
-
- err = jffs2_create(ds.dir, &this, S_IRUGO|S_IXUGO|S_IWUSR|S_IFREG, &node);
-
- if (err != 0) {
- //Possible orphaned inode on the flash - but will be gc'd
- return err;
- }
-
- err = ENOERR;
- }
- } else if (err == ENOERR) {
- // The node exists. If the O_CREAT and O_EXCL bits are set, we
- // must fail the open.
-
- if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
- err = EEXIST;
- else
- node = ds.node;
- }
+#ifndef CYGOPT_FS_JFFS2_WRITE
+ if (mode & (O_CREAT|O_TRUNC|O_WRONLY))
+ return EROFS;
+#endif
+ init_dirsearch(&ds, (struct _inode *) dir, name);
- if (err == ENOERR && (mode & O_TRUNC)) {
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(node);
- struct jffs2_sb_info *c = JFFS2_SB_INFO(node->i_sb);
- // If the O_TRUNC bit is set we must clean out the file data.
-
- node->i_size = 0;
- jffs2_truncate_fraglist(c, &f->fragtree, 0);
- // Update file times
- node->i_ctime = node->i_mtime = cyg_timestamp();
- }
+ err = jffs2_find(&ds);
- if (err != ENOERR)
- return err;
+ if (err == ENOENT) {
+#ifdef CYGOPT_FS_JFFS2_WRITE
+ if (ds.last && (mode & O_CREAT)) {
- // Check that we actually have a file here
- if (S_ISDIR(node->i_mode))
- return EISDIR;
+ // No node there, if the O_CREAT bit is set then we must
+ // create a new one. The dir and name fields of the dirsearch
+ // object will have been updated so we know where to put it.
- node->i_count++; // Count successful open
+ err = jffs2_create(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR|S_IFREG, &node);
- // Initialize the file object
+ if (err != 0) {
+ //Possible orphaned inode on the flash - but will be gc'd
+ return err;
+ }
- file->f_flag |= mode & CYG_FILE_MODE_MASK;
- file->f_type = CYG_FILE_TYPE_FILE;
- file->f_ops = &jffs2_fileops;
- file->f_offset = (mode & O_APPEND) ? node->i_size : 0;
- file->f_data = (CYG_ADDRWORD) node;
- file->f_xops = 0;
+ err = ENOERR;
+ }
+#endif
+ } else if (err == ENOERR) {
+ // The node exists. If the O_CREAT and O_EXCL bits are set, we
+ // must fail the open.
+
+ if ((mode & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) {
+ jffs2_iput(ds.node);
+ err = EEXIST;
+ } else
+ node = ds.node;
+ }
+
+ // Finished with the directory now
+ jffs2_iput(ds.dir);
+
+ if (err != ENOERR)
+ return err;
+
+ // Check that we actually have a file here
+ if (S_ISDIR(node->i_mode)) {
+ jffs2_iput(node);
+ return EISDIR;
+ }
+
+#ifndef CYGOPT_FS_JFFS2_WRITE
+ if (mode & O_TRUNC) {
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(node);
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(node->i_sb);
+ // If the O_TRUNC bit is set we must clean out the file data.
+
+ node->i_size = 0;
+ jffs2_truncate_fraglist(c, &f->fragtree, 0);
+ // Update file times
+ node->i_ctime = node->i_mtime = cyg_timestamp();
+ }
+#endif
+ // Initialise the file object
+ file->f_flag |= mode & CYG_FILE_MODE_MASK;
+ file->f_type = CYG_FILE_TYPE_FILE;
+ file->f_ops = &jffs2_fileops;
+ file->f_offset = (mode & O_APPEND) ? node->i_size : 0;
+ file->f_data = (CYG_ADDRWORD) node;
+ file->f_xops = 0;
- return ENOERR;
+ return ENOERR;
}
+#ifdef CYGOPT_FS_JFFS2_WRITE
// -------------------------------------------------------------------------
// jffs2_ops_unlink()
// Remove a file link from its directory.
static int jffs2_ops_unlink(cyg_mtab_entry * mte, cyg_dir dir, const char *name)
{
- unsigned long hash;
- struct qstr this;
- unsigned int c;
- const char *hashname;
- jffs2_dirsearch ds;
- int err;
-
- D2(printf("jffs2_ops_unlink\n"));
+ jffs2_dirsearch ds;
+ int err;
- icache_evict((struct inode *) mte->root, (struct inode *) dir);
+ D2(printf("jffs2_ops_unlink\n"));
- init_dirsearch(&ds, (struct inode *) dir, name);
+ init_dirsearch(&ds, (struct _inode *) dir, name);
- err = jffs2_find(&ds);
+ err = jffs2_find(&ds);
- if (err != ENOERR)
- return err;
+ if (err != ENOERR) {
+ jffs2_iput(ds.dir);
+ return err;
+ }
- // Cannot unlink directories, use rmdir() instead
- if (S_ISDIR(ds.node->i_mode))
- return EPERM;
+ // Cannot unlink directories, use rmdir() instead
+ if (S_ISDIR(ds.node->i_mode)) {
+ jffs2_iput(ds.dir);
+ jffs2_iput(ds.node);
+ return EPERM;
+ }
- // Delete it from its directory
+ // Delete it from its directory
- hashname = ds.name;
- this.name = hashname;
- c = *(const unsigned char *) hashname;
+ err = jffs2_unlink(ds.dir, ds.node, ds.name);
+ jffs2_iput(ds.dir);
+ jffs2_iput(ds.node);
- hash = init_name_hash();
- do {
- hashname++;
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *) hashname;
- } while (c && (c != '/'));
- this.len = hashname - (const char *) this.name;
- this.hash = end_name_hash(hash);
-
- err = jffs2_unlink(ds.dir, ds.node, &this);
-
- return err;
+ return -err;
}
// -------------------------------------------------------------------------
// jffs2_ops_mkdir()
// Create a new directory.
static int jffs2_ops_mkdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name)
{
- jffs2_dirsearch ds;
- struct inode *node = NULL;
- int err;
-
- D2(printf("jffs2_ops_mkdir\n"));
-
- icache_evict((struct inode *) mte->root, (struct inode *) dir);
-
- init_dirsearch(&ds, (struct inode *) dir, name);
-
- err = jffs2_find(&ds);
-
- if (err == ENOENT) {
- if (ds.last) {
- unsigned long hash;
- struct qstr this;
- unsigned int c;
- const char *hashname;
- // The entry does not exist, and it is the last element in
- // the pathname, so we can create it here.
-
- hashname = ds.name;
- this.name = hashname;
- c = *(const unsigned char *) hashname;
-
- hash = init_name_hash();
- do {
- hashname++;
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *) hashname;
- } while (c && (c != '/'));
- this.len = hashname - (const char *) this.name;
- this.hash = end_name_hash(hash);
+ jffs2_dirsearch ds;
+ int err;
- err = jffs2_mkdir(ds.dir, &this, 0, &node);
+ D2(printf("jffs2_ops_mkdir\n"));
- if (err != 0)
- return ENOSPC;
+ init_dirsearch(&ds, (struct _inode *) dir, name);
- }
- // If this was not the last element, then and intermediate
- // directory does not exist.
- } else {
- // If there we no error, something already exists with that
- // name, so we cannot create another one.
-
- if (err == ENOERR)
- err = EEXIST;
- }
+ err = jffs2_find(&ds);
- return err;
+ if (err == ENOENT) {
+ if (ds.last) {
+ // The entry does not exist, and it is the last element in
+ // the pathname, so we can create it here.
+
+ err = -jffs2_mkdir(ds.dir, ds.name, S_IRUGO|S_IXUGO|S_IWUSR);
+ }
+ // If this was not the last element, then an intermediate
+ // directory does not exist.
+ } else {
+ // If there we no error, something already exists with that
+ // name, so we cannot create another one.
+ jffs2_iput(ds.node);
+ if (err == ENOERR)
+ err = EEXIST;
+ }
+ jffs2_iput(ds.dir);
+ return err;
}
// -------------------------------------------------------------------------
// jffs2_ops_rmdir()
// Remove a directory.
static int jffs2_ops_rmdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name)
{
- unsigned long hash;
- struct qstr this;
- unsigned int c;
- const char *hashname;
- jffs2_dirsearch ds;
- int err;
+ jffs2_dirsearch ds;
+ int err;
- D2(printf("jffs2_ops_rmdir\n"));
+ D2(printf("jffs2_ops_rmdir\n"));
- icache_evict((struct inode *) mte->root, (struct inode *) dir);
+ init_dirsearch(&ds, (struct _inode *) dir, name);
- init_dirsearch(&ds, (struct inode *) dir, name);
+ err = jffs2_find(&ds);
- err = jffs2_find(&ds);
+ if (err != ENOERR) {
+ jffs2_iput(ds.dir);
+ return err;
+ }
- if (err != ENOERR)
- return err;
+ // Check that this is actually a directory.
+ if (!S_ISDIR(ds.node->i_mode)) {
+ jffs2_iput(ds.dir);
+ jffs2_iput(ds.node);
+ return EPERM;
+ }
- // Check that this is actually a directory.
- if (!S_ISDIR(ds.node->i_mode))
- return EPERM;
+ err = jffs2_rmdir(ds.dir, ds.node, ds.name);
- // Delete the entry.
- hashname = ds.name;
- this.name = hashname;
- c = *(const unsigned char *) hashname;
-
- hash = init_name_hash();
- do {
- hashname++;
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *) hashname;
- } while (c && (c != '/'));
- this.len = hashname - (const char *) this.name;
- this.hash = end_name_hash(hash);
-
- err = jffs2_rmdir(ds.dir, ds.node, &this);
-
- return err;
-
- return ENOERR;
+ jffs2_iput(ds.dir);
+ jffs2_iput(ds.node);
+ return -err;
}
// -------------------------------------------------------------------------
// jffs2_ops_rename()
// Rename a file/dir.
static int jffs2_ops_rename(cyg_mtab_entry * mte, cyg_dir dir1,
- const char *name1, cyg_dir dir2, const char *name2)
+ const char *name1, cyg_dir dir2, const char *name2)
{
- unsigned long hash;
- struct qstr this1, this2;
- unsigned int c;
- const char *hashname;
- jffs2_dirsearch ds1, ds2;
- int err;
-
- D2(printf("jffs2_ops_rename\n"));
-
- init_dirsearch(&ds1, (struct inode *) dir1, name1);
-
- err = jffs2_find(&ds1);
-
- if (err != ENOERR)
- return err;
-
- init_dirsearch(&ds2, (struct inode *) dir2, name2);
-
- err = jffs2_find(&ds2);
-
- // Allow through renames to non-existent objects.
- if (ds2.last && err == ENOENT)
- ds2.node = NULL, err = ENOERR;
-
- if (err != ENOERR)
- return err;
-
- // Null rename, just return
- if (ds1.node == ds2.node)
- return ENOERR;
-
- hashname = ds1.name;
- this1.name = hashname;
- c = *(const unsigned char *) hashname;
-
- hash = init_name_hash();
- do {
- hashname++;
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *) hashname;
- } while (c && (c != '/'));
- this1.len = hashname - (const char *) this1.name;
- this1.hash = end_name_hash(hash);
-
- hashname = ds2.name;
- this2.name = hashname;
- c = *(const unsigned char *) hashname;
-
- hash = init_name_hash();
- do {
- hashname++;
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *) hashname;
- } while (c && (c != '/'));
- this2.len = hashname - (const char *) this2.name;
- this2.hash = end_name_hash(hash);
-
- // First deal with any entry that is at the destination
- if (ds2.node) {
- // Check that we are renaming like-for-like
-
- if (!S_ISDIR(ds1.node->i_mode) && S_ISDIR(ds2.node->i_mode))
- return EISDIR;
-
- if (S_ISDIR(ds1.node->i_mode) && !S_ISDIR(ds2.node->i_mode))
- return ENOTDIR;
-
- // Now delete the destination directory entry
+ jffs2_dirsearch ds1, ds2;
+ int err;
- err = jffs2_unlink(ds2.dir, ds2.node, &this2);
+ D2(printf("jffs2_ops_rename\n"));
- if (err != 0)
- return err;
+ init_dirsearch(&ds1, (struct _inode *) dir1, name1);
- }
- // Now we know that there is no clashing node at the destination,
- // make a new direntry at the destination and delete the old entry
- // at the source.
-
- err = jffs2_rename(ds1.dir, ds1.node, &this1, ds2.dir, &this2);
-
- // Update directory times
- if (err == 0)
- ds1.dir->i_ctime =
- ds1.dir->i_mtime =
- ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
-
- return err;
+ err = jffs2_find(&ds1);
+
+ if (err != ENOERR) {
+ jffs2_iput(ds1.dir);
+ return err;
+ }
+
+ init_dirsearch(&ds2, (struct _inode *) dir2, name2);
+
+ err = jffs2_find(&ds2);
+
+ // Allow through renames to non-existent objects.
+ if (ds2.last && err == ENOENT) {
+ ds2.node = NULL;
+ err = ENOERR;
+ }
+
+ if (err != ENOERR) {
+ jffs2_iput(ds1.dir);
+ jffs2_iput(ds1.node);
+ jffs2_iput(ds2.dir);
+ return err;
+ }
+
+ // Null rename, just return
+ if (ds1.node == ds2.node) {
+ err = ENOERR;
+ goto out;
+ }
+
+ // First deal with any entry that is at the destination
+ if (ds2.node) {
+ // Check that we are renaming like-for-like
+
+ if (!S_ISDIR(ds1.node->i_mode) && S_ISDIR(ds2.node->i_mode)) {
+ err = EISDIR;
+ goto out;
+ }
+
+ if (S_ISDIR(ds1.node->i_mode) && !S_ISDIR(ds2.node->i_mode)) {
+ err = ENOTDIR;
+ goto out;
+ }
+
+ // Now delete the destination directory entry
+ /* Er, what happened to atomicity of rename()? */
+ err = -jffs2_unlink(ds2.dir, ds2.node, ds2.name);
+
+ if (err != 0)
+ goto out;
+
+ }
+ // Now we know that there is no clashing node at the destination,
+ // make a new direntry at the destination and delete the old entry
+ // at the source.
+
+ err = -jffs2_rename(ds1.dir, ds1.node, ds1.name, ds2.dir, ds2.name);
+
+ // Update directory times
+ if (!err)
+ ds1.dir->i_ctime =
+ ds1.dir->i_mtime =
+ ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
+ out:
+ jffs2_iput(ds1.dir);
+ jffs2_iput(ds1.node);
+ if (S_ISDIR(ds1.node->i_mode)) {
+ /* Renamed a directory to elsewhere... so fix up its
+ i_parent pointer and the i_counts of its old and
+ new parents. */
+ jffs2_iput(ds1.node->i_parent);
+ ds1.node->i_parent = ds2.dir;
+ /* We effectively increase its use count by not... */
+ } else {
+ jffs2_iput(ds2.dir); /* ... doing this */
+ }
+ if (ds2.node)
+ jffs2_iput(ds2.node);
+
+ return -err;
}
// -------------------------------------------------------------------------
// jffs2_ops_link()
// Make a new directory entry for a file.
static int jffs2_ops_link(cyg_mtab_entry * mte, cyg_dir dir1, const char *name1,
- cyg_dir dir2, const char *name2, int type)
+ cyg_dir dir2, const char *name2, int type)
{
- unsigned long hash;
- struct qstr this;
- unsigned int c;
- const char *hashname;
- jffs2_dirsearch ds1, ds2;
- int err;
-
- D2(printf("jffs2_ops_link\n"));
+ jffs2_dirsearch ds1, ds2;
+ int err;
- // Only do hard links for now in this filesystem
- if (type != CYG_FSLINK_HARD)
- return EINVAL;
+ D2(printf("jffs2_ops_link\n"));
- init_dirsearch(&ds1, (struct inode *) dir1, name1);
+ // Only do hard links for now in this filesystem
+ if (type != CYG_FSLINK_HARD)
+ return EINVAL;
- err = jffs2_find(&ds1);
+ init_dirsearch(&ds1, (struct _inode *) dir1, name1);
- if (err != ENOERR)
- return err;
+ err = jffs2_find(&ds1);
- init_dirsearch(&ds2, (struct inode *) dir2, name2);
+ if (err != ENOERR) {
+ jffs2_iput(ds1.dir);
+ return err;
+ }
- err = jffs2_find(&ds2);
+ init_dirsearch(&ds2, (struct _inode *) dir2, name2);
- // Don't allow links to existing objects
- if (err == ENOERR)
- return EEXIST;
+ err = jffs2_find(&ds2);
- // Allow through links to non-existing terminal objects
- if (ds2.last && err == ENOENT)
- ds2.node = NULL, err = ENOERR;
+ // Don't allow links to existing objects
+ if (err == ENOERR) {
+ jffs2_iput(ds1.dir);
+ jffs2_iput(ds1.node);
+ jffs2_iput(ds2.dir);
+ jffs2_iput(ds2.node);
+ return EEXIST;
+ }
- if (err != ENOERR)
- return err;
+ // Allow through links to non-existing terminal objects
+ if (ds2.last && err == ENOENT) {
+ jffs2_iput(ds2.node);
+ ds2.node = NULL;
+ err = ENOERR;
+ }
- // Now we know that there is no existing node at the destination,
- // make a new direntry at the destination.
+ if (err != ENOERR) {
+ jffs2_iput(ds1.dir);
+ jffs2_iput(ds1.node);
+ jffs2_iput(ds2.dir);
+ return err;
+ }
- hashname = ds2.name;
- this.name = hashname;
- c = *(const unsigned char *) hashname;
+ // Now we know that there is no existing node at the destination,
+ // make a new direntry at the destination.
- hash = init_name_hash();
- do {
- hashname++;
- hash = partial_name_hash(c, hash);
- c = *(const unsigned char *) hashname;
- } while (c && (c != '/'));
- this.len = hashname - (const char *) this.name;
- this.hash = end_name_hash(hash);
+ err = jffs2_link(ds1.node, ds2.dir, ds2.name);
- err = jffs2_link(ds1.node, ds2.dir, &this);
+ if (err == 0)
+ ds1.node->i_ctime =
+ ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
- if (err == 0)
- ds1.node->i_ctime =
- ds2.dir->i_ctime = ds2.dir->i_mtime = cyg_timestamp();
+ jffs2_iput(ds1.dir);
+ jffs2_iput(ds1.node);
+ jffs2_iput(ds2.dir);
- return err;
+ return -err;
}
-
+#endif /* CYGOPT_FS_JFFS2_WRITE */
// -------------------------------------------------------------------------
// jffs2_opendir()
// Open a directory for reading.
static int jffs2_opendir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
- cyg_file * file)
+ cyg_file * file)
{
- jffs2_dirsearch ds;
- int err;
-
- D2(printf("jffs2_opendir\n"));
+ jffs2_dirsearch ds;
+ int err;
- icache_evict((struct inode *) mte->root, (struct inode *) dir);
+ D2(printf("jffs2_opendir\n"));
- init_dirsearch(&ds, (struct inode *) dir, name);
+ init_dirsearch(&ds, (struct _inode *) dir, name);
- err = jffs2_find(&ds);
+ err = jffs2_find(&ds);
- if (err != ENOERR)
- return err;
+ jffs2_iput(ds.dir);
- // check it is really a directory.
- if (!S_ISDIR(ds.node->i_mode))
- return ENOTDIR;
+ if (err != ENOERR)
+ return err;
- ds.node->i_count++; // Count successful open
+ // check it is really a directory.
+ if (!S_ISDIR(ds.node->i_mode)) {
+ jffs2_iput(ds.node);
+ return ENOTDIR;
+ }
- // Initialize the file object, setting the f_ops field to a
- // special set of file ops.
+ // Initialize the file object, setting the f_ops field to a
+ // special set of file ops.
- file->f_type = CYG_FILE_TYPE_FILE;
- file->f_ops = &jffs2_dirops;
- file->f_offset = 0;
- file->f_data = (CYG_ADDRWORD) ds.node;
- file->f_xops = 0;
+ file->f_type = CYG_FILE_TYPE_FILE;
+ file->f_ops = &jffs2_dirops;
+ file->f_offset = 0;
+ file->f_data = (CYG_ADDRWORD) ds.node;
+ file->f_xops = 0;
- return ENOERR;
+ return ENOERR;
}
// -------------------------------------------------------------------------
// jffs2_chdir()
// Change directory support.
static int jffs2_chdir(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
- cyg_dir * dir_out)
+ cyg_dir * dir_out)
{
- D2(printf("jffs2_chdir\n"));
-
- if (dir_out != NULL) {
- // This is a request to get a new directory pointer in
- // *dir_out.
+ D2(printf("jffs2_chdir\n"));
- jffs2_dirsearch ds;
- int err;
+ if (dir_out != NULL) {
+ // This is a request to get a new directory pointer in
+ // *dir_out.
- icache_evict((struct inode *) mte->root, (struct inode *) dir);
+ jffs2_dirsearch ds;
+ int err;
- init_dirsearch(&ds, (struct inode *) dir, name);
+ init_dirsearch(&ds, (struct _inode *) dir, name);
- err = jffs2_find(&ds);
+ err = jffs2_find(&ds);
+ jffs2_iput(ds.dir);
- if (err != ENOERR)
- return err;
+ if (err != ENOERR)
+ return err;
- // check it is a directory
- if (!S_ISDIR(ds.node->i_mode))
- return ENOTDIR;
+ // check it is a directory
+ if (!S_ISDIR(ds.node->i_mode))
+ return ENOTDIR;
- // Increment ref count to keep this directory in existance
- // while it is the current cdir.
- ds.node->i_count++;
+ // Pass it out
+ *dir_out = (cyg_dir) ds.node;
+ } else {
+ // If no output dir is required, this means that the mte and
+ // dir arguments are the current cdir setting and we should
+ // forget this fact.
- // Pass it out
- *dir_out = (cyg_dir) ds.node;
- } else {
- // If no output dir is required, this means that the mte and
- // dir arguments are the current cdir setting and we should
- // forget this fact.
+ struct _inode *node = (struct _inode *) dir;
- struct inode *node = (struct inode *) dir;
+ // Just decrement directory reference count.
+ jffs2_iput(node);
+ }
- // Just decrement directory reference count.
- dec_refcnt(node);
- }
-
- return ENOERR;
+ return ENOERR;
}
// -------------------------------------------------------------------------
// jffs2_stat()
// Get struct stat info for named object.
static int jffs2_stat(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
- struct stat *buf)
+ struct stat *buf)
{
- jffs2_dirsearch ds;
- int err;
-
- D2(printf("jffs2_stat\n"));
+ jffs2_dirsearch ds;
+ int err;
- icache_evict((struct inode *) mte->root, (struct inode *) dir);
+ D2(printf("jffs2_stat\n"));
- init_dirsearch(&ds, (struct inode *) dir, name);
+ init_dirsearch(&ds, (struct _inode *) dir, name);
- err = jffs2_find(&ds);
+ err = jffs2_find(&ds);
+ jffs2_iput(ds.dir);
- if (err != ENOERR)
- return err;
+ if (err != ENOERR)
+ return err;
- // Fill in the status
- buf->st_mode = ds.node->i_mode;
- buf->st_ino = ds.node->i_ino;
- buf->st_dev = 0;
- buf->st_nlink = ds.node->i_nlink;
- buf->st_uid = 0;
- buf->st_gid = 0;
- buf->st_size = ds.node->i_size;
- buf->st_atime = ds.node->i_atime;
- buf->st_mtime = ds.node->i_mtime;
- buf->st_ctime = ds.node->i_ctime;
+ // Fill in the status
+ buf->st_mode = ds.node->i_mode;
+ buf->st_ino = ds.node->i_ino;
+ buf->st_dev = 0;
+ buf->st_nlink = ds.node->i_nlink;
+ buf->st_uid = ds.node->i_uid;
+ buf->st_gid = ds.node->i_gid;
+ buf->st_size = ds.node->i_size;
+ buf->st_atime = ds.node->i_atime;
+ buf->st_mtime = ds.node->i_mtime;
+ buf->st_ctime = ds.node->i_ctime;
- return err;
+ jffs2_iput(ds.node);
- return ENOERR;
+ return ENOERR;
}
// -------------------------------------------------------------------------
// jffs2_getinfo()
// Getinfo. Currently only support pathconf().
static int jffs2_getinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
- int key, void *buf, int len)
+ int key, void *buf, int len)
{
- jffs2_dirsearch ds;
- int err;
+ jffs2_dirsearch ds;
+ int err;
- D2(printf("jffs2_getinfo\n"));
+ D2(printf("jffs2_getinfo\n"));
- icache_evict((struct inode *) mte->root, (struct inode *) dir);
+ init_dirsearch(&ds, (struct _inode *) dir, name);
- init_dirsearch(&ds, (struct inode *) dir, name);
+ err = jffs2_find(&ds);
+ jffs2_iput(ds.dir);
- err = jffs2_find(&ds);
+ if (err != ENOERR)
+ return err;
- if (err != ENOERR)
- return err;
+ switch (key) {
+ case FS_INFO_CONF:
+ err = jffs2_pathconf(ds.node, (struct cyg_pathconf_info *) buf);
+ break;
- switch (key) {
- case FS_INFO_CONF:
- err = jffs2_pathconf(ds.node, (struct cyg_pathconf_info *) buf);
- break;
-
- default:
- err = EINVAL;
- }
- return err;
+ default:
+ err = EINVAL;
+ }
- return ENOERR;
+ jffs2_iput(ds.node);
+ return err;
}
// -------------------------------------------------------------------------
// jffs2_setinfo()
// Setinfo. Nothing to support here at present.
static int jffs2_setinfo(cyg_mtab_entry * mte, cyg_dir dir, const char *name,
- int key, void *buf, int len)
+ int key, void *buf, int len)
{
- // No setinfo keys supported at present
+ // No setinfo keys supported at present
- D2(printf("jffs2_setinfo\n"));
+ D2(printf("jffs2_setinfo\n"));
- return EINVAL;
+ return EINVAL;
}
//==========================================================================
// File operations
@@ -1223,305 +1194,342 @@ static int jffs2_setinfo(cyg_mtab_entry
// jffs2_fo_read()
// Read data from the file.
static int jffs2_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
- struct inode *inode = (struct inode *) fp->f_data;
- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
- int i;
- ssize_t resid = uio->uio_resid;
- off_t pos = fp->f_offset;
-
- down(&f->sem);
-
- // Loop over the io vectors until there are none left
- for (i = 0; i < uio->uio_iovcnt && pos < inode->i_size; i++) {
- int ret;
- cyg_iovec *iov = &uio->uio_iov[i];
- off_t len = min(iov->iov_len, inode->i_size - pos);
-
- D2(printf("jffs2_fo_read inode size %d\n", inode->i_size));
-
- ret =
- jffs2_read_inode_range(c, f,
- (unsigned char *) iov->iov_base, pos,
- len);
- if (ret) {
- D1(printf
- ("jffs2_fo_read(): read_inode_range failed %d\n",
- ret));
- uio->uio_resid = resid;
- up(&f->sem);
- return -ret;
- }
- resid -= len;
- pos += len;
- }
-
- // We successfully read some data, update the node's access time
- // and update the file offset and transfer residue.
-
- inode->i_atime = cyg_timestamp();
+ struct _inode *inode = (struct _inode *) fp->f_data;
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+ int i;
+ ssize_t resid = uio->uio_resid;
+ off_t pos = fp->f_offset;
+
+ down(&f->sem);
+
+ // Loop over the io vectors until there are none left
+ for (i = 0; i < uio->uio_iovcnt && pos < inode->i_size; i++) {
+ int ret;
+ cyg_iovec *iov = &uio->uio_iov[i];
+ off_t len = min(iov->iov_len, inode->i_size - pos);
+
+ D2(printf("jffs2_fo_read inode size %d\n", inode->i_size));
+
+ ret =
+ jffs2_read_inode_range(c, f,
+ (unsigned char *) iov->iov_base, pos,
+ len);
+ if (ret) {
+ D1(printf
+ ("jffs2_fo_read(): read_inode_range failed %d\n",
+ ret));
+ uio->uio_resid = resid;
+ up(&f->sem);
+ return -ret;
+ }
+ resid -= len;
+ pos += len;
+ }
+
+ // We successfully read some data, update the node's access time
+ // and update the file offset and transfer residue.
+
+ inode->i_atime = cyg_timestamp();
+
+ uio->uio_resid = resid;
+ fp->f_offset = pos;
- uio->uio_resid = resid;
- fp->f_offset = pos;
+ up(&f->sem);
- up(&f->sem);
-
- return ENOERR;
+ return ENOERR;
}
+
+#ifdef CYGOPT_FS_JFFS2_WRITE
// -------------------------------------------------------------------------
// jffs2_fo_write()
// Write data to file.
+static int jffs2_extend_file (struct _inode *inode, struct jffs2_raw_inode *ri,
+ unsigned long offset)
+{
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+ struct jffs2_full_dnode *fn;
+ uint32_t phys_ofs, alloc_len;
+ int ret = 0;
+
+ /* Make new hole frag from old EOF to new page */
+ D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
+ (unsigned int)inode->i_size, offset));
+
+ ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL);
+ if (ret)
+ return ret;
+
+ down(&f->sem);
+
+ ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
+ ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
+ ri->totlen = cpu_to_je32(sizeof(ri));
+ ri->hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));
+
+ ri->version = cpu_to_je32(++f->highest_version);
+ ri->isize = cpu_to_je32(max((uint32_t)inode->i_size, offset));
+
+ ri->offset = cpu_to_je32(inode->i_size);
+ ri->dsize = cpu_to_je32(offset - inode->i_size);
+ ri->csize = cpu_to_je32(0);
+ ri->compr = JFFS2_COMPR_ZERO;
+ ri->node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
+ ri->data_crc = cpu_to_je32(0);
+
+ fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
+ jffs2_complete_reservation(c);
+ if (IS_ERR(fn)) {
+ ret = PTR_ERR(fn);
+ up(&f->sem);
+ return ret;
+ }
+ ret = jffs2_add_full_dnode_to_inode(c, f, fn);
+ if (f->metadata) {
+ jffs2_mark_node_obsolete(c, f->metadata->raw);
+ jffs2_free_full_dnode(f->metadata);
+ f->metadata = NULL;
+ }
+ if (ret) {
+ D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret));
+ jffs2_mark_node_obsolete(c, fn->raw);
+ jffs2_free_full_dnode(fn);
+ up(&f->sem);
+ return ret;
+ }
+ inode->i_size = offset;
+ up(&f->sem);
+ return 0;
+}
static int jffs2_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
- struct page write_page;
- off_t page_start_pos;
- struct inode *node = (struct inode *) fp->f_data;
- off_t pos = fp->f_offset;
- ssize_t resid = uio->uio_resid;
- int i;
-
- memset(&read_write_buffer, 0, PAGE_CACHE_SIZE);
- write_page.virtual = &read_write_buffer;
-
- // If the APPEND mode bit was supplied, force all writes to
- // the end of the file.
- if (fp->f_flag & CYG_FAPPEND)
- pos = fp->f_offset = node->i_size;
-
- // Check that pos is within current file size, or at the very end.
- if (pos < 0 || pos > node->i_size)
- return EINVAL;
-
- // Now loop over the iovecs until they are all done, or
- // we get an error.
- for (i = 0; i < uio->uio_iovcnt; i++) {
- cyg_iovec *iov = &uio->uio_iov[i];
- char *buf = (char *) iov->iov_base;
- off_t len = iov->iov_len;
-
- // loop over the vector writing it to the file until it has
- // all been done.
- while (len > 0) {
- //cyg_uint8 *fbuf;
- //size_t bsize;
- size_t writtenlen;
- off_t l = len;
- int err;
-
- write_page.index = 0;
-
- page_start_pos = pos;
- while (page_start_pos >= (PAGE_CACHE_SIZE)) {
- write_page.index++;
- page_start_pos -= PAGE_CACHE_SIZE;
- }
-
- if (l > PAGE_CACHE_SIZE - page_start_pos)
- l = PAGE_CACHE_SIZE - page_start_pos;
-
- D2(printf
- ("jffs2_fo_write write_page.index %d\n",
- write_page.index));
- D2(printf
- ("jffs2_fo_write page_start_pos %d\n",
- page_start_pos));
- D2(printf("jffs2_fo_write transfer size %d\n", l));
-
- err =
- jffs2_prepare_write(node, &write_page,
- page_start_pos,
- page_start_pos + l);
-
- if (err != 0)
- return err;
-
- // copy data in
- memcpy(&read_write_buffer[page_start_pos], buf, l);
-
- writtenlen =
- jffs2_commit_write(node, &write_page,
- page_start_pos,
- page_start_pos + l);
-
- if (writtenlen != l)
- return ENOSPC;
-
- // Update working vars
- len -= l;
- buf += l;
- pos += l;
- resid -= l;
- }
- }
-
- // We wrote some data successfully, update the modified and access
- // times of the node, increase its size appropriately, and update
- // the file offset and transfer residue.
- node->i_mtime = node->i_ctime = cyg_timestamp();
- if (pos > node->i_size)
- node->i_size = pos;
+ struct _inode *inode = (struct _inode *) fp->f_data;
+ off_t pos = fp->f_offset;
+ ssize_t resid = uio->uio_resid;
+ struct jffs2_raw_inode ri;
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
+ int i;
+
+ // If the APPEND mode bit was supplied, force all writes to
+ // the end of the file.
+ if (fp->f_flag & CYG_FAPPEND)
+ pos = fp->f_offset = inode->i_size;
+
+ if (pos < 0)
+ return EINVAL;
+
+ memset(&ri, 0, sizeof(ri));
+
+ ri.ino = cpu_to_je32(f->inocache->ino);
+ ri.mode = cpu_to_jemode(inode->i_mode);
+ ri.uid = cpu_to_je16(inode->i_uid);
+ ri.gid = cpu_to_je16(inode->i_gid);
+ ri.atime = ri.ctime = ri.mtime = cpu_to_je32(cyg_timestamp());
+
+ if (pos > inode->i_size) {
+ int err;
+ ri.version = cpu_to_je32(++f->highest_version);
+ err = jffs2_extend_file(inode, &ri, pos);
+ if (err)
+ return -err;
+ }
+
+ // Now loop over the iovecs until they are all done, or
+ // we get an error.
+ for (i = 0; i < uio->uio_iovcnt; i++) {
+ cyg_iovec *iov = &uio->uio_iov[i];
+ char *buf = (char *) iov->iov_base;
+ off_t len = iov->iov_len;
+
+ uint32_t writtenlen;
+ int err;
+
+ D2(printf("jffs2_fo_write page_start_pos %d\n", pos));
+ D2(printf("jffs2_fo_write transfer size %d\n", l));
+
+ err = jffs2_write_inode_range(c, f, &ri, buf,
+ pos, len, &writtenlen);
+ if (err)
+ return -err;
+
+ if (writtenlen != len)
+ return ENOSPC;
+
+ pos += len;
+ resid -= len;
+ }
+
+ // We wrote some data successfully, update the modified and access
+ // times of the inode, increase its size appropriately, and update
+ // the file offset and transfer residue.
+ inode->i_mtime = inode->i_ctime = je32_to_cpu(ri.mtime);
+ if (pos > inode->i_size)
+ inode->i_size = pos;
- uio->uio_resid = resid;
- fp->f_offset = pos;
+ uio->uio_resid = resid;
+ fp->f_offset = pos;
- return ENOERR;
+ return ENOERR;
}
+#endif /* CYGOPT_FS_JFFS2_WRITE */
// -------------------------------------------------------------------------
// jffs2_fo_lseek()
// Seek to a new file position.
static int jffs2_fo_lseek(struct CYG_FILE_TAG *fp, off_t * apos, int whence)
{
- struct inode *node = (struct inode *) fp->f_data;
- off_t pos = *apos;
-
- D2(printf("jffs2_fo_lseek\n"));
+ struct _inode *node = (struct _inode *) fp->f_data;
+ off_t pos = *apos;
- switch (whence) {
- case SEEK_SET:
- // Pos is already where we want to be.
- break;
-
- case SEEK_CUR:
- // Add pos to current offset.
- pos += fp->f_offset;
- break;
-
- case SEEK_END:
- // Add pos to file size.
- pos += node->i_size;
- break;
+ D2(printf("jffs2_fo_lseek\n"));
- default:
- return EINVAL;
- }
-
- // Check that pos is still within current file size, or at the
- // very end.
- if (pos < 0 || pos > node->i_size)
- return EINVAL;
+ switch (whence) {
+ case SEEK_SET:
+ // Pos is already where we want to be.
+ break;
+
+ case SEEK_CUR:
+ // Add pos to current offset.
+ pos += fp->f_offset;
+ break;
+
+ case SEEK_END:
+ // Add pos to file size.
+ pos += node->i_size;
+ break;
+
+ default:
+ return EINVAL;
+ }
+
+ // Check that pos is still within current file size, or at the
+ // very end.
+ if (pos < 0 || pos > node->i_size)
+ return EINVAL;
- // All OK, set fp offset and return new position.
- *apos = fp->f_offset = pos;
+ // All OK, set fp offset and return new position.
+ *apos = fp->f_offset = pos;
- return ENOERR;
+ return ENOERR;
}
// -------------------------------------------------------------------------
// jffs2_fo_ioctl()
// Handle ioctls. Currently none are defined.
static int jffs2_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
- CYG_ADDRWORD data)
+ CYG_ADDRWORD data)
{
- // No Ioctls currenly defined.
+ // No Ioctls currenly defined.
- D2(printf("jffs2_fo_ioctl\n"));
+ D2(printf("jffs2_fo_ioctl\n"));
- return EINVAL;
+ return EINVAL;
}
// -------------------------------------------------------------------------
// jffs2_fo_fsync().
// Force the file out to data storage.
static int jffs2_fo_fsync(struct CYG_FILE_TAG *fp, int mode)
{
- // Data is always permanently where it belongs, nothing to do
- // here.
+ // Data is always permanently where it belongs, nothing to do
+ // here.
- D2(printf("jffs2_fo_fsync\n"));
+ D2(printf("jffs2_fo_fsync\n"));
- return ENOERR;
+ return ENOERR;
}
// -------------------------------------------------------------------------
// jffs2_fo_close()
// Close a file. We just decrement the refcnt and let it go away if
// that is all that is keeping it here.
static int jffs2_fo_close(struct CYG_FILE_TAG *fp)
{
- struct inode *node = (struct inode *) fp->f_data;
+ struct _inode *node = (struct _inode *) fp->f_data;
- D2(printf("jffs2_fo_close\n"));
+ D2(printf("jffs2_fo_close\n"));
- dec_refcnt(node);
+ jffs2_iput(node);
- fp->f_data = 0; // zero data pointer
+ fp->f_data = 0; // zero data pointer
- return ENOERR;
+ return ENOERR;
}
// -------------------------------------------------------------------------
//jffs2_fo_fstat()
// Get file status.
static int jffs2_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf)
{
- struct inode *node = (struct inode *) fp->f_data;
+ struct _inode *node = (struct _inode *) fp->f_data;
- D2(printf("jffs2_fo_fstat\n"));
+ D2(printf("jffs2_fo_fstat\n"));
- // Fill in the status
- buf->st_mode = node->i_mode;
- buf->st_ino = node->i_ino;
- buf->st_dev = 0;
- buf->st_nlink = node->i_nlink;
- buf->st_uid = 0;
- buf->st_gid = 0;
- buf->st_size = node->i_size;
- buf->st_atime = node->i_atime;
- buf->st_mtime = node->i_mtime;
- buf->st_ctime = node->i_ctime;
+ // Fill in the status
+ buf->st_mode = node->i_mode;
+ buf->st_ino = node->i_ino;
+ buf->st_dev = 0;
+ buf->st_nlink = node->i_nlink;
+ buf->st_uid = node->i_uid;
+ buf->st_gid = node->i_gid;
+ buf->st_size = node->i_size;
+ buf->st_atime = node->i_atime;
+ buf->st_mtime = node->i_mtime;
+ buf->st_ctime = node->i_ctime;
- return ENOERR;
+ return ENOERR;
}
// -------------------------------------------------------------------------
// jffs2_fo_getinfo()
// Get info. Currently only supports fpathconf().
static int jffs2_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
- int len)
+ int len)
{
- struct inode *node = (struct inode *) fp->f_data;
- int err;
+ struct _inode *node = (struct _inode *) fp->f_data;
+ int err;
- D2(printf("jffs2_fo_getinfo\n"));
+ D2(printf("jffs2_fo_getinfo\n"));
- switch (key) {
- case FS_INFO_CONF:
- err = jffs2_pathconf(node, (struct cyg_pathconf_info *) buf);
- break;
+ switch (key) {
+ case FS_INFO_CONF:
+ err = jffs2_pathconf(node, (struct cyg_pathconf_info *) buf);
+ break;
- default:
- err = EINVAL;
- }
- return err;
+ default:
+ err = EINVAL;
+ }
+ return err;
- return ENOERR;
+ return ENOERR;
}
// -------------------------------------------------------------------------
// jffs2_fo_setinfo()
// Set info. Nothing supported here.
static int jffs2_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf,
- int len)
+ int len)
{
- // No setinfo key supported at present
+ // No setinfo key supported at present
- D2(printf("jffs2_fo_setinfo\n"));
+ D2(printf("jffs2_fo_setinfo\n"));
- return ENOERR;
+ return ENOERR;
}
//==========================================================================
// Directory operations
@@ -1529,456 +1537,288 @@ static int jffs2_fo_setinfo(struct CYG_F
// jffs2_fo_dirread()
// Read a single directory entry from a file.
static __inline void filldir(char *nbuf, int nlen, const char *name, int namlen)
{
- int len = nlen < namlen ? nlen : namlen;
- memcpy(nbuf, name, len);
- nbuf[len] = '\0';
+ int len = nlen < namlen ? nlen : namlen;
+ memcpy(nbuf, name, len);
+ nbuf[len] = '\0';
}
static int jffs2_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
- struct inode *d_inode = (struct inode *) fp->f_data;
- struct dirent *ent = (struct dirent *) uio->uio_iov[0].iov_base;
- char *nbuf = ent->d_name;
- int nlen = sizeof (ent->d_name) - 1;
- off_t len = uio->uio_iov[0].iov_len;
- struct jffs2_inode_info *f;
- struct jffs2_sb_info *c;
- struct inode *inode = d_inode;
- struct jffs2_full_dirent *fd;
- unsigned long offset, curofs;
- int found = 1;
-
- if (len < sizeof (struct dirent))
- return EINVAL;
-
- D1(printk
- (KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", d_inode->i_ino));
-
- f = JFFS2_INODE_INFO(inode);
- c = JFFS2_SB_INFO(inode->i_sb);
-
- offset = fp->f_offset;
-
- if (offset == 0) {
- D1(printk
- (KERN_DEBUG "Dirent 0: \".\", ino #%lu\n", inode->i_ino));
- filldir(nbuf, nlen, ".", 1);
- goto out;
- }
- if (offset == 1) {
- filldir(nbuf, nlen, "..", 2);
- goto out;
- }
-
- curofs = 1;
- down(&f->sem);
- for (fd = f->dents; fd; fd = fd->next) {
-
- curofs++;
- /* First loop: curofs = 2; offset = 2 */
- if (curofs < offset) {
- D2(printk
- (KERN_DEBUG
- "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
- fd->name, fd->ino, fd->type, curofs, offset));
- continue;
- }
- if (!fd->ino) {
- D2(printk
- (KERN_DEBUG "Skipping deletion dirent \"%s\"\n",
- fd->name));
- offset++;
- continue;
- }
- D2(printk
- (KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset,
- fd->name, fd->ino, fd->type));
- filldir(nbuf, nlen, fd->name, strlen(fd->name));
- goto out_sem;
- }
- /* Reached the end of the directory */
- found = 0;
+ struct _inode *d_inode = (struct _inode *) fp->f_data;
+ struct dirent *ent = (struct dirent *) uio->uio_iov[0].iov_base;
+ char *nbuf = ent->d_name;
+ int nlen = sizeof (ent->d_name) - 1;
+ off_t len = uio->uio_iov[0].iov_len;
+ struct jffs2_inode_info *f;
+ struct jffs2_sb_info *c;
+ struct _inode *inode = d_inode;
+ struct jffs2_full_dirent *fd;
+ unsigned long offset, curofs;
+ int found = 1;
+
+ if (len < sizeof (struct dirent))
+ return EINVAL;
+
+ D1(printk
+ (KERN_DEBUG "jffs2_readdir() for dir_i #%lu\n", d_inode->i_ino));
+
+ f = JFFS2_INODE_INFO(inode);
+ c = JFFS2_SB_INFO(inode->i_sb);
+
+ offset = fp->f_offset;
+
+ if (offset == 0) {
+ D1(printk
+ (KERN_DEBUG "Dirent 0: \".\", ino #%lu\n", inode->i_ino));
+ filldir(nbuf, nlen, ".", 1);
+ goto out;
+ }
+ if (offset == 1) {
+ filldir(nbuf, nlen, "..", 2);
+ goto out;
+ }
+
+ curofs = 1;
+ down(&f->sem);
+ for (fd = f->dents; fd; fd = fd->next) {
+
+ curofs++;
+ /* First loop: curofs = 2; offset = 2 */
+ if (curofs < offset) {
+ D2(printk
+ (KERN_DEBUG
+ "Skipping dirent: \"%s\", ino #%u, type %d, because curofs %ld < offset %ld\n",
+ fd->name, fd->ino, fd->type, curofs, offset));
+ continue;
+ }
+ if (!fd->ino) {
+ D2(printk
+ (KERN_DEBUG "Skipping deletion dirent \"%s\"\n",
+ fd->name));
+ offset++;
+ continue;
+ }
+ D2(printk
+ (KERN_DEBUG "Dirent %ld: \"%s\", ino #%u, type %d\n", offset,
+ fd->name, fd->ino, fd->type));
+ filldir(nbuf, nlen, fd->name, strlen(fd->name));
+ goto out_sem;
+ }
+ /* Reached the end of the directory */
+ found = 0;
out_sem:
- up(&f->sem);
+ up(&f->sem);
out:
- fp->f_offset = ++offset;
- if (found) {
- uio->uio_resid -= sizeof (struct dirent);
- }
- return ENOERR;
+ fp->f_offset = ++offset;
+ if (found) {
+ uio->uio_resid -= sizeof (struct dirent);
+ }
+ return ENOERR;
}
// -------------------------------------------------------------------------
// jffs2_fo_dirlseek()
// Seek directory to start.
static int jffs2_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t * pos, int whence)
{
- // Only allow SEEK_SET to zero
+ // Only allow SEEK_SET to zero
- D2(printf("jffs2_fo_dirlseek\n"));
+ D2(printf("jffs2_fo_dirlseek\n"));
- if (whence != SEEK_SET || *pos != 0)
- return EINVAL;
+ if (whence != SEEK_SET || *pos != 0)
+ return EINVAL;
- *pos = fp->f_offset = 0;
+ *pos = fp->f_offset = 0;
- return ENOERR;
+ return ENOERR;
}
//==========================================================================
//
// Called by JFFS2
// ===============
//
//
//==========================================================================
-struct page *read_cache_page(unsigned long index,
- int (*filler) (void *, struct page *), void *data)
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
+ struct jffs2_inode_info *f,
+ unsigned long offset,
+ unsigned long *priv)
{
- // Only called in gc.c jffs2_garbage_collect_dnode
- // but gets a real page for the specified inode
-
- int err;
- struct page *gc_page = malloc(sizeof (struct page));
+ /* FIXME: This works only with one file system mounted at a time */
+ int ret;
- printf("read_cache_page\n");
- memset(&gc_buffer, 0, PAGE_CACHE_SIZE);
-
- if (gc_page != NULL) {
- gc_page->virtual = &gc_buffer;
- gc_page->index = index;
-
- err = filler(data, gc_page);
- if (err < 0) {
- free(gc_page);
- gc_page = NULL;
- }
- }
+ ret = jffs2_read_inode_range(c, f, gc_buffer, offset, PAGE_CACHE_SIZE);
+ if (ret)
+ return ERR_PTR(ret);
- return gc_page;
+ return gc_buffer;
}
-void page_cache_release(struct page *pg)
+void jffs2_gc_release_page(struct jffs2_sb_info *c,
+ unsigned char *ptr,
+ unsigned long *priv)
{
-
- // Only called in gc.c jffs2_garbage_collect_dnode
- // but should free the page malloc'd by read_cache_page
-
- printf("page_cache_release\n");
- free(pg);
+ /* Do nothing */
}
-struct inode *new_inode(struct super_block *sb)
+static struct _inode *new_inode(struct super_block *sb)
{
- // Only called in write.c jffs2_new_inode
- // Always adds itself to inode cache
-
- struct inode *inode;
- struct inode *cached_inode;
+ // Only called in write.c jffs2_new_inode
+ // Always adds itself to inode cache
- inode = malloc(sizeof (struct inode));
- if (inode == NULL)
- return 0;
+ struct _inode *inode;
+ struct _inode *cached_inode;
- D2(printf
- ("malloc new_inode %x ####################################\n",
- inode));
+ inode = malloc(sizeof (struct _inode));
+ if (inode == NULL)
+ return 0;
- memset(inode, 0, sizeof (struct inode));
- inode->i_sb = sb;
- inode->i_ino = 1;
- inode->i_count = 0; //1; // Let ecos manage the open count
+ D2(printf
+ ("malloc new_inode %x ####################################\n",
+ inode));
- inode->i_nlink = 1; // Let JFFS2 manage the link count
- inode->i_size = 0;
+ memset(inode, 0, sizeof (struct _inode));
+ inode->i_sb = sb;
+ inode->i_ino = 1;
+ inode->i_count = 1;
+ inode->i_nlink = 1; // Let JFFS2 manage the link count
+ inode->i_size = 0;
- inode->i_cache_next = NULL; // Newest inode, about to be cached
+ inode->i_cache_next = NULL; // Newest inode, about to be cached
- // Add to the icache
- for (cached_inode = sb->s_root; cached_inode != NULL;
- cached_inode = cached_inode->i_cache_next) {
- if (cached_inode->i_cache_next == NULL) {
- cached_inode->i_cache_next = inode; // Current last in cache points to newcomer
- inode->i_cache_prev = cached_inode; // Newcomer points back to last
- break;
- }
- }
+ // Add to the icache
+ for (cached_inode = sb->s_root; cached_inode != NULL;
+ cached_inode = cached_inode->i_cache_next) {
+ if (cached_inode->i_cache_next == NULL) {
+ cached_inode->i_cache_next = inode; // Current last in cache points to newcomer
+ inode->i_cache_prev = cached_inode; // Newcomer points back to last
+ break;
+ }
+ }
- return inode;
+ return inode;
}
-struct inode *ilookup(struct super_block *sb, cyg_uint32 ino)
+
+static struct _inode *ilookup(struct super_block *sb, cyg_uint32 ino)
{
- struct inode *inode = NULL;
+ struct _inode *inode = NULL;
- D2(printf("ilookup\n"));
- // Check for this inode in the cache
- for (inode = sb->s_root; inode != NULL; inode = inode->i_cache_next) {
- if (inode->i_ino == ino) {
- inode->i_count++;
- break;
- }
- }
+ D2(printf("ilookup\n"));
+ // Check for this inode in the cache
+ for (inode = sb->s_root; inode != NULL; inode = inode->i_cache_next) {
+ if (inode->i_ino == ino) {
+ inode->i_count++;
+ break;
+ }
+ }
- return inode;
+ return inode;
}
-struct inode *iget(struct super_block *sb, cyg_uint32 ino)
+struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino)
{
+ // Called in super.c jffs2_read_super, dir.c jffs2_lookup,
+ // and gc.c jffs2_garbage_collect_pass
- // Substitute for iget drops straight through to reading the
- // inode from disk if it is not in the inode cache
+ // Must first check for cached inode
+ // If this fails let new_inode create one
- // Called in super.c jffs2_read_super, dir.c jffs2_lookup,
- // and gc.c jffs2_garbage_collect_pass
+ struct _inode *inode;
+ int err;
- // Must first check for cached inode
- // If this fails let new_inode create one
+ D2(printf("jffs2_iget\n"));
- struct inode *inode;
+ inode = ilookup(sb, ino);
+ if (inode)
+ return inode;
- D2(printf("iget\n"));
+ // Not cached, so malloc it
+ inode = new_inode(sb);
+ if (inode == NULL)
+ return 0;
- inode = ilookup(sb, ino);
- if (inode)
- return inode;
+ inode->i_ino = ino;
- // Not cached, so malloc it
- inode = new_inode(sb);
- if (inode == NULL)
- return 0;
-
- inode->i_ino = ino;
- jffs2_read_inode(inode);
- inode->i_count = 1;
- return inode;
+ err = jffs2_read_inode(inode);
+ if (err) {
+ printf("jffs2_read_inode() failed\n");
+ jffs2_iput(inode);
+ inode = NULL;
+ return ERR_PTR(err);
+ }
+ return inode;
}
-void iput(struct inode *i)
-{
-
- // Called in dec_refcnt, jffs2_find
- // (and jffs2_open and jffs2_ops_mkdir?)
- // super.c jffs2_read_super,
- // and gc.c jffs2_garbage_collect_pass
-
- struct inode *cached_inode;
-
- D2(printf
- ("free iput inode %x $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n", i));
- if (i && i->i_count) {
- /* Added by dwmw2. iget/iput in Linux track the use count,
- don't just unconditionally free it */
- printf("iput called for used inode\n");
- return;
- }
- if (i != NULL) {
- // Remove from the icache
- for (cached_inode = i->i_sb->s_root; cached_inode != NULL;
- cached_inode = cached_inode->i_cache_next) {
- if (cached_inode == i) {
- if(cached_inode->i_cache_prev != NULL) {
- cached_inode->i_cache_prev->i_cache_next = cached_inode->i_cache_next; // Previous entry points ahead of us
- if (cached_inode->i_cache_next != NULL)
- cached_inode->i_cache_next->i_cache_prev = cached_inode->i_cache_prev; // Next entry points behind us
- }
- break;
- }
- }
- // inode has been seperated from the cache
- jffs2_clear_inode(i);
- free(i);
- }
-}
+// -------------------------------------------------------------------------
+// Decrement the reference count on an inode. If this makes the ref count
+// zero, then this inode can be freed.
-static int return_EIO(void)
+void jffs2_iput(struct _inode *i)
{
- return -EIO;
+ // Called in jffs2_find
+ // (and jffs2_open and jffs2_ops_mkdir?)
+ // super.c jffs2_read_super,
+ // and gc.c jffs2_garbage_collect_pass
+ recurse:
+ if (!i) {
+ printf("jffs2_iput() called with NULL inode\n");
+ // and let it fault...
+ }
+
+ i->i_count--;
+
+ if (i->i_count < 0)
+ BUG();
+
+ if (i->i_count)
+ return;
+
+ if (!i->i_nlink) {
+ struct _inode *parent;
+
+ // Remove from the icache linked list and free immediately
+ if (i->i_cache_prev)
+ i->i_cache_prev->i_cache_next = i->i_cache_next;
+ if (i->i_cache_next)
+ i->i_cache_next->i_cache_prev = i->i_cache_prev;
+
+ parent = i->i_parent;
+ jffs2_clear_inode(i);
+ memset(i, 0x5a, sizeof(*i));
+ free(i);
+
+ if (parent && parent != i) {
+ i = parent;
+ goto recurse;
+ }
+
+ } else {
+ // Evict some _other_ inode with i_count zero, leaving
+ // this latest one in the cache for a while
+ icache_evict(i->i_sb->s_root, i);
+ }
}
-#define EIO_ERROR ((void *) (return_EIO))
-void make_bad_inode(struct inode *inode)
-{
-
- // In readinode.c JFFS2 checks whether the inode has appropriate
- // content for its marked type
-
- D2(printf("make_bad_inode\n"));
-
- inode->i_mode = S_IFREG;
- inode->i_atime = inode->i_mtime = inode->i_ctime = cyg_timestamp();
- inode->i_op = EIO_ERROR;
- inode->i_fop = EIO_ERROR;
-}
-
-int is_bad_inode(struct inode *inode)
-{
-
- // Called in super.c jffs2_read_super,
- // and gc.c jffs2_garbage_collect_pass
-
- D2(printf("is_bad_inode\n"));
-
- return (inode->i_op == EIO_ERROR);
- /*if(i == NULL)
- return 1;
- return 0; */
-}
-
-cyg_bool jffs2_flash_read(struct jffs2_sb_info * c,
- cyg_uint32 read_buffer_offset, const size_t size,
- size_t * return_size, char *write_buffer)
-{
- Cyg_ErrNo err;
- cyg_uint32 len = size;
- struct super_block *sb = OFNI_BS_2SFFJ(c);
-
- //D2(printf("FLASH READ\n"));
- //D2(printf("read address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + read_buffer_offset));
- //D2(printf("write address = %x\n", write_buffer));
- //D2(printf("size = %x\n", size));
- err = cyg_io_bread(sb->s_dev, write_buffer, &len, read_buffer_offset);
-
- *return_size = (size_t) len;
- return ((err == ENOERR) ? ENOERR : -EIO);
-}
-
-cyg_bool jffs2_flash_write(struct jffs2_sb_info * c,
- cyg_uint32 write_buffer_offset, const size_t size,
- size_t * return_size, char *read_buffer)
-{
-
- Cyg_ErrNo err;
- cyg_uint32 len = size;
- struct super_block *sb = OFNI_BS_2SFFJ(c);
-
- // D2(printf("FLASH WRITE ENABLED!!!\n"));
- // D2(printf("write address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + write_buffer_offset));
- // D2(printf("read address = %x\n", read_buffer));
- // D2(printf("size = %x\n", size));
-
- err = cyg_io_bwrite(sb->s_dev, read_buffer, &len, write_buffer_offset);
- *return_size = (size_t) len;
-
- return ((err == ENOERR) ? ENOERR : -EIO);
-}
-
-int
-jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs,
- unsigned long count, loff_t to, size_t * retlen)
-{
- unsigned long i;
- size_t totlen = 0, thislen;
- int ret = 0;
-
- for (i = 0; i < count; i++) {
- // writes need to be aligned but the data we're passed may not be
- // Observation suggests most unaligned writes are small, so we
- // optimize for that case.
-
- if (((vecs[i].iov_len & (sizeof (int) - 1))) ||
- (((unsigned long) vecs[i].
- iov_base & (sizeof (unsigned long) - 1)))) {
- // are there iov's after this one? Or is it so much we'd need
- // to do multiple writes anyway?
- if ((i + 1) < count || vecs[i].iov_len > 256) {
- // cop out and malloc
- unsigned long j;
- ssize_t sizetomalloc = 0, totvecsize = 0;
- char *cbuf, *cbufptr;
-
- for (j = i; j < count; j++)
- totvecsize += vecs[j].iov_len;
-
- // pad up in case unaligned
- sizetomalloc = totvecsize + sizeof (int) - 1;
- sizetomalloc &= ~(sizeof (int) - 1);
- cbuf = (char *) malloc(sizetomalloc);
- // malloc returns aligned memory
- if (!cbuf) {
- ret = -ENOMEM;
- goto writev_out;
- }
- cbufptr = cbuf;
- for (j = i; j < count; j++) {
- memcpy(cbufptr, vecs[j].iov_base,
- vecs[j].iov_len);
- cbufptr += vecs[j].iov_len;
- }
- ret =
- jffs2_flash_write(c, to, sizetomalloc,
- &thislen, cbuf);
- if (thislen > totvecsize) // in case it was aligned up
- thislen = totvecsize;
- totlen += thislen;
- free(cbuf);
- goto writev_out;
- } else {
- // otherwise optimize for the common case
- int buf[256 / sizeof (int)]; // int, so int aligned
- size_t lentowrite;
-
- lentowrite = vecs[i].iov_len;
- // pad up in case its unaligned
- lentowrite += sizeof (int) - 1;
- lentowrite &= ~(sizeof (int) - 1);
- memcpy(buf, vecs[i].iov_base, lentowrite);
-
- ret =
- jffs2_flash_write(c, to, lentowrite,
- &thislen, (char *) &buf);
- if (thislen > vecs[i].iov_len)
- thislen = vecs[i].iov_len;
- } // else
- } else
- ret =
- jffs2_flash_write(c, to, vecs[i].iov_len, &thislen,
- vecs[i].iov_base);
- totlen += thislen;
- if (ret || thislen != vecs[i].iov_len)
- break;
- to += vecs[i].iov_len;
- }
- writev_out:
- if (retlen)
- *retlen = totlen;
+// -------------------------------------------------------------------------
+// EOF jffs2.c
- return ret;
-}
-cyg_bool jffs2_flash_erase(struct jffs2_sb_info * c,
- struct jffs2_eraseblock * jeb)
+static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
{
- cyg_io_flash_getconfig_erase_t e;
- void *err_addr;
- Cyg_ErrNo err;
- cyg_uint32 len = sizeof (e);
- struct super_block *sb = OFNI_BS_2SFFJ(c);
-
- e.offset = jeb->offset;
- e.len = c->sector_size;
- e.err_address = &err_addr;
-
- // D2(printf("FLASH ERASE ENABLED!!!\n"));
- // D2(printf("erase address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + jeb->offset));
- // D2(printf("size = %x\n", c->sector_size));
-
- err = cyg_io_get_config(sb->s_dev, CYG_IO_GET_CONFIG_FLASH_ERASE,
- &e, &len);
-
- return (err != ENOERR || e.flasherr != 0);
+ memset(f, 0, sizeof(*f));
+ init_MUTEX_LOCKED(&f->sem);
}
-// -------------------------------------------------------------------------
-// EOF jffs2.c
-void jffs2_clear_inode (struct inode *inode)
+static void jffs2_clear_inode (struct _inode *inode)
{
/* We can forget about this inode for now - drop all
* the nodelists associated with it, etc.
*/
struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
@@ -1990,85 +1830,229 @@ void jffs2_clear_inode (struct inode *in
}
/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
fill in the raw_inode while you're at it. */
-struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri)
+struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw_inode *ri)
{
- struct inode *inode;
- struct super_block *sb = dir_i->i_sb;
- struct jffs2_sb_info *c;
- struct jffs2_inode_info *f;
- int ret;
-
- D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
-
- c = JFFS2_SB_INFO(sb);
-
- inode = new_inode(sb);
-
- if (!inode)
- return ERR_PTR(-ENOMEM);
-
- f = JFFS2_INODE_INFO(inode);
- jffs2_init_inode_info(f);
-
- memset(ri, 0, sizeof(*ri));
- /* Set OS-specific defaults for new inodes */
- ri->uid = ri->gid = cpu_to_je16(0);
- ri->mode = cpu_to_jemode(mode);
- ret = jffs2_do_new_inode (c, f, mode, ri);
- if (ret) {
- make_bad_inode(inode);
- iput(inode);
- return ERR_PTR(ret);
- }
- inode->i_nlink = 1;
- inode->i_ino = je32_to_cpu(ri->ino);
- inode->i_mode = jemode_to_cpu(ri->mode);
- inode->i_gid = je16_to_cpu(ri->gid);
- inode->i_uid = je16_to_cpu(ri->uid);
- inode->i_atime = inode->i_ctime = inode->i_mtime = cyg_timestamp();
- ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime);
-
- inode->i_size = 0;
-
- insert_inode_hash(inode);
-
- return inode;
-}
-
-
-void jffs2_read_inode (struct inode *inode)
-{
- struct jffs2_inode_info *f;
- struct jffs2_sb_info *c;
- struct jffs2_raw_inode latest_node;
- int ret;
-
- D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
-
- f = JFFS2_INODE_INFO(inode);
- c = JFFS2_SB_INFO(inode->i_sb);
-
- jffs2_init_inode_info(f);
-
- ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
-
- if (ret) {
- make_bad_inode(inode);
- up(&f->sem);
- return;
- }
- inode->i_mode = jemode_to_cpu(latest_node.mode);
- inode->i_uid = je16_to_cpu(latest_node.uid);
- inode->i_gid = je16_to_cpu(latest_node.gid);
- inode->i_size = je32_to_cpu(latest_node.isize);
- inode->i_atime = je32_to_cpu(latest_node.atime);
- inode->i_mtime = je32_to_cpu(latest_node.mtime);
- inode->i_ctime = je32_to_cpu(latest_node.ctime);
-
- inode->i_nlink = f->inocache->nlink;
- up(&f->sem);
-
- D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
+ struct _inode *inode;
+ struct super_block *sb = dir_i->i_sb;
+ struct jffs2_sb_info *c;
+ struct jffs2_inode_info *f;
+ int ret;
+
+ D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));
+
+ c = JFFS2_SB_INFO(sb);
+
+ inode = new_inode(sb);
+
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+
+ f = JFFS2_INODE_INFO(inode);
+ jffs2_init_inode_info(f);
+
+ memset(ri, 0, sizeof(*ri));
+ /* Set OS-specific defaults for new inodes */
+ ri->uid = ri->gid = cpu_to_je16(0);
+ ri->mode = cpu_to_jemode(mode);
+ ret = jffs2_do_new_inode (c, f, mode, ri);
+ if (ret) {
+ jffs2_iput(inode);
+ return ERR_PTR(ret);
+ }
+ inode->i_nlink = 1;
+ inode->i_ino = je32_to_cpu(ri->ino);
+ inode->i_mode = jemode_to_cpu(ri->mode);
+ inode->i_gid = je16_to_cpu(ri->gid);
+ inode->i_uid = je16_to_cpu(ri->uid);
+ inode->i_atime = inode->i_ctime = inode->i_mtime = cyg_timestamp();
+ ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime);
+
+ inode->i_size = 0;
+
+ return inode;
+}
+
+
+static int jffs2_read_inode (struct _inode *inode)
+{
+ struct jffs2_inode_info *f;
+ struct jffs2_sb_info *c;
+ struct jffs2_raw_inode latest_node;
+ int ret;
+
+ D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino));
+
+ f = JFFS2_INODE_INFO(inode);
+ c = JFFS2_SB_INFO(inode->i_sb);
+
+ jffs2_init_inode_info(f);
+
+ ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node);
+
+ if (ret) {
+ up(&f->sem);
+ return ret;
+ }
+ inode->i_mode = jemode_to_cpu(latest_node.mode);
+ inode->i_uid = je16_to_cpu(latest_node.uid);
+ inode->i_gid = je16_to_cpu(latest_node.gid);
+ inode->i_size = je32_to_cpu(latest_node.isize);
+ inode->i_atime = je32_to_cpu(latest_node.atime);
+ inode->i_mtime = je32_to_cpu(latest_node.mtime);
+ inode->i_ctime = je32_to_cpu(latest_node.ctime);
+
+ inode->i_nlink = f->inocache->nlink;
+ up(&f->sem);
+
+ D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n"));
+ return 0;
+}
+
+
+void jffs2_gc_release_inode(struct jffs2_sb_info *c,
+ struct jffs2_inode_info *f)
+{
+ jffs2_iput(OFNI_EDONI_2SFFJ(f));
+}
+
+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
+ int inum, int nlink)
+{
+ struct _inode *inode;
+ struct jffs2_inode_cache *ic;
+ if (!nlink) {
+ /* The inode has zero nlink but its nodes weren't yet marked
+ obsolete. This has to be because we're still waiting for
+ the final (close() and) jffs2_iput() to happen.
+
+ There's a possibility that the final jffs2_iput() could have
+ happened while we were contemplating. In order to ensure
+ that we don't cause a new read_inode() (which would fail)
+ for the inode in question, we use ilookup() in this case
+ instead of jffs2_iget().
+
+ The nlink can't _become_ zero at this point because we're
+ holding the alloc_sem, and jffs2_do_unlink() would also
+ need that while decrementing nlink on any inode.
+ */
+ inode = ilookup(OFNI_BS_2SFFJ(c), inum);
+ if (!inode) {
+ D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
+ inum));
+
+ spin_lock(&c->inocache_lock);
+ ic = jffs2_get_ino_cache(c, inum);
+ if (!ic) {
+ D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum));
+ spin_unlock(&c->inocache_lock);
+ return NULL;
+ }
+ if (ic->state != INO_STATE_CHECKEDABSENT) {
+ /* Wait for progress. Don't just loop */
+ D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n",
+ ic->ino, ic->state));
+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
+ } else {
+ spin_unlock(&c->inocache_lock);
+ }
+
+ return NULL;
+ }
+ } else {
+ /* Inode has links to it still; they're not going away because
+ jffs2_do_unlink() would need the alloc_sem and we have it.
+ Just jffs2_iget() it, and if read_inode() is necessary that's OK.
+ */
+ inode = jffs2_iget(OFNI_BS_2SFFJ(c), inum);
+ if (IS_ERR(inode))
+ return (void *)inode;
+ }
+
+ return JFFS2_INODE_INFO(inode);
+}
+
+
+
+uint32_t jffs2_from_os_mode(uint32_t osmode)
+{
+ uint32_t jmode = ((osmode & S_IRUSR)?00400:0) |
+ ((osmode & S_IWUSR)?00200:0) |
+ ((osmode & S_IXUSR)?00100:0) |
+ ((osmode & S_IRGRP)?00040:0) |
+ ((osmode & S_IWGRP)?00020:0) |
+ ((osmode & S_IXGRP)?00010:0) |
+ ((osmode & S_IROTH)?00004:0) |
+ ((osmode & S_IWOTH)?00002:0) |
+ ((osmode & S_IXOTH)?00001:0);
+
+ switch (osmode & S_IFMT) {
+ case S_IFSOCK:
+ return jmode | 0140000;
+ case S_IFLNK:
+ return jmode | 0120000;
+ case S_IFREG:
+ return jmode | 0100000;
+ case S_IFBLK:
+ return jmode | 0060000;
+ case S_IFDIR:
+ return jmode | 0040000;
+ case S_IFCHR:
+ return jmode | 0020000;
+ case S_IFIFO:
+ return jmode | 0010000;
+ case S_ISUID:
+ return jmode | 0004000;
+ case S_ISGID:
+ return jmode | 0002000;
+#ifdef S_ISVTX
+ case S_ISVTX:
+ return jmode | 0001000;
+#endif
+ }
+ printf("os_to_jffs2_mode() cannot convert 0x%x\n", osmode);
+ BUG();
+ return 0;
+}
+
+uint32_t jffs2_to_os_mode (uint32_t jmode)
+{
+ uint32_t osmode = ((jmode & 00400)?S_IRUSR:0) |
+ ((jmode & 00200)?S_IWUSR:0) |
+ ((jmode & 00100)?S_IXUSR:0) |
+ ((jmode & 00040)?S_IRGRP:0) |
+ ((jmode & 00020)?S_IWGRP:0) |
+ ((jmode & 00010)?S_IXGRP:0) |
+ ((jmode & 00004)?S_IROTH:0) |
+ ((jmode & 00002)?S_IWOTH:0) |
+ ((jmode & 00001)?S_IXOTH:0);
+
+ switch(jmode & 00170000) {
+ case 0140000:
+ return osmode | S_IFSOCK;
+ case 0120000:
+ return osmode | S_IFLNK;
+ case 0100000:
+ return osmode | S_IFREG;
+ case 0060000:
+ return osmode | S_IFBLK;
+ case 0040000:
+ return osmode | S_IFDIR;
+ case 0020000:
+ return osmode | S_IFCHR;
+ case 0010000:
+ return osmode | S_IFIFO;
+ case 0004000:
+ return osmode | S_ISUID;
+ case 0002000:
+ return osmode | S_ISGID;
+#ifdef S_ISVTX
+ case 0001000:
+ return osmode | S_ISVTX;
+#endif
+ }
+ printf("jffs2_to_os_mode() cannot convert 0x%x\n", osmode);
+ BUG();
+ return 0;
}
Index: fs/jffs2/current/src/gc.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/gc.c,v
retrieving revision 1.5
diff -u -5 -p -r1.5 gc.c
--- fs/jffs2/current/src/gc.c 20 Nov 2003 16:52:36 -0000 1.5
+++ fs/jffs2/current/src/gc.c 11 Dec 2003 23:28:08 -0000
@@ -5,11 +5,11 @@
*
* Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: gc.c,v 1.129 2003/11/20 16:40:14 dwmw2 Exp $
+ * $Id: gc.c,v 1.132 2003/12/01 11:32:11 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
#include <linux/mtd/mtd.h>
@@ -34,11 +34,11 @@ static int jffs2_garbage_collect_hole(st
uint32_t start, uint32_t end);
static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,
uint32_t start, uint32_t end);
static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
- struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic);
+ struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f);
/* Called with erase_completion_lock held */
static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
{
struct jffs2_eraseblock *ret;
@@ -110,14 +110,15 @@ static struct jffs2_eraseblock *jffs2_fi
* Make a single attempt to progress GC. Move one node, and possibly
* start erasing one eraseblock.
*/
int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
{
+ struct jffs2_inode_info *f;
struct jffs2_inode_cache *ic;
struct jffs2_eraseblock *jeb;
struct jffs2_raw_node_ref *raw;
- int ret = 0;
+ int ret = 0, inum, nlink;
if (down_interruptible(&c->alloc_sem))
return -EINTR;
for (;;) {
@@ -247,11 +248,13 @@ int jffs2_garbage_collect_pass(struct jf
goto eraseit_lock;
}
ic = jffs2_raw_ref_to_ic(raw);
- /* We need to hold the inocache */
+ /* We need to hold the inocache. Either the erase_completion_lock or
+ the inocache_lock are sufficient; we trade down since the inocache_lock
+ causes less contention. */
spin_lock(&c->inocache_lock);
spin_unlock(&c->erase_completion_lock);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), ic->ino));
@@ -341,18 +344,30 @@ int jffs2_garbage_collect_pass(struct jf
}
/* Fall through if it wanted us to, with inocache_lock held */
}
- /* FIXME: We still have the inocache_lock held. This is ugly.
- It's done to prevent the fairly unlikely race where the
- gcblock is entirely obsoleted by the final close of a file
- which had the only valid nodes in the block, followed by
- erasure, followed by freeing of the ic because the erased
- block(s) held _all_ the nodes of that inode.... never been
- seen but it's vaguely possible. */
- ret = jffs2_garbage_collect_live(c, jeb, raw, ic);
+ /* Prevent the fairly unlikely race where the gcblock is
+ entirely obsoleted by the final close of a file which had
+ the only valid nodes in the block, followed by erasure,
+ followed by freeing of the ic because the erased block(s)
+ held _all_ the nodes of that inode.... never been seen but
+ it's vaguely possible. */
+
+ inum = ic->ino;
+ nlink = ic->nlink;
+ spin_unlock(&c->inocache_lock);
+
+ f = jffs2_gc_fetch_inode(c, inum, nlink);
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+ if (!f)
+ return 0;
+
+ ret = jffs2_garbage_collect_live(c, jeb, raw, f);
+
+ jffs2_gc_release_inode(c, f);
release_sem:
up(&c->alloc_sem);
eraseit_lock:
@@ -372,82 +387,18 @@ int jffs2_garbage_collect_pass(struct jf
return ret;
}
static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
- struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic)
+ struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f)
{
- struct jffs2_inode_info *f;
struct jffs2_node_frag *frag;
struct jffs2_full_dnode *fn = NULL;
struct jffs2_full_dirent *fd;
uint32_t start = 0, end = 0, nrfrags = 0;
- struct inode *inode;
int ret = 0;
- if (!ic->nlink) {
- int inum = ic->ino;
-
- spin_unlock(&c->inocache_lock);
-
- /* The inode has zero nlink but its nodes weren't yet marked
- obsolete. This has to be because we're still waiting for
- the final (close() and) iput() to happen.
-
- There's a possibility that the final iput() could have
- happened while we were contemplating. In order to ensure
- that we don't cause a new read_inode() (which would fail)
- for the inode in question, we use ilookup() in this case
- instead of iget().
-
- The nlink can't _become_ zero at this point because we're
- holding the alloc_sem, and jffs2_do_unlink() would also
- need that while decrementing nlink on any inode.
- */
- inode = ilookup(OFNI_BS_2SFFJ(c), inum);
- if (!inode) {
- D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n",
- inum));
-
- spin_lock(&c->inocache_lock);
- ic = jffs2_get_ino_cache(c, inum);
- if (!ic) {
- D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum));
- spin_unlock(&c->inocache_lock);
- return 0;
- }
- if (ic->state != INO_STATE_CHECKEDABSENT) {
- /* Wait for progress. Don't just loop */
- D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n",
- ic->ino, ic->state));
- sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);
- } else {
- spin_unlock(&c->inocache_lock);
- }
-
- return 0;
- }
- } else {
- spin_unlock(&c->inocache_lock);
-
- /* Inode has links to it still; they're not going away because
- jffs2_do_unlink() would need the alloc_sem and we have it.
- Just iget() it, and if read_inode() is necessary that's OK.
- */
- inode = iget(OFNI_BS_2SFFJ(c), ic->ino);
- if (!inode)
- return -ENOMEM;
- }
- if (is_bad_inode(inode)) {
- printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d, state %d\n",
- ic->ino, ic->nlink, ic->state);
- /* NB. This will happen again. We need to do something appropriate here. */
- ret = -EIO;
- goto put_out;
- }
-
- f = JFFS2_INODE_INFO(inode);
down(&f->sem);
/* Now we have the lock for this inode. Check that it's still the one at the head
of the list. */
@@ -484,14 +435,14 @@ static int jffs2_garbage_collect_live(st
break; /* We've found them all */
}
}
if (fn) {
if (ref_flags(raw) == REF_PRISTINE) {
- ret = jffs2_garbage_collect_pristine(c, ic, raw);
+ ret = jffs2_garbage_collect_pristine(c, f->inocache, raw);
if (!ret) {
/* Urgh. Return it sensibly. */
- frag->node->raw = ic->nodes;
+ frag->node->raw = f->inocache->nodes;
}
if (ret != -EBADFD)
goto upnout;
}
/* We found a datanode. Do the GC */
@@ -524,12 +475,10 @@ static int jffs2_garbage_collect_live(st
ret = -EIO;
}
}
upnout:
up(&f->sem);
- put_out:
- iput(inode);
return ret;
}
static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
@@ -1073,14 +1022,13 @@ static int jffs2_garbage_collect_dnode(s
struct jffs2_full_dnode *new_fn;
struct jffs2_raw_inode ri;
uint32_t alloclen, phys_ofs, offset, orig_end, orig_start;
int ret = 0;
unsigned char *comprbuf = NULL, *writebuf;
- struct page *pg;
+ unsigned long pg;
unsigned char *pg_ptr;
- /* FIXME: */ struct inode *inode = OFNI_EDONI_2SFFJ(f);
-
+
memset(&ri, 0, sizeof(ri));
D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n",
f->inocache->ino, start, end));
@@ -1215,20 +1163,16 @@ static int jffs2_garbage_collect_dnode(s
* triggered garbage collection in the first place?
* A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the
* page OK. We'll actually write it out again in commit_write, which is a little
* suboptimal, but at least we're correct.
*/
-#ifdef __ECOS
- pg = read_cache_page(start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode);
-#else
- pg = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode);
-#endif
- if (IS_ERR(pg)) {
- printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg));
- return PTR_ERR(pg);
+ pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg);
+
+ if (IS_ERR(pg_ptr)) {
+ printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg_ptr));
+ return PTR_ERR(pg_ptr);
}
- pg_ptr = (char *)kmap(pg);
offset = start;
while(offset < orig_end) {
uint32_t datalen;
uint32_t cdatalen;
@@ -1265,11 +1209,11 @@ static int jffs2_garbage_collect_dnode(s
ri.offset = cpu_to_je32(offset);
ri.csize = cpu_to_je32(cdatalen);
ri.dsize = cpu_to_je32(datalen);
ri.compr = comprtype;
ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
- ri.data_crc = cpu_to_je32(crc32(0, writebuf, cdatalen));
+ ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));
new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, phys_ofs, ALLOC_GC);
jffs2_free_comprbuf(comprbuf, writebuf);
@@ -1285,12 +1229,9 @@ static int jffs2_garbage_collect_dnode(s
jffs2_free_full_dnode(f->metadata);
f->metadata = NULL;
}
}
- kunmap(pg);
- /* XXX: Does the page get freed automatically? */
- /* AAA: Judging by the unmount getting stuck in __wait_on_page, nope. */
- page_cache_release(pg);
+ jffs2_gc_release_page(c, pg_ptr, &pg);
return ret;
}
Index: fs/jffs2/current/src/malloc-ecos.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/malloc-ecos.c,v
retrieving revision 1.4
diff -u -5 -p -r1.4 malloc-ecos.c
--- fs/jffs2/current/src/malloc-ecos.c 20 Nov 2003 21:06:26 -0000 1.4
+++ fs/jffs2/current/src/malloc-ecos.c 11 Dec 2003 23:28:08 -0000
@@ -1,15 +1,15 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2001, 2002 Red Hat, Inc.
+ * Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: malloc-ecos.c,v 1.2 2003/01/09 13:53:44 dwmw2 Exp $
+ * $Id: malloc-ecos.c,v 1.4 2003/11/26 15:55:35 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
#include <cyg/hal/drv_api.h>
Index: fs/jffs2/current/src/nodelist.h
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/nodelist.h,v
retrieving revision 1.5
diff -u -5 -p -r1.5 nodelist.h
--- fs/jffs2/current/src/nodelist.h 20 Nov 2003 16:52:36 -0000 1.5
+++ fs/jffs2/current/src/nodelist.h 11 Dec 2003 23:28:08 -0000
@@ -5,11 +5,11 @@
*
* Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodelist.h,v 1.113 2003/11/20 16:40:14 dwmw2 Exp $
+ * $Id: nodelist.h,v 1.115 2003/11/26 15:30:58 dwmw2 Exp $
*
*/
#ifndef __JFFS2_NODELIST_H__
#define __JFFS2_NODELIST_H__
@@ -376,10 +376,11 @@ void jffs2_fragtree_insert(struct jffs2_
struct rb_node *rb_next(struct rb_node *);
struct rb_node *rb_prev(struct rb_node *);
void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root);
/* nodemgmt.c */
+int jffs2_thread_should_wake(struct jffs2_sb_info *c);
int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio);
int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len);
int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new);
void jffs2_complete_reservation(struct jffs2_sb_info *c);
void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw);
@@ -451,11 +452,10 @@ void jffs2_rotate_lists(struct jffs2_sb_
int jffs2_do_mount_fs(struct jffs2_sb_info *c);
/* erase.c */
void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count);
-void jffs2_erase_pending_trigger(struct jffs2_sb_info *c);
#ifdef CONFIG_JFFS2_FS_NAND
/* wbuf.c */
int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
Index: fs/jffs2/current/src/nodemgmt.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/nodemgmt.c,v
retrieving revision 1.5
diff -u -5 -p -r1.5 nodemgmt.c
--- fs/jffs2/current/src/nodemgmt.c 20 Nov 2003 16:52:36 -0000 1.5
+++ fs/jffs2/current/src/nodemgmt.c 11 Dec 2003 23:28:08 -0000
@@ -5,11 +5,11 @@
*
* Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodemgmt.c,v 1.106 2003/11/03 17:33:54 dwmw2 Exp $
+ * $Id: nodemgmt.c,v 1.107 2003/11/26 15:30:58 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -706,5 +706,36 @@ void jffs2_dump_block_lists(struct jffs2
jeb->offset, jeb->used_size, jeb->dirty_size, jeb->wasted_size, jeb->unchecked_size, jeb->free_size);
}
}
}
#endif /* CONFIG_JFFS2_FS_DEBUG */
+
+int jffs2_thread_should_wake(struct jffs2_sb_info *c)
+{
+ int ret = 0;
+ uint32_t dirty;
+
+ if (c->unchecked_size) {
+ D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n",
+ c->unchecked_size, c->checked_ino));
+ return 1;
+ }
+
+ /* dirty_size contains blocks on erase_pending_list
+ * those blocks are counted in c->nr_erasing_blocks.
+ * If one block is actually erased, it is not longer counted as dirty_space
+ * but it is counted in c->nr_erasing_blocks, so we add it and subtract it
+ * with c->nr_erasing_blocks * c->sector_size again.
+ * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks
+ * This helps us to force gc and pick eventually a clean block to spread the load.
+ */
+ dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size;
+
+ if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger &&
+ (dirty > c->nospc_dirty_size))
+ ret = 1;
+
+ D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n",
+ c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no"));
+
+ return ret;
+}
Index: fs/jffs2/current/src/os-ecos.h
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/os-ecos.h,v
retrieving revision 1.7
diff -u -5 -p -r1.7 os-ecos.h
--- fs/jffs2/current/src/os-ecos.h 20 Nov 2003 21:06:26 -0000 1.7
+++ fs/jffs2/current/src/os-ecos.h 11 Dec 2003 23:28:08 -0000
@@ -1,15 +1,15 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
- * Copyright (C) 2002 Red Hat, Inc.
+ * Copyright (C) 2002-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: os-ecos.h,v 1.8 2003/11/20 16:41:58 dwmw2 Exp $
+ * $Id: os-ecos.h,v 1.19 2003/11/28 11:38:45 dwmw2 Exp $
*
*/
#ifndef __JFFS2_OS_ECOS_H__
#define __JFFS2_OS_ECOS_H__
@@ -18,218 +18,172 @@
#include <cyg/io/io.h>
#include <sys/types.h>
#include <asm/atomic.h>
#include <linux/stat.h>
#include <linux/compiler.h>
-#include "jffs2port.h"
-#ifndef CONFIG_JFFS2_FS_DEBUG
-# define CONFIG_JFFS2_FS_DEBUG 0
-#endif
+#include <pkgconf/system.h>
+#include <pkgconf/hal.h>
+#include <pkgconf/io_fileio.h>
-static inline uint32_t os_to_jffs2_mode(uint32_t osmode)
-{
- uint32_t jmode = ((osmode & S_IRUSR)?00400:0) |
- ((osmode & S_IWUSR)?00200:0) |
- ((osmode & S_IXUSR)?00100:0) |
- ((osmode & S_IRGRP)?00040:0) |
- ((osmode & S_IWGRP)?00020:0) |
- ((osmode & S_IXGRP)?00010:0) |
- ((osmode & S_IROTH)?00004:0) |
- ((osmode & S_IWOTH)?00002:0) |
- ((osmode & S_IXOTH)?00001:0);
-
- switch (osmode & S_IFMT) {
- case S_IFSOCK:
- return jmode | 0140000;
- case S_IFLNK:
- return jmode | 0120000;
- case S_IFREG:
- return jmode | 0100000;
- case S_IFBLK:
- return jmode | 0060000;
- case S_IFDIR:
- return jmode | 0040000;
- case S_IFCHR:
- return jmode | 0020000;
- case S_IFIFO:
- return jmode | 0010000;
- case S_ISUID:
- return jmode | 0004000;
- case S_ISGID:
- return jmode | 0002000;
-#ifdef S_ISVTX
- case S_ISVTX:
- return jmode | 0001000;
-#endif
- }
- printf("os_to_jffs2_mode() cannot convert 0x%x\n", osmode);
- BUG();
- return 0;
-}
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
-static inline uint32_t jffs2_to_os_mode (uint32_t jmode)
-{
- uint32_t osmode = ((jmode & 00400)?S_IRUSR:0) |
- ((jmode & 00200)?S_IWUSR:0) |
- ((jmode & 00100)?S_IXUSR:0) |
- ((jmode & 00040)?S_IRGRP:0) |
- ((jmode & 00020)?S_IWGRP:0) |
- ((jmode & 00010)?S_IXGRP:0) |
- ((jmode & 00004)?S_IROTH:0) |
- ((jmode & 00002)?S_IWOTH:0) |
- ((jmode & 00001)?S_IXOTH:0);
-
- switch(jmode & 00170000) {
- case 0140000:
- return osmode | S_IFSOCK;
- case 0120000:
- return osmode | S_IFLNK;
- case 0100000:
- return osmode | S_IFREG;
- case 0060000:
- return osmode | S_IFBLK;
- case 0040000:
- return osmode | S_IFDIR;
- case 0020000:
- return osmode | S_IFCHR;
- case 0010000:
- return osmode | S_IFIFO;
- case 0004000:
- return osmode | S_ISUID;
- case 0002000:
- return osmode | S_ISGID;
-#ifdef S_ISVTX
- case 0001000:
- return osmode | S_ISVTX;
-#endif
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <cyg/fileio/fileio.h>
+
+#include <cyg/hal/drv_api.h>
+#include <cyg/infra/diag.h>
+
+#include <cyg/io/flash.h>
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <asm/bug.h>
+
+#define printf diag_printf
+
+struct _inode;
+struct super_block;
+
+struct iovec {
+ void *iov_base;
+ ssize_t iov_len;
+};
+
+static inline unsigned int full_name_hash(const unsigned char * name, unsigned int len) {
+
+ unsigned hash = 0;
+ while (len--) {
+ hash = (hash << 4) | (hash >> 28);
+ hash ^= *(name++);
}
- printf("jffs2_to_os_mode() cannot convert 0x%x\n", osmode);
- BUG();
- return 0;
+ return hash;
}
- /* Read-only operation not currently implemented on eCos */
+#ifdef CYGOPT_FS_JFFS2_WRITE
#define jffs2_is_readonly(c) (0)
+#else
+#define jffs2_is_readonly(c) (1)
+#endif
/* NAND flash not currently supported on eCos */
#define jffs2_can_mark_obsolete(c) (1)
#define JFFS2_INODE_INFO(i) (&(i)->jffs2_i)
-#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->jffs2_i)) ) )
+#define OFNI_EDONI_2SFFJ(f) ((struct _inode *) ( ((char *)f) - ((char *)(&((struct _inode *)NULL)->jffs2_i)) ) )
#define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size)
#define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode)
#define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid)
#define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid)
#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime)
#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime)
#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime)
/* FIXME: eCos doesn't hav a concept of device major/minor numbers */
-#define JFFS2_F_I_RDEV_MIN(f) (MINOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
-#define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
+#define JFFS2_F_I_RDEV_MIN(f) ((OFNI_EDONI_2SFFJ(f)->i_rdev)&0xff)
+#define JFFS2_F_I_RDEV_MAJ(f) ((OFNI_EDONI_2SFFJ(f)->i_rdev)>>8)
-
-//#define ITIME(sec) (sec)
-//#define I_SEC(x) (x)
#define get_seconds cyg_timestamp
-struct inode {
- //struct list_head i_hash;
- //struct list_head i_list;
- struct list_head i_dentry;
-
+struct _inode {
cyg_uint32 i_ino;
- atomic_t i_count;
- //kdev_t i_dev;
+
+ int i_count;
mode_t i_mode;
- nlink_t i_nlink;
+ nlink_t i_nlink; // Could we dispense with this?
uid_t i_uid;
gid_t i_gid;
- kdev_t i_rdev;
- off_t i_size;
time_t i_atime;
time_t i_mtime;
time_t i_ctime;
- unsigned long i_blksize;
- unsigned long i_blocks;
- //unsigned long i_version;
- //struct semaphore i_sem;
- //struct semaphore i_zombie;
- struct inode_operations *i_op;
- struct file_operations *i_fop; // former ->i_op->default_file_ops
- struct super_block *i_sb;
- //wait_queue_head_t i_wait;
- //struct file_lock *i_flock;
- //struct address_space *i_mapping;
- //struct address_space i_data;
- //struct dquot *i_dquot[MAXQUOTAS];
- //struct pipe_inode_info *i_pipe;
- //struct block_device *i_bdev;
-
- //unsigned long i_state;
-
- unsigned int i_flags;
- //unsigned char i_sock;
-
- atomic_t i_writecount;
- //unsigned int i_attr_flags;
- //uint32_t i_generation;
- struct jffs2_inode_info jffs2_i;
+// union {
+ unsigned short i_rdev; // For devices only
+ struct _inode * i_parent; // For directories only
+ off_t i_size; // For files only
+// };
+ struct super_block * i_sb;
- struct inode *i_parent;
+ struct jffs2_inode_info jffs2_i;
- struct inode *i_cache_prev;
- struct inode *i_cache_next;
+ struct _inode * i_cache_prev; // We need doubly-linked?
+ struct _inode * i_cache_next;
};
#define JFFS2_SB_INFO(sb) (&(sb)->jffs2_sb)
-
#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->jffs2_sb)) ) )
struct super_block {
- unsigned long s_blocksize;
- unsigned char s_blocksize_bits;
- unsigned char s_dirt;
- //struct super_operations *s_op;
- unsigned long s_flags;
- unsigned long s_magic;
- //struct dentry *s_root;
- struct inode *s_root;
- struct jffs2_sb_info jffs2_sb;
- unsigned long s_mount_count;
- cyg_io_handle_t s_dev;
+ struct jffs2_sb_info jffs2_sb;
+ struct _inode * s_root;
+ unsigned long s_mount_count;
+ cyg_io_handle_t s_dev;
};
-#define sleep_on_spinunlock(wq, sl) do { ; } while(0)
+#define sleep_on_spinunlock(wq, sl) spin_unlock(sl)
#define EBADFD 32767
/* background.c */
+#ifdef CYGOPT_FS_JFFS2_GCTHREAD
+void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c);
+void jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c);
+void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c);
+#else
static inline void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
{
/* We don't have a GC thread in eCos (yet) */
}
+#endif
-/* dir.c */
-extern struct file_operations jffs2_dir_operations;
-extern struct inode_operations jffs2_dir_inode_operations;
-
-/* file.c */
-extern struct file_operations jffs2_file_operations;
-extern struct inode_operations jffs2_file_inode_operations;
-extern struct address_space_operations jffs2_file_address_operations;
-int jffs2_null_fsync(struct file *, struct dentry *, int);
-int jffs2_setattr (struct dentry *dentry, struct iattr *iattr);
-int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg);
-int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg);
-//int jffs2_readpage (struct file *, struct page *);
-int jffs2_readpage (struct inode *d_inode, struct page *pg);
-//int jffs2_prepare_write (struct file *, struct page *, unsigned, unsigned);
-int jffs2_prepare_write (struct inode *d_inode, struct page *pg, unsigned start, unsigned end);
-//int jffs2_commit_write (struct file *, struct page *, unsigned, unsigned);
-int jffs2_commit_write (struct inode *d_inode, struct page *pg, unsigned start, unsigned end);
+/* fs-ecos.c */
+struct _inode *jffs2_new_inode (struct _inode *dir_i, int mode, struct jffs2_raw_inode *ri);
+struct _inode *jffs2_iget(struct super_block *sb, cyg_uint32 ino);
+void jffs2_iput(struct _inode * i);
+void jffs2_gc_release_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f);
+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, int inum, int nlink);
+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+ unsigned long offset, unsigned long *priv);
+void jffs2_gc_release_page(struct jffs2_sb_info *c, unsigned char *pg, unsigned long *priv);
+
+/* Avoid polluting eCos namespace with names not starting in jffs2_ */
+#define os_to_jffs2_mode(x) jffs2_from_os_mode(x)
+uint32_t jffs2_from_os_mode(uint32_t osmode);
+uint32_t jffs2_to_os_mode (uint32_t jmode);
+
+
+/* flashio.c */
+cyg_bool jffs2_flash_read(struct jffs2_sb_info *c, cyg_uint32 read_buffer_offset,
+ const size_t size, size_t * return_size, char * write_buffer);
+cyg_bool jffs2_flash_write(struct jffs2_sb_info *c, cyg_uint32 write_buffer_offset,
+ const size_t size, size_t * return_size, char * read_buffer);
+int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs,
+ unsigned long count, loff_t to, size_t *retlen);
+cyg_bool jffs2_flash_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
+
+// dir-ecos.c
+struct _inode *jffs2_lookup(struct _inode *dir_i, const unsigned char *name, int namelen);
+int jffs2_create(struct _inode *dir_i, const unsigned char *d_name, int mode, struct _inode **new_i);
+int jffs2_mkdir (struct _inode *dir_i, const unsigned char *d_name, int mode);
+int jffs2_link (struct _inode *old_d_inode, struct _inode *dir_i, const unsigned char *d_name);
+int jffs2_unlink(struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name);
+int jffs2_rmdir (struct _inode *dir_i, struct _inode *d_inode, const unsigned char *d_name);
+int jffs2_rename (struct _inode *old_dir_i, struct _inode *d_inode, const unsigned char *old_d_name,
+ struct _inode *new_dir_i, const unsigned char *new_d_name);
+
+/* erase.c */
+static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
+{ }
#ifndef CONFIG_JFFS2_FS_NAND
#define jffs2_can_mark_obsolete(c) (1)
#define jffs2_cleanmarker_oob(c) (0)
#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
@@ -245,18 +199,11 @@ int jffs2_commit_write (struct inode *d_
#define jffs2_wbuf_timeout NULL
#define jffs2_wbuf_process NULL
#else
#error no nand yet
#endif
-struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri);
-void jffs2_clear_inode (struct inode *inode);
-void jffs2_read_inode (struct inode *inode);
-
-static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
-{
- memset(f, 0, sizeof(*f));
- init_MUTEX_LOCKED(&f->sem);
-}
+#ifndef BUG_ON
#define BUG_ON(x) do { if (unlikely(x)) BUG(); } while(0)
+#endif
#endif /* __JFFS2_OS_ECOS_H__ */
Index: fs/jffs2/current/src/write.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/src/write.c,v
retrieving revision 1.4
diff -u -5 -p -r1.4 write.c
--- fs/jffs2/current/src/write.c 20 Nov 2003 16:52:36 -0000 1.4
+++ fs/jffs2/current/src/write.c 11 Dec 2003 23:28:08 -0000
@@ -5,11 +5,11 @@
*
* Created by David Woodhouse <dwmw2@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: write.c,v 1.77 2003/11/18 21:14:02 dwmw2 Exp $
+ * $Id: write.c,v 1.79 2003/12/03 09:41:03 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -371,12 +371,12 @@ int jffs2_write_inode_range(struct jffs2
if (ret) {
D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret));
break;
}
down(&f->sem);
- datalen = writelen;
- cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), writelen);
+ datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));
+ cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);
comprtype = jffs2_compress(buf, &comprbuf, &datalen, &cdatalen);
ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
Index: fs/jffs2/current/tests/fileio1.c
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/fs/jffs2/current/tests/fileio1.c,v
retrieving revision 1.2
diff -u -5 -p -r1.2 fileio1.c
--- fs/jffs2/current/tests/fileio1.c 23 May 2002 23:01:39 -0000 1.2
+++ fs/jffs2/current/tests/fileio1.c 11 Dec 2003 23:28:09 -0000
@@ -95,11 +95,11 @@ MTAB_ENTRY( jffs2_mte1,
#define SHOW_RESULT( _fn, _res ) \
diag_printf("<FAIL>: " #_fn "() returned %d %s\n", _res, _res<0?strerror(errno):"");
//==========================================================================
-#define IOSIZE 100
+#define IOSIZE 1000
#define LONGNAME1 "long_file_name_that_should_take_up_more_than_one_directory_entry_1"
#define LONGNAME2 "long_file_name_that_should_take_up_more_than_one_directory_entry_2"
@@ -180,11 +180,11 @@ static void listdir( char *name, int sta
//==========================================================================
static void createfile( char *name, size_t size )
{
- char buf[IOSIZE];
+ unsigned char buf[IOSIZE];
int fd;
ssize_t wrote;
int i;
int err;
@@ -253,11 +253,11 @@ static void maxfile( char *name )
//==========================================================================
static void checkfile( char *name )
{
- char buf[IOSIZE];
+ unsigned char buf[IOSIZE];
int fd;
ssize_t done;
int i;
int err;
off_t pos = 0;
Index: fs/jffs2/current/doc/README.Locking
===================================================================
RCS file: fs/jffs2/current/doc/README.Locking
diff -N fs/jffs2/current/doc/README.Locking
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ fs/jffs2/current/doc/README.Locking 11 Dec 2003 23:28:08 -0000
@@ -0,0 +1,116 @@
+ $Id: README.Locking,v 1.6 2003/11/02 19:27:54 dwmw2 Exp $
+
+ JFFS2 LOCKING DOCUMENTATION
+ ---------------------------
+
+At least theoretically, JFFS2 does not require the Big Kernel Lock
+(BKL), which was always helpfully obtained for it by Linux 2.4 VFS
+code. It has its own locking, as described below.
+
+This document attempts to describe the existing locking rules for
+JFFS2. It is not expected to remain perfectly up to date, but ought to
+be fairly close.
+
+
+ alloc_sem
+ ---------
+
+The alloc_sem is a per-filesystem semaphore, used primarily to ensure
+contiguous allocation of space on the medium. It is automatically
+obtained during space allocations (jffs2_reserve_space()) and freed
+upon write completion (jffs2_complete_reservation()). Note that
+the garbage collector will obtain this right at the beginning of
+jffs2_garbage_collect_pass() and release it at the end, thereby
+preventing any other write activity on the file system during a
+garbage collect pass.
+
+When writing new nodes, the alloc_sem must be held until the new nodes
+have been properly linked into the data structures for the inode to
+which they belong. This is for the benefit of NAND flash - adding new
+nodes to an inode may obsolete old ones, and by holding the alloc_sem
+until this happens we ensure that any data in the write-buffer at the
+time this happens are part of the new node, not just something that
+was written afterwards. Hence, we can ensure the newly-obsoleted nodes
+don't actually get erased until the write-buffer has been flushed to
+the medium.
+
+With the introduction of NAND flash support and the write-buffer,
+the alloc_sem is also used to protect the wbuf-related members of the
+jffs2_sb_info structure. Atomically reading the wbuf_len member to see
+if the wbuf is currently holding any data is permitted, though.
+
+Ordering constraints: See f->sem.
+
+
+ File Semaphore f->sem
+ ---------------------
+
+This is the JFFS2-internal equivalent of the inode semaphore i->i_sem.
+It protects the contents of the jffs2_inode_info private inode data,
+including the linked list of node fragments (but see the notes below on
+erase_completion_lock), etc.
+
+The reason that the i_sem itself isn't used for this purpose is to
+avoid deadlocks with garbage collection -- the VFS will lock the i_sem
+before calling a function which may need to allocate space. The
+allocation may trigger garbage-collection, which may need to move a
+node belonging to the inode which was locked in the first place by the
+VFS. If the garbage collection code were to attempt to lock the i_sem
+of the inode from which it's garbage-collecting a physical node, this
+lead to deadlock, unless we played games with unlocking the i_sem
+before calling the space allocation functions.
+
+Instead of playing such games, we just have an extra internal
+semaphore, which is obtained by the garbage collection code and also
+by the normal file system code _after_ allocation of space.
+
+Ordering constraints:
+
+ 1. Never attempt to allocate space or lock alloc_sem with
+ any f->sem held.
+ 2. Never attempt to lock two file semaphores in one thread.
+ No ordering rules have been made for doing so.
+
+
+ erase_completion_lock spinlock
+ ------------------------------
+
+This is used to serialise access to the eraseblock lists, to the
+per-eraseblock lists of physical jffs2_raw_node_ref structures, and
+(NB) the per-inode list of physical nodes. The latter is a special
+case - see below.
+
+As the MTD API no longer permits erase-completion callback functions
+to be called from bottom-half (timer) context (on the basis that nobody
+ever actually implemented such a thing), it's now sufficient to use
+a simple spin_lock() rather than spin_lock_bh().
+
+Note that the per-inode list of physical nodes (f->nodes) is a special
+case. Any changes to _valid_ nodes (i.e. ->flash_offset & 1 == 0) in
+the list are protected by the file semaphore f->sem. But the erase
+code may remove _obsolete_ nodes from the list while holding only the
+erase_completion_lock. So you can walk the list only while holding the
+erase_completion_lock, and can drop the lock temporarily mid-walk as
+long as the pointer you're holding is to a _valid_ node, not an
+obsolete one.
+
+The erase_completion_lock is also used to protect the c->gc_task
+pointer when the garbage collection thread exits. The code to kill the
+GC thread locks it, sends the signal, then unlocks it - while the GC
+thread itself locks it, zeroes c->gc_task, then unlocks on the exit path.
+
+ erase_free_sem
+ --------------
+
+This semaphore is only used by the erase code which frees obsolete
+node references and the jffs2_garbage_collect_deletion_dirent()
+function. The latter function on NAND flash must read _obsolete_ nodes
+to determine whether the 'deletion dirent' under consideration can be
+discarded or whether it is still required to show that an inode has
+been unlinked. Because reading from the flash may sleep, the
+erase_completion_lock cannot be held, so an alternative, more
+heavyweight lock was required to prevent the erase code from freeing
+the jffs2_raw_node_ref structures in question while the garbage
+collection code is looking at them.
+
+Suggestions for alternative solutions to this problem would be welcomed.
Index: fs/jffs2/current/doc/TODO
===================================================================
RCS file: fs/jffs2/current/doc/TODO
diff -N fs/jffs2/current/doc/TODO
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ fs/jffs2/current/doc/TODO 11 Dec 2003 23:28:08 -0000
@@ -0,0 +1,28 @@
+$Id: TODO,v 1.15 2003/10/06 14:50:37 dwmw2 Exp $
+
+ - disable compression in commit_write()?
+ - fine-tune the allocation / GC thresholds
+ - chattr support - turning on/off and tuning compression per-inode
+ - checkpointing (do we need this? scan is quite fast)
+ - make the scan code populate real inodes so read_inode just after
+ mount doesn't have to read the flash twice for large files.
+ Make this a per-inode option, changable with chattr, so you can
+ decide which inodes should be in-core immediately after mount.
+ - test, test, test
+
+ - NAND flash support:
+ - done :)
+
+ - Optimisations:
+ - Split writes so they go to two separate blocks rather than just c->nextblock.
+ By writing _new_ nodes to one block, and garbage-collected REF_PRISTINE
+ nodes to a different one, we can separate clean nodes from those which
+ are likely to become dirty, and end up with blocks which are each far
+ closer to 100% or 0% clean, hence speeding up later GC progress dramatically.
+ - Stop keeping name in-core with struct jffs2_full_dirent. If we keep the hash in
+ the full dirent, we only need to go to the flash in lookup() when we think we've
+ got a match, and in readdir().
+ - Doubly-linked next_in_ino list to allow us to free obsoleted raw_node_refs immediately?
+ - Remove totlen from jffs2_raw_node_ref? Need to have totlen passed into
+ jffs2_mark_node_obsolete(). Can all callers work it out?
+ - Remove size from jffs2_raw_node_frag.
Index: fs/jffs2/current/doc/TODO.eCos
===================================================================
RCS file: fs/jffs2/current/doc/TODO.eCos
diff -N fs/jffs2/current/doc/TODO.eCos
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ fs/jffs2/current/doc/TODO.eCos 11 Dec 2003 23:28:08 -0000
@@ -0,0 +1,25 @@
+$Id: TODO.eCos,v 1.2 2003/11/28 11:15:56 dwmw2 Exp $
+
+ - Make symlinks work properly.
+
+ - Fill in the skeleton gcthread.c so it actually does something.
+
+ - Check and possibly fix locking of icache mangling in fs-ecos.c
+
+ - Check that os-ecos.h defines 'spin_lock()' to something appropriate.
+
+ - Fix unmount of root file system after chdir().
+
+ - Fix atomicity of renames. Why was the unlink added before rename?
+
+ - Further cleanup -- should the functions in dir-ecos.c take 'struct
+ dirsearch' instead of various components thereof, or should each of
+ those functions just be moved inside its only caller in fs-ecos.c?
+
+ - Improve mount time by using pointer directly into flash chip instead
+ of jffs2_flash_read() for the initial scan -- look at the #ifdef
+ __ECOS bit in scan.c for details.
+
+ - Reduce memory usage. There are fields marked for possible removal in
+ struct _inode, and there's the __totlen field in struct
+ jffs2_raw_node_ref as discussed recently.
Index: fs/jffs2/current/src/flashio.c
===================================================================
RCS file: fs/jffs2/current/src/flashio.c
diff -N fs/jffs2/current/src/flashio.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ fs/jffs2/current/src/flashio.c 11 Dec 2003 23:28:08 -0000
@@ -0,0 +1,165 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by Dominic Ostrowski <dominic.ostrowski@3glab.com>
+ * Contributors: David Woodhouse, Nick Garnett, Richard Panton.
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: flashio.c,v 1.1 2003/11/26 14:09:29 dwmw2 Exp $
+ *
+ */
+
+#include <linux/kernel.h>
+#include "nodelist.h"
+
+#include <cyg/io/io.h>
+#include <cyg/io/config_keys.h>
+#include <cyg/io/flash.h>
+
+cyg_bool jffs2_flash_read(struct jffs2_sb_info * c,
+ cyg_uint32 read_buffer_offset, const size_t size,
+ size_t * return_size, char *write_buffer)
+{
+ Cyg_ErrNo err;
+ cyg_uint32 len = size;
+ struct super_block *sb = OFNI_BS_2SFFJ(c);
+
+ //D2(printf("FLASH READ\n"));
+ //D2(printf("read address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + read_buffer_offset));
+ //D2(printf("write address = %x\n", write_buffer));
+ //D2(printf("size = %x\n", size));
+ err = cyg_io_bread(sb->s_dev, write_buffer, &len, read_buffer_offset);
+
+ *return_size = (size_t) len;
+ return ((err == ENOERR) ? ENOERR : -EIO);
+}
+
+cyg_bool jffs2_flash_write(struct jffs2_sb_info * c,
+ cyg_uint32 write_buffer_offset, const size_t size,
+ size_t * return_size, char *read_buffer)
+{
+
+ Cyg_ErrNo err;
+ cyg_uint32 len = size;
+ struct super_block *sb = OFNI_BS_2SFFJ(c);
+
+ // D2(printf("FLASH WRITE ENABLED!!!\n"));
+ // D2(printf("write address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + write_buffer_offset));
+ // D2(printf("read address = %x\n", read_buffer));
+ // D2(printf("size = %x\n", size));
+
+ err = cyg_io_bwrite(sb->s_dev, read_buffer, &len, write_buffer_offset);
+ *return_size = (size_t) len;
+
+ return ((err == ENOERR) ? ENOERR : -EIO);
+}
+
+int
+jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs,
+ unsigned long count, loff_t to, size_t * retlen)
+{
+ unsigned long i;
+ size_t totlen = 0, thislen;
+ int ret = 0;
+
+ for (i = 0; i < count; i++) {
+ // writes need to be aligned but the data we're passed may not be
+ // Observation suggests most unaligned writes are small, so we
+ // optimize for that case.
+
+ if (((vecs[i].iov_len & (sizeof (int) - 1))) ||
+ (((unsigned long) vecs[i].
+ iov_base & (sizeof (unsigned long) - 1)))) {
+ // are there iov's after this one? Or is it so much we'd need
+ // to do multiple writes anyway?
+ if ((i + 1) < count || vecs[i].iov_len > 256) {
+ // cop out and malloc
+ unsigned long j;
+ ssize_t sizetomalloc = 0, totvecsize = 0;
+ char *cbuf, *cbufptr;
+
+ for (j = i; j < count; j++)
+ totvecsize += vecs[j].iov_len;
+
+ // pad up in case unaligned
+ sizetomalloc = totvecsize + sizeof (int) - 1;
+ sizetomalloc &= ~(sizeof (int) - 1);
+ cbuf = (char *) malloc(sizetomalloc);
+ // malloc returns aligned memory
+ if (!cbuf) {
+ ret = -ENOMEM;
+ goto writev_out;
+ }
+ cbufptr = cbuf;
+ for (j = i; j < count; j++) {
+ memcpy(cbufptr, vecs[j].iov_base,
+ vecs[j].iov_len);
+ cbufptr += vecs[j].iov_len;
+ }
+ ret =
+ jffs2_flash_write(c, to, sizetomalloc,
+ &thislen, cbuf);
+ if (thislen > totvecsize) // in case it was aligned up
+ thislen = totvecsize;
+ totlen += thislen;
+ free(cbuf);
+ goto writev_out;
+ } else {
+ // otherwise optimize for the common case
+ int buf[256 / sizeof (int)]; // int, so int aligned
+ size_t lentowrite;
+
+ lentowrite = vecs[i].iov_len;
+ // pad up in case its unaligned
+ lentowrite += sizeof (int) - 1;
+ lentowrite &= ~(sizeof (int) - 1);
+ memcpy(buf, vecs[i].iov_base, lentowrite);
+
+ ret =
+ jffs2_flash_write(c, to, lentowrite,
+ &thislen, (char *) &buf);
+ if (thislen > vecs[i].iov_len)
+ thislen = vecs[i].iov_len;
+ } // else
+ } else
+ ret =
+ jffs2_flash_write(c, to, vecs[i].iov_len, &thislen,
+ vecs[i].iov_base);
+ totlen += thislen;
+ if (ret || thislen != vecs[i].iov_len)
+ break;
+ to += vecs[i].iov_len;
+ }
+ writev_out:
+ if (retlen)
+ *retlen = totlen;
+
+ return ret;
+}
+
+cyg_bool jffs2_flash_erase(struct jffs2_sb_info * c,
+ struct jffs2_eraseblock * jeb)
+{
+ cyg_io_flash_getconfig_erase_t e;
+ void *err_addr;
+ Cyg_ErrNo err;
+ cyg_uint32 len = sizeof (e);
+ struct super_block *sb = OFNI_BS_2SFFJ(c);
+
+ e.offset = jeb->offset;
+ e.len = c->sector_size;
+ e.err_address = &err_addr;
+
+ // D2(printf("FLASH ERASE ENABLED!!!\n"));
+ // D2(printf("erase address = %x\n", CYGNUM_FS_JFFS2_BASE_ADDRESS + jeb->offset));
+ // D2(printf("size = %x\n", c->sector_size));
+
+ err = cyg_io_get_config(sb->s_dev, CYG_IO_GET_CONFIG_FLASH_ERASE,
+ &e, &len);
+
+ return (err != ENOERR || e.flasherr != 0);
+}
+
Index: fs/jffs2/current/src/gcthread.c
===================================================================
RCS file: fs/jffs2/current/src/gcthread.c
diff -N fs/jffs2/current/src/gcthread.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ fs/jffs2/current/src/gcthread.c 11 Dec 2003 23:28:08 -0000
@@ -0,0 +1,52 @@
+/*
+ * JFFS2 -- Journalling Flash File System, Version 2.
+ *
+ * Copyright (C) 2001-2003 Red Hat, Inc.
+ *
+ * Created by David Woodhouse <dwmw2@redhat.com>
+ *
+ * For licensing information, see the file 'LICENCE' in this directory.
+ *
+ * $Id: gcthread.c,v 1.1 2003/11/26 15:55:35 dwmw2 Exp $
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/jffs2.h>
+#include "nodelist.h"
+
+
+static void jffs2_garbage_collect_thread(struct jffs2_sb_info *c);
+
+void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
+{
+ /* Wake up the thread */
+ (void)&jffs2_garbage_collect_thread;
+}
+
+void jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
+{
+ /* Start the thread. Doesn't matter if it fails -- it's only an optimisation anyway */
+}
+
+void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
+{
+ /* Stop the thread and wait for it if necessary */
+}
+
+
+static void jffs2_garbage_collect_thread(struct jffs2_sb_info *c)
+{
+#define this_thread_should_die() 0
+ while(!this_thread_should_die()) {
+ while(!jffs2_thread_should_wake(c)) {
+ /* Sleep.... */
+ continue;
+ }
+ if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
+ printf("No space for garbage collection. Aborting JFFS2 GC thread\n");
+ break;
+ }
+ }
+}