diff options
Diffstat (limited to 'fs/jffs/inode-v23.c')
-rw-r--r-- | fs/jffs/inode-v23.c | 347 |
1 files changed, 218 insertions, 129 deletions
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index 06ac42709..9ea2223d3 100644 --- a/fs/jffs/inode-v23.c +++ b/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 file_operations jffs_dir_operations; 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 @@ jffs_read_super(struct super_block *sb, void *data, int silent) 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_err3: 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 @@ jffs_sb_err1: 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 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr) 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 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr) 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_setattr(struct dentry *dentry, struct iattr *iattr) } 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 @@ struct inode * jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *r *err = -ENOMEM; return NULL; } - + sb = dir->i_sb; c = (struct jffs_control *)sb->u.generic_sbp; @@ -315,12 +349,12 @@ struct inode * jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *r 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_statfs(struct super_block *sb, struct statfs *buf) + 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 @@ jffs_statfs(struct super_block *sb, struct statfs *buf) 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 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry, 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 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry, 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 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry, 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(struct inode *old_dir, struct dentry *old_dentry, } jffs_rename_end: - return result; } /* jffs_rename() */ @@ -524,13 +562,14 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir) 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 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir) return 0; filp->f_pos++; } - + return filp->f_pos; } /* jffs_readdir() */ @@ -565,10 +604,10 @@ jffs_lookup(struct inode *dir, struct dentry *dentry) 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 @@ jffs_lookup(struct inode *dir, struct dentry *dentry) 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 @@ jffs_lookup(struct inode *dir, struct dentry *dentry) 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 @@ jffs_lookup(struct inode *dir, struct dentry *dentry) f, name, d, d->ino)); inode = NULL; } - + d_add(dentry, inode); return NULL; - + jffs_lookup_end: return ERR_PTR(r); } /* jffs_lookup() */ @@ -665,9 +705,9 @@ jffs_readpage(struct file *file, struct page *page) flush_dcache_page(page); UnlockPage(page); - + put_page(page); - + D3(printk("jffs_readpage(): Leaving...\n")); return result; @@ -686,7 +726,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) int dir_mode; int result = 0; int err; - + D1({ int len = dentry->d_name.len; char *_name = (char *) kmalloc(len + 1, GFP_KERNEL); @@ -707,7 +747,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 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")); @@ -718,7 +758,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 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. */ @@ -754,7 +794,8 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) 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--); @@ -762,15 +803,17 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode) } /* 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; @@ -839,7 +882,8 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type) 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; @@ -847,7 +891,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type) } inode = dentry->d_inode; - + result = -EIO; if (del_f->ino != inode->i_ino) goto jffs_remove_end; @@ -936,7 +980,7 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) 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")); @@ -985,7 +1029,8 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) } /* 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; } @@ -995,11 +1040,11 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev) result = err; goto jffs_mknod_end; } - + init_special_inode(inode, mode, rdev); d_instantiate(dentry, inode); - + goto jffs_mknod_end; jffs_mknod_err: @@ -1021,7 +1066,7 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) struct jffs_file *dir_f; struct jffs_node *node; struct inode *inode; - + int symname_len = strlen(symname); int err; @@ -1033,7 +1078,8 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) _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); @@ -1048,7 +1094,7 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) 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")); @@ -1058,7 +1104,7 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) /* 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++); @@ -1095,7 +1141,8 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) } /* 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; } @@ -1103,7 +1150,7 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) if (inode == NULL) { return err; } - + inode->i_op = &page_symlink_inode_operations; inode->i_mapping->a_ops = &jffs_address_operations; @@ -1112,14 +1159,15 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) 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) @@ -1149,7 +1197,7 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode) 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")); @@ -1187,7 +1235,8 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode) 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--); @@ -1195,7 +1244,8 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode) } /* 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; } @@ -1211,33 +1261,35 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode) 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) @@ -1254,7 +1306,7 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) err = -ENOSPC; goto out; } - + if (!S_ISREG(inode->i_mode)) { D(printk("jffs_file_write(): inode->i_mode == 0x%08x\n", inode->i_mode)); @@ -1268,10 +1320,10 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) 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")); @@ -1282,16 +1334,35 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) 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. */ @@ -1300,7 +1371,7 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) 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; /* @@ -1310,7 +1381,7 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) 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; @@ -1319,25 +1390,28 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) 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; @@ -1365,7 +1439,8 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, { 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. " @@ -1402,10 +1477,10 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, 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: @@ -1417,9 +1492,17 @@ jffs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, 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 = { @@ -1427,19 +1510,23 @@ static struct file_operations jffs_file_operations = 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, @@ -1453,6 +1540,7 @@ static struct inode_operations jffs_dir_inode_operations = setattr: jffs_setattr, }; + /* Initialize an inode for the VFS. */ static void jffs_read_inode(struct inode *inode) @@ -1483,7 +1571,7 @@ jffs_read_inode(struct inode *inode) 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; @@ -1494,44 +1582,42 @@ jffs_read_inode(struct inode *inode) 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, @@ -1541,12 +1627,15 @@ static struct super_operations jffs_ops = 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); } |