fat: convert to new aops
[safe/jmp/linux-2.6] / fs / fat / inode.c
index ab96ae8..46b8a67 100644 (file)
 #include <linux/pagemap.h>
 #include <linux/mpage.h>
 #include <linux/buffer_head.h>
+#include <linux/exportfs.h>
 #include <linux/mount.h>
 #include <linux/vfs.h>
 #include <linux/parser.h>
 #include <linux/uio.h>
+#include <linux/writeback.h>
+#include <linux/log2.h>
 #include <asm/unaligned.h>
 
 #ifndef CONFIG_FAT_DEFAULT_IOCHARSET
@@ -138,19 +141,24 @@ static int fat_readpages(struct file *file, struct address_space *mapping,
        return mpage_readpages(mapping, pages, nr_pages, fat_get_block);
 }
 
-static int fat_prepare_write(struct file *file, struct page *page,
-                            unsigned from, unsigned to)
+static int fat_write_begin(struct file *file, struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned flags,
+                       struct page **pagep, void **fsdata)
 {
-       return cont_prepare_write(page, from, to, fat_get_block,
-                                 &MSDOS_I(page->mapping->host)->mmu_private);
+       *pagep = NULL;
+       return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+                               fat_get_block,
+                               &MSDOS_I(mapping->host)->mmu_private);
 }
 
-static int fat_commit_write(struct file *file, struct page *page,
-                           unsigned from, unsigned to)
+static int fat_write_end(struct file *file, struct address_space *mapping,
+                       loff_t pos, unsigned len, unsigned copied,
+                       struct page *pagep, void *fsdata)
 {
-       struct inode *inode = page->mapping->host;
-       int err = generic_commit_write(file, page, from, to);
-       if (!err && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) {
+       struct inode *inode = mapping->host;
+       int err;
+       err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata);
+       if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) {
                inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
                MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
                mark_inode_dirty(inode);
@@ -172,10 +180,12 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
                 *
                 * But we must fill the remaining area or hole by nul for
                 * updating ->mmu_private.
+                *
+                * Return 0, and fallback to normal buffered write.
                 */
                loff_t size = offset + iov_length(iov, nr_segs);
                if (MSDOS_I(inode)->mmu_private < size)
-                       return -EINVAL;
+                       return 0;
        }
 
        /*
@@ -197,8 +207,8 @@ static const struct address_space_operations fat_aops = {
        .writepage      = fat_writepage,
        .writepages     = fat_writepages,
        .sync_page      = block_sync_page,
-       .prepare_write  = fat_prepare_write,
-       .commit_write   = fat_commit_write,
+       .write_begin    = fat_write_begin,
+       .write_end      = fat_write_end,
        .direct_IO      = fat_direct_IO,
        .bmap           = _fat_bmap
 };
@@ -350,8 +360,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
        } else { /* not a directory */
                inode->i_generation |= 1;
                inode->i_mode = MSDOS_MKMODE(de->attr,
-                   ((sbi->options.showexec &&
-                       !is_exec(de->ext))
+                   ((sbi->options.showexec && !is_exec(de->name + 8))
                        ? S_IRUGO|S_IWUGO : S_IRWXUGO)
                    & ~sbi->options.fs_fmask) | S_IFREG;
                MSDOS_I(inode)->i_start = le16_to_cpu(de->start);
@@ -383,7 +392,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
                                      le16_to_cpu(de->cdate)) + secs;
                inode->i_ctime.tv_nsec = csecs * 10000000;
                inode->i_atime.tv_sec =
-                       date_dos2unix(le16_to_cpu(0), le16_to_cpu(de->adate));
+                       date_dos2unix(0, le16_to_cpu(de->adate));
                inode->i_atime.tv_nsec = 0;
        } else
                inode->i_ctime = inode->i_atime = inode->i_mtime;
@@ -476,12 +485,12 @@ static void fat_put_super(struct super_block *sb)
        kfree(sbi);
 }
 
-static kmem_cache_t *fat_inode_cachep;
+static struct kmem_cache *fat_inode_cachep;
 
 static struct inode *fat_alloc_inode(struct super_block *sb)
 {
        struct msdos_inode_info *ei;
-       ei = kmem_cache_alloc(fat_inode_cachep, SLAB_KERNEL);
+       ei = kmem_cache_alloc(fat_inode_cachep, GFP_KERNEL);
        if (!ei)
                return NULL;
        return &ei->vfs_inode;
@@ -492,19 +501,16 @@ static void fat_destroy_inode(struct inode *inode)
        kmem_cache_free(fat_inode_cachep, MSDOS_I(inode));
 }
 
-static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
 {
        struct msdos_inode_info *ei = (struct msdos_inode_info *)foo;
 
-       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
-           SLAB_CTOR_CONSTRUCTOR) {
-               spin_lock_init(&ei->cache_lru_lock);
-               ei->nr_caches = 0;
-               ei->cache_valid_id = FAT_CACHE_VALID + 1;
-               INIT_LIST_HEAD(&ei->cache_lru);
-               INIT_HLIST_NODE(&ei->i_fat_hash);
-               inode_init_once(&ei->vfs_inode);
-       }
+       spin_lock_init(&ei->cache_lru_lock);
+       ei->nr_caches = 0;
+       ei->cache_valid_id = FAT_CACHE_VALID + 1;
+       INIT_LIST_HEAD(&ei->cache_lru);
+       INIT_HLIST_NODE(&ei->i_fat_hash);
+       inode_init_once(&ei->vfs_inode);
 }
 
 static int __init fat_init_inodecache(void)
@@ -513,7 +519,7 @@ static int __init fat_init_inodecache(void)
                                             sizeof(struct msdos_inode_info),
                                             0, (SLAB_RECLAIM_ACCOUNT|
                                                SLAB_MEM_SPREAD),
-                                            init_once, NULL);
+                                            init_once);
        if (fat_inode_cachep == NULL)
                return -ENOMEM;
        return 0;
@@ -617,7 +623,7 @@ int fat_sync_inode(struct inode *inode)
 EXPORT_SYMBOL_GPL(fat_sync_inode);
 
 static int fat_show_options(struct seq_file *m, struct vfsmount *mnt);
-static struct super_operations fat_sops = {
+static const struct super_operations fat_sops = {
        .alloc_inode    = fat_alloc_inode,
        .destroy_inode  = fat_destroy_inode,
        .write_inode    = fat_write_inode,
@@ -822,6 +828,8 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
        }
        if (opts->name_check != 'n')
                seq_printf(m, ",check=%c", opts->name_check);
+       if (opts->usefree)
+               seq_puts(m, ",usefree");
        if (opts->quiet)
                seq_puts(m, ",quiet");
        if (opts->showexec)
@@ -847,13 +855,13 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
 
 enum {
        Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid,
-       Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_nocase,
+       Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_usefree, Opt_nocase,
        Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable,
        Opt_dots, Opt_nodots,
        Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
        Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
        Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
-       Opt_obsolate, Opt_err,
+       Opt_obsolate, Opt_flush, Opt_err,
 };
 
 static match_table_t fat_tokens = {
@@ -869,6 +877,7 @@ static match_table_t fat_tokens = {
        {Opt_dmask, "dmask=%o"},
        {Opt_fmask, "fmask=%o"},
        {Opt_codepage, "codepage=%u"},
+       {Opt_usefree, "usefree"},
        {Opt_nocase, "nocase"},
        {Opt_quiet, "quiet"},
        {Opt_showexec, "showexec"},
@@ -885,7 +894,8 @@ static match_table_t fat_tokens = {
        {Opt_obsolate, "cvf_format=%20s"},
        {Opt_obsolate, "cvf_options=%100s"},
        {Opt_obsolate, "posix"},
-       {Opt_err, NULL}
+       {Opt_flush, "flush"},
+       {Opt_err, NULL},
 };
 static match_table_t msdos_tokens = {
        {Opt_nodots, "nodots"},
@@ -947,7 +957,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
        opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK =  0;
        opts->utf8 = opts->unicode_xlate = 0;
        opts->numtail = 1;
-       opts->nocase = 0;
+       opts->usefree = opts->nocase = 0;
        *debug = 0;
 
        if (!options)
@@ -975,6 +985,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
                case Opt_check_n:
                        opts->name_check = 'n';
                        break;
+               case Opt_usefree:
+                       opts->usefree = 1;
+                       break;
                case Opt_nocase:
                        if (!is_vfat)
                                opts->nocase = 1;
@@ -1026,6 +1039,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
                                return 0;
                        opts->codepage = option;
                        break;
+               case Opt_flush:
+                       opts->flush = 1;
+                       break;
 
                /* msdos specific */
                case Opt_dots:
@@ -1146,7 +1162,7 @@ static int fat_read_root(struct inode *inode)
  * Read the super block of an MS-DOS FS.
  */
 int fat_fill_super(struct super_block *sb, void *data, int silent,
-                  struct inode_operations *fs_dir_inode_ops, int isvfat)
+                  const struct inode_operations *fs_dir_inode_ops, int isvfat)
 {
        struct inode *root_inode = NULL;
        struct buffer_head *bh;
@@ -1211,8 +1227,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
        }
        logical_sector_size =
                le16_to_cpu(get_unaligned((__le16 *)&b->sector_size));
-       if (!logical_sector_size
-           || (logical_sector_size & (logical_sector_size - 1))
+       if (!is_power_of_2(logical_sector_size)
            || (logical_sector_size < 512)
            || (PAGE_CACHE_SIZE < logical_sector_size)) {
                if (!silent)
@@ -1222,8 +1237,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
                goto out_invalid;
        }
        sbi->sec_per_clus = b->sec_per_clus;
-       if (!sbi->sec_per_clus
-           || (sbi->sec_per_clus & (sbi->sec_per_clus - 1))) {
+       if (!is_power_of_2(sbi->sec_per_clus)) {
                if (!silent)
                        printk(KERN_ERR "FAT: bogus sectors per cluster %u\n",
                               sbi->sec_per_clus);
@@ -1299,7 +1313,9 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
                               le32_to_cpu(fsinfo->signature2),
                               sbi->fsinfo_sector);
                } else {
-                       sbi->free_clusters = le32_to_cpu(fsinfo->free_clusters);
+                       if (sbi->options.usefree)
+                               sbi->free_clusters =
+                                       le32_to_cpu(fsinfo->free_clusters);
                        sbi->prev_free = le32_to_cpu(fsinfo->next_cluster);
                }
 
@@ -1425,6 +1441,56 @@ out_fail:
 
 EXPORT_SYMBOL_GPL(fat_fill_super);
 
+/*
+ * helper function for fat_flush_inodes.  This writes both the inode
+ * and the file data blocks, waiting for in flight data blocks before
+ * the start of the call.  It does not wait for any io started
+ * during the call
+ */
+static int writeback_inode(struct inode *inode)
+{
+
+       int ret;
+       struct address_space *mapping = inode->i_mapping;
+       struct writeback_control wbc = {
+              .sync_mode = WB_SYNC_NONE,
+             .nr_to_write = 0,
+       };
+       /* if we used WB_SYNC_ALL, sync_inode waits for the io for the
+       * inode to finish.  So WB_SYNC_NONE is sent down to sync_inode
+       * and filemap_fdatawrite is used for the data blocks
+       */
+       ret = sync_inode(inode, &wbc);
+       if (!ret)
+              ret = filemap_fdatawrite(mapping);
+       return ret;
+}
+
+/*
+ * write data and metadata corresponding to i1 and i2.  The io is
+ * started but we do not wait for any of it to finish.
+ *
+ * filemap_flush is used for the block device, so if there is a dirty
+ * page for a block already in flight, we will not wait and start the
+ * io over again
+ */
+int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2)
+{
+       int ret = 0;
+       if (!MSDOS_SB(sb)->options.flush)
+               return 0;
+       if (i1)
+               ret = writeback_inode(i1);
+       if (!ret && i2)
+               ret = writeback_inode(i2);
+       if (!ret) {
+               struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
+               ret = filemap_flush(mapping);
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(fat_flush_inodes);
+
 static int __init init_fat_fs(void)
 {
        int err;