Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs

Pull btrfs fixes from Chris Mason:
 "We've queued up a few fixes in my for-linus branch"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: fix crash when starting transaction
  Btrfs: fix btrfs_print_leaf for skinny metadata
  Btrfs: fix race of using total_bytes_pinned
  btrfs: use E2BIG instead of EIO if compression does not help
  btrfs: remove stale comment from btrfs_flush_all_pending_stuffs
  Btrfs: fix use-after-free when cloning a trailing file hole
  btrfs: fix null pointer dereference in btrfs_show_devname when name is null
  btrfs: fix null pointer dereference in clone_fs_devices when name is null
  btrfs: fix nossd and ssd_spread mount option regression
  Btrfs: fix race between balance recovery and root deletion
  Btrfs: atomically set inode->i_flags in btrfs_update_iflags
  btrfs: only unlock block in verify_parent_transid if we locked it
  Btrfs: assert send doesn't attempt to start transactions
  btrfs compression: reuse recently used workspace
  Btrfs: fix crash when mounting raid5 btrfs with missing disks
  btrfs: create sprout should rename fsid on the sysfs as well
  btrfs: dev replace should replace the sysfs entry
  btrfs: dev add should add its sysfs entry
  btrfs: dev delete should remove sysfs entry
  btrfs: rename add_device_membership to btrfs_kobj_add_device
This commit is contained in:
Linus Torvalds 2014-07-04 08:53:53 -07:00
commit b82207b8e8
14 changed files with 109 additions and 47 deletions

View File

@ -821,7 +821,7 @@ static void free_workspace(int type, struct list_head *workspace)
spin_lock(workspace_lock);
if (*num_workspace < num_online_cpus()) {
list_add_tail(workspace, idle_workspace);
list_add(workspace, idle_workspace);
(*num_workspace)++;
spin_unlock(workspace_lock);
goto wake;

View File

@ -36,6 +36,7 @@
#include "check-integrity.h"
#include "rcu-string.h"
#include "dev-replace.h"
#include "sysfs.h"
static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
int scrub_ret);
@ -562,6 +563,10 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
fs_info->fs_devices->latest_bdev = tgt_device->bdev;
list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list);
/* replace the sysfs entry */
btrfs_kobj_rm_device(fs_info, src_device);
btrfs_kobj_add_device(fs_info, tgt_device);
btrfs_rm_dev_replace_blocked(fs_info);
btrfs_rm_dev_replace_srcdev(fs_info, src_device);

View File

@ -369,6 +369,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
out:
unlock_extent_cached(io_tree, eb->start, eb->start + eb->len - 1,
&cached_state, GFP_NOFS);
if (need_lock)
btrfs_tree_read_unlock_blocking(eb);
return ret;
}
@ -2904,7 +2905,9 @@ int open_ctree(struct super_block *sb,
if (ret)
goto fail_qgroup;
mutex_lock(&fs_info->cleaner_mutex);
ret = btrfs_recover_relocation(tree_root);
mutex_unlock(&fs_info->cleaner_mutex);
if (ret < 0) {
printk(KERN_WARNING
"BTRFS: failed to recover relocation\n");

View File

@ -5678,7 +5678,6 @@ void btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans,
struct btrfs_caching_control *next;
struct btrfs_caching_control *caching_ctl;
struct btrfs_block_group_cache *cache;
struct btrfs_space_info *space_info;
down_write(&fs_info->commit_root_sem);
@ -5701,9 +5700,6 @@ void btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans,
up_write(&fs_info->commit_root_sem);
list_for_each_entry_rcu(space_info, &fs_info->space_info, list)
percpu_counter_set(&space_info->total_bytes_pinned, 0);
update_global_block_rsv(fs_info);
}
@ -5741,6 +5737,7 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
spin_lock(&cache->lock);
cache->pinned -= len;
space_info->bytes_pinned -= len;
percpu_counter_add(&space_info->total_bytes_pinned, -len);
if (cache->ro) {
space_info->bytes_readonly += len;
readonly = true;

View File

@ -136,19 +136,22 @@ static unsigned int btrfs_flags_to_ioctl(unsigned int flags)
void btrfs_update_iflags(struct inode *inode)
{
struct btrfs_inode *ip = BTRFS_I(inode);
inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
unsigned int new_fl = 0;
if (ip->flags & BTRFS_INODE_SYNC)
inode->i_flags |= S_SYNC;
new_fl |= S_SYNC;
if (ip->flags & BTRFS_INODE_IMMUTABLE)
inode->i_flags |= S_IMMUTABLE;
new_fl |= S_IMMUTABLE;
if (ip->flags & BTRFS_INODE_APPEND)
inode->i_flags |= S_APPEND;
new_fl |= S_APPEND;
if (ip->flags & BTRFS_INODE_NOATIME)
inode->i_flags |= S_NOATIME;
new_fl |= S_NOATIME;
if (ip->flags & BTRFS_INODE_DIRSYNC)
inode->i_flags |= S_DIRSYNC;
new_fl |= S_DIRSYNC;
set_mask_bits(&inode->i_flags,
S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | S_DIRSYNC,
new_fl);
}
/*
@ -3139,7 +3142,6 @@ static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
static void clone_update_extent_map(struct inode *inode,
const struct btrfs_trans_handle *trans,
const struct btrfs_path *path,
struct btrfs_file_extent_item *fi,
const u64 hole_offset,
const u64 hole_len)
{
@ -3154,7 +3156,11 @@ static void clone_update_extent_map(struct inode *inode,
return;
}
if (fi) {
if (path) {
struct btrfs_file_extent_item *fi;
fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
struct btrfs_file_extent_item);
btrfs_extent_item_to_extent_map(inode, path, fi, false, em);
em->generation = -1;
if (btrfs_file_extent_type(path->nodes[0], fi) ==
@ -3508,18 +3514,15 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
btrfs_item_ptr_offset(leaf, slot),
size);
inode_add_bytes(inode, datal);
extent = btrfs_item_ptr(leaf, slot,
struct btrfs_file_extent_item);
}
/* If we have an implicit hole (NO_HOLES feature). */
if (drop_start < new_key.offset)
clone_update_extent_map(inode, trans,
path, NULL, drop_start,
NULL, drop_start,
new_key.offset - drop_start);
clone_update_extent_map(inode, trans, path,
extent, 0, 0);
clone_update_extent_map(inode, trans, path, 0, 0);
btrfs_mark_buffer_dirty(leaf);
btrfs_release_path(path);
@ -3562,12 +3565,10 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
btrfs_end_transaction(trans, root);
goto out;
}
clone_update_extent_map(inode, trans, NULL, last_dest_end,
destoff + len - last_dest_end);
ret = clone_finish_inode_update(trans, inode, destoff + len,
destoff, olen);
if (ret)
goto out;
clone_update_extent_map(inode, trans, path, NULL, last_dest_end,
destoff + len - last_dest_end);
}
out:

View File

@ -54,7 +54,7 @@ static void print_extent_data_ref(struct extent_buffer *eb,
btrfs_extent_data_ref_count(eb, ref));
}
static void print_extent_item(struct extent_buffer *eb, int slot)
static void print_extent_item(struct extent_buffer *eb, int slot, int type)
{
struct btrfs_extent_item *ei;
struct btrfs_extent_inline_ref *iref;
@ -63,7 +63,6 @@ static void print_extent_item(struct extent_buffer *eb, int slot)
struct btrfs_disk_key key;
unsigned long end;
unsigned long ptr;
int type;
u32 item_size = btrfs_item_size_nr(eb, slot);
u64 flags;
u64 offset;
@ -88,7 +87,8 @@ static void print_extent_item(struct extent_buffer *eb, int slot)
btrfs_extent_refs(eb, ei), btrfs_extent_generation(eb, ei),
flags);
if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
if ((type == BTRFS_EXTENT_ITEM_KEY) &&
flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
struct btrfs_tree_block_info *info;
info = (struct btrfs_tree_block_info *)(ei + 1);
btrfs_tree_block_key(eb, info, &key);
@ -223,7 +223,8 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
btrfs_disk_root_refs(l, ri));
break;
case BTRFS_EXTENT_ITEM_KEY:
print_extent_item(l, i);
case BTRFS_METADATA_ITEM_KEY:
print_extent_item(l, i, type);
break;
case BTRFS_TREE_BLOCK_REF_KEY:
printk(KERN_INFO "\t\ttree block backref\n");

View File

@ -1956,9 +1956,10 @@ static int __raid56_parity_recover(struct btrfs_raid_bio *rbio)
* pages are going to be uptodate.
*/
for (stripe = 0; stripe < bbio->num_stripes; stripe++) {
if (rbio->faila == stripe ||
rbio->failb == stripe)
if (rbio->faila == stripe || rbio->failb == stripe) {
atomic_inc(&rbio->bbio->error);
continue;
}
for (pagenr = 0; pagenr < nr_pages; pagenr++) {
struct page *p;

View File

@ -522,9 +522,10 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
case Opt_ssd_spread:
btrfs_set_and_info(root, SSD_SPREAD,
"use spread ssd allocation scheme");
btrfs_set_opt(info->mount_opt, SSD);
break;
case Opt_nossd:
btrfs_clear_and_info(root, NOSSD,
btrfs_set_and_info(root, NOSSD,
"not using ssd allocation scheme");
btrfs_clear_opt(info->mount_opt, SSD);
break;
@ -1467,7 +1468,9 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
goto restore;
/* recover relocation */
mutex_lock(&fs_info->cleaner_mutex);
ret = btrfs_recover_relocation(root);
mutex_unlock(&fs_info->cleaner_mutex);
if (ret)
goto restore;
@ -1808,6 +1811,8 @@ static int btrfs_show_devname(struct seq_file *m, struct dentry *root)
list_for_each_entry(dev, head, dev_list) {
if (dev->missing)
continue;
if (!dev->name)
continue;
if (!first_dev || dev->devid < first_dev->devid)
first_dev = dev;
}

View File

@ -605,14 +605,37 @@ static void init_feature_attrs(void)
}
}
static int add_device_membership(struct btrfs_fs_info *fs_info)
int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info,
struct btrfs_device *one_device)
{
struct hd_struct *disk;
struct kobject *disk_kobj;
if (!fs_info->device_dir_kobj)
return -EINVAL;
if (one_device) {
disk = one_device->bdev->bd_part;
disk_kobj = &part_to_dev(disk)->kobj;
sysfs_remove_link(fs_info->device_dir_kobj,
disk_kobj->name);
}
return 0;
}
int btrfs_kobj_add_device(struct btrfs_fs_info *fs_info,
struct btrfs_device *one_device)
{
int error = 0;
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
struct btrfs_device *dev;
if (!fs_info->device_dir_kobj)
fs_info->device_dir_kobj = kobject_create_and_add("devices",
&fs_info->super_kobj);
if (!fs_info->device_dir_kobj)
return -ENOMEM;
@ -623,6 +646,9 @@ static int add_device_membership(struct btrfs_fs_info *fs_info)
if (!dev->bdev)
continue;
if (one_device && one_device != dev)
continue;
disk = dev->bdev->bd_part;
disk_kobj = &part_to_dev(disk)->kobj;
@ -666,7 +692,7 @@ int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info)
if (error)
goto failure;
error = add_device_membership(fs_info);
error = btrfs_kobj_add_device(fs_info, NULL);
if (error)
goto failure;

View File

@ -66,4 +66,8 @@ char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags);
extern const char * const btrfs_feature_set_names[3];
extern struct kobj_type space_info_ktype;
extern struct kobj_type btrfs_raid_ktype;
int btrfs_kobj_add_device(struct btrfs_fs_info *fs_info,
struct btrfs_device *one_device);
int btrfs_kobj_rm_device(struct btrfs_fs_info *fs_info,
struct btrfs_device *one_device);
#endif /* _BTRFS_SYSFS_H_ */

View File

@ -386,11 +386,13 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
bool reloc_reserved = false;
int ret;
/* Send isn't supposed to start transactions. */
ASSERT(current->journal_info != (void *)BTRFS_SEND_TRANS_STUB);
if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
return ERR_PTR(-EROFS);
if (current->journal_info &&
current->journal_info != (void *)BTRFS_SEND_TRANS_STUB) {
if (current->journal_info) {
WARN_ON(type & TRANS_EXTWRITERS);
h = current->journal_info;
h->use_count++;
@ -491,6 +493,7 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
smp_mb();
if (cur_trans->state >= TRANS_STATE_BLOCKED &&
may_wait_transaction(root, type)) {
current->journal_info = h;
btrfs_commit_transaction(h, root);
goto again;
}
@ -1615,11 +1618,6 @@ static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans,
int ret;
ret = btrfs_run_delayed_items(trans, root);
/*
* running the delayed items may have added new refs. account
* them now so that they hinder processing of more delayed refs
* as little as possible.
*/
if (ret)
return ret;

View File

@ -40,6 +40,7 @@
#include "rcu-string.h"
#include "math.h"
#include "dev-replace.h"
#include "sysfs.h"
static int init_first_rw_device(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
@ -554,12 +555,14 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
* This is ok to do without rcu read locked because we hold the
* uuid mutex so nothing we touch in here is going to disappear.
*/
if (orig_dev->name) {
name = rcu_string_strdup(orig_dev->name->str, GFP_NOFS);
if (!name) {
kfree(device);
goto error;
}
rcu_assign_pointer(device->name, name);
}
list_add(&device->dev_list, &fs_devices->devices);
device->fs_devices = fs_devices;
@ -1680,6 +1683,9 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
if (device->bdev)
device->fs_devices->open_devices--;
/* remove sysfs entry */
btrfs_kobj_rm_device(root->fs_info, device);
call_rcu(&device->rcu, free_device);
num_devices = btrfs_super_num_devices(root->fs_info->super_copy) - 1;
@ -2143,9 +2149,14 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
total_bytes = btrfs_super_num_devices(root->fs_info->super_copy);
btrfs_set_super_num_devices(root->fs_info->super_copy,
total_bytes + 1);
/* add sysfs device entry */
btrfs_kobj_add_device(root->fs_info, device);
mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
if (seeding_dev) {
char fsid_buf[BTRFS_UUID_UNPARSED_SIZE];
ret = init_first_rw_device(trans, root, device);
if (ret) {
btrfs_abort_transaction(trans, root, ret);
@ -2156,6 +2167,14 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
btrfs_abort_transaction(trans, root, ret);
goto error_trans;
}
/* Sprouting would change fsid of the mounted root,
* so rename the fsid on the sysfs
*/
snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU",
root->fs_info->fsid);
if (kobject_rename(&root->fs_info->super_kobj, fsid_buf))
goto error_trans;
} else {
ret = btrfs_add_device(trans, root, device);
if (ret) {
@ -2205,6 +2224,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
unlock_chunks(root);
btrfs_end_transaction(trans, root);
rcu_string_free(device->name);
btrfs_kobj_rm_device(root->fs_info, device);
kfree(device);
error:
blkdev_put(bdev, FMODE_EXCL);

View File

@ -136,7 +136,7 @@ static int zlib_compress_pages(struct list_head *ws,
if (workspace->def_strm.total_in > 8192 &&
workspace->def_strm.total_in <
workspace->def_strm.total_out) {
ret = -EIO;
ret = -E2BIG;
goto out;
}
/* we need another page for writing out. Test this

View File

@ -38,6 +38,7 @@ struct btrfs_ioctl_vol_args {
#define BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2)
#define BTRFS_FSID_SIZE 16
#define BTRFS_UUID_SIZE 16
#define BTRFS_UUID_UNPARSED_SIZE 37
#define BTRFS_QGROUP_INHERIT_SET_LIMITS (1ULL << 0)