diff options
Diffstat (limited to 'fs/ext2/super.c')
-rw-r--r-- | fs/ext2/super.c | 205 |
1 files changed, 103 insertions, 102 deletions
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 1458706bd2ec..de1694512f1f 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -33,6 +33,7 @@ #include <linux/quotaops.h> #include <linux/uaccess.h> #include <linux/dax.h> +#include <linux/iversion.h> #include "ext2.h" #include "xattr.h" #include "acl.h" @@ -75,7 +76,7 @@ void ext2_error(struct super_block *sb, const char *function, if (test_opt(sb, ERRORS_RO)) { ext2_msg(sb, KERN_CRIT, "error: remounting filesystem read-only"); - sb->s_flags |= MS_RDONLY; + sb->s_flags |= SB_RDONLY; } } @@ -184,7 +185,7 @@ static struct inode *ext2_alloc_inode(struct super_block *sb) if (!ei) return NULL; ei->i_block_alloc_info = NULL; - ei->vfs_inode.i_version = 1; + inode_set_iversion(&ei->vfs_inode, 1); #ifdef CONFIG_QUOTA memset(&ei->i_dquot, 0, sizeof(ei->i_dquot)); #endif @@ -220,11 +221,13 @@ static void init_once(void *foo) static int __init init_inodecache(void) { - ext2_inode_cachep = kmem_cache_create("ext2_inode_cache", - sizeof(struct ext2_inode_info), - 0, (SLAB_RECLAIM_ACCOUNT| - SLAB_MEM_SPREAD|SLAB_ACCOUNT), - init_once); + ext2_inode_cachep = kmem_cache_create_usercopy("ext2_inode_cache", + sizeof(struct ext2_inode_info), 0, + (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD| + SLAB_ACCOUNT), + offsetof(struct ext2_inode_info, i_data), + sizeof_field(struct ext2_inode_info, i_data), + init_once); if (ext2_inode_cachep == NULL) return -ENOMEM; return 0; @@ -479,10 +482,10 @@ static const match_table_t tokens = { {Opt_err, NULL} }; -static int parse_options(char *options, struct super_block *sb) +static int parse_options(char *options, struct super_block *sb, + struct ext2_mount_options *opts) { char *p; - struct ext2_sb_info *sbi = EXT2_SB(sb); substring_t args[MAX_OPT_ARGS]; int option; kuid_t uid; @@ -499,16 +502,16 @@ static int parse_options(char *options, struct super_block *sb) token = match_token(p, tokens, args); switch (token) { case Opt_bsd_df: - clear_opt (sbi->s_mount_opt, MINIX_DF); + clear_opt (opts->s_mount_opt, MINIX_DF); break; case Opt_minix_df: - set_opt (sbi->s_mount_opt, MINIX_DF); + set_opt (opts->s_mount_opt, MINIX_DF); break; case Opt_grpid: - set_opt (sbi->s_mount_opt, GRPID); + set_opt (opts->s_mount_opt, GRPID); break; case Opt_nogrpid: - clear_opt (sbi->s_mount_opt, GRPID); + clear_opt (opts->s_mount_opt, GRPID); break; case Opt_resuid: if (match_int(&args[0], &option)) @@ -519,7 +522,7 @@ static int parse_options(char *options, struct super_block *sb) return 0; } - sbi->s_resuid = uid; + opts->s_resuid = uid; break; case Opt_resgid: if (match_int(&args[0], &option)) @@ -529,51 +532,51 @@ static int parse_options(char *options, struct super_block *sb) ext2_msg(sb, KERN_ERR, "Invalid gid value %d", option); return 0; } - sbi->s_resgid = gid; + opts->s_resgid = gid; break; case Opt_sb: /* handled by get_sb_block() instead of here */ /* *sb_block = match_int(&args[0]); */ break; case Opt_err_panic: - clear_opt (sbi->s_mount_opt, ERRORS_CONT); - clear_opt (sbi->s_mount_opt, ERRORS_RO); - set_opt (sbi->s_mount_opt, ERRORS_PANIC); + clear_opt (opts->s_mount_opt, ERRORS_CONT); + clear_opt (opts->s_mount_opt, ERRORS_RO); + set_opt (opts->s_mount_opt, ERRORS_PANIC); break; case Opt_err_ro: - clear_opt (sbi->s_mount_opt, ERRORS_CONT); - clear_opt (sbi->s_mount_opt, ERRORS_PANIC); - set_opt (sbi->s_mount_opt, ERRORS_RO); + clear_opt (opts->s_mount_opt, ERRORS_CONT); + clear_opt (opts->s_mount_opt, ERRORS_PANIC); + set_opt (opts->s_mount_opt, ERRORS_RO); break; case Opt_err_cont: - clear_opt (sbi->s_mount_opt, ERRORS_RO); - clear_opt (sbi->s_mount_opt, ERRORS_PANIC); - set_opt (sbi->s_mount_opt, ERRORS_CONT); + clear_opt (opts->s_mount_opt, ERRORS_RO); + clear_opt (opts->s_mount_opt, ERRORS_PANIC); + set_opt (opts->s_mount_opt, ERRORS_CONT); break; case Opt_nouid32: - set_opt (sbi->s_mount_opt, NO_UID32); + set_opt (opts->s_mount_opt, NO_UID32); break; case Opt_nocheck: - clear_opt (sbi->s_mount_opt, CHECK); + clear_opt (opts->s_mount_opt, CHECK); break; case Opt_debug: - set_opt (sbi->s_mount_opt, DEBUG); + set_opt (opts->s_mount_opt, DEBUG); break; case Opt_oldalloc: - set_opt (sbi->s_mount_opt, OLDALLOC); + set_opt (opts->s_mount_opt, OLDALLOC); break; case Opt_orlov: - clear_opt (sbi->s_mount_opt, OLDALLOC); + clear_opt (opts->s_mount_opt, OLDALLOC); break; case Opt_nobh: - set_opt (sbi->s_mount_opt, NOBH); + set_opt (opts->s_mount_opt, NOBH); break; #ifdef CONFIG_EXT2_FS_XATTR case Opt_user_xattr: - set_opt (sbi->s_mount_opt, XATTR_USER); + set_opt (opts->s_mount_opt, XATTR_USER); break; case Opt_nouser_xattr: - clear_opt (sbi->s_mount_opt, XATTR_USER); + clear_opt (opts->s_mount_opt, XATTR_USER); break; #else case Opt_user_xattr: @@ -584,10 +587,10 @@ static int parse_options(char *options, struct super_block *sb) #endif #ifdef CONFIG_EXT2_FS_POSIX_ACL case Opt_acl: - set_opt(sbi->s_mount_opt, POSIX_ACL); + set_opt(opts->s_mount_opt, POSIX_ACL); break; case Opt_noacl: - clear_opt(sbi->s_mount_opt, POSIX_ACL); + clear_opt(opts->s_mount_opt, POSIX_ACL); break; #else case Opt_acl: @@ -598,13 +601,13 @@ static int parse_options(char *options, struct super_block *sb) #endif case Opt_xip: ext2_msg(sb, KERN_INFO, "use dax instead of xip"); - set_opt(sbi->s_mount_opt, XIP); + set_opt(opts->s_mount_opt, XIP); /* Fall through */ case Opt_dax: #ifdef CONFIG_FS_DAX ext2_msg(sb, KERN_WARNING, "DAX enabled. Warning: EXPERIMENTAL, use at your own risk"); - set_opt(sbi->s_mount_opt, DAX); + set_opt(opts->s_mount_opt, DAX); #else ext2_msg(sb, KERN_INFO, "dax option not supported"); #endif @@ -613,11 +616,11 @@ static int parse_options(char *options, struct super_block *sb) #if defined(CONFIG_QUOTA) case Opt_quota: case Opt_usrquota: - set_opt(sbi->s_mount_opt, USRQUOTA); + set_opt(opts->s_mount_opt, USRQUOTA); break; case Opt_grpquota: - set_opt(sbi->s_mount_opt, GRPQUOTA); + set_opt(opts->s_mount_opt, GRPQUOTA); break; #else case Opt_quota: @@ -629,11 +632,11 @@ static int parse_options(char *options, struct super_block *sb) #endif case Opt_reservation: - set_opt(sbi->s_mount_opt, RESERVATION); + set_opt(opts->s_mount_opt, RESERVATION); ext2_msg(sb, KERN_INFO, "reservations ON"); break; case Opt_noreservation: - clear_opt(sbi->s_mount_opt, RESERVATION); + clear_opt(opts->s_mount_opt, RESERVATION); ext2_msg(sb, KERN_INFO, "reservations OFF"); break; case Opt_ignore: @@ -656,7 +659,7 @@ static int ext2_setup_super (struct super_block * sb, ext2_msg(sb, KERN_ERR, "error: revision level too high, " "forcing read-only mode"); - res = MS_RDONLY; + res = SB_RDONLY; } if (read_only) return res; @@ -824,14 +827,14 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) unsigned long logic_sb_block; unsigned long offset = 0; unsigned long def_mount_opts; - long ret = -EINVAL; + long ret = -ENOMEM; int blocksize = BLOCK_SIZE; int db_count; int i, j; __le32 features; int err; + struct ext2_mount_options opts; - err = -ENOMEM; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) goto failed; @@ -847,6 +850,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) sbi->s_daxdev = dax_dev; spin_lock_init(&sbi->s_lock); + ret = -EINVAL; /* * See what the current blocksize for the device is, and @@ -890,38 +894,42 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) /* Set defaults before we parse the mount options */ def_mount_opts = le32_to_cpu(es->s_default_mount_opts); if (def_mount_opts & EXT2_DEFM_DEBUG) - set_opt(sbi->s_mount_opt, DEBUG); + set_opt(opts.s_mount_opt, DEBUG); if (def_mount_opts & EXT2_DEFM_BSDGROUPS) - set_opt(sbi->s_mount_opt, GRPID); + set_opt(opts.s_mount_opt, GRPID); if (def_mount_opts & EXT2_DEFM_UID16) - set_opt(sbi->s_mount_opt, NO_UID32); + set_opt(opts.s_mount_opt, NO_UID32); #ifdef CONFIG_EXT2_FS_XATTR if (def_mount_opts & EXT2_DEFM_XATTR_USER) - set_opt(sbi->s_mount_opt, XATTR_USER); + set_opt(opts.s_mount_opt, XATTR_USER); #endif #ifdef CONFIG_EXT2_FS_POSIX_ACL if (def_mount_opts & EXT2_DEFM_ACL) - set_opt(sbi->s_mount_opt, POSIX_ACL); + set_opt(opts.s_mount_opt, POSIX_ACL); #endif if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC) - set_opt(sbi->s_mount_opt, ERRORS_PANIC); + set_opt(opts.s_mount_opt, ERRORS_PANIC); else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE) - set_opt(sbi->s_mount_opt, ERRORS_CONT); + set_opt(opts.s_mount_opt, ERRORS_CONT); else - set_opt(sbi->s_mount_opt, ERRORS_RO); + set_opt(opts.s_mount_opt, ERRORS_RO); - sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid)); - sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid)); + opts.s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid)); + opts.s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid)); - set_opt(sbi->s_mount_opt, RESERVATION); + set_opt(opts.s_mount_opt, RESERVATION); - if (!parse_options((char *) data, sb)) + if (!parse_options((char *) data, sb, &opts)) goto failed_mount; - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | + sbi->s_mount_opt = opts.s_mount_opt; + sbi->s_resuid = opts.s_resuid; + sbi->s_resgid = opts.s_resgid; + + sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? - MS_POSIXACL : 0); + SB_POSIXACL : 0); sb->s_iflags |= SB_I_CGROUPWB; if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && @@ -954,8 +962,11 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) if (sbi->s_mount_opt & EXT2_MOUNT_DAX) { err = bdev_dax_supported(sb, blocksize); - if (err) - goto failed_mount; + if (err) { + ext2_msg(sb, KERN_ERR, + "DAX unsupported by block device. Turning off DAX."); + sbi->s_mount_opt &= ~EXT2_MOUNT_DAX; + } } /* If the blocksize doesn't match, re-read the thing.. */ @@ -1173,7 +1184,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ext2_msg(sb, KERN_WARNING, "warning: mounting ext3 filesystem as ext2"); if (ext2_setup_super (sb, es, sb_rdonly(sb))) - sb->s_flags |= MS_RDONLY; + sb->s_flags |= SB_RDONLY; ext2_write_super(sb); return 0; @@ -1220,7 +1231,7 @@ static void ext2_clear_super_error(struct super_block *sb) * write and hope for the best. */ ext2_msg(sb, KERN_ERR, - "previous I/O error to superblock detected\n"); + "previous I/O error to superblock detected"); clear_buffer_write_io_error(sbh); set_buffer_uptodate(sbh); } @@ -1312,46 +1323,36 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) { struct ext2_sb_info * sbi = EXT2_SB(sb); struct ext2_super_block * es; - struct ext2_mount_options old_opts; - unsigned long old_sb_flags; + struct ext2_mount_options new_opts; int err; sync_filesystem(sb); - spin_lock(&sbi->s_lock); - /* Store the old options */ - old_sb_flags = sb->s_flags; - old_opts.s_mount_opt = sbi->s_mount_opt; - old_opts.s_resuid = sbi->s_resuid; - old_opts.s_resgid = sbi->s_resgid; + spin_lock(&sbi->s_lock); + new_opts.s_mount_opt = sbi->s_mount_opt; + new_opts.s_resuid = sbi->s_resuid; + new_opts.s_resgid = sbi->s_resgid; + spin_unlock(&sbi->s_lock); /* * Allow the "check" option to be passed as a remount option. */ - if (!parse_options(data, sb)) { - err = -EINVAL; - goto restore_opts; - } - - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); + if (!parse_options(data, sb, &new_opts)) + return -EINVAL; + spin_lock(&sbi->s_lock); es = sbi->s_es; - if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT2_MOUNT_DAX) { + if ((sbi->s_mount_opt ^ new_opts.s_mount_opt) & EXT2_MOUNT_DAX) { ext2_msg(sb, KERN_WARNING, "warning: refusing change of " "dax flag with busy inodes while remounting"); - sbi->s_mount_opt ^= EXT2_MOUNT_DAX; - } - if ((bool)(*flags & MS_RDONLY) == sb_rdonly(sb)) { - spin_unlock(&sbi->s_lock); - return 0; + new_opts.s_mount_opt ^= EXT2_MOUNT_DAX; } - if (*flags & MS_RDONLY) { + if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb)) + goto out_set; + if (*flags & SB_RDONLY) { if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || - !(sbi->s_mount_state & EXT2_VALID_FS)) { - spin_unlock(&sbi->s_lock); - return 0; - } + !(sbi->s_mount_state & EXT2_VALID_FS)) + goto out_set; /* * OK, we are remounting a valid rw partition rdonly, so set @@ -1362,22 +1363,20 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) spin_unlock(&sbi->s_lock); err = dquot_suspend(sb, -1); - if (err < 0) { - spin_lock(&sbi->s_lock); - goto restore_opts; - } + if (err < 0) + return err; ext2_sync_super(sb, es, 1); } else { __le32 ret = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP); if (ret) { + spin_unlock(&sbi->s_lock); ext2_msg(sb, KERN_WARNING, "warning: couldn't remount RDWR because of " "unsupported optional features (%x).", le32_to_cpu(ret)); - err = -EROFS; - goto restore_opts; + return -EROFS; } /* * Mounting a RDONLY partition read-write, so reread and @@ -1386,7 +1385,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) */ sbi->s_mount_state = le16_to_cpu(es->s_state); if (!ext2_setup_super (sb, es, 0)) - sb->s_flags &= ~MS_RDONLY; + sb->s_flags &= ~SB_RDONLY; spin_unlock(&sbi->s_lock); ext2_write_super(sb); @@ -1394,14 +1393,16 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) dquot_resume(sb, -1); } - return 0; -restore_opts: - sbi->s_mount_opt = old_opts.s_mount_opt; - sbi->s_resuid = old_opts.s_resuid; - sbi->s_resgid = old_opts.s_resgid; - sb->s_flags = old_sb_flags; + spin_lock(&sbi->s_lock); +out_set: + sbi->s_mount_opt = new_opts.s_mount_opt; + sbi->s_resuid = new_opts.s_resuid; + sbi->s_resgid = new_opts.s_resgid; + sb->s_flags = (sb->s_flags & ~SB_POSIXACL) | + ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? SB_POSIXACL : 0); spin_unlock(&sbi->s_lock); - return err; + + return 0; } static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf) @@ -1574,7 +1575,7 @@ out: return err; if (inode->i_size < off+len-towrite) i_size_write(inode, off+len-towrite); - inode->i_version++; + inode_inc_iversion(inode); inode->i_mtime = inode->i_ctime = current_time(inode); mark_inode_dirty(inode); return len - towrite; |