aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2009-01-06 06:52:25 -0500
committerSteven Whitehouse <steve@dolmen.chygwyn.com>2009-03-24 07:21:10 -0400
commit6f04c1c7fe9566d777fb7961391690866839e722 (patch)
treede864fb7c56ef59a799c7fddc713bdb16bb4435c /fs
parent8e0ee43bc2c3e19db56a4adaa9a9b04ce885cd84 (diff)
GFS2: Fix remount argument parsing
The following patch fixes an issue relating to remount and argument parsing. After this fix is applied, remount becomes atomic in that it either succeeds changing the mount to the new state, or it fails and leaves it in the old state. Previously it was possible for the parsing of options to fail part way though and for the fs to be left in a state where some of the new arguments had been applied, but some had not. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/gfs2/mount.c111
-rw-r--r--fs/gfs2/mount.h17
-rw-r--r--fs/gfs2/ops_fstype.c11
-rw-r--r--fs/gfs2/ops_super.c41
-rw-r--r--fs/gfs2/super.h26
5 files changed, 73 insertions, 133 deletions
diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c
index 3cb0a44ba023..3524ae81189b 100644
--- a/fs/gfs2/mount.c
+++ b/fs/gfs2/mount.c
@@ -17,7 +17,7 @@
17 17
18#include "gfs2.h" 18#include "gfs2.h"
19#include "incore.h" 19#include "incore.h"
20#include "mount.h" 20#include "super.h"
21#include "sys.h" 21#include "sys.h"
22#include "util.h" 22#include "util.h"
23 23
@@ -77,101 +77,46 @@ static const match_table_t tokens = {
77 * Return: errno 77 * Return: errno
78 */ 78 */
79 79
80int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount) 80int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
81{ 81{
82 struct gfs2_args *args = &sdp->sd_args; 82 char *o;
83 char *data = data_arg; 83 int token;
84 char *options, *o, *v; 84 substring_t tmp[MAX_OPT_ARGS];
85 int error = 0;
86
87 if (!remount) {
88 /* Set some defaults */
89 args->ar_quota = GFS2_QUOTA_DEFAULT;
90 args->ar_data = GFS2_DATA_DEFAULT;
91 }
92 85
93 /* Split the options into tokens with the "," character and 86 /* Split the options into tokens with the "," character and
94 process them */ 87 process them */
95 88
96 for (options = data; (o = strsep(&options, ",")); ) { 89 while (1) {
97 int token; 90 o = strsep(&options, ",");
98 substring_t tmp[MAX_OPT_ARGS]; 91 if (o == NULL)
99 92 break;
100 if (!*o) 93 if (*o == '\0')
101 continue; 94 continue;
102 95
103 token = match_token(o, tokens, tmp); 96 token = match_token(o, tokens, tmp);
104 switch (token) { 97 switch (token) {
105 case Opt_lockproto: 98 case Opt_lockproto:
106 v = match_strdup(&tmp[0]); 99 match_strlcpy(args->ar_lockproto, &tmp[0],
107 if (!v) { 100 GFS2_LOCKNAME_LEN);
108 fs_info(sdp, "no memory for lockproto\n");
109 error = -ENOMEM;
110 goto out_error;
111 }
112
113 if (remount && strcmp(v, args->ar_lockproto)) {
114 kfree(v);
115 goto cant_remount;
116 }
117
118 strncpy(args->ar_lockproto, v, GFS2_LOCKNAME_LEN);
119 args->ar_lockproto[GFS2_LOCKNAME_LEN - 1] = 0;
120 kfree(v);
121 break; 101 break;
122 case Opt_locktable: 102 case Opt_locktable:
123 v = match_strdup(&tmp[0]); 103 match_strlcpy(args->ar_locktable, &tmp[0],
124 if (!v) { 104 GFS2_LOCKNAME_LEN);
125 fs_info(sdp, "no memory for locktable\n");
126 error = -ENOMEM;
127 goto out_error;
128 }
129
130 if (remount && strcmp(v, args->ar_locktable)) {
131 kfree(v);
132 goto cant_remount;
133 }
134
135 strncpy(args->ar_locktable, v, GFS2_LOCKNAME_LEN);
136 args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0;
137 kfree(v);
138 break; 105 break;
139 case Opt_hostdata: 106 case Opt_hostdata:
140 v = match_strdup(&tmp[0]); 107 match_strlcpy(args->ar_hostdata, &tmp[0],
141 if (!v) { 108 GFS2_LOCKNAME_LEN);
142 fs_info(sdp, "no memory for hostdata\n");
143 error = -ENOMEM;
144 goto out_error;
145 }
146
147 if (remount && strcmp(v, args->ar_hostdata)) {
148 kfree(v);
149 goto cant_remount;
150 }
151
152 strncpy(args->ar_hostdata, v, GFS2_LOCKNAME_LEN);
153 args->ar_hostdata[GFS2_LOCKNAME_LEN - 1] = 0;
154 kfree(v);
155 break; 109 break;
156 case Opt_spectator: 110 case Opt_spectator:
157 if (remount && !args->ar_spectator)
158 goto cant_remount;
159 args->ar_spectator = 1; 111 args->ar_spectator = 1;
160 sdp->sd_vfs->s_flags |= MS_RDONLY;
161 break; 112 break;
162 case Opt_ignore_local_fs: 113 case Opt_ignore_local_fs:
163 if (remount && !args->ar_ignore_local_fs)
164 goto cant_remount;
165 args->ar_ignore_local_fs = 1; 114 args->ar_ignore_local_fs = 1;
166 break; 115 break;
167 case Opt_localflocks: 116 case Opt_localflocks:
168 if (remount && !args->ar_localflocks)
169 goto cant_remount;
170 args->ar_localflocks = 1; 117 args->ar_localflocks = 1;
171 break; 118 break;
172 case Opt_localcaching: 119 case Opt_localcaching:
173 if (remount && !args->ar_localcaching)
174 goto cant_remount;
175 args->ar_localcaching = 1; 120 args->ar_localcaching = 1;
176 break; 121 break;
177 case Opt_debug: 122 case Opt_debug:
@@ -181,17 +126,13 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
181 args->ar_debug = 0; 126 args->ar_debug = 0;
182 break; 127 break;
183 case Opt_upgrade: 128 case Opt_upgrade:
184 if (remount && !args->ar_upgrade)
185 goto cant_remount;
186 args->ar_upgrade = 1; 129 args->ar_upgrade = 1;
187 break; 130 break;
188 case Opt_acl: 131 case Opt_acl:
189 args->ar_posix_acl = 1; 132 args->ar_posix_acl = 1;
190 sdp->sd_vfs->s_flags |= MS_POSIXACL;
191 break; 133 break;
192 case Opt_noacl: 134 case Opt_noacl:
193 args->ar_posix_acl = 0; 135 args->ar_posix_acl = 0;
194 sdp->sd_vfs->s_flags &= ~MS_POSIXACL;
195 break; 136 break;
196 case Opt_quota_off: 137 case Opt_quota_off:
197 args->ar_quota = GFS2_QUOTA_OFF; 138 args->ar_quota = GFS2_QUOTA_OFF;
@@ -215,29 +156,15 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
215 args->ar_data = GFS2_DATA_ORDERED; 156 args->ar_data = GFS2_DATA_ORDERED;
216 break; 157 break;
217 case Opt_meta: 158 case Opt_meta:
218 if (remount && args->ar_meta != 1)
219 goto cant_remount;
220 args->ar_meta = 1; 159 args->ar_meta = 1;
221 break; 160 break;
222 case Opt_err: 161 case Opt_err:
223 default: 162 default:
224 fs_info(sdp, "unknown option: %s\n", o); 163 fs_info(sdp, "invalid mount option: %s\n", o);
225 error = -EINVAL; 164 return -EINVAL;
226 goto out_error;
227 } 165 }
228 } 166 }
229 167
230out_error: 168 return 0;
231 if (error)
232 fs_info(sdp, "invalid mount option(s)\n");
233
234 if (data != data_arg)
235 kfree(data);
236
237 return error;
238
239cant_remount:
240 fs_info(sdp, "can't remount with option %s\n", o);
241 return -EINVAL;
242} 169}
243 170
diff --git a/fs/gfs2/mount.h b/fs/gfs2/mount.h
deleted file mode 100644
index 401288acfdf3..000000000000
--- a/fs/gfs2/mount.h
+++ /dev/null
@@ -1,17 +0,0 @@
1/*
2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
3 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
4 *
5 * This copyrighted material is made available to anyone wishing to use,
6 * modify, copy, or redistribute it subject to the terms and conditions
7 * of the GNU General Public License version 2.
8 */
9
10#ifndef __MOUNT_DOT_H__
11#define __MOUNT_DOT_H__
12
13struct gfs2_sbd;
14
15int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount);
16
17#endif /* __MOUNT_DOT_H__ */
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index f91eebdde581..3eb49edae542 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -25,7 +25,6 @@
25#include "glock.h" 25#include "glock.h"
26#include "glops.h" 26#include "glops.h"
27#include "inode.h" 27#include "inode.h"
28#include "mount.h"
29#include "recovery.h" 28#include "recovery.h"
30#include "rgrp.h" 29#include "rgrp.h"
31#include "super.h" 30#include "super.h"
@@ -1116,12 +1115,20 @@ static int fill_super(struct super_block *sb, void *data, int silent)
1116 return -ENOMEM; 1115 return -ENOMEM;
1117 } 1116 }
1118 1117
1119 error = gfs2_mount_args(sdp, (char *)data, 0); 1118 sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT;
1119 sdp->sd_args.ar_data = GFS2_DATA_DEFAULT;
1120
1121 error = gfs2_mount_args(sdp, &sdp->sd_args, data);
1120 if (error) { 1122 if (error) {
1121 printk(KERN_WARNING "GFS2: can't parse mount arguments\n"); 1123 printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
1122 goto fail; 1124 goto fail;
1123 } 1125 }
1124 1126
1127 if (sdp->sd_args.ar_spectator)
1128 sb->s_flags |= MS_RDONLY;
1129 if (sdp->sd_args.ar_posix_acl)
1130 sb->s_flags |= MS_POSIXACL;
1131
1125 sb->s_magic = GFS2_MAGIC; 1132 sb->s_magic = GFS2_MAGIC;
1126 sb->s_op = &gfs2_super_ops; 1133 sb->s_op = &gfs2_super_ops;
1127 sb->s_export_op = &gfs2_export_ops; 1134 sb->s_export_op = &gfs2_export_ops;
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
index 320323d03479..f0699ac453f7 100644
--- a/fs/gfs2/ops_super.c
+++ b/fs/gfs2/ops_super.c
@@ -27,7 +27,6 @@
27#include "glock.h" 27#include "glock.h"
28#include "inode.h" 28#include "inode.h"
29#include "log.h" 29#include "log.h"
30#include "mount.h"
31#include "quota.h" 30#include "quota.h"
32#include "recovery.h" 31#include "recovery.h"
33#include "rgrp.h" 32#include "rgrp.h"
@@ -40,6 +39,8 @@
40#include "bmap.h" 39#include "bmap.h"
41#include "meta_io.h" 40#include "meta_io.h"
42 41
42#define args_neq(a1, a2, x) ((a1)->ar_##x != (a2)->ar_##x)
43
43/** 44/**
44 * gfs2_write_inode - Make sure the inode is stable on the disk 45 * gfs2_write_inode - Make sure the inode is stable on the disk
45 * @inode: The inode 46 * @inode: The inode
@@ -435,25 +436,45 @@ static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
435static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) 436static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
436{ 437{
437 struct gfs2_sbd *sdp = sb->s_fs_info; 438 struct gfs2_sbd *sdp = sb->s_fs_info;
439 struct gfs2_args args = sdp->sd_args; /* Default to current settings */
438 int error; 440 int error;
439 441
440 error = gfs2_mount_args(sdp, data, 1); 442 error = gfs2_mount_args(sdp, &args, data);
441 if (error) 443 if (error)
442 return error; 444 return error;
443 445
446 /* Not allowed to change locking details */
447 if (strcmp(args.ar_lockproto, sdp->sd_args.ar_lockproto) ||
448 strcmp(args.ar_locktable, sdp->sd_args.ar_locktable) ||
449 strcmp(args.ar_hostdata, sdp->sd_args.ar_hostdata))
450 return -EINVAL;
451
452 /* Some flags must not be changed */
453 if (args_neq(&args, &sdp->sd_args, spectator) ||
454 args_neq(&args, &sdp->sd_args, ignore_local_fs) ||
455 args_neq(&args, &sdp->sd_args, localflocks) ||
456 args_neq(&args, &sdp->sd_args, localcaching) ||
457 args_neq(&args, &sdp->sd_args, meta))
458 return -EINVAL;
459
444 if (sdp->sd_args.ar_spectator) 460 if (sdp->sd_args.ar_spectator)
445 *flags |= MS_RDONLY; 461 *flags |= MS_RDONLY;
446 else { 462
447 if (*flags & MS_RDONLY) { 463 if ((sb->s_flags ^ *flags) & MS_RDONLY) {
448 if (!(sb->s_flags & MS_RDONLY)) 464 if (*flags & MS_RDONLY)
449 error = gfs2_make_fs_ro(sdp); 465 error = gfs2_make_fs_ro(sdp);
450 } else if (!(*flags & MS_RDONLY) && 466 else
451 (sb->s_flags & MS_RDONLY)) {
452 error = gfs2_make_fs_rw(sdp); 467 error = gfs2_make_fs_rw(sdp);
453 } 468 if (error)
469 return error;
454 } 470 }
455 471
456 return error; 472 sdp->sd_args = args;
473 if (sdp->sd_args.ar_posix_acl)
474 sb->s_flags |= MS_POSIXACL;
475 else
476 sb->s_flags &= ~MS_POSIXACL;
477 return 0;
457} 478}
458 479
459/** 480/**
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h
index f6b8b00ad881..91abdbedcc86 100644
--- a/fs/gfs2/super.h
+++ b/fs/gfs2/super.h
@@ -14,7 +14,7 @@
14#include <linux/dcache.h> 14#include <linux/dcache.h>
15#include "incore.h" 15#include "incore.h"
16 16
17void gfs2_lm_unmount(struct gfs2_sbd *sdp); 17extern void gfs2_lm_unmount(struct gfs2_sbd *sdp);
18 18
19static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp) 19static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
20{ 20{
@@ -27,21 +27,23 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
27 27
28void gfs2_jindex_free(struct gfs2_sbd *sdp); 28void gfs2_jindex_free(struct gfs2_sbd *sdp);
29 29
30struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); 30extern int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *data);
31int gfs2_jdesc_check(struct gfs2_jdesc *jd);
32 31
33int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename, 32extern struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid);
34 struct gfs2_inode **ipp); 33extern int gfs2_jdesc_check(struct gfs2_jdesc *jd);
35 34
36int gfs2_make_fs_rw(struct gfs2_sbd *sdp); 35extern int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename,
36 struct gfs2_inode **ipp);
37 37
38int gfs2_statfs_init(struct gfs2_sbd *sdp); 38extern int gfs2_make_fs_rw(struct gfs2_sbd *sdp);
39void gfs2_statfs_change(struct gfs2_sbd *sdp,
40 s64 total, s64 free, s64 dinodes);
41int gfs2_statfs_sync(struct gfs2_sbd *sdp);
42 39
43int gfs2_freeze_fs(struct gfs2_sbd *sdp); 40extern int gfs2_statfs_init(struct gfs2_sbd *sdp);
44void gfs2_unfreeze_fs(struct gfs2_sbd *sdp); 41extern void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
42 s64 dinodes);
43extern int gfs2_statfs_sync(struct gfs2_sbd *sdp);
44
45extern int gfs2_freeze_fs(struct gfs2_sbd *sdp);
46extern void gfs2_unfreeze_fs(struct gfs2_sbd *sdp);
45 47
46extern struct file_system_type gfs2_fs_type; 48extern struct file_system_type gfs2_fs_type;
47extern struct file_system_type gfs2meta_fs_type; 49extern struct file_system_type gfs2meta_fs_type;