gfs2: Convert gfs2 to fs_context

Convert gfs2 and gfs2meta to fs_context. Removes the duplicated vfs code
from gfs2_mount and instead uses the new vfs_get_block_super() before
switching the ->root to the appropriate dentry.

The mount option parsing has been converted to the new API and error
reporting for invalid options has been made more precise at the same
time.

All of the mount/remount code has been moved into ops_fstype.c

Signed-off-by: Andrew Price <anprice@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
cc: cluster-devel@redhat.com
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Andrew Price 2019-03-27 14:46:00 +00:00 committed by Al Viro
parent d2e0981c3b
commit 1f52aa08d1
4 changed files with 381 additions and 460 deletions

View File

@ -584,10 +584,10 @@ struct gfs2_args {
unsigned int ar_rgrplvb:1; /* use lvbs for rgrp info */ unsigned int ar_rgrplvb:1; /* use lvbs for rgrp info */
unsigned int ar_loccookie:1; /* use location based readdir unsigned int ar_loccookie:1; /* use location based readdir
cookies */ cookies */
int ar_commit; /* Commit interval */ s32 ar_commit; /* Commit interval */
int ar_statfs_quantum; /* The fast statfs interval */ s32 ar_statfs_quantum; /* The fast statfs interval */
int ar_quota_quantum; /* The quota interval */ s32 ar_quota_quantum; /* The quota interval */
int ar_statfs_percent; /* The % change to force sync */ s32 ar_statfs_percent; /* The % change to force sync */
}; };
struct gfs2_tune { struct gfs2_tune {

View File

@ -21,6 +21,7 @@
#include <linux/lockdep.h> #include <linux/lockdep.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/fs_parser.h>
#include "gfs2.h" #include "gfs2.h"
#include "incore.h" #include "incore.h"
@ -1030,16 +1031,17 @@ void gfs2_online_uevent(struct gfs2_sbd *sdp)
} }
/** /**
* fill_super - Read in superblock * gfs2_fill_super - Read in superblock
* @sb: The VFS superblock * @sb: The VFS superblock
* @data: Mount options * @args: Mount options
* @silent: Don't complain if it's not a GFS2 filesystem * @silent: Don't complain if it's not a GFS2 filesystem
* *
* Returns: errno * Returns: -errno
*/ */
static int gfs2_fill_super(struct super_block *sb, struct fs_context *fc)
static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent)
{ {
struct gfs2_args *args = fc->fs_private;
int silent = fc->sb_flags & SB_SILENT;
struct gfs2_sbd *sdp; struct gfs2_sbd *sdp;
struct gfs2_holder mount_gh; struct gfs2_holder mount_gh;
int error; int error;
@ -1204,161 +1206,411 @@ fail_debug:
return error; return error;
} }
static int set_gfs2_super(struct super_block *s, void *data) /**
* gfs2_get_tree - Get the GFS2 superblock and root directory
* @fc: The filesystem context
*
* Returns: 0 or -errno on error
*/
static int gfs2_get_tree(struct fs_context *fc)
{ {
s->s_bdev = data; struct gfs2_args *args = fc->fs_private;
s->s_dev = s->s_bdev->bd_dev; struct gfs2_sbd *sdp;
s->s_bdi = bdi_get(s->s_bdev->bd_bdi); int error;
error = get_tree_bdev(fc, gfs2_fill_super);
if (error)
return error;
sdp = fc->root->d_sb->s_fs_info;
dput(fc->root);
if (args->ar_meta)
fc->root = dget(sdp->sd_master_dir);
else
fc->root = dget(sdp->sd_root_dir);
return 0; return 0;
} }
static int test_gfs2_super(struct super_block *s, void *ptr) static void gfs2_fc_free(struct fs_context *fc)
{ {
struct block_device *bdev = ptr; struct gfs2_args *args = fc->fs_private;
return (bdev == s->s_bdev);
kfree(args);
} }
/** enum gfs2_param {
* gfs2_mount - Get the GFS2 superblock Opt_lockproto,
* @fs_type: The GFS2 filesystem type Opt_locktable,
* @flags: Mount flags Opt_hostdata,
* @dev_name: The name of the device Opt_spectator,
* @data: The mount arguments Opt_ignore_local_fs,
* Opt_localflocks,
* Q. Why not use get_sb_bdev() ? Opt_localcaching,
* A. We need to select one of two root directories to mount, independent Opt_debug,
* of whether this is the initial, or subsequent, mount of this sb Opt_upgrade,
* Opt_acl,
* Returns: 0 or -ve on error Opt_quota,
*/ Opt_suiddir,
Opt_data,
Opt_meta,
Opt_discard,
Opt_commit,
Opt_errors,
Opt_statfs_quantum,
Opt_statfs_percent,
Opt_quota_quantum,
Opt_barrier,
Opt_rgrplvb,
Opt_loccookie,
};
static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags, enum opt_quota {
const char *dev_name, void *data) Opt_quota_unset = 0,
Opt_quota_off,
Opt_quota_account,
Opt_quota_on,
};
static const unsigned int opt_quota_values[] = {
[Opt_quota_off] = GFS2_QUOTA_OFF,
[Opt_quota_account] = GFS2_QUOTA_ACCOUNT,
[Opt_quota_on] = GFS2_QUOTA_ON,
};
enum opt_data {
Opt_data_writeback = GFS2_DATA_WRITEBACK,
Opt_data_ordered = GFS2_DATA_ORDERED,
};
enum opt_errors {
Opt_errors_withdraw = GFS2_ERRORS_WITHDRAW,
Opt_errors_panic = GFS2_ERRORS_PANIC,
};
static const struct fs_parameter_spec gfs2_param_specs[] = {
fsparam_string ("lockproto", Opt_lockproto),
fsparam_string ("locktable", Opt_locktable),
fsparam_string ("hostdata", Opt_hostdata),
fsparam_flag ("spectator", Opt_spectator),
fsparam_flag ("norecovery", Opt_spectator),
fsparam_flag ("ignore_local_fs", Opt_ignore_local_fs),
fsparam_flag ("localflocks", Opt_localflocks),
fsparam_flag ("localcaching", Opt_localcaching),
fsparam_flag_no("debug", Opt_debug),
fsparam_flag ("upgrade", Opt_upgrade),
fsparam_flag_no("acl", Opt_acl),
fsparam_flag_no("suiddir", Opt_suiddir),
fsparam_enum ("data", Opt_data),
fsparam_flag ("meta", Opt_meta),
fsparam_flag_no("discard", Opt_discard),
fsparam_s32 ("commit", Opt_commit),
fsparam_enum ("errors", Opt_errors),
fsparam_s32 ("statfs_quantum", Opt_statfs_quantum),
fsparam_s32 ("statfs_percent", Opt_statfs_percent),
fsparam_s32 ("quota_quantum", Opt_quota_quantum),
fsparam_flag_no("barrier", Opt_barrier),
fsparam_flag_no("rgrplvb", Opt_rgrplvb),
fsparam_flag_no("loccookie", Opt_loccookie),
/* quota can be a flag or an enum so it gets special treatment */
__fsparam(fs_param_is_enum, "quota", Opt_quota, fs_param_neg_with_no|fs_param_v_optional),
{}
};
static const struct fs_parameter_enum gfs2_param_enums[] = {
{ Opt_quota, "off", Opt_quota_off },
{ Opt_quota, "account", Opt_quota_account },
{ Opt_quota, "on", Opt_quota_on },
{ Opt_data, "writeback", Opt_data_writeback },
{ Opt_data, "ordered", Opt_data_ordered },
{ Opt_errors, "withdraw", Opt_errors_withdraw },
{ Opt_errors, "panic", Opt_errors_panic },
{}
};
const struct fs_parameter_description gfs2_fs_parameters = {
.name = "gfs2",
.specs = gfs2_param_specs,
.enums = gfs2_param_enums,
};
/* Parse a single mount parameter */
static int gfs2_parse_param(struct fs_context *fc, struct fs_parameter *param)
{ {
struct block_device *bdev; struct gfs2_args *args = fc->fs_private;
struct super_block *s; struct fs_parse_result result;
fmode_t mode = FMODE_READ | FMODE_EXCL; int o;
int error;
struct gfs2_args args;
struct gfs2_sbd *sdp;
if (!(flags & SB_RDONLY)) o = fs_parse(fc, &gfs2_fs_parameters, param, &result);
mode |= FMODE_WRITE; if (o < 0)
return o;
bdev = blkdev_get_by_path(dev_name, mode, fs_type); switch (o) {
if (IS_ERR(bdev)) case Opt_lockproto:
return ERR_CAST(bdev); strlcpy(args->ar_lockproto, param->string, GFS2_LOCKNAME_LEN);
break;
/* case Opt_locktable:
* once the super is inserted into the list by sget, s_umount strlcpy(args->ar_locktable, param->string, GFS2_LOCKNAME_LEN);
* will protect the lockfs code from trying to start a snapshot break;
* while we are mounting case Opt_hostdata:
*/ strlcpy(args->ar_hostdata, param->string, GFS2_LOCKNAME_LEN);
mutex_lock(&bdev->bd_fsfreeze_mutex); break;
if (bdev->bd_fsfreeze_count > 0) { case Opt_spectator:
mutex_unlock(&bdev->bd_fsfreeze_mutex); args->ar_spectator = 1;
error = -EBUSY; break;
goto error_bdev; case Opt_ignore_local_fs:
/* Retained for backwards compat only */
break;
case Opt_localflocks:
args->ar_localflocks = 1;
break;
case Opt_localcaching:
/* Retained for backwards compat only */
break;
case Opt_debug:
if (result.boolean && args->ar_errors == GFS2_ERRORS_PANIC)
return invalf(fc, "gfs2: -o debug and -o errors=panic are mutually exclusive");
args->ar_debug = result.boolean;
break;
case Opt_upgrade:
/* Retained for backwards compat only */
break;
case Opt_acl:
args->ar_posix_acl = result.boolean;
break;
case Opt_quota:
/* The quota option can be a flag or an enum. A non-zero int_32
result means that we have an enum index. Otherwise we have
to rely on the 'negated' flag to tell us whether 'quota' or
'noquota' was specified. */
if (result.negated)
args->ar_quota = GFS2_QUOTA_OFF;
else if (result.int_32 > 0)
args->ar_quota = opt_quota_values[result.int_32];
else
args->ar_quota = GFS2_QUOTA_ON;
break;
case Opt_suiddir:
args->ar_suiddir = result.boolean;
break;
case Opt_data:
/* The uint_32 result maps directly to GFS2_DATA_* */
args->ar_data = result.uint_32;
break;
case Opt_meta:
args->ar_meta = 1;
break;
case Opt_discard:
args->ar_discard = result.boolean;
break;
case Opt_commit:
if (result.int_32 <= 0)
return invalf(fc, "gfs2: commit mount option requires a positive numeric argument");
args->ar_commit = result.int_32;
break;
case Opt_statfs_quantum:
if (result.int_32 < 0)
return invalf(fc, "gfs2: statfs_quantum mount option requires a non-negative numeric argument");
args->ar_statfs_quantum = result.int_32;
break;
case Opt_quota_quantum:
if (result.int_32 <= 0)
return invalf(fc, "gfs2: quota_quantum mount option requires a positive numeric argument");
args->ar_quota_quantum = result.int_32;
break;
case Opt_statfs_percent:
if (result.int_32 < 0 || result.int_32 > 100)
return invalf(fc, "gfs2: statfs_percent mount option requires a numeric argument between 0 and 100");
args->ar_statfs_percent = result.int_32;
break;
case Opt_errors:
if (args->ar_debug && result.uint_32 == GFS2_ERRORS_PANIC)
return invalf(fc, "gfs2: -o debug and -o errors=panic are mutually exclusive");
args->ar_errors = result.uint_32;
break;
case Opt_barrier:
args->ar_nobarrier = result.boolean;
break;
case Opt_rgrplvb:
args->ar_rgrplvb = result.boolean;
break;
case Opt_loccookie:
args->ar_loccookie = result.boolean;
break;
default:
return invalf(fc, "gfs2: invalid mount option: %s", param->key);
} }
s = sget(fs_type, test_gfs2_super, set_gfs2_super, flags, bdev); return 0;
mutex_unlock(&bdev->bd_fsfreeze_mutex); }
error = PTR_ERR(s);
if (IS_ERR(s))
goto error_bdev;
if (s->s_root) { static int gfs2_reconfigure(struct fs_context *fc)
/* {
* s_umount nests inside bd_mutex during struct super_block *sb = fc->root->d_sb;
* __invalidate_device(). blkdev_put() acquires struct gfs2_sbd *sdp = sb->s_fs_info;
* bd_mutex and can't be called under s_umount. Drop struct gfs2_args *oldargs = &sdp->sd_args;
* s_umount temporarily. This is safe as we're struct gfs2_args *newargs = fc->fs_private;
* holding an active reference. struct gfs2_tune *gt = &sdp->sd_tune;
*/ int error = 0;
up_write(&s->s_umount);
blkdev_put(bdev, mode);
down_write(&s->s_umount);
} else {
/* s_mode must be set before deactivate_locked_super calls */
s->s_mode = mode;
}
memset(&args, 0, sizeof(args)); sync_filesystem(sb);
args.ar_quota = GFS2_QUOTA_DEFAULT;
args.ar_data = GFS2_DATA_DEFAULT;
args.ar_commit = 30;
args.ar_statfs_quantum = 30;
args.ar_quota_quantum = 60;
args.ar_errors = GFS2_ERRORS_DEFAULT;
error = gfs2_mount_args(&args, data); spin_lock(&gt->gt_spin);
if (error) { oldargs->ar_commit = gt->gt_logd_secs;
pr_warn("can't parse mount arguments\n"); oldargs->ar_quota_quantum = gt->gt_quota_quantum;
goto error_super; if (gt->gt_statfs_slow)
} oldargs->ar_statfs_quantum = 0;
if (s->s_root) {
error = -EBUSY;
if ((flags ^ s->s_flags) & SB_RDONLY)
goto error_super;
} else {
snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
sb_set_blocksize(s, block_size(bdev));
error = fill_super(s, &args, flags & SB_SILENT ? 1 : 0);
if (error)
goto error_super;
s->s_flags |= SB_ACTIVE;
bdev->bd_super = s;
}
sdp = s->s_fs_info;
if (args.ar_meta)
return dget(sdp->sd_master_dir);
else else
return dget(sdp->sd_root_dir); oldargs->ar_statfs_quantum = gt->gt_statfs_quantum;
spin_unlock(&gt->gt_spin);
error_super: if (strcmp(newargs->ar_lockproto, oldargs->ar_lockproto)) {
deactivate_locked_super(s); errorf(fc, "gfs2: reconfiguration of locking protocol not allowed");
return ERR_PTR(error); return -EINVAL;
error_bdev: }
blkdev_put(bdev, mode); if (strcmp(newargs->ar_locktable, oldargs->ar_locktable)) {
return ERR_PTR(error); errorf(fc, "gfs2: reconfiguration of lock table not allowed");
return -EINVAL;
}
if (strcmp(newargs->ar_hostdata, oldargs->ar_hostdata)) {
errorf(fc, "gfs2: reconfiguration of host data not allowed");
return -EINVAL;
}
if (newargs->ar_spectator != oldargs->ar_spectator) {
errorf(fc, "gfs2: reconfiguration of spectator mode not allowed");
return -EINVAL;
}
if (newargs->ar_localflocks != oldargs->ar_localflocks) {
errorf(fc, "gfs2: reconfiguration of localflocks not allowed");
return -EINVAL;
}
if (newargs->ar_meta != oldargs->ar_meta) {
errorf(fc, "gfs2: switching between gfs2 and gfs2meta not allowed");
return -EINVAL;
}
if (oldargs->ar_spectator)
fc->sb_flags |= SB_RDONLY;
if ((sb->s_flags ^ fc->sb_flags) & SB_RDONLY) {
if (fc->sb_flags & SB_RDONLY) {
error = gfs2_make_fs_ro(sdp);
if (error)
errorf(fc, "gfs2: unable to remount read-only");
} else {
error = gfs2_make_fs_rw(sdp);
if (error)
errorf(fc, "gfs2: unable to remount read-write");
}
}
sdp->sd_args = *newargs;
if (sdp->sd_args.ar_posix_acl)
sb->s_flags |= SB_POSIXACL;
else
sb->s_flags &= ~SB_POSIXACL;
if (sdp->sd_args.ar_nobarrier)
set_bit(SDF_NOBARRIERS, &sdp->sd_flags);
else
clear_bit(SDF_NOBARRIERS, &sdp->sd_flags);
spin_lock(&gt->gt_spin);
gt->gt_logd_secs = newargs->ar_commit;
gt->gt_quota_quantum = newargs->ar_quota_quantum;
if (newargs->ar_statfs_quantum) {
gt->gt_statfs_slow = 0;
gt->gt_statfs_quantum = newargs->ar_statfs_quantum;
}
else {
gt->gt_statfs_slow = 1;
gt->gt_statfs_quantum = 30;
}
spin_unlock(&gt->gt_spin);
gfs2_online_uevent(sdp);
return error;
} }
static int set_meta_super(struct super_block *s, void *ptr) static const struct fs_context_operations gfs2_context_ops = {
.free = gfs2_fc_free,
.parse_param = gfs2_parse_param,
.get_tree = gfs2_get_tree,
.reconfigure = gfs2_reconfigure,
};
/* Set up the filesystem mount context */
static int gfs2_init_fs_context(struct fs_context *fc)
{
struct gfs2_args *args;
args = kzalloc(sizeof(*args), GFP_KERNEL);
if (args == NULL)
return -ENOMEM;
args->ar_quota = GFS2_QUOTA_DEFAULT;
args->ar_data = GFS2_DATA_DEFAULT;
args->ar_commit = 30;
args->ar_statfs_quantum = 30;
args->ar_quota_quantum = 60;
args->ar_errors = GFS2_ERRORS_DEFAULT;
fc->fs_private = args;
fc->ops = &gfs2_context_ops;
return 0;
}
static int set_meta_super(struct super_block *s, struct fs_context *fc)
{ {
return -EINVAL; return -EINVAL;
} }
static struct dentry *gfs2_mount_meta(struct file_system_type *fs_type, static int test_meta_super(struct super_block *s, struct fs_context *fc)
int flags, const char *dev_name, void *data) {
return (fc->sget_key == s->s_bdev);
}
static int gfs2_meta_get_tree(struct fs_context *fc)
{ {
struct super_block *s; struct super_block *s;
struct gfs2_sbd *sdp; struct gfs2_sbd *sdp;
struct path path; struct path path;
int error; int error;
if (!dev_name || !*dev_name) if (!fc->source || !*fc->source)
return ERR_PTR(-EINVAL); return -EINVAL;
error = kern_path(dev_name, LOOKUP_FOLLOW, &path); error = kern_path(fc->source, LOOKUP_FOLLOW, &path);
if (error) { if (error) {
pr_warn("path_lookup on %s returned error %d\n", pr_warn("path_lookup on %s returned error %d\n",
dev_name, error); fc->source, error);
return ERR_PTR(error); return error;
} }
s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super, flags, fc->fs_type = &gfs2_fs_type;
path.dentry->d_sb->s_bdev); fc->sget_key = path.dentry->d_sb->s_bdev;
s = sget_fc(fc, test_meta_super, set_meta_super);
path_put(&path); path_put(&path);
if (IS_ERR(s)) { if (IS_ERR(s)) {
pr_warn("gfs2 mount does not exist\n"); pr_warn("gfs2 mount does not exist\n");
return ERR_CAST(s); return PTR_ERR(s);
} }
if ((flags ^ s->s_flags) & SB_RDONLY) { if ((fc->sb_flags ^ s->s_flags) & SB_RDONLY) {
deactivate_locked_super(s); deactivate_locked_super(s);
return ERR_PTR(-EBUSY); return -EBUSY;
} }
sdp = s->s_fs_info; sdp = s->s_fs_info;
return dget(sdp->sd_master_dir); fc->root = dget(sdp->sd_master_dir);
return 0;
}
static const struct fs_context_operations gfs2_meta_context_ops = {
.get_tree = gfs2_meta_get_tree,
};
static int gfs2_meta_init_fs_context(struct fs_context *fc)
{
int ret = gfs2_init_fs_context(fc);
if (ret)
return ret;
fc->ops = &gfs2_meta_context_ops;
return 0;
} }
static void gfs2_kill_sb(struct super_block *sb) static void gfs2_kill_sb(struct super_block *sb)
@ -1382,7 +1634,8 @@ static void gfs2_kill_sb(struct super_block *sb)
struct file_system_type gfs2_fs_type = { struct file_system_type gfs2_fs_type = {
.name = "gfs2", .name = "gfs2",
.fs_flags = FS_REQUIRES_DEV, .fs_flags = FS_REQUIRES_DEV,
.mount = gfs2_mount, .init_fs_context = gfs2_init_fs_context,
.parameters = &gfs2_fs_parameters,
.kill_sb = gfs2_kill_sb, .kill_sb = gfs2_kill_sb,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
@ -1391,7 +1644,7 @@ MODULE_ALIAS_FS("gfs2");
struct file_system_type gfs2meta_fs_type = { struct file_system_type gfs2meta_fs_type = {
.name = "gfs2meta", .name = "gfs2meta",
.fs_flags = FS_REQUIRES_DEV, .fs_flags = FS_REQUIRES_DEV,
.mount = gfs2_mount_meta, .init_fs_context = gfs2_meta_init_fs_context,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
MODULE_ALIAS_FS("gfs2meta"); MODULE_ALIAS_FS("gfs2meta");

View File

@ -44,258 +44,6 @@
#include "xattr.h" #include "xattr.h"
#include "lops.h" #include "lops.h"
#define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x)
enum {
Opt_lockproto,
Opt_locktable,
Opt_hostdata,
Opt_spectator,
Opt_ignore_local_fs,
Opt_localflocks,
Opt_localcaching,
Opt_debug,
Opt_nodebug,
Opt_upgrade,
Opt_acl,
Opt_noacl,
Opt_quota_off,
Opt_quota_account,
Opt_quota_on,
Opt_quota,
Opt_noquota,
Opt_suiddir,
Opt_nosuiddir,
Opt_data_writeback,
Opt_data_ordered,
Opt_meta,
Opt_discard,
Opt_nodiscard,
Opt_commit,
Opt_err_withdraw,
Opt_err_panic,
Opt_statfs_quantum,
Opt_statfs_percent,
Opt_quota_quantum,
Opt_barrier,
Opt_nobarrier,
Opt_rgrplvb,
Opt_norgrplvb,
Opt_loccookie,
Opt_noloccookie,
Opt_error,
};
static const match_table_t tokens = {
{Opt_lockproto, "lockproto=%s"},
{Opt_locktable, "locktable=%s"},
{Opt_hostdata, "hostdata=%s"},
{Opt_spectator, "spectator"},
{Opt_spectator, "norecovery"},
{Opt_ignore_local_fs, "ignore_local_fs"},
{Opt_localflocks, "localflocks"},
{Opt_localcaching, "localcaching"},
{Opt_debug, "debug"},
{Opt_nodebug, "nodebug"},
{Opt_upgrade, "upgrade"},
{Opt_acl, "acl"},
{Opt_noacl, "noacl"},
{Opt_quota_off, "quota=off"},
{Opt_quota_account, "quota=account"},
{Opt_quota_on, "quota=on"},
{Opt_quota, "quota"},
{Opt_noquota, "noquota"},
{Opt_suiddir, "suiddir"},
{Opt_nosuiddir, "nosuiddir"},
{Opt_data_writeback, "data=writeback"},
{Opt_data_ordered, "data=ordered"},
{Opt_meta, "meta"},
{Opt_discard, "discard"},
{Opt_nodiscard, "nodiscard"},
{Opt_commit, "commit=%d"},
{Opt_err_withdraw, "errors=withdraw"},
{Opt_err_panic, "errors=panic"},
{Opt_statfs_quantum, "statfs_quantum=%d"},
{Opt_statfs_percent, "statfs_percent=%d"},
{Opt_quota_quantum, "quota_quantum=%d"},
{Opt_barrier, "barrier"},
{Opt_nobarrier, "nobarrier"},
{Opt_rgrplvb, "rgrplvb"},
{Opt_norgrplvb, "norgrplvb"},
{Opt_loccookie, "loccookie"},
{Opt_noloccookie, "noloccookie"},
{Opt_error, NULL}
};
/**
* gfs2_mount_args - Parse mount options
* @args: The structure into which the parsed options will be written
* @options: The options to parse
*
* Return: errno
*/
int gfs2_mount_args(struct gfs2_args *args, char *options)
{
char *o;
int token;
substring_t tmp[MAX_OPT_ARGS];
int rv;
/* Split the options into tokens with the "," character and
process them */
while (1) {
o = strsep(&options, ",");
if (o == NULL)
break;
if (*o == '\0')
continue;
token = match_token(o, tokens, tmp);
switch (token) {
case Opt_lockproto:
match_strlcpy(args->ar_lockproto, &tmp[0],
GFS2_LOCKNAME_LEN);
break;
case Opt_locktable:
match_strlcpy(args->ar_locktable, &tmp[0],
GFS2_LOCKNAME_LEN);
break;
case Opt_hostdata:
match_strlcpy(args->ar_hostdata, &tmp[0],
GFS2_LOCKNAME_LEN);
break;
case Opt_spectator:
args->ar_spectator = 1;
break;
case Opt_ignore_local_fs:
/* Retained for backwards compat only */
break;
case Opt_localflocks:
args->ar_localflocks = 1;
break;
case Opt_localcaching:
/* Retained for backwards compat only */
break;
case Opt_debug:
if (args->ar_errors == GFS2_ERRORS_PANIC) {
pr_warn("-o debug and -o errors=panic are mutually exclusive\n");
return -EINVAL;
}
args->ar_debug = 1;
break;
case Opt_nodebug:
args->ar_debug = 0;
break;
case Opt_upgrade:
/* Retained for backwards compat only */
break;
case Opt_acl:
args->ar_posix_acl = 1;
break;
case Opt_noacl:
args->ar_posix_acl = 0;
break;
case Opt_quota_off:
case Opt_noquota:
args->ar_quota = GFS2_QUOTA_OFF;
break;
case Opt_quota_account:
args->ar_quota = GFS2_QUOTA_ACCOUNT;
break;
case Opt_quota_on:
case Opt_quota:
args->ar_quota = GFS2_QUOTA_ON;
break;
case Opt_suiddir:
args->ar_suiddir = 1;
break;
case Opt_nosuiddir:
args->ar_suiddir = 0;
break;
case Opt_data_writeback:
args->ar_data = GFS2_DATA_WRITEBACK;
break;
case Opt_data_ordered:
args->ar_data = GFS2_DATA_ORDERED;
break;
case Opt_meta:
args->ar_meta = 1;
break;
case Opt_discard:
args->ar_discard = 1;
break;
case Opt_nodiscard:
args->ar_discard = 0;
break;
case Opt_commit:
rv = match_int(&tmp[0], &args->ar_commit);
if (rv || args->ar_commit <= 0) {
pr_warn("commit mount option requires a positive numeric argument\n");
return rv ? rv : -EINVAL;
}
break;
case Opt_statfs_quantum:
rv = match_int(&tmp[0], &args->ar_statfs_quantum);
if (rv || args->ar_statfs_quantum < 0) {
pr_warn("statfs_quantum mount option requires a non-negative numeric argument\n");
return rv ? rv : -EINVAL;
}
break;
case Opt_quota_quantum:
rv = match_int(&tmp[0], &args->ar_quota_quantum);
if (rv || args->ar_quota_quantum <= 0) {
pr_warn("quota_quantum mount option requires a positive numeric argument\n");
return rv ? rv : -EINVAL;
}
break;
case Opt_statfs_percent:
rv = match_int(&tmp[0], &args->ar_statfs_percent);
if (rv || args->ar_statfs_percent < 0 ||
args->ar_statfs_percent > 100) {
pr_warn("statfs_percent mount option requires a numeric argument between 0 and 100\n");
return rv ? rv : -EINVAL;
}
break;
case Opt_err_withdraw:
args->ar_errors = GFS2_ERRORS_WITHDRAW;
break;
case Opt_err_panic:
if (args->ar_debug) {
pr_warn("-o debug and -o errors=panic are mutually exclusive\n");
return -EINVAL;
}
args->ar_errors = GFS2_ERRORS_PANIC;
break;
case Opt_barrier:
args->ar_nobarrier = 0;
break;
case Opt_nobarrier:
args->ar_nobarrier = 1;
break;
case Opt_rgrplvb:
args->ar_rgrplvb = 1;
break;
case Opt_norgrplvb:
args->ar_rgrplvb = 0;
break;
case Opt_loccookie:
args->ar_loccookie = 1;
break;
case Opt_noloccookie:
args->ar_loccookie = 0;
break;
case Opt_error:
default:
pr_warn("invalid mount option: %s\n", o);
return -EINVAL;
}
}
return 0;
}
/** /**
* gfs2_jindex_free - Clear all the journal index information * gfs2_jindex_free - Clear all the journal index information
* @sdp: The GFS2 superblock * @sdp: The GFS2 superblock
@ -847,7 +595,7 @@ out:
* Returns: errno * Returns: errno
*/ */
static int gfs2_make_fs_ro(struct gfs2_sbd *sdp) int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
{ {
struct gfs2_holder freeze_gh; struct gfs2_holder freeze_gh;
int error; int error;
@ -1226,84 +974,6 @@ static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0; return 0;
} }
/**
* gfs2_remount_fs - called when the FS is remounted
* @sb: the filesystem
* @flags: the remount flags
* @data: extra data passed in (not used right now)
*
* Returns: errno
*/
static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
{
struct gfs2_sbd *sdp = sb->s_fs_info;
struct gfs2_args args = sdp->sd_args; /* Default to current settings */
struct gfs2_tune *gt = &sdp->sd_tune;
int error;
sync_filesystem(sb);
spin_lock(&gt->gt_spin);
args.ar_commit = gt->gt_logd_secs;
args.ar_quota_quantum = gt->gt_quota_quantum;
if (gt->gt_statfs_slow)
args.ar_statfs_quantum = 0;
else
args.ar_statfs_quantum = gt->gt_statfs_quantum;
spin_unlock(&gt->gt_spin);
error = gfs2_mount_args(&args, data);
if (error)
return error;
/* Not allowed to change locking details */
if (strcmp(args.ar_lockproto, sdp->sd_args.ar_lockproto) ||
strcmp(args.ar_locktable, sdp->sd_args.ar_locktable) ||
strcmp(args.ar_hostdata, sdp->sd_args.ar_hostdata))
return -EINVAL;
/* Some flags must not be changed */
if (args_neq(&args, &sdp->sd_args, spectator) ||
args_neq(&args, &sdp->sd_args, localflocks) ||
args_neq(&args, &sdp->sd_args, meta))
return -EINVAL;
if (sdp->sd_args.ar_spectator)
*flags |= SB_RDONLY;
if ((sb->s_flags ^ *flags) & SB_RDONLY) {
if (*flags & SB_RDONLY)
error = gfs2_make_fs_ro(sdp);
else
error = gfs2_make_fs_rw(sdp);
}
sdp->sd_args = args;
if (sdp->sd_args.ar_posix_acl)
sb->s_flags |= SB_POSIXACL;
else
sb->s_flags &= ~SB_POSIXACL;
if (sdp->sd_args.ar_nobarrier)
set_bit(SDF_NOBARRIERS, &sdp->sd_flags);
else
clear_bit(SDF_NOBARRIERS, &sdp->sd_flags);
spin_lock(&gt->gt_spin);
gt->gt_logd_secs = args.ar_commit;
gt->gt_quota_quantum = args.ar_quota_quantum;
if (args.ar_statfs_quantum) {
gt->gt_statfs_slow = 0;
gt->gt_statfs_quantum = args.ar_statfs_quantum;
}
else {
gt->gt_statfs_slow = 1;
gt->gt_statfs_quantum = 30;
}
spin_unlock(&gt->gt_spin);
gfs2_online_uevent(sdp);
return error;
}
/** /**
* gfs2_drop_inode - Drop an inode (test for remote unlink) * gfs2_drop_inode - Drop an inode (test for remote unlink)
* @inode: The inode to drop * @inode: The inode to drop
@ -1748,7 +1418,6 @@ const struct super_operations gfs2_super_ops = {
.freeze_super = gfs2_freeze, .freeze_super = gfs2_freeze,
.thaw_super = gfs2_unfreeze, .thaw_super = gfs2_unfreeze,
.statfs = gfs2_statfs, .statfs = gfs2_statfs,
.remount_fs = gfs2_remount_fs,
.drop_inode = gfs2_drop_inode, .drop_inode = gfs2_drop_inode,
.show_options = gfs2_show_options, .show_options = gfs2_show_options,
}; };

View File

@ -24,8 +24,6 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
extern void gfs2_jindex_free(struct gfs2_sbd *sdp); extern void gfs2_jindex_free(struct gfs2_sbd *sdp);
extern int gfs2_mount_args(struct gfs2_args *args, char *data);
extern struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); extern struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid);
extern int gfs2_jdesc_check(struct gfs2_jdesc *jd); extern int gfs2_jdesc_check(struct gfs2_jdesc *jd);
@ -33,6 +31,7 @@ extern int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename,
struct gfs2_inode **ipp); struct gfs2_inode **ipp);
extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp); extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp);
extern int gfs2_make_fs_ro(struct gfs2_sbd *sdp);
extern void gfs2_online_uevent(struct gfs2_sbd *sdp); extern void gfs2_online_uevent(struct gfs2_sbd *sdp);
extern int gfs2_statfs_init(struct gfs2_sbd *sdp); extern int gfs2_statfs_init(struct gfs2_sbd *sdp);
extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free, extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,