}
enum {
- Opt_subvol, Opt_nodatasum, Opt_nodatacow, Opt_max_extent,
- Opt_max_inline, Opt_alloc_start, Opt_nobarrier, Opt_ssd, Opt_err,
+ Opt_degraded, Opt_subvol, Opt_nodatasum, Opt_nodatacow,
+ Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
+ Opt_ssd, Opt_err,
};
static match_table_t tokens = {
+ {Opt_degraded, "degraded"},
{Opt_subvol, "subvol=%s"},
{Opt_nodatasum, "nodatasum"},
{Opt_nodatacow, "nodatacow"},
return res;
}
-static int parse_options (char * options,
- struct btrfs_root *root,
- char **subvol_name)
+int btrfs_parse_options(char *options, struct btrfs_root *root,
+ char **subvol_name)
{
char * p;
struct btrfs_fs_info *info = NULL;
token = match_token(p, tokens, args);
switch (token) {
+ case Opt_degraded:
+ if (info) {
+ printk("btrfs: allowing degraded mounts\n");
+ btrfs_set_opt(info->mount_opt, DEGRADED);
+ }
+ break;
case Opt_subvol:
if (subvol_name) {
*subvol_name = match_strdup(&args[0]);
sb->s_xattr = btrfs_xattr_handlers;
sb->s_time_gran = 1;
- tree_root = open_ctree(sb, fs_devices);
+ tree_root = open_ctree(sb, fs_devices, (char *)data);
if (IS_ERR(tree_root)) {
printk("btrfs: open_ctree failed\n");
goto fail_close;
}
- parse_options((char *)data, tree_root, NULL);
-
/* this does the super kobj at the same time */
err = btrfs_sysfs_add_super(tree_root->fs_info);
if (err)
sb->s_dirt = 0;
}
-/*
- * This is almost a copy of get_sb_bdev in fs/super.c.
- * We need the local copy to allow direct mounting of
- * subvolumes, but this could be easily integrated back
- * into the generic version. --hch
- */
-
-/* start copy & paste */
-static int set_bdev_super(struct super_block *s, void *data)
+static int btrfs_test_super(struct super_block *s, void *data)
{
- s->s_bdev = data;
- s->s_dev = s->s_bdev->bd_dev;
- return 0;
-}
+ struct btrfs_fs_devices *test_fs_devices = data;
+ struct btrfs_root *root = btrfs_sb(s);
-static int test_bdev_super(struct super_block *s, void *data)
-{
- return (void *)s->s_bdev == data;
+ return root->fs_info->fs_devices == test_fs_devices;
}
int btrfs_get_sb_bdev(struct file_system_type *fs_type,
if (error)
return error;
- bdev = fs_devices->lowest_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
- */
- down(&bdev->bd_mount_sem);
- s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);
- up(&bdev->bd_mount_sem);
+ bdev = fs_devices->latest_bdev;
+ btrfs_lock_volumes();
+ s = sget(fs_type, btrfs_test_super, set_anon_super, fs_devices);
+ btrfs_unlock_volumes();
if (IS_ERR(s))
goto error_s;
goto error_bdev;
}
- close_bdev_excl(bdev);
} else {
char b[BDEVNAME_SIZE];
s->s_flags = flags;
strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
- sb_set_blocksize(s, block_size(bdev));
error = btrfs_fill_super(s, fs_devices, data,
flags & MS_SILENT ? 1 : 0);
if (error) {
int ret;
char *subvol_name = NULL;
- parse_options((char *)data, NULL, &subvol_name);
+ btrfs_parse_options((char *)data, NULL, &subvol_name);
ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data, mnt,
subvol_name ? subvol_name : "default");
if (subvol_name)
.owner = THIS_MODULE,
.name = "btrfs",
.get_sb = btrfs_get_sb,
- .kill_sb = kill_block_super,
+ .kill_sb = kill_anon_super,
.fs_flags = FS_REQUIRES_DEV,
};
static struct super_operations btrfs_super_ops = {
.delete_inode = btrfs_delete_inode,
- .put_inode = btrfs_put_inode,
.put_super = btrfs_put_super,
.write_super = btrfs_write_super,
.sync_fs = btrfs_sync_fs,