Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ryusuke...
[safe/jmp/linux-2.6] / fs / ramfs / inode.c
index 0a88917..3a6b193 100644 (file)
 #include <linux/fs.h>
 #include <linux/pagemap.h>
 #include <linux/highmem.h>
+#include <linux/time.h>
 #include <linux/init.h>
 #include <linux/string.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/ramfs.h>
-
+#include <linux/sched.h>
+#include <linux/parser.h>
 #include <asm/uaccess.h>
+#include "internal.h"
 
 /* some random number */
 #define RAMFS_MAGIC    0x858458f6
 
-static struct super_operations ramfs_ops;
-static struct address_space_operations ramfs_aops;
-static struct inode_operations ramfs_file_inode_operations;
-static struct inode_operations ramfs_dir_inode_operations;
+#define RAMFS_DEFAULT_MODE     0755
+
+static const struct super_operations ramfs_ops;
+static const struct inode_operations ramfs_dir_inode_operations;
 
 static struct backing_dev_info ramfs_backing_dev_info = {
        .ra_pages       = 0,    /* No readahead */
-       .capabilities   = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK |
+       .capabilities   = BDI_CAP_NO_ACCT_AND_WRITEBACK |
                          BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |
                          BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,
 };
@@ -56,12 +58,12 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
 
        if (inode) {
                inode->i_mode = mode;
-               inode->i_uid = current->fsuid;
-               inode->i_gid = current->fsgid;
-               inode->i_blksize = PAGE_CACHE_SIZE;
-               inode->i_blocks = 0;
+               inode->i_uid = current_fsuid();
+               inode->i_gid = current_fsgid();
                inode->i_mapping->a_ops = &ramfs_aops;
                inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
+               mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
+               mapping_set_unevictable(inode->i_mapping);
                inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
                switch (mode & S_IFMT) {
                default:
@@ -76,7 +78,7 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
                        inode->i_fop = &simple_dir_operations;
 
                        /* directory inodes start off with i_nlink == 2 (for "." entry) */
-                       inode->i_nlink++;
+                       inc_nlink(inode);
                        break;
                case S_IFLNK:
                        inode->i_op = &page_symlink_inode_operations;
@@ -105,6 +107,7 @@ ramfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
                d_instantiate(dentry, inode);
                dget(dentry);   /* Extra count - pin the dentry in core */
                error = 0;
+               dir->i_mtime = dir->i_ctime = CURRENT_TIME;
        }
        return error;
 }
@@ -113,7 +116,7 @@ static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
 {
        int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
        if (!retval)
-               dir->i_nlink++;
+               inc_nlink(dir);
        return retval;
 }
 
@@ -136,32 +139,14 @@ static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char *
                                inode->i_gid = dir->i_gid;
                        d_instantiate(dentry, inode);
                        dget(dentry);
+                       dir->i_mtime = dir->i_ctime = CURRENT_TIME;
                } else
                        iput(inode);
        }
        return error;
 }
 
-static struct address_space_operations ramfs_aops = {
-       .readpage       = simple_readpage,
-       .prepare_write  = simple_prepare_write,
-       .commit_write   = simple_commit_write
-};
-
-struct file_operations ramfs_file_operations = {
-       .read           = generic_file_read,
-       .write          = generic_file_write,
-       .mmap           = generic_file_mmap,
-       .fsync          = simple_sync_file,
-       .sendfile       = generic_file_sendfile,
-       .llseek         = generic_file_llseek,
-};
-
-static struct inode_operations ramfs_file_inode_operations = {
-       .getattr        = simple_getattr,
-};
-
-static struct inode_operations ramfs_dir_inode_operations = {
+static const struct inode_operations ramfs_dir_inode_operations = {
        .create         = ramfs_create,
        .lookup         = simple_lookup,
        .link           = simple_link,
@@ -173,51 +158,130 @@ static struct inode_operations ramfs_dir_inode_operations = {
        .rename         = simple_rename,
 };
 
-static struct super_operations ramfs_ops = {
+static const struct super_operations ramfs_ops = {
        .statfs         = simple_statfs,
        .drop_inode     = generic_delete_inode,
+       .show_options   = generic_show_options,
+};
+
+struct ramfs_mount_opts {
+       umode_t mode;
+};
+
+enum {
+       Opt_mode,
+       Opt_err
 };
 
+static const match_table_t tokens = {
+       {Opt_mode, "mode=%o"},
+       {Opt_err, NULL}
+};
+
+struct ramfs_fs_info {
+       struct ramfs_mount_opts mount_opts;
+};
+
+static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts)
+{
+       substring_t args[MAX_OPT_ARGS];
+       int option;
+       int token;
+       char *p;
+
+       opts->mode = RAMFS_DEFAULT_MODE;
+
+       while ((p = strsep(&data, ",")) != NULL) {
+               if (!*p)
+                       continue;
+
+               token = match_token(p, tokens, args);
+               switch (token) {
+               case Opt_mode:
+                       if (match_octal(&args[0], &option))
+                               return -EINVAL;
+                       opts->mode = option & S_IALLUGO;
+                       break;
+               default:
+                       printk(KERN_ERR "ramfs: bad mount option: %s\n", p);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
 {
-       struct inode * inode;
-       struct dentry * root;
-
-       sb->s_maxbytes = MAX_LFS_FILESIZE;
-       sb->s_blocksize = PAGE_CACHE_SIZE;
-       sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
-       sb->s_magic = RAMFS_MAGIC;
-       sb->s_op = &ramfs_ops;
-       sb->s_time_gran = 1;
-       inode = ramfs_get_inode(sb, S_IFDIR | 0755, 0);
-       if (!inode)
-               return -ENOMEM;
+       struct ramfs_fs_info *fsi;
+       struct inode *inode = NULL;
+       struct dentry *root;
+       int err;
+
+       save_mount_options(sb, data);
+
+       fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL);
+       sb->s_fs_info = fsi;
+       if (!fsi) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       err = ramfs_parse_options(data, &fsi->mount_opts);
+       if (err)
+               goto fail;
+
+       sb->s_maxbytes          = MAX_LFS_FILESIZE;
+       sb->s_blocksize         = PAGE_CACHE_SIZE;
+       sb->s_blocksize_bits    = PAGE_CACHE_SHIFT;
+       sb->s_magic             = RAMFS_MAGIC;
+       sb->s_op                = &ramfs_ops;
+       sb->s_time_gran         = 1;
+
+       inode = ramfs_get_inode(sb, S_IFDIR | fsi->mount_opts.mode, 0);
+       if (!inode) {
+               err = -ENOMEM;
+               goto fail;
+       }
 
        root = d_alloc_root(inode);
+       sb->s_root = root;
        if (!root) {
-               iput(inode);
-               return -ENOMEM;
+               err = -ENOMEM;
+               goto fail;
        }
-       sb->s_root = root;
+
        return 0;
+fail:
+       kfree(fsi);
+       sb->s_fs_info = NULL;
+       iput(inode);
+       return err;
 }
 
-struct super_block *ramfs_get_sb(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
+int ramfs_get_sb(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *data, struct vfsmount *mnt)
 {
-       return get_sb_nodev(fs_type, flags, data, ramfs_fill_super);
+       return get_sb_nodev(fs_type, flags, data, ramfs_fill_super, mnt);
 }
 
-static struct super_block *rootfs_get_sb(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
+static int rootfs_get_sb(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *data, struct vfsmount *mnt)
 {
-       return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super);
+       return get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,
+                           mnt);
+}
+
+static void ramfs_kill_sb(struct super_block *sb)
+{
+       kfree(sb->s_fs_info);
+       kill_litter_super(sb);
 }
 
 static struct file_system_type ramfs_fs_type = {
        .name           = "ramfs",
        .get_sb         = ramfs_get_sb,
-       .kill_sb        = kill_litter_super,
+       .kill_sb        = ramfs_kill_sb,
 };
 static struct file_system_type rootfs_fs_type = {
        .name           = "rootfs",
@@ -240,7 +304,17 @@ module_exit(exit_ramfs_fs)
 
 int __init init_rootfs(void)
 {
-       return register_filesystem(&rootfs_fs_type);
+       int err;
+
+       err = bdi_init(&ramfs_backing_dev_info);
+       if (err)
+               return err;
+
+       err = register_filesystem(&rootfs_fs_type);
+       if (err)
+               bdi_destroy(&ramfs_backing_dev_info);
+
+       return err;
 }
 
 MODULE_LICENSE("GPL");