Commit 79023d0e authored by David Woodhouse's avatar David Woodhouse

Update to 2002-03-12 JFFS2 development tree. Main features:

 - Preliminary version of NAND flash support.
 - Locking documentation and fixes (including BKL removal because it's superfluous).
 - Performance improvements - especially for mount time. 
 - Annoying stuff like i_nlink on directories fixed.
 - Portability cleanups.
parent ace5d474
......@@ -44,7 +44,8 @@ if [ "$CONFIG_JFFS_FS" = "y" -o "$CONFIG_JFFS_FS" = "m" ] ; then
fi
dep_tristate 'Journalling Flash File System v2 (JFFS2) support' CONFIG_JFFS2_FS $CONFIG_MTD
if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFIG_JFFS2_FS" = "m" ] ; then
int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0
int ' JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0
dep_bool ' JFFS2 support for NAND flash' CONFIG_JFFS2_FS_NAND $CONFIG_EXPERIMENTAL
fi
tristate 'Compressed ROM file system support' CONFIG_CRAMFS
bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
......
#
# Makefile for the linux Journalling Flash FileSystem (JFFS) routines.
#
# $Id: Makefile,v 1.25 2001/09/25 20:59:41 dwmw2 Exp $
# $Id: Makefile,v 1.34 2002/03/08 11:27:59 dwmw2 Exp $
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
......@@ -10,15 +10,20 @@
# Note 2! The CFLAGS definitions are now in the main makefile...
COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o pushpull.o \
compr_zlib.o
COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o compr_zlib.o
JFFS2_OBJS := dir.o file.o ioctl.o nodelist.o malloc.o \
read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \
symlink.o build.o erase.o background.o
read.o nodemgmt.o readinode.o write.o scan.o gc.o \
symlink.o build.o erase.o background.o fs.o writev.o
LINUX_OBJS-24 := super-v24.o crc32.o
LINUX_OBJS-25 := super.o
NAND_OBJS-$(CONFIG_JFFS2_FS_NAND) := wbuf.o
O_TARGET := jffs2.o
obj-y := $(COMPR_OBJS) $(JFFS2_OBJS)
obj-y := $(COMPR_OBJS) $(JFFS2_OBJS) $(VERS_OBJS) $(NAND_OBJS-y) \
$(LINUX_OBJS-$(VERSION)$(PATCHLEVEL))
obj-m := $(O_TARGET)
include $(TOPDIR)/Rules.make
......
$Id: README.Locking,v 1.4 2002/03/08 16:20:06 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 permits erase-completion callback functions to be
called from bottom-half (timer) context, and these functions access
the data structures protected by this lock, it must be locked with
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.
node_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.
$Id: TODO,v 1.3 2001/03/01 23:26:48 dwmw2 Exp $
$Id: TODO,v 1.7 2002/03/11 12:36:59 dwmw2 Exp $
- disable compression in commit_write()? Or at least optimise the 'always write
whole page' bit.
- fix zlib. It's ugly as hell and there are at least three copies in the kernel tree
- Locking audit. Even more so now 2.5 took away the BKL.
- 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)
......@@ -10,11 +9,16 @@ $Id: TODO,v 1.3 2001/03/01 23:26:48 dwmw2 Exp $
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.
- stop it depending on a block device. mount(8) needs a change for this.
- make it work on NAND flash. We need to know when we can GC
deletion dirents, etc. And think about holes/truncation. It can
all be done reasonably simply, but it need implementing.
- NAND flash will require new dirent/dnode structures on the medium with
ECC data in rather than just the CRC we're using ATM.
- stop it depending on a block device.
- test, test, test
- NAND flash support:
- flush_wbuf using GC to fill it, don't just pad.
- Deal with write errors. Data don't get lost - we just have to write
the affected node(s) out again somewhere else.
- make fsync flush only if actually required
- make sys_sync() work.
- reboot notifier
- timed flush of old wbuf
- fix magical second arg of jffs2_flush_wbuf(). Split into two or more functions instead.
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001 Red Hat, Inc.
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
......@@ -31,19 +31,19 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
* $Id: background.c,v 1.16 2001/10/08 09:22:38 dwmw2 Exp $
* $Id: background.c,v 1.23 2002/03/06 12:37:08 dwmw2 Exp $
*
*/
#define __KERNEL_SYSCALLS__
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/unistd.h>
#include <linux/jffs2.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/mtd/compatmac.h> /* recalc_sigpending() */
#include "nodelist.h"
......@@ -106,10 +106,7 @@ static int jffs2_garbage_collect_thread(void *_c)
sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
/* FIXME in the 2.2 backport */
current->nice = 10;
#endif
set_user_nice(current, 10);
for (;;) {
spin_lock_irq(&current->sigmask_lock);
......
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001 Red Hat, Inc.
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
......@@ -31,12 +31,11 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
* $Id: build.c,v 1.16 2001/03/15 15:38:23 dwmw2 Exp $
* $Id: build.c,v 1.32 2002/03/08 15:11:24 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
#include <linux/jffs2.h>
#include <linux/slab.h>
#include "nodelist.h"
......@@ -51,7 +50,7 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode
- Scan directory tree from top down, setting nlink in inocaches
- Scan inocaches for inodes with nlink==0
*/
int jffs2_build_filesystem(struct jffs2_sb_info *c)
static int jffs2_build_filesystem(struct jffs2_sb_info *c)
{
int ret;
int i;
......@@ -59,7 +58,11 @@ int jffs2_build_filesystem(struct jffs2_sb_info *c)
/* First, scan the medium and build all the inode caches with
lists of physical nodes */
c->flags |= JFFS2_SB_FLAG_MOUNTING;
ret = jffs2_scan_medium(c);
c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
if (ret)
return ret;
......@@ -147,6 +150,7 @@ int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *i
D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring old metadata at 0x%08x\n",
metadata->fn->raw->flash_offset &~3));
jffs2_mark_node_obsolete(c, metadata->fn->raw);
jffs2_free_full_dnode(metadata->fn);
jffs2_free_tmp_dnode_info(metadata);
metadata = NULL;
......@@ -159,15 +163,25 @@ int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *i
if (!metadata) {
metadata = tn;
} else {
/* This will only happen if it has the _same_ version
number as the existing metadata node. */
D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring new metadata at 0x%08x\n",
tn->fn->raw->flash_offset &~3));
jffs2_mark_node_obsolete(c, tn->fn->raw);
jffs2_free_full_dnode(tn->fn);
jffs2_free_tmp_dnode_info(tn);
}
}
}
if (ic->scan->version) {
/* It's a regular file, so truncate it to the last known
i_size, if necessary */
D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 truncating fraglist to 0x%08x\n", ic->scan->isize));
jffs2_truncate_fraglist(c, &fraglist, ic->scan->isize);
}
/* OK. Now clear up */
if (metadata) {
jffs2_free_full_dnode(metadata->fn);
......@@ -201,6 +215,10 @@ int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *i
if (child_ic->nlink++ && fd->type == DT_DIR) {
printk(KERN_NOTICE "Child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n", fd->name, fd->ino, ic->ino);
if (fd->ino == 1 && ic->ino == 1) {
printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n");
printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n");
}
/* What do we do about it? */
}
D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino));
......@@ -251,7 +269,58 @@ int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inod
}
kfree(ic->scan);
ic->scan = NULL;
// jffs2_del_ino_cache(c, ic);
// jffs2_free_inode_cache(ic);
/*
We don't delete the inocache from the hash list and free it yet.
The erase code will do that, when all the nodes are completely gone.
*/
return ret;
}
int jffs2_do_mount_fs(struct jffs2_sb_info *c)
{
int i;
c->free_size = c->flash_size;
c->nr_blocks = c->flash_size / c->sector_size;
c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
if (!c->blocks)
return -ENOMEM;
for (i=0; i<c->nr_blocks; i++) {
INIT_LIST_HEAD(&c->blocks[i].list);
c->blocks[i].offset = i * c->sector_size;
c->blocks[i].free_size = c->sector_size;
c->blocks[i].dirty_size = 0;
c->blocks[i].used_size = 0;
c->blocks[i].first_node = NULL;
c->blocks[i].last_node = NULL;
}
init_MUTEX(&c->alloc_sem);
init_MUTEX(&c->erase_free_sem);
init_waitqueue_head(&c->erase_wait);
spin_lock_init(&c->erase_completion_lock);
spin_lock_init(&c->inocache_lock);
INIT_LIST_HEAD(&c->clean_list);
INIT_LIST_HEAD(&c->dirty_list);
INIT_LIST_HEAD(&c->erasable_list);
INIT_LIST_HEAD(&c->erasing_list);
INIT_LIST_HEAD(&c->erase_pending_list);
INIT_LIST_HEAD(&c->erasable_pending_wbuf_list);
INIT_LIST_HEAD(&c->erase_complete_list);
INIT_LIST_HEAD(&c->free_list);
INIT_LIST_HEAD(&c->bad_list);
INIT_LIST_HEAD(&c->bad_used_list);
c->highest_ino = 1;
if (jffs2_build_filesystem(c)) {
D1(printk(KERN_DEBUG "build_fs failed\n"));
jffs2_free_ino_caches(c);
jffs2_free_raw_node_refs(c);
kfree(c->blocks);
return -EIO;
}
return 0;
}
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001 Red Hat, Inc.
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
* Created by Arjan van de Ven <arjanv@redhat.com>
*
......@@ -31,24 +31,34 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
* $Id: compr.c,v 1.17 2001/09/23 09:56:46 dwmw2 Exp $
* $Id: compr.c,v 1.23 2002/01/25 01:49:26 dwmw2 Exp $
*
*/
#ifdef __KERNEL__
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/errno.h>
#else
#define KERN_DEBUG
#define KERN_NOTICE
#define KERN_WARNING
#define printk printf
#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#endif
#include <linux/jffs2.h>
int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen);
void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
int rtime_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen);
void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
int rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen);
void rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen);
void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen);
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);
int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen);
void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen);
/* jffs2_compress:
......@@ -69,28 +79,28 @@ void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32
* *datalen accordingly to show the amount of data which were compressed.
*/
unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
__u32 *datalen, __u32 *cdatalen)
uint32_t *datalen, uint32_t *cdatalen)
{
int ret;
ret = zlib_compress(data_in, cpage_out, datalen, cdatalen);
ret = jffs2_zlib_compress(data_in, cpage_out, datalen, cdatalen);
if (!ret) {
return JFFS2_COMPR_ZLIB;
}
#if 0 /* Disabled 23/9/1. With zlib it hardly ever gets a look in */
ret = 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
#if 0 /* Disabled 26/2/1. Obsoleted by dynrubin */
ret = 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
/* rtime does manage to recompress already-compressed data */
ret = rtime_compress(data_in, cpage_out, datalen, cdatalen);
ret = jffs2_rtime_compress(data_in, cpage_out, datalen, cdatalen);
if (!ret) {
return JFFS2_COMPR_RTIME;
}
......@@ -108,7 +118,7 @@ unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
unsigned char *data_out, __u32 cdatalen, __u32 datalen)
unsigned char *data_out, uint32_t cdatalen, uint32_t datalen)
{
switch (comprtype) {
case JFFS2_COMPR_NONE:
......@@ -121,23 +131,23 @@ int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
break;
case JFFS2_COMPR_ZLIB:
zlib_decompress(cdata_in, data_out, cdatalen, datalen);
jffs2_zlib_decompress(cdata_in, data_out, cdatalen, datalen);
break;
case JFFS2_COMPR_RTIME:
rtime_decompress(cdata_in, data_out, cdatalen, datalen);
jffs2_rtime_decompress(cdata_in, data_out, cdatalen, datalen);
break;
case JFFS2_COMPR_RUBINMIPS:
#if 0 /* Disabled 23/9/1 */
rubinmips_decompress(cdata_in, data_out, cdatalen, datalen);
jffs2_rubinmips_decompress(cdata_in, data_out, cdatalen, datalen);
#else
printk(KERN_WARNING "JFFS2: Rubinmips compression encountered but support not compiled in!\n");
#endif
break;
case JFFS2_COMPR_DYNRUBIN:
#if 1 /* Phase this one out */
dynrubin_decompress(cdata_in, data_out, cdatalen, datalen);
jffs2_dynrubin_decompress(cdata_in, data_out, cdatalen, datalen);
#else
printk(KERN_WARNING "JFFS2: Dynrubin compression encountered but support not compiled in!\n");
#endif
......
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001 Red Hat, Inc.
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
* Created by Arjan van de Ven <arjanv@redhat.com>
*
......@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
* $Id: compr_rtime.c,v 1.5 2001/03/15 15:38:23 dwmw2 Exp $
* $Id: compr_rtime.c,v 1.8 2002/01/25 01:49:26 dwmw2 Exp $
*
*
* Very simple lz77-ish encoder.
......@@ -51,8 +51,8 @@
#include <linux/string.h>
/* _compress returns the compressed size, -1 if bigger */
int rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
__u32 *sourcelen, __u32 *dstlen)
int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t *sourcelen, uint32_t *dstlen)
{
int positions[256];
int outpos = 0;
......@@ -91,8 +91,8 @@ int rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
}
void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
__u32 srclen, __u32 destlen)
void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t srclen, uint32_t destlen)
{
int positions[256];
int outpos = 0;
......
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001 Red Hat, Inc.
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
* Created by Arjan van de Ven <arjanv@redhat.com>
*
......@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
* $Id: compr_rubin.c,v 1.13 2001/09/23 10:06:05 rmk Exp $
* $Id: compr_rubin.c,v 1.16 2002/01/25 01:49:26 dwmw2 Exp $
*
*/
......@@ -43,7 +43,7 @@
void init_rubin(struct rubin_state *rs, int div, int *bits)
static void init_rubin(struct rubin_state *rs, int div, int *bits)
{
int c;
......@@ -56,7 +56,7 @@ void init_rubin(struct rubin_state *rs, int div, int *bits)
}
int encode(struct rubin_state *rs, long A, long B, int symbol)
static int encode(struct rubin_state *rs, long A, long B, int symbol)
{
long i0, i1;
......@@ -91,7 +91,7 @@ int encode(struct rubin_state *rs, long A, long B, int symbol)
}
void end_rubin(struct rubin_state *rs)
static void end_rubin(struct rubin_state *rs)
{
int i;
......@@ -104,7 +104,7 @@ void end_rubin(struct rubin_state *rs)
}
void init_decode(struct rubin_state *rs, int div, int *bits)
static void init_decode(struct rubin_state *rs, int div, int *bits)
{
init_rubin(rs, div, bits);
......@@ -151,7 +151,7 @@ static void __do_decode(struct rubin_state *rs, unsigned long p, unsigned long q
rs->rec_q = rec_q;
}
int decode(struct rubin_state *rs, long A, long B)
static int decode(struct rubin_state *rs, long A, long B)
{
unsigned long p = rs->p, q = rs->q;
long i0, threshold;
......@@ -212,8 +212,8 @@ static int in_byte(struct rubin_state *rs)
int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in,
unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen)
static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in,
unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen)
{
int outpos = 0;
int pos=0;
......@@ -246,20 +246,20 @@ int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in,
}
#if 0
/* _compress returns the compressed size, -1 if bigger */
int rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out,
__u32 *sourcelen, __u32 *dstlen)
int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t *sourcelen, uint32_t *dstlen)
{
return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
}
#endif
int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out,
__u32 *sourcelen, __u32 *dstlen)
int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t *sourcelen, uint32_t *dstlen)
{
int bits[8];
unsigned char histo[256];
int i;
int ret;
__u32 mysrclen, mydstlen;
uint32_t mysrclen, mydstlen;
mysrclen = *sourcelen;
mydstlen = *dstlen - 8;
......@@ -315,8 +315,8 @@ int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out,
return 0;
}
void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in,
unsigned char *page_out, __u32 srclen, __u32 destlen)
static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in,
unsigned char *page_out, uint32_t srclen, uint32_t destlen)
{
int outpos = 0;
struct rubin_state rs;
......@@ -330,14 +330,14 @@ void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in,
}
void rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out,
__u32 sourcelen, __u32 dstlen)
void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t sourcelen, uint32_t dstlen)
{
rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen);
}
void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out,
__u32 sourcelen, __u32 dstlen)
void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t sourcelen, uint32_t dstlen)
{
int bits[8];
int c;
......
/* Rubin encoder/decoder header */
/* work started at : aug 3, 1994 */
/* last modification : aug 15, 1994 */
/* $Id: compr_rubin.h,v 1.5 2001/02/26 13:50:01 dwmw2 Exp $ */
/* $Id: compr_rubin.h,v 1.6 2002/01/25 01:49:26 dwmw2 Exp $ */
#include "pushpull.h"
......@@ -19,10 +19,3 @@ struct rubin_state {
int bit_divider;
int bits[8];
};
void init_rubin (struct rubin_state *rs, int div, int *bits);
int encode (struct rubin_state *, long, long, int);
void end_rubin (struct rubin_state *);
void init_decode (struct rubin_state *, int div, int *bits);
int decode (struct rubin_state *, long, long);
......@@ -85,7 +85,7 @@ void __exit jffs2_zlib_exit(void)
vfree(inflate_workspace);
}
int zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t *sourcelen, uint32_t *dstlen)
{
z_stream strm;
......@@ -145,7 +145,7 @@ int zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
return 0;
}
void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t srclen, uint32_t destlen)
{
z_stream strm;
......
/* $Id: comprtest.c,v 1.4 2001/02/21 14:03:20 dwmw2 Exp $ */
/* $Id: comprtest.c,v 1.5 2002/01/03 15:20:44 dwmw2 Exp $ */
#include <linux/kernel.h>
#include <linux/string.h>
......@@ -266,13 +266,13 @@ static unsigned char comprbuf[TESTDATA_LEN];
static unsigned char decomprbuf[TESTDATA_LEN];
int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in,
unsigned char *data_out, __u32 cdatalen, __u32 datalen);
unsigned char *data_out, uint32_t cdatalen, uint32_t datalen);
unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out,
__u32 *datalen, __u32 *cdatalen);
uint32_t *datalen, uint32_t *cdatalen);
int init_module(void ) {
unsigned char comprtype;
__u32 c, d;
uint32_t c, d;
int ret;
printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001 Red Hat, Inc.
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
......@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
* $Id: malloc.c,v 1.16 2001/03/15 15:38:24 dwmw2 Exp $
* $Id: malloc.c,v 1.21 2002/03/12 17:36:55 dwmw2 Exp $
*
*/
......@@ -49,7 +49,6 @@
/* These are initialised to NULL in the kernel startup code.
If you're porting to other operating systems, beware */
static kmem_cache_t *jffs2_inode_cachep;
static kmem_cache_t *full_dnode_slab;
static kmem_cache_t *raw_dirent_slab;
static kmem_cache_t *raw_inode_slab;
......@@ -58,89 +57,47 @@ static kmem_cache_t *raw_node_ref_slab;
static kmem_cache_t *node_frag_slab;
static kmem_cache_t *inode_cache_slab;
void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn)
{
struct jffs2_tmp_dnode_info *next;
while (tn) {
next = tn;
tn = tn->next;
jffs2_free_full_dnode(next->fn);
jffs2_free_tmp_dnode_info(next);
}
}
void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
{
struct jffs2_full_dirent *next;
while (fd) {
next = fd->next;
jffs2_free_full_dirent(fd);
fd = next;
}
}
struct inode *jffs2_alloc_inode(struct super_block *sb)
{
struct jffs2_inode_info *ei;
ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, SLAB_KERNEL);
if (!ei)
return NULL;
return &ei->vfs_inode;
}
void jffs2_destroy_inode(struct inode *inode)
{
kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
}
static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
{
struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR) {
init_MUTEX(&ei->sem);
inode_init_once(&ei->vfs_inode);
}
}
int __init jffs2_create_slab_caches(void)
{
full_dnode_slab = kmem_cache_create("jffs2_full_dnode", sizeof(struct jffs2_full_dnode), 0, JFFS2_SLAB_POISON, NULL, NULL);
full_dnode_slab = kmem_cache_create("jffs2_full_dnode",
sizeof(struct jffs2_full_dnode),
0, JFFS2_SLAB_POISON, NULL, NULL);
if (!full_dnode_slab)
goto err;
raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", sizeof(struct jffs2_raw_dirent), 0, JFFS2_SLAB_POISON, NULL, NULL);
raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent",
sizeof(struct jffs2_raw_dirent),
0, JFFS2_SLAB_POISON, NULL, NULL);
if (!raw_dirent_slab)
goto err;
raw_inode_slab = kmem_cache_create("jffs2_raw_inode", sizeof(struct jffs2_raw_inode), 0, JFFS2_SLAB_POISON, NULL, NULL);
raw_inode_slab = kmem_cache_create("jffs2_raw_inode",
sizeof(struct jffs2_raw_inode),
0, JFFS2_SLAB_POISON, NULL, NULL);
if (!raw_inode_slab)
goto err;
tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", sizeof(struct jffs2_tmp_dnode_info), 0, JFFS2_SLAB_POISON, NULL, NULL);
tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode",
sizeof(struct jffs2_tmp_dnode_info),
0, JFFS2_SLAB_POISON, NULL, NULL);
if (!tmp_dnode_info_slab)
goto err;
raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", sizeof(struct jffs2_raw_node_ref), 0, JFFS2_SLAB_POISON, NULL, NULL);
raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref",
sizeof(struct jffs2_raw_node_ref),
0, JFFS2_SLAB_POISON, NULL, NULL);
if (!raw_node_ref_slab)
goto err;
node_frag_slab = kmem_cache_create("jffs2_node_frag", sizeof(struct jffs2_node_frag), 0, JFFS2_SLAB_POISON, NULL, NULL);
node_frag_slab = kmem_cache_create("jffs2_node_frag",
sizeof(struct jffs2_node_frag),
0, JFFS2_SLAB_POISON, NULL, NULL);
if (!node_frag_slab)
goto err;
jffs2_inode_cachep = kmem_cache_create("jffs2_inode_cache",
sizeof(struct jffs2_inode_info),
0, SLAB_HWCACHE_ALIGN,
init_once, NULL);
if (!jffs2_inode_cachep)
goto err;
inode_cache_slab = kmem_cache_create("jffs2_inode", sizeof(struct jffs2_inode_cache), 0, JFFS2_SLAB_POISON, NULL, NULL);
inode_cache_slab = kmem_cache_create("jffs2_inode_cache",
sizeof(struct jffs2_inode_cache),
0, JFFS2_SLAB_POISON, NULL, NULL);
if (inode_cache_slab)
return 0;
err:
......@@ -164,9 +121,6 @@ void jffs2_destroy_slab_caches(void)
kmem_cache_destroy(node_frag_slab);
if(inode_cache_slab)
kmem_cache_destroy(inode_cache_slab);
if(jffs2_inode_cachep)
kmem_cache_destroy(jffs2_inode_cachep);
}
struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize)
......
......@@ -31,14 +31,14 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
* $Id: nodelist.c,v 1.30.2.3 2002/02/23 14:04:44 dwmw2 Exp $
* $Id: nodelist.c,v 1.42 2002/03/11 11:17:29 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
#include <linux/jffs2.h>
#include <linux/fs.h>
#include <linux/mtd/mtd.h>
#include <linux/interrupt.h>
#include "nodelist.h"
void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list)
......@@ -89,13 +89,37 @@ void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnod
*prev = tn;
}
static void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn)
{
struct jffs2_tmp_dnode_info *next;
while (tn) {
next = tn;
tn = tn->next;
jffs2_free_full_dnode(next->fn);
jffs2_free_tmp_dnode_info(next);
}
}
static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
{
struct jffs2_full_dirent *next;
while (fd) {
next = fd->next;
jffs2_free_full_dirent(fd);
fd = next;
}
}
/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
with this ino, returning the former in order of version */
int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f,
struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
__u32 *highest_version, __u32 *latest_mctime,
__u32 *mctime_ver)
uint32_t *highest_version, uint32_t *latest_mctime,
uint32_t *mctime_ver)
{
struct jffs2_raw_node_ref *ref = f->inocache->nodes;
struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL;
......@@ -111,6 +135,9 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
if (!f->inocache->nodes) {
printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", ino);
}
spin_lock_bh(&c->erase_completion_lock);
for (ref = f->inocache->nodes; ref && ref->next_in_ino; ref = ref->next_in_ino) {
/* Work out whether it's a data node or a dirent node */
if (ref->flash_offset & 1) {
......@@ -118,7 +145,12 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref->flash_offset &~3));
continue;
}
err = c->mtd->read(c->mtd, (ref->flash_offset & ~3), min(ref->totlen, sizeof(node)), &retlen, (void *)&node);
/* We can hold a pointer to a non-obsolete node without the spinlock,
but _obsolete_ nodes may disappear at any time, if the block
they're in gets erased */
spin_unlock_bh(&c->erase_completion_lock);
err = jffs2_flash_read(c, (ref->flash_offset & ~3), min(ref->totlen, sizeof(node)), &retlen, (void *)&node);
if (err) {
printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, (ref->flash_offset) & ~3);
goto free_out;
......@@ -143,8 +175,10 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
if (node.d.version > *highest_version)
*highest_version = node.d.version;
if (ref->flash_offset & 1) {
/* Obsoleted */
continue;
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n",
ref->flash_offset & ~3);
BUG();
}
fd = jffs2_alloc_full_dirent(node.d.nsize+1);
if (!fd) {
......@@ -167,7 +201,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
dirent we've already read from the flash
*/
if (retlen > sizeof(struct jffs2_raw_dirent))
memcpy(&fd->name[0], &node.d.name[0], min((__u32)node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
memcpy(&fd->name[0], &node.d.name[0], min((uint32_t)node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
/* Do we need to copy any more of the name directly
from the flash?
......@@ -175,7 +209,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) {
int already = retlen - sizeof(struct jffs2_raw_dirent);
err = c->mtd->read(c->mtd, (ref->flash_offset & ~3) + retlen,
err = jffs2_flash_read(c, (ref->flash_offset & ~3) + retlen,
node.d.nsize - already, &retlen, &fd->name[already]);
if (!err && retlen != node.d.nsize - already)
err = -EIO;
......@@ -207,9 +241,10 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", node.d.version, *highest_version));
if (ref->flash_offset & 1) {
D1(printk(KERN_DEBUG "obsoleted\n"));
/* Obsoleted */
continue;
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n",
ref->flash_offset & ~3);
BUG();
}
tn = jffs2_alloc_tmp_dnode_info();
if (!tn) {
......@@ -254,7 +289,10 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode
break;
}
}
spin_lock_bh(&c->erase_completion_lock);
}
spin_unlock_bh(&c->erase_completion_lock);
*tnp = ret_tn;
*fdp = ret_fd;
......@@ -272,15 +310,19 @@ struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, int ino)
D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino));
spin_lock (&c->inocache_lock);
ret = c->inocache_list[ino % INOCACHE_HASHSIZE];
while (ret && ret->ino < ino) {
ret = ret->next;
}
spin_unlock(&c->inocache_lock);
if (c->inocache_last && c->inocache_last->ino == ino) {
ret = c->inocache_last;
} else {
ret = c->inocache_list[ino % INOCACHE_HASHSIZE];
while (ret && ret->ino < ino) {
ret = ret->next;
}
if (ret && ret->ino != ino)
ret = NULL;
if (ret && ret->ino != ino)
ret = NULL;
}
spin_unlock(&c->inocache_lock);
D2(printk(KERN_DEBUG "jffs2_get_ino_cache found %p for ino %u\n", ret, ino));
return ret;
......@@ -299,6 +341,9 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new
}
new->next = *prev;
*prev = new;
c->inocache_last = new;
spin_unlock(&c->inocache_lock);
}
......@@ -316,6 +361,9 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
if ((*prev) == old) {
*prev = old->next;
}
if (c->inocache_last == old)
c->inocache_last = NULL;
spin_unlock(&c->inocache_lock);
}
......@@ -334,6 +382,7 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c)
}
c->inocache_list[i] = NULL;
}
c->inocache_last = NULL;
}
void jffs2_free_raw_node_refs(struct jffs2_sb_info *c)
......
This diff is collapsed.
This diff is collapsed.
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2002 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
* The original JFFS, from which the design for JFFS2 was derived,
* was designed and implemented by Axis Communications AB.
*
* The contents of this file are subject to the Red Hat eCos Public
* License Version 1.1 (the "Licence"); you may not use this file
* except in compliance with the Licence. You may obtain a copy of
* the Licence at http://www.redhat.com/
*
* Software distributed under the Licence is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the Licence for the specific language governing rights and
* limitations under the Licence.
*
* The Original Code is JFFS2 - Journalling Flash File System, version 2
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU General Public License version 2 (the "GPL"), in
* which case the provisions of the GPL are applicable instead of the
* above. If you wish to allow the use of your version of this file
* only under the terms of the GPL and not to allow others to use your
* version of this file under the RHEPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the GPL. If you do not delete the
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
* $Id: os-linux.h,v 1.15 2002/03/08 11:31:48 dwmw2 Exp $
*
*/
#ifndef __JFFS2_OS_LINUX_H__
#define __JFFS2_OS_LINUX_H__
#include <linux/version.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
#define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode))
#define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode)
#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb)
#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
#elif defined(JFFS2_OUT_OF_KERNEL)
#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u)
#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) )
#define JFFS2_SB_INFO(sb) ((struct jffs2_sb_info *) &(sb)->u)
#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
#else
#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i)
#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) )
#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb)
#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
#endif
#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)
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,1)
#define JFFS2_F_I_RDEV_MIN(f) (minor(OFNI_EDONI_2SFFJ(f)->i_rdev))
#define JFFS2_F_I_RDEV_MAJ(f) (major(OFNI_EDONI_2SFFJ(f)->i_rdev))
#else
#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)))
#endif
static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
f->highest_version = 0;
f->fraglist = NULL;
f->metadata = NULL;
f->dents = NULL;
f->flags = 0;
f->usercompr = 0;
#else
memset(f, 0, sizeof(*f));
init_MUTEX_LOCKED(&f->sem);
#endif
}
#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
#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)
#define jffs2_flash_write(c, ofs, len, retlen, buf) ((c)->mtd->write((c)->mtd, ofs, len, retlen, buf))
#define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf))
#define jffs2_flush_wbuf(c, flag) do { ; } while(0)
#define jffs2_nand_read_failcnt(c,jeb) do { ; } while(0)
#define jffs2_write_nand_badblock(c,jeb) do { ; } while(0)
#define jffs2_flash_writev jffs2_flash_direct_writev
#else /* NAND support present */
#define jffs2_can_mark_obsolete(c) (c->mtd->type == MTD_NORFLASH || c->mtd->type == MTD_RAM)
#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
#define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
#define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf))
/* wbuf.c */
int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf);
int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf);
int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,int mode);
int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
#endif /* NAND */
/* background.c */
int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c);
void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c);
void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c);
/* 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_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_prepare_write (struct file *, struct page *, unsigned, unsigned);
int jffs2_commit_write (struct file *, struct page *, unsigned, unsigned);
/* ioctl.c */
int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
/* symlink.c */
extern struct inode_operations jffs2_symlink_inode_operations;
/* fs.c */
void jffs2_read_inode (struct inode *);
void jffs2_clear_inode (struct inode *);
struct inode *jffs2_new_inode (struct inode *dir_i, int mode,
struct jffs2_raw_inode *ri);
int jffs2_statfs (struct super_block *, struct statfs *);
void jffs2_write_super (struct super_block *);
int jffs2_remount_fs (struct super_block *, int *, char *);
int jffs2_do_fill_super(struct super_block *sb, void *data, int silent);
/* writev.c */
int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs,
unsigned long count, loff_t to, size_t *retlen);
/* super.c */
#endif /* __JFFS2_OS_LINUX_H__ */
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001 Red Hat, Inc.
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
......@@ -31,12 +31,15 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
* $Id: pushpull.h,v 1.5 2001/09/23 10:04:15 rmk Exp $
* $Id: pushpull.h,v 1.7 2002/03/06 12:37:08 dwmw2 Exp $
*
*/
#ifndef __PUSHPULL_H__
#define __PUSHPULL_H__
#include <linux/errno.h>
struct pushpull {
unsigned char *buf;
unsigned int buflen;
......@@ -44,9 +47,36 @@ struct pushpull {
unsigned int reserve;
};
void init_pushpull(struct pushpull *, char *, unsigned, unsigned, unsigned);
int pushbit(struct pushpull *pp, int bit, int use_reserved);
int pushedbits(struct pushpull *pp);
static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve)
{
pp->buf = buf;
pp->buflen = buflen;
pp->ofs = ofs;
pp->reserve = reserve;
}
static inline int pushbit(struct pushpull *pp, int bit, int use_reserved)
{
if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) {
return -ENOSPC;
}
if (bit) {
pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7)));
}
else {
pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7)));
}
pp->ofs++;
return 0;
}
static inline int pushedbits(struct pushpull *pp)
{
return pp->ofs;
}
static inline int pullbit(struct pushpull *pp)
{
......
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001 Red Hat, Inc.
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
......@@ -31,14 +31,14 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
* $Id: read.c,v 1.13.2.1 2002/02/01 23:32:33 dwmw2 Exp $
* $Id: read.c,v 1.22 2002/03/02 22:08:27 dwmw2 Exp $
*
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/crc32.h>
#include <linux/jffs2.h>
#include <linux/pagemap.h>
#include <linux/mtd/mtd.h>
#include "nodelist.h"
......@@ -46,7 +46,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
{
struct jffs2_raw_inode *ri;
size_t readlen;
__u32 crc;
uint32_t crc;
unsigned char *decomprbuf = NULL;
unsigned char *readbuf = NULL;
int ret = 0;
......@@ -55,7 +55,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
if (!ri)
return -ENOMEM;
ret = c->mtd->read(c->mtd, fd->raw->flash_offset & ~3, sizeof(*ri), &readlen, (char *)ri);
ret = jffs2_flash_read(c, fd->raw->flash_offset & ~3, sizeof(*ri), &readlen, (char *)ri);
if (ret) {
jffs2_free_raw_inode(ri);
printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", fd->raw->flash_offset & ~3, ret);
......@@ -124,7 +124,7 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
}
D2(printk(KERN_DEBUG "Read %d bytes to %p\n", ri->csize, readbuf));
ret = c->mtd->read(c->mtd, (fd->raw->flash_offset &~3) + sizeof(*ri), ri->csize, &readlen, readbuf);
ret = jffs2_flash_read(c, (fd->raw->flash_offset &~3) + sizeof(*ri), ri->csize, &readlen, readbuf);
if (!ret && readlen != ri->csize)
ret = -EIO;
......@@ -161,3 +161,99 @@ int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsig
return ret;
}
int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
unsigned char *buf, uint32_t offset, uint32_t len)
{
uint32_t end = offset + len;
struct jffs2_node_frag *frag = f->fraglist;
int ret;
D1(printk(KERN_DEBUG "jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x\n",
f->inocache->ino, offset, offset+len));
while(frag && frag->ofs + frag->size <= offset) {
D2(printk(KERN_DEBUG "skipping frag %d-%d; before the region we care about\n", frag->ofs, frag->ofs + frag->size));
frag = frag->next;
}
/* XXX FIXME: Where a single physical node actually shows up in two
frags, we read it twice. Don't do that. */
/* Now we're pointing at the first frag which overlaps our page */
while(offset < end) {
D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end));
if (!frag || frag->ofs > offset) {
uint32_t holesize = end - offset;
if (frag) {
D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset));
holesize = min(holesize, frag->ofs - offset);
D1(jffs2_print_frag_list(f));
}
D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize));
memset(buf, 0, holesize);
buf += holesize;
offset += holesize;
continue;
} else if (frag->ofs < offset && (offset & (PAGE_CACHE_SIZE-1)) != 0) {
D1(printk(KERN_NOTICE "Eep. Overlap in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n",
f->inocache->ino, frag->ofs, offset));
D1(jffs2_print_frag_list(f));
memset(buf, 0, end - offset);
return -EIO;
} else if (!frag->node) {
uint32_t holeend = min(end, frag->ofs + frag->size);
D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size));
memset(buf, 0, holeend - offset);
buf += holeend - offset;
offset = holeend;
frag = frag->next;
continue;
} else {
uint32_t readlen;
readlen = min(frag->size, end - offset);
D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%x\n", frag->ofs, frag->ofs+readlen, frag->node->raw->flash_offset & ~3));
ret = jffs2_read_dnode(c, frag->node, buf, frag->ofs - frag->node->ofs, readlen);
D2(printk(KERN_DEBUG "node read done\n"));
if (ret) {
D1(printk(KERN_DEBUG"jffs2_read_inode_range error %d\n",ret));
memset(buf, 0, frag->size);
return ret;
}
}
buf += frag->size;
offset += frag->size;
frag = frag->next;
D2(printk(KERN_DEBUG "node read was OK. Looping\n"));
}
return 0;
}
/* Core function to read symlink target. */
char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
{
char *buf;
int ret;
down(&f->sem);
if (!f->metadata) {
printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino);
up(&f->sem);
return ERR_PTR(-EINVAL);
}
buf = kmalloc(f->metadata->size+1, GFP_USER);
if (!buf) {
up(&f->sem);
return ERR_PTR(-ENOMEM);
}
buf[f->metadata->size]=0;
ret = jffs2_read_dnode(c, f->metadata, buf, 0, f->metadata->size);
up(&f->sem);
if (ret) {
kfree(buf);
return ERR_PTR(ret);
}
return buf;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -31,7 +31,7 @@
* provisions above, a recipient may use your version of this file
* under either the RHEPL or the GPL.
*
* $Id: symlink.c,v 1.5.2.1 2002/01/15 10:39:06 dwmw2 Exp $
* $Id: symlink.c,v 1.9 2002/01/10 09:29:53 dwmw2 Exp $
*
*/
......@@ -39,7 +39,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/jffs2.h>
#include "nodelist.h"
int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen);
......@@ -52,40 +51,12 @@ struct inode_operations jffs2_symlink_inode_operations =
setattr: jffs2_setattr
};
static char *jffs2_getlink(struct dentry *dentry)
{
struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
char *buf;
int ret;
down(&f->sem);
if (!f->metadata) {
up(&f->sem);
printk(KERN_NOTICE "No metadata for symlink inode #%lu\n", dentry->d_inode->i_ino);
return ERR_PTR(-EINVAL);
}
buf = kmalloc(f->metadata->size+1, GFP_USER);
if (!buf) {
up(&f->sem);
return ERR_PTR(-ENOMEM);
}
buf[f->metadata->size]=0;
ret = jffs2_read_dnode(JFFS2_SB_INFO(dentry->d_inode->i_sb), f->metadata, buf, 0, f->metadata->size);
up(&f->sem);
if (ret) {
kfree(buf);
return ERR_PTR(ret);
}
return buf;
}
int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen)
{
unsigned char *kbuf;
int ret;
kbuf = jffs2_getlink(dentry);
kbuf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode));
if (IS_ERR(kbuf))
return PTR_ERR(kbuf);
......@@ -99,7 +70,7 @@ int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
unsigned char *buf;
int ret;
buf = jffs2_getlink(dentry);
buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode));
if (IS_ERR(buf))
return PTR_ERR(buf);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment