|
@@ -1114,7 +1114,7 @@ void gfs2_online_uevent(struct gfs2_sbd *sdp)
|
|
|
* Returns: errno
|
|
|
*/
|
|
|
|
|
|
-static int fill_super(struct super_block *sb, void *data, int silent)
|
|
|
+static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent)
|
|
|
{
|
|
|
struct gfs2_sbd *sdp;
|
|
|
struct gfs2_holder mount_gh;
|
|
@@ -1125,17 +1125,7 @@ static int fill_super(struct super_block *sb, void *data, int silent)
|
|
|
printk(KERN_WARNING "GFS2: can't alloc struct gfs2_sbd\n");
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
-
|
|
|
- sdp->sd_args.ar_quota = GFS2_QUOTA_DEFAULT;
|
|
|
- sdp->sd_args.ar_data = GFS2_DATA_DEFAULT;
|
|
|
- sdp->sd_args.ar_commit = 60;
|
|
|
- sdp->sd_args.ar_errors = GFS2_ERRORS_DEFAULT;
|
|
|
-
|
|
|
- error = gfs2_mount_args(sdp, &sdp->sd_args, data);
|
|
|
- if (error) {
|
|
|
- printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
|
|
|
- goto fail;
|
|
|
- }
|
|
|
+ sdp->sd_args = *args;
|
|
|
|
|
|
if (sdp->sd_args.ar_spectator) {
|
|
|
sb->s_flags |= MS_RDONLY;
|
|
@@ -1243,18 +1233,125 @@ fail:
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
-static int gfs2_get_sb(struct file_system_type *fs_type, int flags,
|
|
|
- const char *dev_name, void *data, struct vfsmount *mnt)
|
|
|
+static int set_gfs2_super(struct super_block *s, void *data)
|
|
|
{
|
|
|
- return get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt);
|
|
|
+ s->s_bdev = data;
|
|
|
+ s->s_dev = s->s_bdev->bd_dev;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We set the bdi here to the queue backing, file systems can
|
|
|
+ * overwrite this in ->fill_super()
|
|
|
+ */
|
|
|
+ s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info;
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-static int test_meta_super(struct super_block *s, void *ptr)
|
|
|
+static int test_gfs2_super(struct super_block *s, void *ptr)
|
|
|
{
|
|
|
struct block_device *bdev = ptr;
|
|
|
return (bdev == s->s_bdev);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * gfs2_get_sb - Get the GFS2 superblock
|
|
|
+ * @fs_type: The GFS2 filesystem type
|
|
|
+ * @flags: Mount flags
|
|
|
+ * @dev_name: The name of the device
|
|
|
+ * @data: The mount arguments
|
|
|
+ * @mnt: The vfsmnt for this mount
|
|
|
+ *
|
|
|
+ * Q. Why not use get_sb_bdev() ?
|
|
|
+ * A. We need to select one of two root directories to mount, independent
|
|
|
+ * of whether this is the initial, or subsequent, mount of this sb
|
|
|
+ *
|
|
|
+ * Returns: 0 or -ve on error
|
|
|
+ */
|
|
|
+
|
|
|
+static int gfs2_get_sb(struct file_system_type *fs_type, int flags,
|
|
|
+ const char *dev_name, void *data, struct vfsmount *mnt)
|
|
|
+{
|
|
|
+ struct block_device *bdev;
|
|
|
+ struct super_block *s;
|
|
|
+ fmode_t mode = FMODE_READ;
|
|
|
+ int error;
|
|
|
+ struct gfs2_args args;
|
|
|
+ struct gfs2_sbd *sdp;
|
|
|
+
|
|
|
+ if (!(flags & MS_RDONLY))
|
|
|
+ mode |= FMODE_WRITE;
|
|
|
+
|
|
|
+ bdev = open_bdev_exclusive(dev_name, mode, fs_type);
|
|
|
+ if (IS_ERR(bdev))
|
|
|
+ return PTR_ERR(bdev);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * once the super is inserted into the list by sget, s_umount
|
|
|
+ * will protect the lockfs code from trying to start a snapshot
|
|
|
+ * while we are mounting
|
|
|
+ */
|
|
|
+ mutex_lock(&bdev->bd_fsfreeze_mutex);
|
|
|
+ if (bdev->bd_fsfreeze_count > 0) {
|
|
|
+ mutex_unlock(&bdev->bd_fsfreeze_mutex);
|
|
|
+ error = -EBUSY;
|
|
|
+ goto error_bdev;
|
|
|
+ }
|
|
|
+ s = sget(fs_type, test_gfs2_super, set_gfs2_super, bdev);
|
|
|
+ mutex_unlock(&bdev->bd_fsfreeze_mutex);
|
|
|
+ error = PTR_ERR(s);
|
|
|
+ if (IS_ERR(s))
|
|
|
+ goto error_bdev;
|
|
|
+
|
|
|
+ memset(&args, 0, sizeof(args));
|
|
|
+ args.ar_quota = GFS2_QUOTA_DEFAULT;
|
|
|
+ args.ar_data = GFS2_DATA_DEFAULT;
|
|
|
+ args.ar_commit = 60;
|
|
|
+ args.ar_errors = GFS2_ERRORS_DEFAULT;
|
|
|
+
|
|
|
+ error = gfs2_mount_args(&args, data);
|
|
|
+ if (error) {
|
|
|
+ printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
|
|
|
+ if (s->s_root)
|
|
|
+ goto error_super;
|
|
|
+ deactivate_locked_super(s);
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (s->s_root) {
|
|
|
+ error = -EBUSY;
|
|
|
+ if ((flags ^ s->s_flags) & MS_RDONLY)
|
|
|
+ goto error_super;
|
|
|
+ close_bdev_exclusive(bdev, mode);
|
|
|
+ } else {
|
|
|
+ char b[BDEVNAME_SIZE];
|
|
|
+
|
|
|
+ s->s_flags = flags;
|
|
|
+ s->s_mode = mode;
|
|
|
+ strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
|
|
|
+ sb_set_blocksize(s, block_size(bdev));
|
|
|
+ error = fill_super(s, &args, flags & MS_SILENT ? 1 : 0);
|
|
|
+ if (error) {
|
|
|
+ deactivate_locked_super(s);
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+ s->s_flags |= MS_ACTIVE;
|
|
|
+ bdev->bd_super = s;
|
|
|
+ }
|
|
|
+
|
|
|
+ sdp = s->s_fs_info;
|
|
|
+ mnt->mnt_sb = s;
|
|
|
+ if (args.ar_meta)
|
|
|
+ mnt->mnt_root = dget(sdp->sd_master_dir);
|
|
|
+ else
|
|
|
+ mnt->mnt_root = dget(sdp->sd_root_dir);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+error_super:
|
|
|
+ deactivate_locked_super(s);
|
|
|
+error_bdev:
|
|
|
+ close_bdev_exclusive(bdev, mode);
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
static int set_meta_super(struct super_block *s, void *ptr)
|
|
|
{
|
|
|
return -EINVAL;
|
|
@@ -1274,13 +1371,17 @@ static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
|
|
|
dev_name, error);
|
|
|
return error;
|
|
|
}
|
|
|
- s = sget(&gfs2_fs_type, test_meta_super, set_meta_super,
|
|
|
+ s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super,
|
|
|
path.dentry->d_inode->i_sb->s_bdev);
|
|
|
path_put(&path);
|
|
|
if (IS_ERR(s)) {
|
|
|
printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n");
|
|
|
return PTR_ERR(s);
|
|
|
}
|
|
|
+ if ((flags ^ s->s_flags) & MS_RDONLY) {
|
|
|
+ deactivate_locked_super(s);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
sdp = s->s_fs_info;
|
|
|
mnt->mnt_sb = s;
|
|
|
mnt->mnt_root = dget(sdp->sd_master_dir);
|