aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2009-09-28 05:30:49 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2009-12-03 06:42:47 -0500
commitf55073ff1eaf99f6b3bc62134a456638bca043a3 (patch)
tree9637792f97494de2336f17a90a756e91c7d25527 /fs
parent7e71c55ee73988d0cb61045660b899eaac23bf8f (diff)
GFS2: Fix -o meta mounts for subsequent mounts (i.e. all but the first one)
We have a long term plan to use the "-o meta" flag to GFS2 mounts to access the alternate root which is used to store metadata for a GFS2 filesystem. This will allow us to eventually remove support for the gfs2meta filesystem type (which is in any case just a "front end" to the gfs2 filesystem type with the meta/master root). Currently the "-o meta" option is only taken into account on the initial mount of the filesystem. Subsequent mounts of the same filesystem (i.e. on the same device) result in basically the same as bind mounting the root of the original mount. This patch changes that by using what is more or less a copy of get_sb_bdev() and extending it so that it will take into account the alternate root in all cases. The main difference is that we have to parse the mount options a bit earlier. We can then use them to select the appropriate root towards the end of the function. In addition this also fixes a bug where it was possible (but certainly not desirable) to set different ro/rw options for the meta root when mounted via the gfs2meta fs compared with the original mount. Signed-off-by: Steven Whitehouse <swhiteho@redhat.com> Cc: Alexander Viro <aviro@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/gfs2/ops_fstype.c135
-rw-r--r--fs/gfs2/super.c16
-rw-r--r--fs/gfs2/super.h2
3 files changed, 127 insertions, 26 deletions
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 52fb6c048981..e5ee06231ae5 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1114,7 +1114,7 @@ void gfs2_online_uevent(struct gfs2_sbd *sdp)
1114 * Returns: errno 1114 * Returns: errno
1115 */ 1115 */
1116 1116
1117static int fill_super(struct super_block *sb, void *data, int silent) 1117static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent)
1118{ 1118{
1119 struct gfs2_sbd *sdp; 1119 struct gfs2_sbd *sdp;
1120 struct gfs2_holder mount_gh; 1120 struct gfs2_holder mount_gh;
@@ -1125,17 +1125,7 @@ static int fill_super(struct super_block *sb, void *data, int silent)
1125 printk(KERN_WARNING "GFS2: can't alloc struct gfs2_sbd\n"); 1125 printk(KERN_WARNING "GFS2: can't alloc struct gfs2_sbd\n");
1126 return -ENOMEM; 1126 return -ENOMEM;
1127 } 1127 }
1128 1128 sdp->sd_args = *args;
1129 sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT;
1130 sdp->sd_args.ar_data = GFS2_DATA_DEFAULT;
1131 sdp->sd_args.ar_commit = 60;
1132 sdp->sd_args.ar_errors = GFS2_ERRORS_DEFAULT;
1133
1134 error = gfs2_mount_args(sdp, &sdp->sd_args, data);
1135 if (error) {
1136 printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
1137 goto fail;
1138 }
1139 1129
1140 if (sdp->sd_args.ar_spectator) { 1130 if (sdp->sd_args.ar_spectator) {
1141 sb->s_flags |= MS_RDONLY; 1131 sb->s_flags |= MS_RDONLY;
@@ -1243,18 +1233,125 @@ fail:
1243 return error; 1233 return error;
1244} 1234}
1245 1235
1246static int gfs2_get_sb(struct file_system_type *fs_type, int flags, 1236static int set_gfs2_super(struct super_block *s, void *data)
1247 const char *dev_name, void *data, struct vfsmount *mnt)
1248{ 1237{
1249 return get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt); 1238 s->s_bdev = data;
1239 s->s_dev = s->s_bdev->bd_dev;
1240
1241 /*
1242 * We set the bdi here to the queue backing, file systems can
1243 * overwrite this in ->fill_super()
1244 */
1245 s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
1246 return 0;
1250} 1247}
1251 1248
1252static int test_meta_super(struct super_block *s, void *ptr) 1249static int test_gfs2_super(struct super_block *s, void *ptr)
1253{ 1250{
1254 struct block_device *bdev = ptr; 1251 struct block_device *bdev = ptr;
1255 return (bdev == s->s_bdev); 1252 return (bdev == s->s_bdev);
1256} 1253}
1257 1254
1255/**
1256 * gfs2_get_sb - Get the GFS2 superblock
1257 * @fs_type: The GFS2 filesystem type
1258 * @flags: Mount flags
1259 * @dev_name: The name of the device
1260 * @data: The mount arguments
1261 * @mnt: The vfsmnt for this mount
1262 *
1263 * Q. Why not use get_sb_bdev() ?
1264 * A. We need to select one of two root directories to mount, independent
1265 * of whether this is the initial, or subsequent, mount of this sb
1266 *
1267 * Returns: 0 or -ve on error
1268 */
1269
1270static int gfs2_get_sb(struct file_system_type *fs_type, int flags,
1271 const char *dev_name, void *data, struct vfsmount *mnt)
1272{
1273 struct block_device *bdev;
1274 struct super_block *s;
1275 fmode_t mode = FMODE_READ;
1276 int error;
1277 struct gfs2_args args;
1278 struct gfs2_sbd *sdp;
1279
1280 if (!(flags & MS_RDONLY))
1281 mode |= FMODE_WRITE;
1282
1283 bdev = open_bdev_exclusive(dev_name, mode, fs_type);
1284 if (IS_ERR(bdev))
1285 return PTR_ERR(bdev);
1286
1287 /*
1288 * once the super is inserted into the list by sget, s_umount
1289 * will protect the lockfs code from trying to start a snapshot
1290 * while we are mounting
1291 */
1292 mutex_lock(&bdev->bd_fsfreeze_mutex);
1293 if (bdev->bd_fsfreeze_count > 0) {
1294 mutex_unlock(&bdev->bd_fsfreeze_mutex);
1295 error = -EBUSY;
1296 goto error_bdev;
1297 }
1298 s = sget(fs_type, test_gfs2_super, set_gfs2_super, bdev);
1299 mutex_unlock(&bdev->bd_fsfreeze_mutex);
1300 error = PTR_ERR(s);
1301 if (IS_ERR(s))
1302 goto error_bdev;
1303
1304 memset(&args, 0, sizeof(args));
1305 args.ar_quota = GFS2_QUOTA_DEFAULT;
1306 args.ar_data = GFS2_DATA_DEFAULT;
1307 args.ar_commit = 60;
1308 args.ar_errors = GFS2_ERRORS_DEFAULT;
1309
1310 error = gfs2_mount_args(&args, data);
1311 if (error) {
1312 printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
1313 if (s->s_root)
1314 goto error_super;
1315 deactivate_locked_super(s);
1316 return error;
1317 }
1318
1319 if (s->s_root) {
1320 error = -EBUSY;
1321 if ((flags ^ s->s_flags) & MS_RDONLY)
1322 goto error_super;
1323 close_bdev_exclusive(bdev, mode);
1324 } else {
1325 char b[BDEVNAME_SIZE];
1326
1327 s->s_flags = flags;
1328 s->s_mode = mode;
1329 strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
1330 sb_set_blocksize(s, block_size(bdev));
1331 error = fill_super(s, &args, flags & MS_SILENT ? 1 : 0);
1332 if (error) {
1333 deactivate_locked_super(s);
1334 return error;
1335 }
1336 s->s_flags |= MS_ACTIVE;
1337 bdev->bd_super = s;
1338 }
1339
1340 sdp = s->s_fs_info;
1341 mnt->mnt_sb = s;
1342 if (args.ar_meta)
1343 mnt->mnt_root = dget(sdp->sd_master_dir);
1344 else
1345 mnt->mnt_root = dget(sdp->sd_root_dir);
1346 return 0;
1347
1348error_super:
1349 deactivate_locked_super(s);
1350error_bdev:
1351 close_bdev_exclusive(bdev, mode);
1352 return error;
1353}
1354
1258static int set_meta_super(struct super_block *s, void *ptr) 1355static int set_meta_super(struct super_block *s, void *ptr)
1259{ 1356{
1260 return -EINVAL; 1357 return -EINVAL;
@@ -1274,13 +1371,17 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
1274 dev_name, error); 1371 dev_name, error);
1275 return error; 1372 return error;
1276 } 1373 }
1277 s = sget(&gfs2_fs_type, test_meta_super, set_meta_super, 1374 s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super,
1278 path.dentry->d_inode->i_sb->s_bdev); 1375 path.dentry->d_inode->i_sb->s_bdev);
1279 path_put(&path); 1376 path_put(&path);
1280 if (IS_ERR(s)) { 1377 if (IS_ERR(s)) {
1281 printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n"); 1378 printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n");
1282 return PTR_ERR(s); 1379 return PTR_ERR(s);
1283 } 1380 }
1381 if ((flags ^ s->s_flags) & MS_RDONLY) {
1382 deactivate_locked_super(s);
1383 return -EBUSY;
1384 }
1284 sdp = s->s_fs_info; 1385 sdp = s->s_fs_info;
1285 mnt->mnt_sb = s; 1386 mnt->mnt_sb = s;
1286 mnt->mnt_root = dget(sdp->sd_master_dir); 1387 mnt->mnt_root = dget(sdp->sd_master_dir);
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index 0ec3ec672de1..42e5458703f0 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -106,13 +106,13 @@ static const match_table_t tokens = {
106 106
107/** 107/**
108 * gfs2_mount_args - Parse mount options 108 * gfs2_mount_args - Parse mount options
109 * @sdp: 109 * @args: The structure into which the parsed options will be written
110 * @data: 110 * @options: The options to parse
111 * 111 *
112 * Return: errno 112 * Return: errno
113 */ 113 */
114 114
115int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options) 115int gfs2_mount_args(struct gfs2_args *args, char *options)
116{ 116{
117 char *o; 117 char *o;
118 int token; 118 int token;
@@ -157,7 +157,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
157 break; 157 break;
158 case Opt_debug: 158 case Opt_debug:
159 if (args->ar_errors == GFS2_ERRORS_PANIC) { 159 if (args->ar_errors == GFS2_ERRORS_PANIC) {
160 fs_info(sdp, "-o debug and -o errors=panic " 160 printk(KERN_WARNING "GFS2: -o debug and -o errors=panic "
161 "are mutually exclusive.\n"); 161 "are mutually exclusive.\n");
162 return -EINVAL; 162 return -EINVAL;
163 } 163 }
@@ -210,7 +210,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
210 case Opt_commit: 210 case Opt_commit:
211 rv = match_int(&tmp[0], &args->ar_commit); 211 rv = match_int(&tmp[0], &args->ar_commit);
212 if (rv || args->ar_commit <= 0) { 212 if (rv || args->ar_commit <= 0) {
213 fs_info(sdp, "commit mount option requires a positive numeric argument\n"); 213 printk(KERN_WARNING "GFS2: commit mount option requires a positive numeric argument\n");
214 return rv ? rv : -EINVAL; 214 return rv ? rv : -EINVAL;
215 } 215 }
216 break; 216 break;
@@ -219,7 +219,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
219 break; 219 break;
220 case Opt_err_panic: 220 case Opt_err_panic:
221 if (args->ar_debug) { 221 if (args->ar_debug) {
222 fs_info(sdp, "-o debug and -o errors=panic " 222 printk(KERN_WARNING "GFS2: -o debug and -o errors=panic "
223 "are mutually exclusive.\n"); 223 "are mutually exclusive.\n");
224 return -EINVAL; 224 return -EINVAL;
225 } 225 }
@@ -227,7 +227,7 @@ int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *options)
227 break; 227 break;
228 case Opt_error: 228 case Opt_error:
229 default: 229 default:
230 fs_info(sdp, "invalid mount option: %s\n", o); 230 printk(KERN_WARNING "GFS2: invalid mount option: %s\n", o);
231 return -EINVAL; 231 return -EINVAL;
232 } 232 }
233 } 233 }
@@ -1062,7 +1062,7 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
1062 spin_lock(&gt->gt_spin); 1062 spin_lock(&gt->gt_spin);
1063 args.ar_commit = gt->gt_log_flush_secs; 1063 args.ar_commit = gt->gt_log_flush_secs;
1064 spin_unlock(&gt->gt_spin); 1064 spin_unlock(&gt->gt_spin);
1065 error = gfs2_mount_args(sdp, &args, data); 1065 error = gfs2_mount_args(&args, data);
1066 if (error) 1066 if (error)
1067 return error; 1067 return error;
1068 1068
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h
index 235db3682885..ed962ea68c3a 100644
--- a/fs/gfs2/super.h
+++ b/fs/gfs2/super.h
@@ -27,7 +27,7 @@ static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
27 27
28extern void gfs2_jindex_free(struct gfs2_sbd *sdp); 28extern void gfs2_jindex_free(struct gfs2_sbd *sdp);
29 29
30extern int gfs2_mount_args(struct gfs2_sbd *sdp, struct gfs2_args *args, char *data); 30extern int gfs2_mount_args(struct gfs2_args *args, char *data);
31 31
32extern struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid); 32extern struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid);
33extern int gfs2_jdesc_check(struct gfs2_jdesc *jd); 33extern int gfs2_jdesc_check(struct gfs2_jdesc *jd);