summaryrefslogtreecommitdiff
path: root/fs/xfs/linux-2.6
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2008-07-18 17:12:36 +1000
committerNiv Sardi <xaiki@debian.org>2008-07-28 16:59:28 +1000
commit62a877e35d5085c65936ed3194d1bbaf84f419e1 (patch)
tree76f16d460d8eec4f1d39bb533167e591bb6113c6 /fs/xfs/linux-2.6
parentdeeb5912db12e8b7ccf3f4b1afaad60bc29abed9 (diff)
downloadlwn-62a877e35d5085c65936ed3194d1bbaf84f419e1.tar.gz
lwn-62a877e35d5085c65936ed3194d1bbaf84f419e1.zip
[XFS] fix mount option parsing in remount
Remount currently happily accept any option thrown at it, although the only filesystem specific option it actually handles is barrier/nobarrier. And it actually doesn't handle these correctly either because it only uses the value it parsed when we're doing a ro->rw transition. In addition to that there's also a bad bug in xfs_parseargs which doesn't touch the actual option in the mount point except for a single one, XFS_MOUNT_SMALL_INUMS and thus forced any filesystem that's every remounted in some way to not support 64bit inodes with no way to recover unless unmounted. This patch changes xfs_fs_remount to use it's own linux/parser.h based options parse instead of xfs_parseargs and reject all options except for barrier/nobarrier and to the right thing in general. Eventually I'd like to have a single big option table used for mount aswell but that can wait for a while. SGI-PV: 983964 SGI-Modid: xfs-linux-melb:xfs-kern:31382a Signed-off-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Tim Shimmin <tes@sgi.com> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
Diffstat (limited to 'fs/xfs/linux-2.6')
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c72
1 files changed, 54 insertions, 18 deletions
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index fcb4931902ac..b40086680047 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -66,6 +66,7 @@
#include <linux/writeback.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
+#include <linux/parser.h>
static struct quotactl_ops xfs_quotactl_operations;
static struct super_operations xfs_super_operations;
@@ -147,6 +148,23 @@ xfs_args_allocate(
#define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */
#define MNTOPT_DMI "dmi" /* DMI enabled (DMAPI / XDSM) */
+/*
+ * Table driven mount option parser.
+ *
+ * Currently only used for remount, but it will be used for mount
+ * in the future, too.
+ */
+enum {
+ Opt_barrier, Opt_nobarrier, Opt_err
+};
+
+static match_table_t tokens = {
+ {Opt_barrier, "barrier"},
+ {Opt_nobarrier, "nobarrier"},
+ {Opt_err, NULL}
+};
+
+
STATIC unsigned long
suffix_strtoul(char *s, char **endp, unsigned int base)
{
@@ -1364,36 +1382,54 @@ xfs_fs_remount(
char *options)
{
struct xfs_mount *mp = XFS_M(sb);
- struct xfs_mount_args *args;
- int error;
+ substring_t args[MAX_OPT_ARGS];
+ char *p;
- args = xfs_args_allocate(sb, 0);
- if (!args)
- return -ENOMEM;
+ while ((p = strsep(&options, ",")) != NULL) {
+ int token;
- error = xfs_parseargs(mp, options, args, 1);
- if (error)
- goto out_free_args;
+ if (!*p)
+ continue;
- if (!(*flags & MS_RDONLY)) { /* rw/ro -> rw */
- if (mp->m_flags & XFS_MOUNT_RDONLY)
- mp->m_flags &= ~XFS_MOUNT_RDONLY;
- if (args->flags & XFSMNT_BARRIER) {
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case Opt_barrier:
mp->m_flags |= XFS_MOUNT_BARRIER;
- xfs_mountfs_check_barriers(mp);
- } else {
+
+ /*
+ * Test if barriers are actually working if we can,
+ * else delay this check until the filesystem is
+ * marked writeable.
+ */
+ if (!(mp->m_flags & XFS_MOUNT_RDONLY))
+ xfs_mountfs_check_barriers(mp);
+ break;
+ case Opt_nobarrier:
mp->m_flags &= ~XFS_MOUNT_BARRIER;
+ break;
+ default:
+ printk(KERN_INFO
+ "XFS: mount option \"%s\" not supported for remount\n", p);
+ return -EINVAL;
}
- } else if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { /* rw -> ro */
+ }
+
+ /* rw/ro -> rw */
+ if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) {
+ mp->m_flags &= ~XFS_MOUNT_RDONLY;
+ if (mp->m_flags & XFS_MOUNT_BARRIER)
+ xfs_mountfs_check_barriers(mp);
+ }
+
+ /* rw -> ro */
+ if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) {
xfs_filestream_flush(mp);
xfs_sync(mp, SYNC_DATA_QUIESCE);
xfs_attr_quiesce(mp);
mp->m_flags |= XFS_MOUNT_RDONLY;
}
- out_free_args:
- kfree(args);
- return -error;
+ return 0;
}
/*