1
linux/fs/gfs2/mount.c
Steven Whitehouse 97cc1025b1 GFS2: Kill two daemons with one patch
This patch removes the two daemons, gfs2_scand and gfs2_glockd
and replaces them with a shrinker which is called from the VM.

The net result is that GFS2 responds better when there is memory
pressure, since it shrinks the glock cache at the same rate
as the VFS shrinks the dcache and icache. There are no longer
any time based criteria for shrinking glocks, they are kept
until such time as the VM asks for more memory and then we
demote just as many glocks as required.

There are potential future changes to this code, including the
possibility of sorting the glocks which are to be written back
into inode number order, to get a better I/O ordering. It would
be very useful to have an elevator based workqueue implementation
for this, as that would automatically deal with the read I/O cases
at the same time.

This patch is my answer to Andrew Morton's remark, made during
the initial review of GFS2, asking why GFS2 needs so many kernel
threads, the answer being that it doesn't :-) This patch is a
net loss of about 200 lines of code.

Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
2009-01-05 07:39:09 +00:00

252 lines
5.4 KiB
C

/*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License version 2.
*/
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h>
#include <linux/lm_interface.h>
#include <linux/parser.h>
#include "gfs2.h"
#include "incore.h"
#include "mount.h"
#include "sys.h"
#include "util.h"
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_suiddir,
Opt_nosuiddir,
Opt_data_writeback,
Opt_data_ordered,
Opt_meta,
Opt_err,
};
static const match_table_t tokens = {
{Opt_lockproto, "lockproto=%s"},
{Opt_locktable, "locktable=%s"},
{Opt_hostdata, "hostdata=%s"},
{Opt_spectator, "spectator"},
{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_suiddir, "suiddir"},
{Opt_nosuiddir, "nosuiddir"},
{Opt_data_writeback, "data=writeback"},
{Opt_data_ordered, "data=ordered"},
{Opt_meta, "meta"},
{Opt_err, NULL}
};
/**
* gfs2_mount_args - Parse mount options
* @sdp:
* @data:
*
* Return: errno
*/
int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
{
struct gfs2_args *args = &sdp->sd_args;
char *data = data_arg;
char *options, *o, *v;
int error = 0;
if (!remount) {
/* If someone preloaded options, use those instead */
spin_lock(&gfs2_sys_margs_lock);
if (gfs2_sys_margs) {
data = gfs2_sys_margs;
gfs2_sys_margs = NULL;
}
spin_unlock(&gfs2_sys_margs_lock);
/* Set some defaults */
args->ar_quota = GFS2_QUOTA_DEFAULT;
args->ar_data = GFS2_DATA_DEFAULT;
}
/* Split the options into tokens with the "," character and
process them */
for (options = data; (o = strsep(&options, ",")); ) {
int token;
substring_t tmp[MAX_OPT_ARGS];
if (!*o)
continue;
token = match_token(o, tokens, tmp);
switch (token) {
case Opt_lockproto:
v = match_strdup(&tmp[0]);
if (!v) {
fs_info(sdp, "no memory for lockproto\n");
error = -ENOMEM;
goto out_error;
}
if (remount && strcmp(v, args->ar_lockproto)) {
kfree(v);
goto cant_remount;
}
strncpy(args->ar_lockproto, v, GFS2_LOCKNAME_LEN);
args->ar_lockproto[GFS2_LOCKNAME_LEN - 1] = 0;
kfree(v);
break;
case Opt_locktable:
v = match_strdup(&tmp[0]);
if (!v) {
fs_info(sdp, "no memory for locktable\n");
error = -ENOMEM;
goto out_error;
}
if (remount && strcmp(v, args->ar_locktable)) {
kfree(v);
goto cant_remount;
}
strncpy(args->ar_locktable, v, GFS2_LOCKNAME_LEN);
args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0;
kfree(v);
break;
case Opt_hostdata:
v = match_strdup(&tmp[0]);
if (!v) {
fs_info(sdp, "no memory for hostdata\n");
error = -ENOMEM;
goto out_error;
}
if (remount && strcmp(v, args->ar_hostdata)) {
kfree(v);
goto cant_remount;
}
strncpy(args->ar_hostdata, v, GFS2_LOCKNAME_LEN);
args->ar_hostdata[GFS2_LOCKNAME_LEN - 1] = 0;
kfree(v);
break;
case Opt_spectator:
if (remount && !args->ar_spectator)
goto cant_remount;
args->ar_spectator = 1;
sdp->sd_vfs->s_flags |= MS_RDONLY;
break;
case Opt_ignore_local_fs:
if (remount && !args->ar_ignore_local_fs)
goto cant_remount;
args->ar_ignore_local_fs = 1;
break;
case Opt_localflocks:
if (remount && !args->ar_localflocks)
goto cant_remount;
args->ar_localflocks = 1;
break;
case Opt_localcaching:
if (remount && !args->ar_localcaching)
goto cant_remount;
args->ar_localcaching = 1;
break;
case Opt_debug:
args->ar_debug = 1;
break;
case Opt_nodebug:
args->ar_debug = 0;
break;
case Opt_upgrade:
if (remount && !args->ar_upgrade)
goto cant_remount;
args->ar_upgrade = 1;
break;
case Opt_acl:
args->ar_posix_acl = 1;
sdp->sd_vfs->s_flags |= MS_POSIXACL;
break;
case Opt_noacl:
args->ar_posix_acl = 0;
sdp->sd_vfs->s_flags &= ~MS_POSIXACL;
break;
case Opt_quota_off:
args->ar_quota = GFS2_QUOTA_OFF;
break;
case Opt_quota_account:
args->ar_quota = GFS2_QUOTA_ACCOUNT;
break;
case Opt_quota_on:
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:
if (remount && args->ar_meta != 1)
goto cant_remount;
args->ar_meta = 1;
break;
case Opt_err:
default:
fs_info(sdp, "unknown option: %s\n", o);
error = -EINVAL;
goto out_error;
}
}
out_error:
if (error)
fs_info(sdp, "invalid mount option(s)\n");
if (data != data_arg)
kfree(data);
return error;
cant_remount:
fs_info(sdp, "can't remount with option %s\n", o);
return -EINVAL;
}