fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / fs / jffs2 / file.c
index 4b14101..242875f 100644 (file)
@@ -3,15 +3,14 @@
  *
  * Copyright (C) 2001-2003 Red Hat, Inc.
  *
- * Created by David Woodhouse <dwmw2@redhat.com>
+ * Created by David Woodhouse <dwmw2@infradead.org>
  *
  * For licensing information, see the file 'LICENCE' in this directory.
  *
- * $Id: file.c,v 1.98 2004/03/19 16:41:09 dwmw2 Exp $
+ * $Id: file.c,v 1.104 2005/10/18 23:29:35 tpoynor Exp $
  *
  */
 
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/jffs2.h>
 #include "nodelist.h"
 
-extern int generic_file_open(struct inode *, struct file *) __attribute__((weak));
-extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak));
-
+static int jffs2_commit_write (struct file *filp, struct page *pg,
+                              unsigned start, unsigned end);
+static int jffs2_prepare_write (struct file *filp, struct page *pg,
+                               unsigned start, unsigned end);
+static int jffs2_readpage (struct file *filp, struct page *pg);
 
 int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
 {
@@ -33,39 +34,44 @@ int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync)
 
        /* Trigger GC to flush any pending writes for this inode */
        jffs2_flush_wbuf_gc(c, inode->i_ino);
-                       
-       return 0;       
+
+       return 0;
 }
 
-struct file_operations jffs2_file_operations =
+const struct file_operations jffs2_file_operations =
 {
        .llseek =       generic_file_llseek,
        .open =         generic_file_open,
-       .read =         generic_file_read,
-       .write =        generic_file_write,
+       .read =         do_sync_read,
+       .aio_read =     generic_file_aio_read,
+       .write =        do_sync_write,
+       .aio_write =    generic_file_aio_write,
        .ioctl =        jffs2_ioctl,
        .mmap =         generic_file_readonly_mmap,
        .fsync =        jffs2_fsync,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,29)
        .sendfile =     generic_file_sendfile
-#endif
 };
 
 /* jffs2_file_inode_operations */
 
 struct inode_operations jffs2_file_inode_operations =
 {
-       .setattr =      jffs2_setattr
+       .permission =   jffs2_permission,
+       .setattr =      jffs2_setattr,
+       .setxattr =     jffs2_setxattr,
+       .getxattr =     jffs2_getxattr,
+       .listxattr =    jffs2_listxattr,
+       .removexattr =  jffs2_removexattr
 };
 
-struct address_space_operations jffs2_file_address_operations =
+const struct address_space_operations jffs2_file_address_operations =
 {
        .readpage =     jffs2_readpage,
        .prepare_write =jffs2_prepare_write,
        .commit_write = jffs2_commit_write
 };
 
-int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
+static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
 {
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
        struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
@@ -74,8 +80,7 @@ int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
 
        D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT));
 
-       if (!PageLocked(pg))
-                PAGE_BUG(pg);
+       BUG_ON(!PageLocked(pg));
 
        pg_buf = kmap(pg);
        /* FIXME: Can kmap fail? */
@@ -105,18 +110,19 @@ int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg)
 }
 
 
-int jffs2_readpage (struct file *filp, struct page *pg)
+static int jffs2_readpage (struct file *filp, struct page *pg)
 {
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(pg->mapping->host);
        int ret;
-       
+
        down(&f->sem);
        ret = jffs2_do_readpage_unlock(pg->mapping->host, pg);
        up(&f->sem);
        return ret;
 }
 
-int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, unsigned end)
+static int jffs2_prepare_write (struct file *filp, struct page *pg,
+                               unsigned start, unsigned end)
 {
        struct inode *inode = pg->mapping->host;
        struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
@@ -130,12 +136,13 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
                struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb);
                struct jffs2_raw_inode ri;
                struct jffs2_full_dnode *fn;
-               uint32_t phys_ofs, alloc_len;
-               
+               uint32_t alloc_len;
+
                D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n",
                          (unsigned int)inode->i_size, pageofs));
 
-               ret = jffs2_reserve_space(c, sizeof(ri), &phys_ofs, &alloc_len, ALLOC_NORMAL);
+               ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
+                                         ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
                if (ret)
                        return ret;
 
@@ -160,8 +167,8 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
                ri.compr = JFFS2_COMPR_ZERO;
                ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));
                ri.data_crc = cpu_to_je32(0);
-               
-               fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_NORMAL);
+
+               fn = jffs2_write_dnode(c, f, &ri, NULL, 0, ALLOC_NORMAL);
 
                if (IS_ERR(fn)) {
                        ret = PTR_ERR(fn);
@@ -187,7 +194,7 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
                inode->i_size = pageofs;
                up(&f->sem);
        }
-       
+
        /* Read in the page if it wasn't already present, unless it's a whole page */
        if (!PageUptodate(pg) && (start || end < PAGE_CACHE_SIZE)) {
                down(&f->sem);
@@ -198,7 +205,8 @@ int jffs2_prepare_write (struct file *filp, struct page *pg, unsigned start, uns
        return ret;
 }
 
-int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsigned end)
+static int jffs2_commit_write (struct file *filp, struct page *pg,
+                              unsigned start, unsigned end)
 {
        /* Actually commit the write from the page cache page we're looking at.
         * For now, we write the full page out each time. It sucks, but it's simple
@@ -214,12 +222,20 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
        D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n",
                  inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags));
 
-       if (!start && end == PAGE_CACHE_SIZE) {
-               /* We need to avoid deadlock with page_cache_read() in
-                  jffs2_garbage_collect_pass(). So we have to mark the
-                  page up to date, to prevent page_cache_read() from 
-                  trying to re-lock it. */
-               SetPageUptodate(pg);
+       if (end == PAGE_CACHE_SIZE) {
+               if (!start) {
+                       /* We need to avoid deadlock with page_cache_read() in
+                          jffs2_garbage_collect_pass(). So we have to mark the
+                          page up to date, to prevent page_cache_read() from
+                          trying to re-lock it. */
+                       SetPageUptodate(pg);
+               } else {
+                       /* When writing out the end of a page, write out the 
+                          _whole_ page. This helps to reduce the number of
+                          nodes in files which have many short writes, like
+                          syslog files. */
+                       start = aligned_start = 0;
+               }
        }
 
        ri = jffs2_alloc_raw_inode();
@@ -251,7 +267,7 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
                /* There was an error writing. */
                SetPageError(pg);
        }
-       
+
        /* Adjust writtenlen for the padding we did, so we don't confuse our caller */
        if (writtenlen < (start&3))
                writtenlen = 0;
@@ -262,7 +278,7 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
                if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) {
                        inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen;
                        inode->i_blocks = (inode->i_size + 511) >> 9;
-                       
+
                        inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime));
                }
        }
@@ -271,13 +287,13 @@ int jffs2_commit_write (struct file *filp, struct page *pg, unsigned start, unsi
 
        if (start+writtenlen < end) {
                /* generic_file_write has written more to the page cache than we've
-                  actually written to the medium. Mark the page !Uptodate so that 
+                  actually written to the medium. Mark the page !Uptodate so that
                   it gets reread */
                D1(printk(KERN_DEBUG "jffs2_commit_write(): Not all bytes written. Marking page !uptodate\n"));
                SetPageError(pg);
                ClearPageUptodate(pg);
        }
 
-       D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",writtenlen?writtenlen:ret));
-       return writtenlen?writtenlen:ret;
+       D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",start+writtenlen==end?0:ret));
+       return start+writtenlen==end?0:ret;
 }