patch-2.4.0-test6 linux/fs/jffs/inode-v23.c

Next file: linux/fs/jffs/intrep.c
Previous file: linux/fs/jffs/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test5/linux/fs/jffs/inode-v23.c linux/fs/jffs/inode-v23.c
@@ -1,19 +1,21 @@
 /*
  * JFFS -- Journalling Flash File System, Linux implementation.
  *
- * Copyright (C) 1999, 2000  Finn Hakansson, Axis Communications, Inc.
+ * Copyright (C) 1999, 2000  Axis Communications AB.
+ *
+ * Created by Finn Hakansson <finn@axis.com>.
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * $Id: inode-v23.c,v 1.17 2000/07/06 20:35:19 prumpf Exp $
+ * $Id: inode-v23.c,v 1.33 2000/08/09 15:59:06 dwmw2 Exp $
  *
  *
  * Ported to Linux 2.3.x and MTD:
  * Copyright (C) 2000  Alexander Larsson (alex@cendio.se), Cendio Systems AB
- * 
+ *
  */
 
 /* inode.c -- Contains the code that is called from the VFS.  */
@@ -24,7 +26,15 @@
  * maybe other stuff do to.
  */
 
-#include <linux/config.h>
+/* Argh. Some architectures have kernel_thread in asm/processor.h
+   Some have it in unistd.h and you need to define __KERNEL_SYSCALLS__
+   Pass me a baseball bat and the person responsible.
+   dwmw2
+*/
+#define __KERNEL_SYSCALLS__
+#include <linux/sched.h>
+#include <linux/unistd.h>
+
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/types.h>
@@ -45,16 +55,6 @@
 #include "jffs_fm.h"
 #include "intrep.h"
 
-#if defined(CONFIG_JFFS_FS_VERBOSE) && CONFIG_JFFS_FS_VERBOSE
-#define D(x) x
-#else
-#define D(x)
-#endif
-#define D1(x) D(x)
-#define D2(x) 
-#define D3(x) 
-#define ASSERT(x) x
-
 static int jffs_remove(struct inode *dir, struct dentry *dentry, int type);
 
 static struct super_operations jffs_ops;
@@ -64,22 +64,24 @@
 static struct inode_operations jffs_dir_inode_operations;
 static struct address_space_operations jffs_address_operations;
 
+
 /* Called by the VFS at mount time to initialize the whole file system.  */
 static struct super_block *
 jffs_read_super(struct super_block *sb, void *data, int silent)
 {
 	kdev_t dev = sb->s_dev;
 	struct inode *root_inode;
+	struct jffs_control *c;
 
-	printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n",
-	       kdevname(dev));
+	D1(printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n",
+		  kdevname(dev)));
 
-	if (MAJOR(dev)!=MTD_BLOCK_MAJOR) {
-	  printk(KERN_WARNING "JFFS: Trying to mount non-mtd device.\n");
-	  return 0;
+	if (MAJOR(dev) != MTD_BLOCK_MAJOR) {
+		printk(KERN_WARNING "JFFS: Trying to mount a "
+		       "non-mtd device.\n");
+		return 0;
 	}
 
-	set_blocksize(dev, PAGE_CACHE_SIZE);
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
 	sb->u.generic_sbp = (void *) 0;
@@ -98,19 +100,36 @@
 	root_inode = iget(sb, JFFS_MIN_INO);
 	if (!root_inode)
 	        goto jffs_sb_err2;
-	
+
 	/* Get the root directory of this file system.  */
 	if (!(sb->s_root = d_alloc_root(root_inode))) {
 		goto jffs_sb_err3;
 	}
 
-#ifdef USE_GC
-	/* Do a garbage collect every time we mount.  */
-	jffs_garbage_collect((struct jffs_control *)sb->u.generic_sbp);
-#endif
+	c = (struct jffs_control *) sb->u.generic_sbp;
 
-	printk(KERN_NOTICE "JFFS: Successfully mounted device %s.\n",
-	       kdevname(dev));
+	/* Set the Garbage Collection thresholds */
+
+	/* GC if free space goes below 5% of the total size */
+	c->gc_minfree_threshold = c->fmc->flash_size / 20;
+
+	if (c->gc_minfree_threshold < c->fmc->sector_size)
+		c->gc_minfree_threshold = c->fmc->sector_size;
+
+	/* GC if dirty space exceeds 33% of the total size. */
+	c->gc_maxdirty_threshold = c->fmc->flash_size / 3;
+
+	if (c->gc_maxdirty_threshold < c->fmc->sector_size)
+		c->gc_maxdirty_threshold = c->fmc->sector_size;
+
+
+	c->thread_pid = kernel_thread (jffs_garbage_collect_thread, 
+				        (void *) c, 
+				        CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	D1(printk(KERN_NOTICE "JFFS: GC thread pid=%d.\n", (int) c->thread_pid));
+
+	D1(printk(KERN_NOTICE "JFFS: Successfully mounted device %s.\n",
+	       kdevname(dev)));
 	return sb;
 
 jffs_sb_err3:
@@ -118,7 +137,6 @@
 jffs_sb_err2:
 	jffs_cleanup_control((struct jffs_control *)sb->u.generic_sbp);
 jffs_sb_err1:
-	
 	printk(KERN_WARNING "JFFS: Failed to mount device %s.\n",
 	       kdevname(dev));
 	return 0;
@@ -129,14 +147,27 @@
 static void
 jffs_put_super(struct super_block *sb)
 {
-	kdev_t dev = sb->s_dev;
+	struct jffs_control *c = (struct jffs_control *) sb->u.generic_sbp;
+	D1(kdev_t dev = sb->s_dev);
+
 	D2(printk("jffs_put_super()\n"));
+
+	D1(printk (KERN_NOTICE "jffs_put_super(): Telling gc thread to die.\n"));
+	if (c->gc_task) {
+		send_sig(SIGQUIT, c->gc_task, 1);
+		send_sig(SIGCONT, c->gc_task, 1);
+	}
+	down (&c->gc_thread_sem);
+
+	D1(printk (KERN_NOTICE "jffs_put_super(): Successfully waited on thread.\n"));
+
 	sb->s_dev = 0;
 	jffs_cleanup_control((struct jffs_control *)sb->u.generic_sbp);
-	printk(KERN_NOTICE "JFFS: Successfully unmounted device %s.\n",
-	       kdevname(dev));
+	D1(printk(KERN_NOTICE "JFFS: Successfully unmounted device %s.\n",
+	       kdevname(dev)));
 }
 
+
 /* This function is called when user commands like chmod, chgrp and
    chown are executed. System calls like trunc() results in a call
    to this function.  */
@@ -165,9 +196,9 @@
 
 	c = f->c;
 	fmc = c->fmc;
-        update_all = iattr->ia_valid & ATTR_FORCE;
+	update_all = iattr->ia_valid & ATTR_FORCE;
 
-	if (!JFFS_ENOUGH_SPACE(fmc)) {
+	if (!JFFS_ENOUGH_SPACE(c)) {
 		if ( (update_all || iattr->ia_valid & ATTR_SIZE)
 		     && (iattr->ia_size < f->size) ) {
 			/* See this case where someone is trying to
@@ -212,7 +243,7 @@
 	raw_inode.spare = 0;
 	raw_inode.rename = 0;
 	raw_inode.deleted = 0;
-	
+
 	if (update_all || iattr->ia_valid & ATTR_MODE) {
 		raw_inode.mode = iattr->ia_mode;
 		inode->i_mode = iattr->ia_mode;
@@ -282,13 +313,16 @@
 	}
 
 	jffs_insert_node(c, f, &raw_inode, 0, new_node);
-	
+
 	mark_inode_dirty(inode);
-	
+
 	return 0;
 } /* jffs_notify_change()  */
 
-struct inode * jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode, int * err)
+
+struct inode *
+jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode,
+	       int * err)
 {
 	struct super_block * sb;
 	struct inode * inode;
@@ -299,7 +333,7 @@
 		*err = -ENOMEM;
 		return NULL;
 	}
-	
+
 	sb = dir->i_sb;
 	c = (struct jffs_control *)sb->u.generic_sbp;
 
@@ -315,12 +349,12 @@
 	inode->i_atime = raw_inode->atime;
 	inode->i_mtime = raw_inode->mtime;
 	inode->i_ctime = raw_inode->ctime;
-	inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
-	inode->i_blocks = 0;
+	inode->i_blksize = PAGE_SIZE;
+	inode->i_blocks = (raw_inode->dsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	inode->i_version = 0;
 	inode->i_flags = sb->s_flags;
 	inode->u.generic_ip = (void *)jffs_find_file(c, raw_inode->ino);
-	
+
 	insert_inode_hash(inode);
 
 	return inode;
@@ -343,7 +377,7 @@
 		       + jffs_free_size2(fmc) / PAGE_CACHE_SIZE)
 		      - (fmc->min_free_size / PAGE_CACHE_SIZE);
 	buf->f_bavail = buf->f_bfree;
-	
+
 	/* Find out how many files there are in the filesystem.  */
 	buf->f_files = jffs_foreach_file(c, jffs_file_count);
 	buf->f_ffree = buf->f_bfree;
@@ -352,10 +386,11 @@
 	return 0;
 }
 
+
 /* Rename a file.  */
 int
 jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
-            struct inode *new_dir, struct dentry *new_dentry)
+	    struct inode *new_dir, struct dentry *new_dentry)
 {
 	struct jffs_raw_inode raw_inode;
 	struct jffs_control *c;
@@ -382,14 +417,14 @@
 		return -1;
 	});
 
-	if (!JFFS_ENOUGH_SPACE(c->fmc)) {
+	if (!JFFS_ENOUGH_SPACE(c)) {
 		D1(printk("jffs_rename(): Free size = %u\n",
 			  jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
 		D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
 		return -ENOSPC;
 	}
-	
-	/* Find the the old directory.  */
+
+	/* Find the old directory.  */
 	result = -ENOTDIR;
 	if (!(old_dir_f = (struct jffs_file *)old_dir->u.generic_ip)) {
 		D(printk("jffs_rename(): Old dir invalid.\n"));
@@ -402,8 +437,8 @@
 				  old_dentry->d_name.len))) {
 		goto jffs_rename_end;
 	}
-	
-	/* Try to find the new directory's node.  */
+
+	/* Find the new directory.  */
 	result = -ENOTDIR;
 	if (!(new_dir_f = (struct jffs_file *)new_dir->u.generic_ip)) {
 		D(printk("jffs_rename(): New dir invalid.\n"));
@@ -450,27 +485,31 @@
 	if ((del_f = jffs_find_child(new_dir_f, new_dentry->d_name.name,
 				     new_dentry->d_name.len))) {
 		raw_inode.rename = 1;
-		/*raw_inode.mode = del_f->ino;*/
+		raw_inode.dsize = sizeof(__u32);
+		rename_data = del_f->ino;
 	}
 
 	/* Write the new node to the flash memory.  */
-	if ((result = jffs_write_node(c, node, &raw_inode, new_dentry->d_name.name,
+	if ((result = jffs_write_node(c, node, &raw_inode,
+				      new_dentry->d_name.name,
 				      (unsigned char*)&rename_data)) < 0) {
 		D(printk("jffs_rename(): Failed to write node to flash.\n"));
 		kfree(node);
 		DJM(no_jffs_node--);
 		goto jffs_rename_end;
 	}
+	raw_inode.dsize = 0;
 
 	if (raw_inode.rename) {
 		/* The file with the same name must be deleted.  */
-	        c->fmc->no_call_gc = 1; /* TODO: What kind of locking is this? */
-		if ((result = jffs_remove(new_dir, new_dentry, del_f->mode)) < 0) {
+	        down(&c->fmc->gclock);
+		if ((result = jffs_remove(new_dir, new_dentry,
+					  del_f->mode)) < 0) {
 			/* This is really bad.  */
 			printk(KERN_ERR "JFFS: An error occurred in "
 			       "rename().\n");
 		}
-		c->fmc->no_call_gc = 0;
+		up(&c->fmc->gclock);
 	}
 
 	if (old_dir_f != new_dir_f) {
@@ -501,7 +540,6 @@
 	}
 
 jffs_rename_end:
-	
 	return result;
 } /* jffs_rename()  */
 
@@ -524,13 +562,14 @@
 			return 0;
 		}
 		filp->f_pos = 1;
-	} 
+	}
 	if (filp->f_pos == 1) {
 		if (inode->i_ino == JFFS_MIN_INO) {
 			ddino = JFFS_MIN_INO;
 		}
 		else {
-			ddino = ((struct jffs_file *)inode->u.generic_ip)->pino;
+			ddino = ((struct jffs_file *)
+				 inode->u.generic_ip)->pino;
 		}
 		D3(printk("jffs_readdir(): \"..\" %u\n", ddino));
 		if (filldir(dirent, "..", 2, filp->f_pos, ddino) < 0)
@@ -549,7 +588,7 @@
 			return 0;
 		filp->f_pos++;
 	}
-	
+
 	return filp->f_pos;
 } /* jffs_readdir()  */
 
@@ -565,10 +604,10 @@
 	int r = 0;
 	const char *name;
 	struct inode *inode = NULL;
-	
+
 	len = dentry->d_name.len;
 	name = dentry->d_name.name;
-	
+
 	D3({
 		char *s = (char *)kmalloc(len + 1, GFP_KERNEL);
 		memcpy(s, name, len);
@@ -576,7 +615,7 @@
 		printk("jffs_lookup(): dir: 0x%p, name: \"%s\"\n", dir, s);
 		kfree(s);
 	});
-	
+
 	r = -ENAMETOOLONG;
 	if (len > JFFS_MAX_NAME_LEN) {
 		goto jffs_lookup_end;
@@ -584,7 +623,8 @@
 
 	r = -EACCES;
 	if (!(d = (struct jffs_file *)dir->u.generic_ip)) {
-		D(printk("jffs_lookup(): No such inode! (%lu)\n", dir->i_ino));
+		D(printk("jffs_lookup(): No such inode! (%lu)\n",
+			 dir->i_ino));
 		goto jffs_lookup_end;
 	}
 
@@ -610,10 +650,10 @@
 			  f, name, d, d->ino));
 		inode = NULL;
 	}
-	
+
 	d_add(dentry, inode);
 	return NULL;
-	
+
 jffs_lookup_end:
 	return ERR_PTR(r);
 } /* jffs_lookup()  */
@@ -623,7 +663,7 @@
 static int
 jffs_readpage(struct file *file, struct page *page)
 {
-	unsigned long buf;
+	void *buf;
 	unsigned long read_len;
 	int result = -EIO;
 	struct inode *inode = (struct inode*)page->mapping->host;
@@ -643,10 +683,10 @@
 	offset = page->index << PAGE_CACHE_SHIFT;
 	if (offset < inode->i_size) {
 		read_len = jffs_min(inode->i_size - offset, PAGE_SIZE);
-		r = jffs_read_data(f, (char *)buf, offset, read_len);
+		r = jffs_read_data(f, buf, offset, read_len);
 		if (r == read_len) {
 			if (read_len < PAGE_SIZE) {
-				memset((void *)(buf + read_len), 0,
+				memset(buf + read_len, 0,
 				       PAGE_SIZE - read_len);
 			}
 			SetPageUptodate(page);
@@ -659,14 +699,15 @@
 		});
 	}
 	if (result) {
-		memset((void *)buf, 0, PAGE_SIZE);
+		memset(buf, 0, PAGE_SIZE);
 	        SetPageError(page);
 	}
+	flush_dcache_page(page);
 
 	UnlockPage(page);
-	
+
 	put_page(page);
-	
+
 	D3(printk("jffs_readpage(): Leaving...\n"));
 
 	return result;
@@ -685,7 +726,7 @@
 	int dir_mode;
 	int result = 0;
 	int err;
-	
+
 	D1({
 	        int len = dentry->d_name.len;
 		char *_name = (char *) kmalloc(len + 1, GFP_KERNEL);
@@ -706,7 +747,7 @@
 
 	c = dir_f->c;
 
-	if (!JFFS_ENOUGH_SPACE(c->fmc)) {
+	if (!JFFS_ENOUGH_SPACE(c)) {
 		D1(printk("jffs_mkdir(): Free size = %u\n",
 			  jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
 		D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
@@ -717,7 +758,7 @@
 	dir_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX)
 			      & ~current->fs->umask);
 	if (dir->i_mode & S_ISGID) {
-                dir_mode |= S_ISGID;
+		dir_mode |= S_ISGID;
 	}
 
 	/* Create a node and initialize it as much as needed.  */
@@ -753,7 +794,8 @@
 	raw_inode.deleted = 0;
 
 	/* Write the new node to the flash.  */
-	if ((result = jffs_write_node(c, node, &raw_inode, dentry->d_name.name, 0)) < 0) {
+	if ((result = jffs_write_node(c, node, &raw_inode,
+				      dentry->d_name.name, 0)) < 0) {
 		D(printk("jffs_mkdir(): jffs_write_node() failed.\n"));
 		kfree(node);
 		DJM(no_jffs_node--);
@@ -761,15 +803,17 @@
 	}
 
 	/* Insert the new node into the file system.  */
-	if ((result = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name, node))<0)
-	  goto jffs_mkdir_end;
-	
+	if ((result = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name,
+				       node)) < 0) {
+		goto jffs_mkdir_end;
+	}
+
 	inode = jffs_new_inode(dir, &raw_inode, &err);
 	if (inode == NULL) {
 		result = err;
 		goto jffs_mkdir_end;
 	}
-	
+
 	inode->i_op = &jffs_dir_inode_operations;
 	inode->i_fop = &jffs_dir_operations;
 
@@ -838,7 +882,8 @@
 			result = -ENOTEMPTY;
 			goto jffs_remove_end;
 		}
-        } else if (S_ISDIR(del_f->mode)) {
+	}
+	else if (S_ISDIR(del_f->mode)) {
 		D(printk("jffs_remove(): node is a directory "
 			 "but it shouldn't be.\n"));
 		result = -EPERM;
@@ -846,7 +891,7 @@
 	}
 
 	inode = dentry->d_inode;
-	
+
 	result = -EIO;
 	if (del_f->ino != inode->i_ino)
 		goto jffs_remove_end;
@@ -935,7 +980,7 @@
 	dir_f = (struct jffs_file *)dir->u.generic_ip;
 	c = dir_f->c;
 
-	if (!JFFS_ENOUGH_SPACE(c->fmc)) {
+	if (!JFFS_ENOUGH_SPACE(c)) {
 		D1(printk("jffs_mknod(): Free size = %u\n",
 			  jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
 		D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
@@ -984,7 +1029,8 @@
 	}
 
 	/* Insert the new node into the file system.  */
-	if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name, node)) < 0) {
+	if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name,
+				    node)) < 0) {
 		result = err;
 		goto jffs_mknod_end;
 	}
@@ -994,11 +1040,11 @@
 		result = err;
 		goto jffs_mknod_end;
 	}
-	
+
 	init_special_inode(inode, mode, rdev);
 
 	d_instantiate(dentry, inode);
-	
+
 	goto jffs_mknod_end;
 
 jffs_mknod_err:
@@ -1020,7 +1066,7 @@
 	struct jffs_file *dir_f;
 	struct jffs_node *node;
 	struct inode *inode;
-	
+
 	int symname_len = strlen(symname);
 	int err;
 
@@ -1032,7 +1078,8 @@
 		_name[len] = '\0';
 		memcpy(_symname, symname, symname_len);
 		_symname[symname_len] = '\0';
-		printk("***jffs_symlink(): dir = 0x%p, dentry->dname.name = \"%s\", "
+		printk("***jffs_symlink(): dir = 0x%p, "
+		       "dentry->dname.name = \"%s\", "
 		       "symname = \"%s\"\n", dir, _name, _symname);
 		kfree(_name);
 		kfree(_symname);
@@ -1047,7 +1094,7 @@
 
 	c = dir_f->c;
 
-	if (!JFFS_ENOUGH_SPACE(c->fmc)) {
+	if (!JFFS_ENOUGH_SPACE(c)) {
 		D1(printk("jffs_symlink(): Free size = %u\n",
 			  jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
 		D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
@@ -1057,7 +1104,7 @@
 	/* Create a node and initialize it as much as needed.  */
 	if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
 						  GFP_KERNEL))) {
-		D(printk("jffs_symlink(): Allocation failed: node == NULL\n"));
+		D(printk("jffs_symlink(): Allocation failed: node = NULL\n"));
 		return -ENOMEM;
 	}
 	DJM(no_jffs_node++);
@@ -1094,7 +1141,8 @@
 	}
 
 	/* Insert the new node into the file system.  */
-	if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name, node)) < 0) {
+	if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name,
+				    node)) < 0) {
 		return err;
 	}
 
@@ -1102,7 +1150,7 @@
 	if (inode == NULL) {
 		return err;
 	}
-	
+
 	inode->i_op = &page_symlink_inode_operations;
 	inode->i_mapping->a_ops = &jffs_address_operations;
 
@@ -1111,14 +1159,15 @@
 	return 0;
 } /* jffs_symlink()  */
 
-/* Create an inode inside a JFFS directory (dir) and return it.  
+
+/* Create an inode inside a JFFS directory (dir) and return it.
  *
  * By the time this is called, we already have created
  * the directory cache entry for the new file, but it
  * is so far negative - it has no inode.
  *
  * If the create succeeds, we fill in the inode information
- * with d_instantiate(). 
+ * with d_instantiate().
  */
 static int
 jffs_create(struct inode *dir, struct dentry *dentry, int mode)
@@ -1148,7 +1197,7 @@
 
 	c = dir_f->c;
 
-	if (!JFFS_ENOUGH_SPACE(c->fmc)) {
+	if (!JFFS_ENOUGH_SPACE(c)) {
 		D1(printk("jffs_create(): Free size = %u\n",
 			  jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
 		D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
@@ -1186,7 +1235,8 @@
 	raw_inode.deleted = 0;
 
 	/* Write the new node to the flash.  */
-	if ((err = jffs_write_node(c, node, &raw_inode, dentry->d_name.name, 0)) < 0) {
+	if ((err = jffs_write_node(c, node, &raw_inode,
+				   dentry->d_name.name, 0)) < 0) {
 		D(printk("jffs_create(): jffs_write_node() failed.\n"));
 		kfree(node);
 		DJM(no_jffs_node--);
@@ -1194,7 +1244,8 @@
 	}
 
 	/* Insert the new node into the file system.  */
-	if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name, node)) < 0) {
+	if ((err = jffs_insert_node(c, 0, &raw_inode, dentry->d_name.name,
+				    node)) < 0) {
 		return err;
 	}
 
@@ -1210,33 +1261,35 @@
 	inode->i_mapping->nrpages = 0;
 
 	d_instantiate(dentry, inode);
-	
+
 	return 0;
 } /* jffs_create()  */
 
 
 /* Write, append or rewrite data to an existing file.  */
 static ssize_t
-jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
+jffs_file_write(struct file *filp, const char *buf, size_t count,
+		loff_t *ppos)
 {
 	struct jffs_raw_inode raw_inode;
 	struct jffs_control *c;
 	struct jffs_file *f;
 	struct jffs_node *node;
-	struct dentry *dentry = filp->f_dentry; 
-	struct inode *inode = dentry->d_inode; 
+	struct dentry *dentry = filp->f_dentry;
+	struct inode *inode = dentry->d_inode;
+	unsigned char *vbuf;
 	int written = 0;
 	loff_t pos;
 	int err;
 
 	inode = filp->f_dentry->d_inode;
-	
+
 	D2(printk("***jffs_file_write(): inode: 0x%p (ino: %lu), "
 		  "filp: 0x%p, buf: 0x%p, count: %d\n",
 		  inode, inode->i_ino, filp, buf, count));
 
 	down(&inode->i_sem);
-	
+
 	pos = *ppos;
 	err = -EINVAL;
 	if (pos < 0)
@@ -1253,7 +1306,7 @@
 		err = -ENOSPC;
 		goto out;
 	}
-	
+
 	if (!S_ISREG(inode->i_mode)) {
 		D(printk("jffs_file_write(): inode->i_mode == 0x%08x\n",
 			 inode->i_mode));
@@ -1267,10 +1320,10 @@
 		err = -EINVAL;
 		goto out;
 	}
-	
+
 	c = f->c;
 
-	if (!JFFS_ENOUGH_SPACE(c->fmc)) {
+	if (!JFFS_ENOUGH_SPACE(c)) {
 		D1(printk("jffs_file_write(): Free size = %u\n",
 			  jffs_free_size1(c->fmc) + jffs_free_size2(c->fmc)));
 		D(printk(KERN_NOTICE "JFFS: No space left on device\n"));
@@ -1281,16 +1334,35 @@
 	if (filp->f_flags & O_APPEND)
 		pos = inode->i_size;
 
+
+	if (!(vbuf = kmalloc(count, GFP_KERNEL))) {
+		D(printk("jffs_file_write(): failed to allocate bounce buffer. Fix me to use page cache\n"));
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* FIXME: This is entirely gratuitous use of bounce buffers.
+	   Get a clue and use the page cache. 
+	   /me wanders off to get a crash course on Linux VFS
+	   dwmw2
+	*/
+	if (copy_from_user(vbuf, buf, count)) {
+		kfree(vbuf);
+		return -EFAULT;
+	}
+		
+
 	/* Things are going to be written so we could allocate and
 	   initialize the necessary data structures now.  */
 	if (!(node = (struct jffs_node *) kmalloc(sizeof(struct jffs_node),
 						  GFP_KERNEL))) {
 		D(printk("jffs_file_write(): node == 0\n"));
 		err = -ENOMEM;
+		kfree(vbuf);
 		goto out;
 	}
 	DJM(no_jffs_node++);
-	node->data_offset = f->size;
+	node->data_offset = pos;
 	node->removed_size = 0;
 
 	/* Initialize the raw inode.  */
@@ -1299,7 +1371,7 @@
 	raw_inode.pino = f->pino;
 	raw_inode.version = f->highest_version + 1;
 	raw_inode.mode = f->mode;
-	
+
 	raw_inode.uid = f->uid;
 	raw_inode.gid = f->gid;
 	/*
@@ -1309,7 +1381,7 @@
 	raw_inode.atime = CURRENT_TIME;
 	raw_inode.mtime = raw_inode.atime;
 	raw_inode.ctime = f->ctime;
-	raw_inode.offset = f->size;
+	raw_inode.offset = pos;
 	raw_inode.dsize = count;
 	raw_inode.rsize = 0;
 	raw_inode.nsize = 0;
@@ -1318,25 +1390,28 @@
 	raw_inode.rename = 0;
 	raw_inode.deleted = 0;
 
+	if (pos < f->size) {
+		node->removed_size = raw_inode.rsize = jffs_min(count, f->size - pos);
+	}
 
-	/* TODO: BAAAAAAAAD! buf is a userspace-pointer, and should be
-	         treated as such, with copy_from_user etc...
-         */
 	/* Write the new node to the flash.  */
 	if ((written = jffs_write_node(c, node, &raw_inode, 0,
-				       (const unsigned char *)buf)) < 0) {
+				       (const unsigned char *)vbuf)) < 0) {
 		D(printk("jffs_file_write(): jffs_write_node() failed.\n"));
 		kfree(node);
+		kfree(vbuf);
 		DJM(no_jffs_node--);
 		err = written;
 		goto out;
 	}
 
+	kfree(vbuf);
+
 	/* Insert the new node into the file system.  */
 	if ((err = jffs_insert_node(c, f, &raw_inode, 0, node)) < 0) {
 		goto out;
 	}
-	
+
 	pos += written;
 	*ppos = pos;
 
@@ -1364,7 +1439,8 @@
 {
 	struct jffs_control *c;
 
-	D2(printk("***jffs_ioctl(): cmd = 0x%08x, arg = 0x%08lx\n", cmd, arg));
+	D2(printk("***jffs_ioctl(): cmd = 0x%08x, arg = 0x%08lx\n",
+		  cmd, arg));
 
 	if (!(c = (struct jffs_control *)inode->i_sb->u.generic_sbp)) {
 		printk(KERN_ERR "JFFS: Bad inode in ioctl() call. "
@@ -1401,10 +1477,10 @@
 			       fst.size, fst.used, fst.dirty,
 			       fst.begin, fst.end);
 			if (copy_to_user((struct jffs_flash_status *)arg,
-					 &fst, sizeof(struct jffs_flash_status))) {
+					 &fst,
+					 sizeof(struct jffs_flash_status))) {
 			  return -EFAULT;
 			}
-			
 		}
 		break;
 	default:
@@ -1416,9 +1492,17 @@
 
 
 static struct address_space_operations jffs_address_operations = {
-        readpage: jffs_readpage,
+	readpage: jffs_readpage,
 };
 
+static int jffs_fsync(struct file *f, struct dentry *d, int datasync)
+{
+	/* We currently have O_SYNC operations at all times. 
+	   Do nothing
+	*/
+	return 0;
+}
+
 
 static struct file_operations jffs_file_operations =
 {
@@ -1426,19 +1510,23 @@
 	write: jffs_file_write,      /* write */
 	ioctl: jffs_ioctl,           /* ioctl */
 	mmap:  generic_file_mmap,    /* mmap */
+	fsync: jffs_fsync,
 };
 
+
 static struct inode_operations jffs_file_inode_operations =
 {
 	lookup:  jffs_lookup,          /* lookup */
 	setattr: jffs_setattr,
 };
 
+
 static struct file_operations jffs_dir_operations =
 {
 	readdir:	jffs_readdir,
 };
 
+
 static struct inode_operations jffs_dir_inode_operations =
 {
 	create:   jffs_create,
@@ -1452,6 +1540,7 @@
 	setattr:  jffs_setattr,
 };
 
+
 /* Initialize an inode for the VFS.  */
 static void
 jffs_read_inode(struct inode *inode)
@@ -1482,7 +1571,7 @@
 	inode->i_mtime = f->mtime;
 	inode->i_ctime = f->ctime;
 	inode->i_blksize = PAGE_SIZE;
-	inode->i_blocks = 0;
+	inode->i_blocks = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	if (S_ISREG(inode->i_mode)) {
 		inode->i_op = &jffs_file_inode_operations;
 		inode->i_fop = &jffs_file_operations;
@@ -1493,44 +1582,42 @@
 		inode->i_fop = &jffs_dir_operations;
 	}
 	else if (S_ISLNK(inode->i_mode)) {
-                inode->i_op = &page_symlink_inode_operations;
+		inode->i_op = &page_symlink_inode_operations;
 		inode->i_mapping->a_ops = &jffs_address_operations;
-	} else {
-	  /* If the node is a device of some sort, then the number of the
-	     device should be read from the flash memory and then added
-	     to the inode's i_rdev member.  */
+	}
+	else {
+		/* If the node is a device of some sort, then the number of
+		   the device should be read from the flash memory and then
+		   added to the inode's i_rdev member.  */
 		kdev_t rdev;
 		jffs_read_data(f, (char *)&rdev, 0, sizeof(kdev_t));
 		init_special_inode(inode, inode->i_mode, kdev_t_to_nr(rdev));
 	}
 }
 
+
 void
 jffs_delete_inode(struct inode *inode)
 {
+	D3(printk("jffs_delete_inode(): inode->i_ino == %lu\n",
+		  inode->i_ino));
 
-        D3(printk("jffs_delete_inode(): inode->i_ino == %lu\n", inode->i_ino));
-
-  	lock_kernel();
-	
+	lock_kernel();
 	inode->i_size = 0;
-
 	clear_inode(inode);
-
 	unlock_kernel();
 }
 
+
 void
 jffs_write_super(struct super_block *sb)
 {
-#ifdef USE_GC
 	struct jffs_control *c = (struct jffs_control *)sb->u.generic_sbp;
-	
-	if(!c->fmc->no_call_gc)
-		jffs_garbage_collect(c);
-#endif
+
+	jffs_garbage_collect_trigger(c);
 }
 
+
 static struct super_operations jffs_ops =
 {
 	read_inode:   jffs_read_inode,
@@ -1540,12 +1627,15 @@
 	statfs:       jffs_statfs,
 };
 
+
 static DECLARE_FSTYPE_DEV(jffs_fs_type, "jffs", jffs_read_super);
 
 static int __init
 init_jffs_fs(void)
 {
-	printk("JFFS version " JFFS_VERSION_STRING ", (C) 1999, 2000  Axis Communications AB\n");
+	printk("JFFS version "
+	       JFFS_VERSION_STRING
+	       ", (C) 1999, 2000  Axis Communications AB\n");
 	return register_filesystem(&jffs_fs_type);
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)