Commit dfe25020 authored by Chris Mason's avatar Chris Mason

Btrfs: Add mount -o degraded to allow mounts to continue with missing devices

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 1259ab75
...@@ -657,6 +657,7 @@ struct btrfs_root { ...@@ -657,6 +657,7 @@ struct btrfs_root {
#define BTRFS_MOUNT_NODATACOW (1 << 1) #define BTRFS_MOUNT_NODATACOW (1 << 1)
#define BTRFS_MOUNT_NOBARRIER (1 << 2) #define BTRFS_MOUNT_NOBARRIER (1 << 2)
#define BTRFS_MOUNT_SSD (1 << 3) #define BTRFS_MOUNT_SSD (1 << 3)
#define BTRFS_MOUNT_DEGRADED (1 << 4)
#define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) #define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt)
#define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) #define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt)
...@@ -1606,4 +1607,6 @@ int btrfs_delete_xattrs(struct btrfs_trans_handle *trans, ...@@ -1606,4 +1607,6 @@ int btrfs_delete_xattrs(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct inode *inode); struct btrfs_root *root, struct inode *inode);
/* super.c */ /* super.c */
u64 btrfs_parse_size(char *str); u64 btrfs_parse_size(char *str);
int btrfs_parse_options(char *options, struct btrfs_root *root,
char **subvol_name);
#endif #endif
...@@ -614,21 +614,6 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize, ...@@ -614,21 +614,6 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize,
return ret; return ret;
} }
static int close_all_devices(struct btrfs_fs_info *fs_info)
{
struct list_head *list;
struct list_head *next;
struct btrfs_device *device;
list = &fs_info->fs_devices->devices;
list_for_each(next, list) {
device = list_entry(next, struct btrfs_device, dev_list);
close_bdev_excl(device->bdev);
device->bdev = NULL;
}
return 0;
}
struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
u64 bytenr, u32 blocksize) u64 bytenr, u32 blocksize)
{ {
...@@ -927,6 +912,8 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits) ...@@ -927,6 +912,8 @@ static int btrfs_congested_fn(void *congested_data, int bdi_bits)
list_for_each(cur, &info->fs_devices->devices) { list_for_each(cur, &info->fs_devices->devices) {
device = list_entry(cur, struct btrfs_device, dev_list); device = list_entry(cur, struct btrfs_device, dev_list);
if (!device->bdev)
continue;
bdi = blk_get_backing_dev_info(device->bdev); bdi = blk_get_backing_dev_info(device->bdev);
if (bdi && bdi_congested(bdi, bdi_bits)) { if (bdi && bdi_congested(bdi, bdi_bits)) {
ret = 1; ret = 1;
...@@ -1140,7 +1127,8 @@ static void btrfs_async_submit_work(struct work_struct *work) ...@@ -1140,7 +1127,8 @@ static void btrfs_async_submit_work(struct work_struct *work)
} }
struct btrfs_root *open_ctree(struct super_block *sb, struct btrfs_root *open_ctree(struct super_block *sb,
struct btrfs_fs_devices *fs_devices) struct btrfs_fs_devices *fs_devices,
char *options)
{ {
u32 sectorsize; u32 sectorsize;
u32 nodesize; u32 nodesize;
...@@ -1276,12 +1264,19 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1276,12 +1264,19 @@ struct btrfs_root *open_ctree(struct super_block *sb,
if (!btrfs_super_root(disk_super)) if (!btrfs_super_root(disk_super))
goto fail_sb_buffer; goto fail_sb_buffer;
if (btrfs_super_num_devices(disk_super) != fs_devices->num_devices) { btrfs_parse_options(options, tree_root, NULL);
if (btrfs_super_num_devices(disk_super) > fs_devices->num_devices) {
printk("Btrfs: wanted %llu devices, but found %llu\n", printk("Btrfs: wanted %llu devices, but found %llu\n",
(unsigned long long)btrfs_super_num_devices(disk_super), (unsigned long long)btrfs_super_num_devices(disk_super),
(unsigned long long)fs_devices->num_devices); (unsigned long long)fs_devices->num_devices);
goto fail_sb_buffer; if (btrfs_test_opt(tree_root, DEGRADED))
printk("continuing in degraded mode\n");
else {
goto fail_sb_buffer;
}
} }
fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super); fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
nodesize = btrfs_super_nodesize(disk_super); nodesize = btrfs_super_nodesize(disk_super);
...@@ -1329,6 +1324,8 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1329,6 +1324,8 @@ struct btrfs_root *open_ctree(struct super_block *sb,
ret = btrfs_read_chunk_tree(chunk_root); ret = btrfs_read_chunk_tree(chunk_root);
BUG_ON(ret); BUG_ON(ret);
btrfs_close_extra_devices(fs_devices);
blocksize = btrfs_level_size(tree_root, blocksize = btrfs_level_size(tree_root,
btrfs_super_root_level(disk_super)); btrfs_super_root_level(disk_super));
...@@ -1374,7 +1371,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, ...@@ -1374,7 +1371,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
fail_iput: fail_iput:
iput(fs_info->btree_inode); iput(fs_info->btree_inode);
fail: fail:
close_all_devices(fs_info); btrfs_close_devices(fs_info->fs_devices);
btrfs_mapping_tree_free(&fs_info->mapping_tree); btrfs_mapping_tree_free(&fs_info->mapping_tree);
kfree(extent_root); kfree(extent_root);
...@@ -1429,6 +1426,13 @@ int write_all_supers(struct btrfs_root *root) ...@@ -1429,6 +1426,13 @@ int write_all_supers(struct btrfs_root *root)
dev_item = &sb->dev_item; dev_item = &sb->dev_item;
list_for_each(cur, head) { list_for_each(cur, head) {
dev = list_entry(cur, struct btrfs_device, dev_list); dev = list_entry(cur, struct btrfs_device, dev_list);
if (!dev->bdev) {
total_errors++;
continue;
}
if (!dev->in_fs_metadata)
continue;
btrfs_set_stack_device_type(dev_item, dev->type); btrfs_set_stack_device_type(dev_item, dev->type);
btrfs_set_stack_device_id(dev_item, dev->devid); btrfs_set_stack_device_id(dev_item, dev->devid);
btrfs_set_stack_device_total_bytes(dev_item, dev->total_bytes); btrfs_set_stack_device_total_bytes(dev_item, dev->total_bytes);
...@@ -1482,6 +1486,11 @@ int write_all_supers(struct btrfs_root *root) ...@@ -1482,6 +1486,11 @@ int write_all_supers(struct btrfs_root *root)
list_for_each(cur, head) { list_for_each(cur, head) {
dev = list_entry(cur, struct btrfs_device, dev_list); dev = list_entry(cur, struct btrfs_device, dev_list);
if (!dev->bdev)
continue;
if (!dev->in_fs_metadata)
continue;
BUG_ON(!dev->pending_io); BUG_ON(!dev->pending_io);
bh = dev->pending_io; bh = dev->pending_io;
wait_on_buffer(bh); wait_on_buffer(bh);
...@@ -1631,7 +1640,7 @@ int close_ctree(struct btrfs_root *root) ...@@ -1631,7 +1640,7 @@ int close_ctree(struct btrfs_root *root)
kfree(hasher); kfree(hasher);
} }
#endif #endif
close_all_devices(fs_info); btrfs_close_devices(fs_info->fs_devices);
btrfs_mapping_tree_free(&fs_info->mapping_tree); btrfs_mapping_tree_free(&fs_info->mapping_tree);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
......
...@@ -33,7 +33,8 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, ...@@ -33,7 +33,8 @@ struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
int clean_tree_block(struct btrfs_trans_handle *trans, int clean_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct extent_buffer *buf); struct btrfs_root *root, struct extent_buffer *buf);
struct btrfs_root *open_ctree(struct super_block *sb, struct btrfs_root *open_ctree(struct super_block *sb,
struct btrfs_fs_devices *fs_devices); struct btrfs_fs_devices *fs_devices,
char *options);
int close_ctree(struct btrfs_root *root); int close_ctree(struct btrfs_root *root);
int write_ctree_super(struct btrfs_trans_handle *trans, int write_ctree_super(struct btrfs_trans_handle *trans,
struct btrfs_root *root); struct btrfs_root *root);
......
...@@ -65,11 +65,13 @@ static void btrfs_put_super (struct super_block * sb) ...@@ -65,11 +65,13 @@ static void btrfs_put_super (struct super_block * sb)
} }
enum { enum {
Opt_subvol, Opt_nodatasum, Opt_nodatacow, Opt_max_extent, Opt_degraded, Opt_subvol, Opt_nodatasum, Opt_nodatacow,
Opt_max_inline, Opt_alloc_start, Opt_nobarrier, Opt_ssd, Opt_err, Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
Opt_ssd, Opt_err,
}; };
static match_table_t tokens = { static match_table_t tokens = {
{Opt_degraded, "degraded"},
{Opt_subvol, "subvol=%s"}, {Opt_subvol, "subvol=%s"},
{Opt_nodatasum, "nodatasum"}, {Opt_nodatasum, "nodatasum"},
{Opt_nodatacow, "nodatacow"}, {Opt_nodatacow, "nodatacow"},
...@@ -106,9 +108,8 @@ u64 btrfs_parse_size(char *str) ...@@ -106,9 +108,8 @@ u64 btrfs_parse_size(char *str)
return res; return res;
} }
static int parse_options (char * options, int btrfs_parse_options(char *options, struct btrfs_root *root,
struct btrfs_root *root, char **subvol_name)
char **subvol_name)
{ {
char * p; char * p;
struct btrfs_fs_info *info = NULL; struct btrfs_fs_info *info = NULL;
...@@ -135,6 +136,12 @@ static int parse_options (char * options, ...@@ -135,6 +136,12 @@ static int parse_options (char * options,
token = match_token(p, tokens, args); token = match_token(p, tokens, args);
switch (token) { switch (token) {
case Opt_degraded:
if (info) {
printk("btrfs: allowing degraded mounts\n");
btrfs_set_opt(info->mount_opt, DEGRADED);
}
break;
case Opt_subvol: case Opt_subvol:
if (subvol_name) { if (subvol_name) {
*subvol_name = match_strdup(&args[0]); *subvol_name = match_strdup(&args[0]);
...@@ -234,7 +241,7 @@ static int btrfs_fill_super(struct super_block * sb, ...@@ -234,7 +241,7 @@ static int btrfs_fill_super(struct super_block * sb,
sb->s_xattr = btrfs_xattr_handlers; sb->s_xattr = btrfs_xattr_handlers;
sb->s_time_gran = 1; 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)) { if (IS_ERR(tree_root)) {
printk("btrfs: open_ctree failed\n"); printk("btrfs: open_ctree failed\n");
...@@ -267,8 +274,6 @@ static int btrfs_fill_super(struct super_block * sb, ...@@ -267,8 +274,6 @@ static int btrfs_fill_super(struct super_block * sb,
goto fail_close; goto fail_close;
} }
parse_options((char *)data, tree_root, NULL);
/* this does the super kobj at the same time */ /* this does the super kobj at the same time */
err = btrfs_sysfs_add_super(tree_root->fs_info); err = btrfs_sysfs_add_super(tree_root->fs_info);
if (err) if (err)
...@@ -341,7 +346,7 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type, ...@@ -341,7 +346,7 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type,
if (error) if (error)
return error; return error;
bdev = fs_devices->lowest_bdev; bdev = fs_devices->latest_bdev;
btrfs_lock_volumes(); btrfs_lock_volumes();
s = sget(fs_type, btrfs_test_super, set_anon_super, fs_devices); s = sget(fs_type, btrfs_test_super, set_anon_super, fs_devices);
btrfs_unlock_volumes(); btrfs_unlock_volumes();
...@@ -411,7 +416,7 @@ static int btrfs_get_sb(struct file_system_type *fs_type, ...@@ -411,7 +416,7 @@ static int btrfs_get_sb(struct file_system_type *fs_type,
int ret; int ret;
char *subvol_name = NULL; 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, ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data, mnt,
subvol_name ? subvol_name : "default"); subvol_name ? subvol_name : "default");
if (subvol_name) if (subvol_name)
......
This diff is collapsed.
...@@ -27,8 +27,10 @@ struct btrfs_device { ...@@ -27,8 +27,10 @@ struct btrfs_device {
struct list_head dev_alloc_list; struct list_head dev_alloc_list;
struct btrfs_root *dev_root; struct btrfs_root *dev_root;
struct buffer_head *pending_io; struct buffer_head *pending_io;
u64 generation;
int barriers; int barriers;
int in_fs_metadata;
spinlock_t io_lock; spinlock_t io_lock;
...@@ -122,6 +124,7 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, ...@@ -122,6 +124,7 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices,
int btrfs_scan_one_device(const char *path, int flags, void *holder, int btrfs_scan_one_device(const char *path, int flags, void *holder,
struct btrfs_fs_devices **fs_devices_ret); struct btrfs_fs_devices **fs_devices_ret);
int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); int btrfs_close_devices(struct btrfs_fs_devices *fs_devices);
int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices);
int btrfs_add_device(struct btrfs_trans_handle *trans, int btrfs_add_device(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct btrfs_device *device); struct btrfs_device *device);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment