diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-07-18 00:46:57 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-07-18 00:46:57 -0400 |
commit | 8be5701342790eb42c67f4f8609e203d6a461a4a (patch) | |
tree | 5791328ce0ce868ea79c21911a232dcf3d2efe68 | |
parent | dfe91c9766578f2ec24ebf53b7fd07e288f170d1 (diff) | |
parent | ed958762644b404654a6f5d23e869f496fe127c6 (diff) |
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
-rw-r--r-- | fs/btrfs/extent-tree.c | 13 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 5 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 18 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 4 |
4 files changed, 34 insertions, 6 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 1c2bd1723e40..171312d51799 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -2296,9 +2296,22 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans, | |||
2296 | static inline struct btrfs_delayed_ref_node * | 2296 | static inline struct btrfs_delayed_ref_node * |
2297 | select_delayed_ref(struct btrfs_delayed_ref_head *head) | 2297 | select_delayed_ref(struct btrfs_delayed_ref_head *head) |
2298 | { | 2298 | { |
2299 | struct btrfs_delayed_ref_node *ref; | ||
2300 | |||
2299 | if (list_empty(&head->ref_list)) | 2301 | if (list_empty(&head->ref_list)) |
2300 | return NULL; | 2302 | return NULL; |
2301 | 2303 | ||
2304 | /* | ||
2305 | * Select a delayed ref of type BTRFS_ADD_DELAYED_REF first. | ||
2306 | * This is to prevent a ref count from going down to zero, which deletes | ||
2307 | * the extent item from the extent tree, when there still are references | ||
2308 | * to add, which would fail because they would not find the extent item. | ||
2309 | */ | ||
2310 | list_for_each_entry(ref, &head->ref_list, list) { | ||
2311 | if (ref->action == BTRFS_ADD_DELAYED_REF) | ||
2312 | return ref; | ||
2313 | } | ||
2314 | |||
2302 | return list_entry(head->ref_list.next, struct btrfs_delayed_ref_node, | 2315 | return list_entry(head->ref_list.next, struct btrfs_delayed_ref_node, |
2303 | list); | 2316 | list); |
2304 | } | 2317 | } |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b33c0cf02668..e33dff356460 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -4209,7 +4209,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, | |||
4209 | u64 extent_num_bytes = 0; | 4209 | u64 extent_num_bytes = 0; |
4210 | u64 extent_offset = 0; | 4210 | u64 extent_offset = 0; |
4211 | u64 item_end = 0; | 4211 | u64 item_end = 0; |
4212 | u64 last_size = (u64)-1; | 4212 | u64 last_size = new_size; |
4213 | u32 found_type = (u8)-1; | 4213 | u32 found_type = (u8)-1; |
4214 | int found_extent; | 4214 | int found_extent; |
4215 | int del_item; | 4215 | int del_item; |
@@ -4493,8 +4493,7 @@ out: | |||
4493 | btrfs_abort_transaction(trans, root, ret); | 4493 | btrfs_abort_transaction(trans, root, ret); |
4494 | } | 4494 | } |
4495 | error: | 4495 | error: |
4496 | if (last_size != (u64)-1 && | 4496 | if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) |
4497 | root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) | ||
4498 | btrfs_ordered_update_i_size(inode, last_size, NULL); | 4497 | btrfs_ordered_update_i_size(inode, last_size, NULL); |
4499 | 4498 | ||
4500 | btrfs_free_path(path); | 4499 | btrfs_free_path(path); |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 5d91776e12a2..0770c91586ca 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -3090,7 +3090,7 @@ out_unlock: | |||
3090 | static long btrfs_ioctl_file_extent_same(struct file *file, | 3090 | static long btrfs_ioctl_file_extent_same(struct file *file, |
3091 | struct btrfs_ioctl_same_args __user *argp) | 3091 | struct btrfs_ioctl_same_args __user *argp) |
3092 | { | 3092 | { |
3093 | struct btrfs_ioctl_same_args *same; | 3093 | struct btrfs_ioctl_same_args *same = NULL; |
3094 | struct btrfs_ioctl_same_extent_info *info; | 3094 | struct btrfs_ioctl_same_extent_info *info; |
3095 | struct inode *src = file_inode(file); | 3095 | struct inode *src = file_inode(file); |
3096 | u64 off; | 3096 | u64 off; |
@@ -3120,6 +3120,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file, | |||
3120 | 3120 | ||
3121 | if (IS_ERR(same)) { | 3121 | if (IS_ERR(same)) { |
3122 | ret = PTR_ERR(same); | 3122 | ret = PTR_ERR(same); |
3123 | same = NULL; | ||
3123 | goto out; | 3124 | goto out; |
3124 | } | 3125 | } |
3125 | 3126 | ||
@@ -3190,6 +3191,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file, | |||
3190 | 3191 | ||
3191 | out: | 3192 | out: |
3192 | mnt_drop_write_file(file); | 3193 | mnt_drop_write_file(file); |
3194 | kfree(same); | ||
3193 | return ret; | 3195 | return ret; |
3194 | } | 3196 | } |
3195 | 3197 | ||
@@ -3586,6 +3588,20 @@ process_slot: | |||
3586 | u64 trim = 0; | 3588 | u64 trim = 0; |
3587 | u64 aligned_end = 0; | 3589 | u64 aligned_end = 0; |
3588 | 3590 | ||
3591 | /* | ||
3592 | * Don't copy an inline extent into an offset | ||
3593 | * greater than zero. Having an inline extent | ||
3594 | * at such an offset results in chaos as btrfs | ||
3595 | * isn't prepared for such cases. Just skip | ||
3596 | * this case for the same reasons as commented | ||
3597 | * at btrfs_ioctl_clone(). | ||
3598 | */ | ||
3599 | if (last_dest_end > 0) { | ||
3600 | ret = -EOPNOTSUPP; | ||
3601 | btrfs_end_transaction(trans, root); | ||
3602 | goto out; | ||
3603 | } | ||
3604 | |||
3589 | if (off > key.offset) { | 3605 | if (off > key.offset) { |
3590 | skip = off - key.offset; | 3606 | skip = off - key.offset; |
3591 | new_key.offset += skip; | 3607 | new_key.offset += skip; |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index c0f18e7266b6..51e0f0d0053e 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -761,7 +761,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
761 | 761 | ||
762 | if (!list_empty(&trans->ordered)) { | 762 | if (!list_empty(&trans->ordered)) { |
763 | spin_lock(&info->trans_lock); | 763 | spin_lock(&info->trans_lock); |
764 | list_splice(&trans->ordered, &cur_trans->pending_ordered); | 764 | list_splice_init(&trans->ordered, &cur_trans->pending_ordered); |
765 | spin_unlock(&info->trans_lock); | 765 | spin_unlock(&info->trans_lock); |
766 | } | 766 | } |
767 | 767 | ||
@@ -1866,7 +1866,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1866 | } | 1866 | } |
1867 | 1867 | ||
1868 | spin_lock(&root->fs_info->trans_lock); | 1868 | spin_lock(&root->fs_info->trans_lock); |
1869 | list_splice(&trans->ordered, &cur_trans->pending_ordered); | 1869 | list_splice_init(&trans->ordered, &cur_trans->pending_ordered); |
1870 | if (cur_trans->state >= TRANS_STATE_COMMIT_START) { | 1870 | if (cur_trans->state >= TRANS_STATE_COMMIT_START) { |
1871 | spin_unlock(&root->fs_info->trans_lock); | 1871 | spin_unlock(&root->fs_info->trans_lock); |
1872 | atomic_inc(&cur_trans->use_count); | 1872 | atomic_inc(&cur_trans->use_count); |