NFSv4: Fix up the documentation for nfs_do_refmount
[safe/jmp/linux-2.6] / fs / ramfs / inode.c
index d40d22b..c948534 100644 (file)
 #include <linux/backing-dev.h>
 #include <linux/ramfs.h>
 #include <linux/sched.h>
+#include <linux/parser.h>
+#include <linux/magic.h>
+#include <linux/slab.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
-/* some random number */
-#define RAMFS_MAGIC    0x858458f6
+#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 = {
+       .name           = "ramfs",
        .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,
 };
@@ -55,11 +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_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:
@@ -157,30 +161,105 @@ static const struct inode_operations ramfs_dir_inode_operations = {
 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;
+               /*
+                * We might like to report bad mount options here;
+                * but traditionally ramfs has ignored all mount options,
+                * and as it is used as a !CONFIG_SHMEM simple substitute
+                * for tmpfs, better continue to ignore other mount options.
+                */
+               }
+       }
+
+       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;
 }
 
 int ramfs_get_sb(struct file_system_type *fs_type,
@@ -196,10 +275,16 @@ static int rootfs_get_sb(struct file_system_type *fs_type,
                            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",
@@ -222,7 +307,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");