Commit 8be57013 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull btrfs fixes from Chris Mason:
 "These are all from Filipe, and cover a few problems we've had reported
  on the list recently (along with ones he found on his own)"

* 'for-linus-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
  Btrfs: fix file corruption after cloning inline extents
  Btrfs: fix order by which delayed references are run
  Btrfs: fix list transaction->pending_ordered corruption
  Btrfs: fix memory leak in the extent_same ioctl
  Btrfs: fix shrinking truncate when the no_holes feature is enabled
parents dfe91c97 ed958762
...@@ -2296,9 +2296,22 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans, ...@@ -2296,9 +2296,22 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
static inline struct btrfs_delayed_ref_node * static inline struct btrfs_delayed_ref_node *
select_delayed_ref(struct btrfs_delayed_ref_head *head) select_delayed_ref(struct btrfs_delayed_ref_head *head)
{ {
struct btrfs_delayed_ref_node *ref;
if (list_empty(&head->ref_list)) if (list_empty(&head->ref_list))
return NULL; return NULL;
/*
* Select a delayed ref of type BTRFS_ADD_DELAYED_REF first.
* This is to prevent a ref count from going down to zero, which deletes
* the extent item from the extent tree, when there still are references
* to add, which would fail because they would not find the extent item.
*/
list_for_each_entry(ref, &head->ref_list, list) {
if (ref->action == BTRFS_ADD_DELAYED_REF)
return ref;
}
return list_entry(head->ref_list.next, struct btrfs_delayed_ref_node, return list_entry(head->ref_list.next, struct btrfs_delayed_ref_node,
list); list);
} }
......
...@@ -4209,7 +4209,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -4209,7 +4209,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
u64 extent_num_bytes = 0; u64 extent_num_bytes = 0;
u64 extent_offset = 0; u64 extent_offset = 0;
u64 item_end = 0; u64 item_end = 0;
u64 last_size = (u64)-1; u64 last_size = new_size;
u32 found_type = (u8)-1; u32 found_type = (u8)-1;
int found_extent; int found_extent;
int del_item; int del_item;
...@@ -4493,8 +4493,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, ...@@ -4493,8 +4493,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
btrfs_abort_transaction(trans, root, ret); btrfs_abort_transaction(trans, root, ret);
} }
error: error:
if (last_size != (u64)-1 && if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID)
btrfs_ordered_update_i_size(inode, last_size, NULL); btrfs_ordered_update_i_size(inode, last_size, NULL);
btrfs_free_path(path); btrfs_free_path(path);
......
...@@ -3090,7 +3090,7 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen, ...@@ -3090,7 +3090,7 @@ static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen,
static long btrfs_ioctl_file_extent_same(struct file *file, static long btrfs_ioctl_file_extent_same(struct file *file,
struct btrfs_ioctl_same_args __user *argp) struct btrfs_ioctl_same_args __user *argp)
{ {
struct btrfs_ioctl_same_args *same; struct btrfs_ioctl_same_args *same = NULL;
struct btrfs_ioctl_same_extent_info *info; struct btrfs_ioctl_same_extent_info *info;
struct inode *src = file_inode(file); struct inode *src = file_inode(file);
u64 off; u64 off;
...@@ -3120,6 +3120,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file, ...@@ -3120,6 +3120,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
if (IS_ERR(same)) { if (IS_ERR(same)) {
ret = PTR_ERR(same); ret = PTR_ERR(same);
same = NULL;
goto out; goto out;
} }
...@@ -3190,6 +3191,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file, ...@@ -3190,6 +3191,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
out: out:
mnt_drop_write_file(file); mnt_drop_write_file(file);
kfree(same);
return ret; return ret;
} }
...@@ -3586,6 +3588,20 @@ static int btrfs_clone(struct inode *src, struct inode *inode, ...@@ -3586,6 +3588,20 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
u64 trim = 0; u64 trim = 0;
u64 aligned_end = 0; u64 aligned_end = 0;
/*
* Don't copy an inline extent into an offset
* greater than zero. Having an inline extent
* at such an offset results in chaos as btrfs
* isn't prepared for such cases. Just skip
* this case for the same reasons as commented
* at btrfs_ioctl_clone().
*/
if (last_dest_end > 0) {
ret = -EOPNOTSUPP;
btrfs_end_transaction(trans, root);
goto out;
}
if (off > key.offset) { if (off > key.offset) {
skip = off - key.offset; skip = off - key.offset;
new_key.offset += skip; new_key.offset += skip;
......
...@@ -761,7 +761,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, ...@@ -761,7 +761,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
if (!list_empty(&trans->ordered)) { if (!list_empty(&trans->ordered)) {
spin_lock(&info->trans_lock); spin_lock(&info->trans_lock);
list_splice(&trans->ordered, &cur_trans->pending_ordered); list_splice_init(&trans->ordered, &cur_trans->pending_ordered);
spin_unlock(&info->trans_lock); spin_unlock(&info->trans_lock);
} }
...@@ -1866,7 +1866,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -1866,7 +1866,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
} }
spin_lock(&root->fs_info->trans_lock); spin_lock(&root->fs_info->trans_lock);
list_splice(&trans->ordered, &cur_trans->pending_ordered); list_splice_init(&trans->ordered, &cur_trans->pending_ordered);
if (cur_trans->state >= TRANS_STATE_COMMIT_START) { if (cur_trans->state >= TRANS_STATE_COMMIT_START) {
spin_unlock(&root->fs_info->trans_lock); spin_unlock(&root->fs_info->trans_lock);
atomic_inc(&cur_trans->use_count); atomic_inc(&cur_trans->use_count);
......
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