Commit 859862dd authored by Linus Torvalds's avatar Linus Torvalds

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

Pull btrfs updates from Chris Mason:
 "The biggest change here is Josef's rework of the btrfs quota
  accounting, which improves the in-memory tracking of delayed extent
  operations.

  I had been working on Btrfs stack usage for a while, mostly because it
  had become impossible to do long stress runs with slab, lockdep and
  pagealloc debugging turned on without blowing the stack.  Even though
  you upgraded us to a nice king sized stack, I kept most of the
  patches.

  We also have some very hard to find corruption fixes, an awesome sysfs
  use after free, and the usual assortment of optimizations, cleanups
  and other fixes"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (80 commits)
  Btrfs: convert smp_mb__{before,after}_clear_bit
  Btrfs: fix scrub_print_warning to handle skinny metadata extents
  Btrfs: make fsync work after cloning into a file
  Btrfs: use right type to get real comparison
  Btrfs: don't check nodes for extent items
  Btrfs: don't release invalid page in btrfs_page_exists_in_range()
  Btrfs: make sure we retry if page is a retriable exception
  Btrfs: make sure we retry if we couldn't get the page
  btrfs: replace EINVAL with EOPNOTSUPP for dev_replace raid56
  trivial: fs/btrfs/ioctl.c: fix typo s/substract/subtract/
  Btrfs: fix leaf corruption after __btrfs_drop_extents
  Btrfs: ensure btrfs_prev_leaf doesn't miss 1 item
  Btrfs: fix clone to deal with holes when NO_HOLES feature is enabled
  btrfs: free delayed node outside of root->inode_lock
  btrfs: replace EINVAL with ERANGE for resize when ULLONG_MAX
  Btrfs: fix transaction leak during fsync call
  btrfs: Avoid trucating page or punching hole in a already existed hole.
  Btrfs: update commit root on snapshot creation after orphan cleanup
  Btrfs: ioctl, don't re-lock extent range when not necessary
  Btrfs: avoid visiting all extent items when cloning a range
  ...
parents 412dd3a6 c7548af6
...@@ -16,4 +16,4 @@ btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o ...@@ -16,4 +16,4 @@ btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \ btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \
tests/extent-buffer-tests.o tests/btrfs-tests.o \ tests/extent-buffer-tests.o tests/btrfs-tests.o \
tests/extent-io-tests.o tests/inode-tests.o tests/extent-io-tests.o tests/inode-tests.o tests/qgroup-tests.o
...@@ -79,13 +79,6 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans, ...@@ -79,13 +79,6 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
const char *name; const char *name;
char *value = NULL; char *value = NULL;
if (acl) {
ret = posix_acl_valid(acl);
if (ret < 0)
return ret;
ret = 0;
}
switch (type) { switch (type) {
case ACL_TYPE_ACCESS: case ACL_TYPE_ACCESS:
name = POSIX_ACL_XATTR_ACCESS; name = POSIX_ACL_XATTR_ACCESS;
......
...@@ -900,7 +900,11 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, ...@@ -900,7 +900,11 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
goto out; goto out;
BUG_ON(ret == 0); BUG_ON(ret == 0);
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
if (trans && likely(trans->type != __TRANS_DUMMY)) {
#else
if (trans) { if (trans) {
#endif
/* /*
* look if there are updates for this ref queued and lock the * look if there are updates for this ref queued and lock the
* head * head
...@@ -984,11 +988,12 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans, ...@@ -984,11 +988,12 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
goto out; goto out;
} }
if (ref->count && ref->parent) { if (ref->count && ref->parent) {
if (extent_item_pos && !ref->inode_list) { if (extent_item_pos && !ref->inode_list &&
ref->level == 0) {
u32 bsz; u32 bsz;
struct extent_buffer *eb; struct extent_buffer *eb;
bsz = btrfs_level_size(fs_info->extent_root, bsz = btrfs_level_size(fs_info->extent_root,
info_level); ref->level);
eb = read_tree_block(fs_info->extent_root, eb = read_tree_block(fs_info->extent_root,
ref->parent, bsz, 0); ref->parent, bsz, 0);
if (!eb || !extent_buffer_uptodate(eb)) { if (!eb || !extent_buffer_uptodate(eb)) {
...@@ -1404,6 +1409,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, ...@@ -1404,6 +1409,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
* returns <0 on error * returns <0 on error
*/ */
static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb, static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb,
struct btrfs_key *key,
struct btrfs_extent_item *ei, u32 item_size, struct btrfs_extent_item *ei, u32 item_size,
struct btrfs_extent_inline_ref **out_eiref, struct btrfs_extent_inline_ref **out_eiref,
int *out_type) int *out_type)
...@@ -1416,19 +1422,26 @@ static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb, ...@@ -1416,19 +1422,26 @@ static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb,
/* first call */ /* first call */
flags = btrfs_extent_flags(eb, ei); flags = btrfs_extent_flags(eb, ei);
if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
if (key->type == BTRFS_METADATA_ITEM_KEY) {
/* a skinny metadata extent */
*out_eiref =
(struct btrfs_extent_inline_ref *)(ei + 1);
} else {
WARN_ON(key->type != BTRFS_EXTENT_ITEM_KEY);
info = (struct btrfs_tree_block_info *)(ei + 1); info = (struct btrfs_tree_block_info *)(ei + 1);
*out_eiref = *out_eiref =
(struct btrfs_extent_inline_ref *)(info + 1); (struct btrfs_extent_inline_ref *)(info + 1);
}
} else { } else {
*out_eiref = (struct btrfs_extent_inline_ref *)(ei + 1); *out_eiref = (struct btrfs_extent_inline_ref *)(ei + 1);
} }
*ptr = (unsigned long)*out_eiref; *ptr = (unsigned long)*out_eiref;
if ((void *)*ptr >= (void *)ei + item_size) if ((unsigned long)(*ptr) >= (unsigned long)ei + item_size)
return -ENOENT; return -ENOENT;
} }
end = (unsigned long)ei + item_size; end = (unsigned long)ei + item_size;
*out_eiref = (struct btrfs_extent_inline_ref *)*ptr; *out_eiref = (struct btrfs_extent_inline_ref *)(*ptr);
*out_type = btrfs_extent_inline_ref_type(eb, *out_eiref); *out_type = btrfs_extent_inline_ref_type(eb, *out_eiref);
*ptr += btrfs_extent_inline_ref_size(*out_type); *ptr += btrfs_extent_inline_ref_size(*out_type);
...@@ -1447,8 +1460,8 @@ static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb, ...@@ -1447,8 +1460,8 @@ static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb,
* <0 on error. * <0 on error.
*/ */
int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb, int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
struct btrfs_extent_item *ei, u32 item_size, struct btrfs_key *key, struct btrfs_extent_item *ei,
u64 *out_root, u8 *out_level) u32 item_size, u64 *out_root, u8 *out_level)
{ {
int ret; int ret;
int type; int type;
...@@ -1459,7 +1472,7 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb, ...@@ -1459,7 +1472,7 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
return 1; return 1;
while (1) { while (1) {
ret = __get_extent_inline_ref(ptr, eb, ei, item_size, ret = __get_extent_inline_ref(ptr, eb, key, ei, item_size,
&eiref, &type); &eiref, &type);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -40,8 +40,8 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, ...@@ -40,8 +40,8 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
u64 *flags); u64 *flags);
int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb, int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
struct btrfs_extent_item *ei, u32 item_size, struct btrfs_key *key, struct btrfs_extent_item *ei,
u64 *out_root, u8 *out_level); u32 item_size, u64 *out_root, u8 *out_level);
int iterate_extent_inodes(struct btrfs_fs_info *fs_info, int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
u64 extent_item_objectid, u64 extent_item_objectid,
......
...@@ -284,4 +284,6 @@ static inline void btrfs_inode_resume_unlocked_dio(struct inode *inode) ...@@ -284,4 +284,6 @@ static inline void btrfs_inode_resume_unlocked_dio(struct inode *inode)
&BTRFS_I(inode)->runtime_flags); &BTRFS_I(inode)->runtime_flags);
} }
bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end);
#endif #endif
...@@ -1093,6 +1093,7 @@ static int btrfsic_process_metablock( ...@@ -1093,6 +1093,7 @@ static int btrfsic_process_metablock(
next_stack = next_stack =
btrfsic_stack_frame_alloc(); btrfsic_stack_frame_alloc();
if (NULL == next_stack) { if (NULL == next_stack) {
sf->error = -1;
btrfsic_release_block_ctx( btrfsic_release_block_ctx(
&sf-> &sf->
next_block_ctx); next_block_ctx);
...@@ -1190,8 +1191,10 @@ static int btrfsic_process_metablock( ...@@ -1190,8 +1191,10 @@ static int btrfsic_process_metablock(
sf->next_block_ctx.datav[0]; sf->next_block_ctx.datav[0];
next_stack = btrfsic_stack_frame_alloc(); next_stack = btrfsic_stack_frame_alloc();
if (NULL == next_stack) if (NULL == next_stack) {
sf->error = -1;
goto one_stack_frame_backwards; goto one_stack_frame_backwards;
}
next_stack->i = -1; next_stack->i = -1;
next_stack->block = sf->next_block; next_stack->block = sf->next_block;
......
...@@ -887,7 +887,7 @@ int btrfs_compress_pages(int type, struct address_space *mapping, ...@@ -887,7 +887,7 @@ int btrfs_compress_pages(int type, struct address_space *mapping,
workspace = find_workspace(type); workspace = find_workspace(type);
if (IS_ERR(workspace)) if (IS_ERR(workspace))
return -1; return PTR_ERR(workspace);
ret = btrfs_compress_op[type-1]->compress_pages(workspace, mapping, ret = btrfs_compress_op[type-1]->compress_pages(workspace, mapping,
start, len, pages, start, len, pages,
...@@ -923,7 +923,7 @@ static int btrfs_decompress_biovec(int type, struct page **pages_in, ...@@ -923,7 +923,7 @@ static int btrfs_decompress_biovec(int type, struct page **pages_in,
workspace = find_workspace(type); workspace = find_workspace(type);
if (IS_ERR(workspace)) if (IS_ERR(workspace))
return -ENOMEM; return PTR_ERR(workspace);
ret = btrfs_compress_op[type-1]->decompress_biovec(workspace, pages_in, ret = btrfs_compress_op[type-1]->decompress_biovec(workspace, pages_in,
disk_start, disk_start,
...@@ -945,7 +945,7 @@ int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page, ...@@ -945,7 +945,7 @@ int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page,
workspace = find_workspace(type); workspace = find_workspace(type);
if (IS_ERR(workspace)) if (IS_ERR(workspace))
return -ENOMEM; return PTR_ERR(workspace);
ret = btrfs_compress_op[type-1]->decompress(workspace, data_in, ret = btrfs_compress_op[type-1]->decompress(workspace, data_in,
dest_page, start_byte, dest_page, start_byte,
......
...@@ -224,7 +224,8 @@ static struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root) ...@@ -224,7 +224,8 @@ static struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root)
static void add_root_to_dirty_list(struct btrfs_root *root) static void add_root_to_dirty_list(struct btrfs_root *root)
{ {
spin_lock(&root->fs_info->trans_lock); spin_lock(&root->fs_info->trans_lock);
if (root->track_dirty && list_empty(&root->dirty_list)) { if (test_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state) &&
list_empty(&root->dirty_list)) {
list_add(&root->dirty_list, list_add(&root->dirty_list,
&root->fs_info->dirty_cowonly_roots); &root->fs_info->dirty_cowonly_roots);
} }
...@@ -246,9 +247,10 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans, ...@@ -246,9 +247,10 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
int level; int level;
struct btrfs_disk_key disk_key; struct btrfs_disk_key disk_key;
WARN_ON(root->ref_cows && trans->transid != WARN_ON(test_bit(BTRFS_ROOT_REF_COWS, &root->state) &&
root->fs_info->running_transaction->transid); trans->transid != root->fs_info->running_transaction->transid);
WARN_ON(root->ref_cows && trans->transid != root->last_trans); WARN_ON(test_bit(BTRFS_ROOT_REF_COWS, &root->state) &&
trans->transid != root->last_trans);
level = btrfs_header_level(buf); level = btrfs_header_level(buf);
if (level == 0) if (level == 0)
...@@ -354,43 +356,13 @@ static inline void tree_mod_log_write_unlock(struct btrfs_fs_info *fs_info) ...@@ -354,43 +356,13 @@ static inline void tree_mod_log_write_unlock(struct btrfs_fs_info *fs_info)
} }
/* /*
* Increment the upper half of tree_mod_seq, set lower half zero. * Pull a new tree mod seq number for our operation.
*
* Must be called with fs_info->tree_mod_seq_lock held.
*/ */
static inline u64 btrfs_inc_tree_mod_seq_major(struct btrfs_fs_info *fs_info) static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info)
{
u64 seq = atomic64_read(&fs_info->tree_mod_seq);
seq &= 0xffffffff00000000ull;
seq += 1ull << 32;
atomic64_set(&fs_info->tree_mod_seq, seq);
return seq;
}
/*
* Increment the lower half of tree_mod_seq.
*
* Must be called with fs_info->tree_mod_seq_lock held. The way major numbers
* are generated should not technically require a spin lock here. (Rationale:
* incrementing the minor while incrementing the major seq number is between its
* atomic64_read and atomic64_set calls doesn't duplicate sequence numbers, it
* just returns a unique sequence number as usual.) We have decided to leave
* that requirement in here and rethink it once we notice it really imposes a
* problem on some workload.
*/
static inline u64 btrfs_inc_tree_mod_seq_minor(struct btrfs_fs_info *fs_info)
{ {
return atomic64_inc_return(&fs_info->tree_mod_seq); return atomic64_inc_return(&fs_info->tree_mod_seq);
} }
/*
* return the last minor in the previous major tree_mod_seq number
*/
u64 btrfs_tree_mod_seq_prev(u64 seq)
{
return (seq & 0xffffffff00000000ull) - 1ull;
}
/* /*
* This adds a new blocker to the tree mod log's blocker list if the @elem * This adds a new blocker to the tree mod log's blocker list if the @elem
* passed does not already have a sequence number set. So when a caller expects * passed does not already have a sequence number set. So when a caller expects
...@@ -402,19 +374,16 @@ u64 btrfs_tree_mod_seq_prev(u64 seq) ...@@ -402,19 +374,16 @@ u64 btrfs_tree_mod_seq_prev(u64 seq)
u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info, u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info,
struct seq_list *elem) struct seq_list *elem)
{ {
u64 seq;
tree_mod_log_write_lock(fs_info); tree_mod_log_write_lock(fs_info);
spin_lock(&fs_info->tree_mod_seq_lock); spin_lock(&fs_info->tree_mod_seq_lock);
if (!elem->seq) { if (!elem->seq) {
elem->seq = btrfs_inc_tree_mod_seq_major(fs_info); elem->seq = btrfs_inc_tree_mod_seq(fs_info);
list_add_tail(&elem->list, &fs_info->tree_mod_seq_list); list_add_tail(&elem->list, &fs_info->tree_mod_seq_list);
} }
seq = btrfs_inc_tree_mod_seq_minor(fs_info);
spin_unlock(&fs_info->tree_mod_seq_lock); spin_unlock(&fs_info->tree_mod_seq_lock);
tree_mod_log_write_unlock(fs_info); tree_mod_log_write_unlock(fs_info);
return seq; return elem->seq;
} }
void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,
...@@ -487,9 +456,7 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm) ...@@ -487,9 +456,7 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
BUG_ON(!tm); BUG_ON(!tm);
spin_lock(&fs_info->tree_mod_seq_lock); tm->seq = btrfs_inc_tree_mod_seq(fs_info);
tm->seq = btrfs_inc_tree_mod_seq_minor(fs_info);
spin_unlock(&fs_info->tree_mod_seq_lock);
tm_root = &fs_info->tree_mod_log; tm_root = &fs_info->tree_mod_log;
new = &tm_root->rb_node; new = &tm_root->rb_node;
...@@ -997,14 +964,14 @@ int btrfs_block_can_be_shared(struct btrfs_root *root, ...@@ -997,14 +964,14 @@ int btrfs_block_can_be_shared(struct btrfs_root *root,
* snapshot and the block was not allocated by tree relocation, * snapshot and the block was not allocated by tree relocation,
* we know the block is not shared. * we know the block is not shared.
*/ */
if (root->ref_cows && if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) &&
buf != root->node && buf != root->commit_root && buf != root->node && buf != root->commit_root &&
(btrfs_header_generation(buf) <= (btrfs_header_generation(buf) <=
btrfs_root_last_snapshot(&root->root_item) || btrfs_root_last_snapshot(&root->root_item) ||
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)))
return 1; return 1;
#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 #ifdef BTRFS_COMPAT_EXTENT_TREE_V0
if (root->ref_cows && if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) &&
btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV)
return 1; return 1;
#endif #endif
...@@ -1146,9 +1113,10 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -1146,9 +1113,10 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
btrfs_assert_tree_locked(buf); btrfs_assert_tree_locked(buf);
WARN_ON(root->ref_cows && trans->transid != WARN_ON(test_bit(BTRFS_ROOT_REF_COWS, &root->state) &&
root->fs_info->running_transaction->transid); trans->transid != root->fs_info->running_transaction->transid);
WARN_ON(root->ref_cows && trans->transid != root->last_trans); WARN_ON(test_bit(BTRFS_ROOT_REF_COWS, &root->state) &&
trans->transid != root->last_trans);
level = btrfs_header_level(buf); level = btrfs_header_level(buf);
...@@ -1193,7 +1161,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, ...@@ -1193,7 +1161,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
if (root->ref_cows) { if (test_bit(BTRFS_ROOT_REF_COWS, &root->state)) {
ret = btrfs_reloc_cow_block(trans, root, buf, cow); ret = btrfs_reloc_cow_block(trans, root, buf, cow);
if (ret) if (ret)
return ret; return ret;
...@@ -1538,6 +1506,10 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans, ...@@ -1538,6 +1506,10 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_root *root,
struct extent_buffer *buf) struct extent_buffer *buf)
{ {
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state)))
return 0;
#endif
/* ensure we can see the force_cow */ /* ensure we can see the force_cow */
smp_rmb(); smp_rmb();
...@@ -1556,7 +1528,7 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans, ...@@ -1556,7 +1528,7 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) && !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) &&
!(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID && !(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID &&
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)) && btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)) &&
!root->force_cow) !test_bit(BTRFS_ROOT_FORCE_COW, &root->state))
return 0; return 0;
return 1; return 1;
} }
...@@ -5125,7 +5097,17 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) ...@@ -5125,7 +5097,17 @@ int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
return ret; return ret;
btrfs_item_key(path->nodes[0], &found_key, 0); btrfs_item_key(path->nodes[0], &found_key, 0);
ret = comp_keys(&found_key, &key); ret = comp_keys(&found_key, &key);
if (ret < 0) /*
* We might have had an item with the previous key in the tree right
* before we released our path. And after we released our path, that
* item might have been pushed to the first slot (0) of the leaf we
* were holding due to a tree balance. Alternatively, an item with the
* previous key can exist as the only element of a leaf (big fat item).
* Therefore account for these 2 cases, so that our callers (like
* btrfs_previous_item) don't miss an existing item with a key matching
* the previous key we computed above.
*/
if (ret <= 0)
return 0; return 0;
return 1; return 1;
} }
...@@ -5736,6 +5718,24 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, ...@@ -5736,6 +5718,24 @@ int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
ret = 0; ret = 0;
goto done; goto done;
} }
/*
* So the above check misses one case:
* - after releasing the path above, someone has removed the item that
* used to be at the very end of the block, and balance between leafs
* gets another one with bigger key.offset to replace it.
*
* This one should be returned as well, or we can get leaf corruption
* later(esp. in __btrfs_drop_extents()).
*
* And a bit more explanation about this check,
* with ret > 0, the key isn't found, the path points to the slot
* where it should be inserted, so the path->slots[0] item must be the
* bigger one.
*/
if (nritems > 0 && ret > 0 && path->slots[0] == nritems - 1) {
ret = 0;
goto done;
}
while (level < BTRFS_MAX_LEVEL) { while (level < BTRFS_MAX_LEVEL) {
if (!path->nodes[level]) { if (!path->nodes[level]) {
......
This diff is collapsed.
...@@ -149,8 +149,8 @@ static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node( ...@@ -149,8 +149,8 @@ static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
spin_lock(&root->inode_lock); spin_lock(&root->inode_lock);
ret = radix_tree_insert(&root->delayed_nodes_tree, ino, node); ret = radix_tree_insert(&root->delayed_nodes_tree, ino, node);
if (ret == -EEXIST) { if (ret == -EEXIST) {
kmem_cache_free(delayed_node_cache, node);
spin_unlock(&root->inode_lock); spin_unlock(&root->inode_lock);
kmem_cache_free(delayed_node_cache, node);
radix_tree_preload_end(); radix_tree_preload_end();
goto again; goto again;
} }
...@@ -267,14 +267,17 @@ static void __btrfs_release_delayed_node( ...@@ -267,14 +267,17 @@ static void __btrfs_release_delayed_node(
mutex_unlock(&delayed_node->mutex); mutex_unlock(&delayed_node->mutex);
if (atomic_dec_and_test(&delayed_node->refs)) { if (atomic_dec_and_test(&delayed_node->refs)) {
bool free = false;
struct btrfs_root *root = delayed_node->root; struct btrfs_root *root = delayed_node->root;
spin_lock(&root->inode_lock); spin_lock(&root->inode_lock);
if (atomic_read(&delayed_node->refs) == 0) { if (atomic_read(&delayed_node->refs) == 0) {
radix_tree_delete(&root->delayed_nodes_tree, radix_tree_delete(&root->delayed_nodes_tree,
delayed_node->inode_id); delayed_node->inode_id);
kmem_cache_free(delayed_node_cache, delayed_node); free = true;
} }
spin_unlock(&root->inode_lock); spin_unlock(&root->inode_lock);
if (free)
kmem_cache_free(delayed_node_cache, delayed_node);
} }
} }
......
...@@ -106,6 +106,10 @@ static int comp_entry(struct btrfs_delayed_ref_node *ref2, ...@@ -106,6 +106,10 @@ static int comp_entry(struct btrfs_delayed_ref_node *ref2,
return -1; return -1;
if (ref1->type > ref2->type) if (ref1->type > ref2->type)
return 1; return 1;
if (ref1->no_quota > ref2->no_quota)
return 1;
if (ref1->no_quota < ref2->no_quota)
return -1;
/* merging of sequenced refs is not allowed */ /* merging of sequenced refs is not allowed */
if (compare_seq) { if (compare_seq) {
if (ref1->seq < ref2->seq) if (ref1->seq < ref2->seq)
...@@ -635,7 +639,7 @@ add_delayed_tree_ref(struct btrfs_fs_info *fs_info, ...@@ -635,7 +639,7 @@ add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
struct btrfs_delayed_ref_head *head_ref, struct btrfs_delayed_ref_head *head_ref,
struct btrfs_delayed_ref_node *ref, u64 bytenr, struct btrfs_delayed_ref_node *ref, u64 bytenr,
u64 num_bytes, u64 parent, u64 ref_root, int level, u64 num_bytes, u64 parent, u64 ref_root, int level,
int action, int for_cow) int action, int no_quota)
{ {
struct btrfs_delayed_ref_node *existing; struct btrfs_delayed_ref_node *existing;
struct btrfs_delayed_tree_ref *full_ref; struct btrfs_delayed_tree_ref *full_ref;
...@@ -645,6 +649,8 @@ add_delayed_tree_ref(struct btrfs_fs_info *fs_info, ...@@ -645,6 +649,8 @@ add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
if (action == BTRFS_ADD_DELAYED_EXTENT) if (action == BTRFS_ADD_DELAYED_EXTENT)
action = BTRFS_ADD_DELAYED_REF; action = BTRFS_ADD_DELAYED_REF;
if (is_fstree(ref_root))
seq = atomic64_read(&fs_info->tree_mod_seq);
delayed_refs = &trans->transaction->delayed_refs; delayed_refs = &trans->transaction->delayed_refs;
/* first set the basic ref node struct up */ /* first set the basic ref node struct up */
...@@ -655,9 +661,7 @@ add_delayed_tree_ref(struct btrfs_fs_info *fs_info, ...@@ -655,9 +661,7 @@ add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
ref->action = action; ref->action = action;
ref->is_head = 0; ref->is_head = 0;
ref->in_tree = 1; ref->in_tree = 1;
ref->no_quota = no_quota;
if (need_ref_seq(for_cow, ref_root))
seq = btrfs_get_tree_mod_seq(fs_info, &trans->delayed_ref_elem);
ref->seq = seq; ref->seq = seq;
full_ref = btrfs_delayed_node_to_tree_ref(ref); full_ref = btrfs_delayed_node_to_tree_ref(ref);
...@@ -697,7 +701,7 @@ add_delayed_data_ref(struct btrfs_fs_info *fs_info, ...@@ -697,7 +701,7 @@ add_delayed_data_ref(struct btrfs_fs_info *fs_info,
struct btrfs_delayed_ref_head *head_ref, struct btrfs_delayed_ref_head *head_ref,
struct btrfs_delayed_ref_node *ref, u64 bytenr, struct btrfs_delayed_ref_node *ref, u64 bytenr,
u64 num_bytes, u64 parent, u64 ref_root, u64 owner, u64 num_bytes, u64 parent, u64 ref_root, u64 owner,
u64 offset, int action, int for_cow) u64 offset, int action, int no_quota)
{ {
struct btrfs_delayed_ref_node *existing; struct btrfs_delayed_ref_node *existing;
struct btrfs_delayed_data_ref *full_ref; struct btrfs_delayed_data_ref *full_ref;
...@@ -709,6 +713,9 @@ add_delayed_data_ref(struct btrfs_fs_info *fs_info, ...@@ -709,6 +713,9 @@ add_delayed_data_ref(struct btrfs_fs_info *fs_info,
delayed_refs = &trans->transaction->delayed_refs; delayed_refs = &trans->transaction->delayed_refs;
if (is_fstree(ref_root))
seq = atomic64_read(&fs_info->tree_mod_seq);
/* first set the basic ref node struct up */ /* first set the basic ref node struct up */
atomic_set(&ref->refs, 1); atomic_set(&ref->refs, 1);
ref->bytenr = bytenr; ref->bytenr = bytenr;
...@@ -717,9 +724,7 @@ add_delayed_data_ref(struct btrfs_fs_info *fs_info, ...@@ -717,9 +724,7 @@ add_delayed_data_ref(struct btrfs_fs_info *fs_info,
ref->action = action; ref->action = action;
ref->is_head = 0; ref->is_head = 0;
ref->in_tree = 1; ref->in_tree = 1;
ref->no_quota = no_quota;
if (need_ref_seq(for_cow, ref_root))
seq = btrfs_get_tree_mod_seq(fs_info, &trans->delayed_ref_elem);
ref->seq = seq; ref->seq = seq;
full_ref = btrfs_delayed_node_to_data_ref(ref); full_ref = btrfs_delayed_node_to_data_ref(ref);
...@@ -762,12 +767,15 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info, ...@@ -762,12 +767,15 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
u64 bytenr, u64 num_bytes, u64 parent, u64 bytenr, u64 num_bytes, u64 parent,
u64 ref_root, int level, int action, u64 ref_root, int level, int action,
struct btrfs_delayed_extent_op *extent_op, struct btrfs_delayed_extent_op *extent_op,
int for_cow) int no_quota)
{ {
struct btrfs_delayed_tree_ref *ref; struct btrfs_delayed_tree_ref *ref;
struct btrfs_delayed_ref_head *head_ref; struct btrfs_delayed_ref_head *head_ref;
struct btrfs_delayed_ref_root *delayed_refs; struct btrfs_delayed_ref_root *delayed_refs;
if (!is_fstree(ref_root) || !fs_info->quota_enabled)
no_quota = 0;
BUG_ON(extent_op && extent_op->is_data); BUG_ON(extent_op && extent_op->is_data);
ref = kmem_cache_alloc(btrfs_delayed_tree_ref_cachep, GFP_NOFS); ref = kmem_cache_alloc(btrfs_delayed_tree_ref_cachep, GFP_NOFS);
if (!ref) if (!ref)
...@@ -793,10 +801,8 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info, ...@@ -793,10 +801,8 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
add_delayed_tree_ref(fs_info, trans, head_ref, &ref->node, bytenr, add_delayed_tree_ref(fs_info, trans, head_ref, &ref->node, bytenr,
num_bytes, parent, ref_root, level, action, num_bytes, parent, ref_root, level, action,
for_cow); no_quota);
spin_unlock(&delayed_refs->lock); spin_unlock(&delayed_refs->lock);
if (need_ref_seq(for_cow, ref_root))
btrfs_qgroup_record_ref(trans, &ref->node, extent_op);
return 0; return 0;
} }
...@@ -810,12 +816,15 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info, ...@@ -810,12 +816,15 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
u64 parent, u64 ref_root, u64 parent, u64 ref_root,
u64 owner, u64 offset, int action, u64 owner, u64 offset, int action,
struct btrfs_delayed_extent_op *extent_op, struct btrfs_delayed_extent_op *extent_op,
int for_cow) int no_quota)
{ {
struct btrfs_delayed_data_ref *ref; struct btrfs_delayed_data_ref *ref;
struct btrfs_delayed_ref_head *head_ref; struct btrfs_delayed_ref_head *head_ref;
struct btrfs_delayed_ref_root *delayed_refs; struct btrfs_delayed_ref_root *delayed_refs;
if (!is_fstree(ref_root) || !fs_info->quota_enabled)
no_quota = 0;
BUG_ON(extent_op && !extent_op->is_data); BUG_ON(extent_op && !extent_op->is_data);
ref = kmem_cache_alloc(btrfs_delayed_data_ref_cachep, GFP_NOFS); ref = kmem_cache_alloc(btrfs_delayed_data_ref_cachep, GFP_NOFS);
if (!ref) if (!ref)
...@@ -841,10 +850,8 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info, ...@@ -841,10 +850,8 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
add_delayed_data_ref(fs_info, trans, head_ref, &ref->node, bytenr, add_delayed_data_ref(fs_info, trans, head_ref, &ref->node, bytenr,
num_bytes, parent, ref_root, owner, offset, num_bytes, parent, ref_root, owner, offset,
action, for_cow); action, no_quota);
spin_unlock(&delayed_refs->lock); spin_unlock(&delayed_refs->lock);
if (need_ref_seq(for_cow, ref_root))
btrfs_qgroup_record_ref(trans, &ref->node, extent_op);
return 0; return 0;
} }
......
...@@ -52,6 +52,7 @@ struct btrfs_delayed_ref_node { ...@@ -52,6 +52,7 @@ struct btrfs_delayed_ref_node {
unsigned int action:8; unsigned int action:8;
unsigned int type:8; unsigned int type:8;
unsigned int no_quota:1;
/* is this node still in the rbtree? */ /* is this node still in the rbtree? */
unsigned int is_head:1; unsigned int is_head:1;
unsigned int in_tree:1; unsigned int in_tree:1;
...@@ -196,14 +197,14 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info, ...@@ -196,14 +197,14 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
u64 bytenr, u64 num_bytes, u64 parent, u64 bytenr, u64 num_bytes, u64 parent,
u64 ref_root, int level, int action, u64 ref_root, int level, int action,
struct btrfs_delayed_extent_op *extent_op, struct btrfs_delayed_extent_op *extent_op,
int for_cow); int no_quota);
int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info, int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
struct btrfs_trans_handle *trans, struct btrfs_trans_handle *trans,
u64 bytenr, u64 num_bytes, u64 bytenr, u64 num_bytes,
u64 parent, u64 ref_root, u64 parent, u64 ref_root,
u64 owner, u64 offset, int action, u64 owner, u64 offset, int action,
struct btrfs_delayed_extent_op *extent_op, struct btrfs_delayed_extent_op *extent_op,
int for_cow); int no_quota);
int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info, int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
struct btrfs_trans_handle *trans, struct btrfs_trans_handle *trans,
u64 bytenr, u64 num_bytes, u64 bytenr, u64 num_bytes,
...@@ -230,25 +231,6 @@ int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, ...@@ -230,25 +231,6 @@ int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info,
struct btrfs_delayed_ref_root *delayed_refs, struct btrfs_delayed_ref_root *delayed_refs,
u64 seq); u64 seq);
/*
* delayed refs with a ref_seq > 0 must be held back during backref walking.
* this only applies to items in one of the fs-trees. for_cow items never need
* to be held back, so they won't get a ref_seq number.
*/
static inline int need_ref_seq(int for_cow, u64 rootid)
{
if (for_cow)
return 0;
if (rootid == BTRFS_FS_TREE_OBJECTID)
return 1;
if ((s64)rootid >= (s64)BTRFS_FIRST_FREE_OBJECTID)
return 1;
return 0;
}
/* /*
* a node might live in a head or a regular ref, this lets you * a node might live in a head or a regular ref, this lets you
* test for the proper type to use. * test for the proper type to use.
......
...@@ -313,7 +313,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root, ...@@ -313,7 +313,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
if (btrfs_fs_incompat(fs_info, RAID56)) { if (btrfs_fs_incompat(fs_info, RAID56)) {
btrfs_warn(fs_info, "dev_replace cannot yet handle RAID5/RAID6"); btrfs_warn(fs_info, "dev_replace cannot yet handle RAID5/RAID6");
return -EINVAL; return -EOPNOTSUPP;
} }
switch (args->start.cont_reading_from_srcdev_mode) { switch (args->start.cont_reading_from_srcdev_mode) {
......
This diff is collapsed.
...@@ -68,6 +68,7 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root, ...@@ -68,6 +68,7 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root,
int btrfs_init_fs_root(struct btrfs_root *root); int btrfs_init_fs_root(struct btrfs_root *root);
int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info, int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_root *root); struct btrfs_root *root);
void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info);
struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_key *key, struct btrfs_key *key,
......
This diff is collapsed.
This diff is collapsed.
...@@ -350,5 +350,7 @@ noinline u64 find_lock_delalloc_range(struct inode *inode, ...@@ -350,5 +350,7 @@ noinline u64 find_lock_delalloc_range(struct inode *inode,
struct extent_io_tree *tree, struct extent_io_tree *tree,
struct page *locked_page, u64 *start, struct page *locked_page, u64 *start,
u64 *end, u64 max_bytes); u64 *end, u64 max_bytes);
struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info,
u64 start, unsigned long len);
#endif #endif
#endif #endif
...@@ -281,10 +281,10 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, ...@@ -281,10 +281,10 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
found: found:
csum += count * csum_size; csum += count * csum_size;
nblocks -= count; nblocks -= count;
bio_index += count;
while (count--) { while (count--) {
disk_bytenr += bvec->bv_len; disk_bytenr += bvec->bv_len;
offset += bvec->bv_len; offset += bvec->bv_len;
bio_index++;
bvec++; bvec++;
} }
} }
...@@ -750,7 +750,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, ...@@ -750,7 +750,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
int slot = path->slots[0] + 1; int slot = path->slots[0] + 1;
/* we didn't find a csum item, insert one */ /* we didn't find a csum item, insert one */
nritems = btrfs_header_nritems(path->nodes[0]); nritems = btrfs_header_nritems(path->nodes[0]);
if (path->slots[0] >= nritems - 1) { if (!nritems || (path->slots[0] >= nritems - 1)) {
ret = btrfs_next_leaf(root, path); ret = btrfs_next_leaf(root, path);
if (ret == 1) if (ret == 1)
found_next = 1; found_next = 1;
...@@ -885,3 +885,79 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, ...@@ -885,3 +885,79 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
fail_unlock: fail_unlock:
goto out; goto out;
} }
void btrfs_extent_item_to_extent_map(struct inode *inode,
const struct btrfs_path *path,
struct btrfs_file_extent_item *fi,
const bool new_inline,
struct extent_map *em)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
struct extent_buffer *leaf = path->nodes[0];
const int slot = path->slots[0];
struct btrfs_key key;
u64 extent_start, extent_end;
u64 bytenr;
u8 type = btrfs_file_extent_type(leaf, fi);
int compress_type = btrfs_file_extent_compression(leaf, fi);
em->bdev = root->fs_info->fs_devices->latest_bdev;
btrfs_item_key_to_cpu(leaf, &key, slot);
extent_start = key.offset;
if (type == BTRFS_FILE_EXTENT_REG ||
type == BTRFS_FILE_EXTENT_PREALLOC) {
extent_end = extent_start +
btrfs_file_extent_num_bytes(leaf, fi);
} else if (type == BTRFS_FILE_EXTENT_INLINE) {
size_t size;
size = btrfs_file_extent_inline_len(leaf, slot, fi);
extent_end = ALIGN(extent_start + size, root->sectorsize);
}
em->ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi);
if (type == BTRFS_FILE_EXTENT_REG ||
type == BTRFS_FILE_EXTENT_PREALLOC) {
em->start = extent_start;
em->len = extent_end - extent_start;
em->orig_start = extent_start -
btrfs_file_extent_offset(leaf, fi);
em->orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi);
bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
if (bytenr == 0) {
em->block_start = EXTENT_MAP_HOLE;
return;
}
if (compress_type != BTRFS_COMPRESS_NONE) {
set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
em->compress_type = compress_type;
em->block_start = bytenr;
em->block_len = em->orig_block_len;
} else {
bytenr += btrfs_file_extent_offset(leaf, fi);
em->block_start = bytenr;
em->block_len = em->len;
if (type == BTRFS_FILE_EXTENT_PREALLOC)
set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
}
} else if (type == BTRFS_FILE_EXTENT_INLINE) {
em->block_start = EXTENT_MAP_INLINE;
em->start = extent_start;
em->len = extent_end - extent_start;
/*
* Initialize orig_start and block_len with the same values
* as in inode.c:btrfs_get_extent().
*/
em->orig_start = EXTENT_MAP_HOLE;
em->block_len = (u64)-1;
if (!new_inline && compress_type != BTRFS_COMPRESS_NONE) {
set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
em->compress_type = compress_type;
}
} else {
btrfs_err(root->fs_info,
"unknown file extent item type %d, inode %llu, offset %llu, root %llu",
type, btrfs_ino(inode), extent_start,
root->root_key.objectid);
}
}
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "tree-log.h" #include "tree-log.h"
#include "locking.h" #include "locking.h"
#include "volumes.h" #include "volumes.h"
#include "qgroup.h"
static struct kmem_cache *btrfs_inode_defrag_cachep; static struct kmem_cache *btrfs_inode_defrag_cachep;
/* /*
...@@ -715,7 +716,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -715,7 +716,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
int recow; int recow;
int ret; int ret;
int modify_tree = -1; int modify_tree = -1;
int update_refs = (root->ref_cows || root == root->fs_info->tree_root); int update_refs;
int found = 0; int found = 0;
int leafs_visited = 0; int leafs_visited = 0;
...@@ -725,6 +726,8 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -725,6 +726,8 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
if (start >= BTRFS_I(inode)->disk_i_size && !replace_extent) if (start >= BTRFS_I(inode)->disk_i_size && !replace_extent)
modify_tree = 0; modify_tree = 0;
update_refs = (test_bit(BTRFS_ROOT_REF_COWS, &root->state) ||
root == root->fs_info->tree_root);
while (1) { while (1) {
recow = 0; recow = 0;
ret = btrfs_lookup_file_extent(trans, root, path, ino, ret = btrfs_lookup_file_extent(trans, root, path, ino,
...@@ -781,6 +784,18 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -781,6 +784,18 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
extent_end = search_start; extent_end = search_start;
} }
/*
* Don't skip extent items representing 0 byte lengths. They
* used to be created (bug) if while punching holes we hit
* -ENOSPC condition. So if we find one here, just ensure we
* delete it, otherwise we would insert a new file extent item
* with the same key (offset) as that 0 bytes length file
* extent item in the call to setup_items_for_insert() later
* in this function.
*/
if (extent_end == key.offset && extent_end >= search_start)
goto delete_extent_item;
if (extent_end <= search_start) { if (extent_end <= search_start) {
path->slots[0]++; path->slots[0]++;
goto next_slot; goto next_slot;
...@@ -836,7 +851,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -836,7 +851,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
disk_bytenr, num_bytes, 0, disk_bytenr, num_bytes, 0,
root->root_key.objectid, root->root_key.objectid,
new_key.objectid, new_key.objectid,
start - extent_offset, 0); start - extent_offset, 1);
BUG_ON(ret); /* -ENOMEM */ BUG_ON(ret); /* -ENOMEM */
} }
key.offset = start; key.offset = start;
...@@ -894,6 +909,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -894,6 +909,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
* | ------ extent ------ | * | ------ extent ------ |
*/ */
if (start <= key.offset && end >= extent_end) { if (start <= key.offset && end >= extent_end) {
delete_extent_item:
if (del_nr == 0) { if (del_nr == 0) {
del_slot = path->slots[0]; del_slot = path->slots[0];
del_nr = 1; del_nr = 1;
...@@ -1192,7 +1208,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, ...@@ -1192,7 +1208,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0, ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
root->root_key.objectid, root->root_key.objectid,
ino, orig_offset, 0); ino, orig_offset, 1);
BUG_ON(ret); /* -ENOMEM */ BUG_ON(ret); /* -ENOMEM */
if (split == start) { if (split == start) {
...@@ -2010,9 +2026,11 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -2010,9 +2026,11 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
if (!full_sync) { if (!full_sync) {
ret = btrfs_wait_ordered_range(inode, start, ret = btrfs_wait_ordered_range(inode, start,
end - start + 1); end - start + 1);
if (ret) if (ret) {
btrfs_end_transaction(trans, root);
goto out; goto out;
} }
}
ret = btrfs_commit_transaction(trans, root); ret = btrfs_commit_transaction(trans, root);
} else { } else {
ret = btrfs_end_transaction(trans, root); ret = btrfs_end_transaction(trans, root);
...@@ -2169,6 +2187,37 @@ static int fill_holes(struct btrfs_trans_handle *trans, struct inode *inode, ...@@ -2169,6 +2187,37 @@ static int fill_holes(struct btrfs_trans_handle *trans, struct inode *inode,
return 0; return 0;
} }
/*
* Find a hole extent on given inode and change start/len to the end of hole
* extent.(hole/vacuum extent whose em->start <= start &&
* em->start + em->len > start)
* When a hole extent is found, return 1 and modify start/len.
*/
static int find_first_non_hole(struct inode *inode, u64 *start, u64 *len)
{
struct extent_map *em;
int ret = 0;
em = btrfs_get_extent(inode, NULL, 0, *start, *len, 0);
if (IS_ERR_OR_NULL(em)) {
if (!em)
ret = -ENOMEM;
else
ret = PTR_ERR(em);
return ret;
}
/* Hole or vacuum extent(only exists in no-hole mode) */
if (em->block_start == EXTENT_MAP_HOLE) {
ret = 1;
*len = em->start + em->len > *start + *len ?
0 : *start + *len - em->start - em->len;
*start = em->start + em->len;
}
free_extent_map(em);
return ret;
}
static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
{ {
struct btrfs_root *root = BTRFS_I(inode)->root; struct btrfs_root *root = BTRFS_I(inode)->root;
...@@ -2176,25 +2225,42 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) ...@@ -2176,25 +2225,42 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_block_rsv *rsv; struct btrfs_block_rsv *rsv;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
u64 lockstart = round_up(offset, BTRFS_I(inode)->root->sectorsize); u64 lockstart;
u64 lockend = round_down(offset + len, u64 lockend;
BTRFS_I(inode)->root->sectorsize) - 1; u64 tail_start;
u64 cur_offset = lockstart; u64 tail_len;
u64 orig_start = offset;
u64 cur_offset;
u64 min_size = btrfs_calc_trunc_metadata_size(root, 1); u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
u64 drop_end; u64 drop_end;
int ret = 0; int ret = 0;
int err = 0; int err = 0;
int rsv_count; int rsv_count;
bool same_page = ((offset >> PAGE_CACHE_SHIFT) == bool same_page;
((offset + len - 1) >> PAGE_CACHE_SHIFT));
bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES); bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES);
u64 ino_size = round_up(inode->i_size, PAGE_CACHE_SIZE); u64 ino_size;
ret = btrfs_wait_ordered_range(inode, offset, len); ret = btrfs_wait_ordered_range(inode, offset, len);
if (ret) if (ret)
return ret; return ret;
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
ino_size = round_up(inode->i_size, PAGE_CACHE_SIZE);
ret = find_first_non_hole(inode, &offset, &len);
if (ret < 0)
goto out_only_mutex;
if (ret && !len) {
/* Already in a large hole */
ret = 0;
goto out_only_mutex;
}
lockstart = round_up(offset , BTRFS_I(inode)->root->sectorsize);
lockend = round_down(offset + len,
BTRFS_I(inode)->root->sectorsize) - 1;
same_page = ((offset >> PAGE_CACHE_SHIFT) ==
((offset + len - 1) >> PAGE_CACHE_SHIFT));
/* /*
* We needn't truncate any page which is beyond the end of the file * We needn't truncate any page which is beyond the end of the file
* because we are sure there is no data there. * because we are sure there is no data there.
...@@ -2206,8 +2272,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) ...@@ -2206,8 +2272,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
if (same_page && len < PAGE_CACHE_SIZE) { if (same_page && len < PAGE_CACHE_SIZE) {
if (offset < ino_size) if (offset < ino_size)
ret = btrfs_truncate_page(inode, offset, len, 0); ret = btrfs_truncate_page(inode, offset, len, 0);
mutex_unlock(&inode->i_mutex); goto out_only_mutex;
return ret;
} }
/* zero back part of the first page */ /* zero back part of the first page */
...@@ -2219,12 +2284,39 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) ...@@ -2219,12 +2284,39 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
} }
} }
/* Check the aligned pages after the first unaligned page,
* if offset != orig_start, which means the first unaligned page
* including serveral following pages are already in holes,
* the extra check can be skipped */
if (offset == orig_start) {
/* after truncate page, check hole again */
len = offset + len - lockstart;
offset = lockstart;
ret = find_first_non_hole(inode, &offset, &len);
if (ret < 0)
goto out_only_mutex;
if (ret && !len) {
ret = 0;
goto out_only_mutex;
}
lockstart = offset;
}
/* Check the tail unaligned part is in a hole */
tail_start = lockend + 1;
tail_len = offset + len - tail_start;
if (tail_len) {
ret = find_first_non_hole(inode, &tail_start, &tail_len);
if (unlikely(ret < 0))
goto out_only_mutex;
if (!ret) {
/* zero the front end of the last page */ /* zero the front end of the last page */
if (offset + len < ino_size) { if (tail_start + tail_len < ino_size) {
ret = btrfs_truncate_page(inode, offset + len, 0, 1); ret = btrfs_truncate_page(inode,
if (ret) { tail_start + tail_len, 0, 1);
mutex_unlock(&inode->i_mutex); if (ret)
return ret; goto out_only_mutex;
}
} }
} }
...@@ -2250,9 +2342,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) ...@@ -2250,9 +2342,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
if ((!ordered || if ((!ordered ||
(ordered->file_offset + ordered->len <= lockstart || (ordered->file_offset + ordered->len <= lockstart ||
ordered->file_offset > lockend)) && ordered->file_offset > lockend)) &&
!test_range_bit(&BTRFS_I(inode)->io_tree, lockstart, !btrfs_page_exists_in_range(inode, lockstart, lockend)) {
lockend, EXTENT_UPTODATE, 0,
cached_state)) {
if (ordered) if (ordered)
btrfs_put_ordered_extent(ordered); btrfs_put_ordered_extent(ordered);
break; break;
...@@ -2300,6 +2390,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) ...@@ -2300,6 +2390,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
BUG_ON(ret); BUG_ON(ret);
trans->block_rsv = rsv; trans->block_rsv = rsv;
cur_offset = lockstart;
len = lockend - cur_offset;
while (cur_offset < lockend) { while (cur_offset < lockend) {
ret = __btrfs_drop_extents(trans, root, inode, path, ret = __btrfs_drop_extents(trans, root, inode, path,
cur_offset, lockend + 1, cur_offset, lockend + 1,
...@@ -2340,6 +2432,14 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) ...@@ -2340,6 +2432,14 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
rsv, min_size); rsv, min_size);
BUG_ON(ret); /* shouldn't happen */ BUG_ON(ret); /* shouldn't happen */
trans->block_rsv = rsv; trans->block_rsv = rsv;
ret = find_first_non_hole(inode, &cur_offset, &len);
if (unlikely(ret < 0))
break;
if (ret && !len) {
ret = 0;
break;
}
} }
if (ret) { if (ret) {
...@@ -2348,7 +2448,12 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) ...@@ -2348,7 +2448,12 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
} }
trans->block_rsv = &root->fs_info->trans_block_rsv; trans->block_rsv = &root->fs_info->trans_block_rsv;
if (cur_offset < ino_size) { /*
* Don't insert file hole extent item if it's for a range beyond eof
* (because it's useless) or if it represents a 0 bytes range (when
* cur_offset == drop_end).
*/
if (cur_offset < ino_size && cur_offset < drop_end) {
ret = fill_holes(trans, inode, path, cur_offset, drop_end); ret = fill_holes(trans, inode, path, cur_offset, drop_end);
if (ret) { if (ret) {
err = ret; err = ret;
...@@ -2373,6 +2478,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) ...@@ -2373,6 +2478,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
out: out:
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
&cached_state, GFP_NOFS); &cached_state, GFP_NOFS);
out_only_mutex:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
if (ret && !err) if (ret && !err)
err = ret; err = ret;
......
This diff is collapsed.
...@@ -174,7 +174,7 @@ static void start_caching(struct btrfs_root *root) ...@@ -174,7 +174,7 @@ static void start_caching(struct btrfs_root *root)
BTRFS_LAST_FREE_OBJECTID - objectid + 1); BTRFS_LAST_FREE_OBJECTID - objectid + 1);
} }
tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu\n", tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu",
root->root_key.objectid); root->root_key.objectid);
if (IS_ERR(tsk)) { if (IS_ERR(tsk)) {
btrfs_warn(root->fs_info, "failed to start inode caching task"); btrfs_warn(root->fs_info, "failed to start inode caching task");
......
This diff is collapsed.
This diff is collapsed.
...@@ -143,7 +143,7 @@ static int lzo_compress_pages(struct list_head *ws, ...@@ -143,7 +143,7 @@ static int lzo_compress_pages(struct list_head *ws,
if (ret != LZO_E_OK) { if (ret != LZO_E_OK) {
printk(KERN_DEBUG "BTRFS: deflate in loop returned %d\n", printk(KERN_DEBUG "BTRFS: deflate in loop returned %d\n",
ret); ret);
ret = -1; ret = -EIO;
goto out; goto out;
} }
...@@ -189,7 +189,7 @@ static int lzo_compress_pages(struct list_head *ws, ...@@ -189,7 +189,7 @@ static int lzo_compress_pages(struct list_head *ws,
kunmap(out_page); kunmap(out_page);
if (nr_pages == nr_dest_pages) { if (nr_pages == nr_dest_pages) {
out_page = NULL; out_page = NULL;
ret = -1; ret = -E2BIG;
goto out; goto out;
} }
...@@ -208,7 +208,7 @@ static int lzo_compress_pages(struct list_head *ws, ...@@ -208,7 +208,7 @@ static int lzo_compress_pages(struct list_head *ws,
/* we're making it bigger, give up */ /* we're making it bigger, give up */
if (tot_in > 8192 && tot_in < tot_out) { if (tot_in > 8192 && tot_in < tot_out) {
ret = -1; ret = -E2BIG;
goto out; goto out;
} }
...@@ -335,7 +335,7 @@ static int lzo_decompress_biovec(struct list_head *ws, ...@@ -335,7 +335,7 @@ static int lzo_decompress_biovec(struct list_head *ws,
break; break;
if (page_in_index + 1 >= total_pages_in) { if (page_in_index + 1 >= total_pages_in) {
ret = -1; ret = -EIO;
goto done; goto done;
} }
...@@ -358,7 +358,7 @@ static int lzo_decompress_biovec(struct list_head *ws, ...@@ -358,7 +358,7 @@ static int lzo_decompress_biovec(struct list_head *ws,
kunmap(pages_in[page_in_index - 1]); kunmap(pages_in[page_in_index - 1]);
if (ret != LZO_E_OK) { if (ret != LZO_E_OK) {
printk(KERN_WARNING "BTRFS: decompress failed\n"); printk(KERN_WARNING "BTRFS: decompress failed\n");
ret = -1; ret = -EIO;
break; break;
} }
...@@ -402,12 +402,12 @@ static int lzo_decompress(struct list_head *ws, unsigned char *data_in, ...@@ -402,12 +402,12 @@ static int lzo_decompress(struct list_head *ws, unsigned char *data_in,
ret = lzo1x_decompress_safe(data_in, in_len, workspace->buf, &out_len); ret = lzo1x_decompress_safe(data_in, in_len, workspace->buf, &out_len);
if (ret != LZO_E_OK) { if (ret != LZO_E_OK) {
printk(KERN_WARNING "BTRFS: decompress failed!\n"); printk(KERN_WARNING "BTRFS: decompress failed!\n");
ret = -1; ret = -EIO;
goto out; goto out;
} }
if (out_len < start_byte) { if (out_len < start_byte) {
ret = -1; ret = -EIO;
goto out; goto out;
} }
......
...@@ -67,7 +67,7 @@ static void ordered_data_tree_panic(struct inode *inode, int errno, ...@@ -67,7 +67,7 @@ static void ordered_data_tree_panic(struct inode *inode, int errno,
{ {
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
btrfs_panic(fs_info, errno, "Inconsistency in ordered tree at offset " btrfs_panic(fs_info, errno, "Inconsistency in ordered tree at offset "
"%llu\n", offset); "%llu", offset);
} }
/* /*
......
This diff is collapsed.
/*
* Copyright (C) 2014 Facebook. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License v2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*/
#ifndef __BTRFS_QGROUP__
#define __BTRFS_QGROUP__
/*
* A description of the operations, all of these operations only happen when we
* are adding the 1st reference for that subvolume in the case of adding space
* or on the last reference delete in the case of subtraction. The only
* exception is the last one, which is added for confusion.
*
* BTRFS_QGROUP_OPER_ADD_EXCL: adding bytes where this subvolume is the only
* one pointing at the bytes we are adding. This is called on the first
* allocation.
*
* BTRFS_QGROUP_OPER_ADD_SHARED: adding bytes where this bytenr is going to be
* shared between subvols. This is called on the creation of a ref that already
* has refs from a different subvolume, so basically reflink.
*
* BTRFS_QGROUP_OPER_SUB_EXCL: removing bytes where this subvolume is the only
* one referencing the range.
*
* BTRFS_QGROUP_OPER_SUB_SHARED: removing bytes where this subvolume shares with
* refs with other subvolumes.
*/
enum btrfs_qgroup_operation_type {
BTRFS_QGROUP_OPER_ADD_EXCL,
BTRFS_QGROUP_OPER_ADD_SHARED,
BTRFS_QGROUP_OPER_SUB_EXCL,
BTRFS_QGROUP_OPER_SUB_SHARED,
};
struct btrfs_qgroup_operation {
u64 ref_root;
u64 bytenr;
u64 num_bytes;
u64 seq;
enum btrfs_qgroup_operation_type type;
struct seq_list elem;
struct rb_node n;
struct list_head list;
};
int btrfs_quota_enable(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
int btrfs_quota_disable(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
int btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info);
void btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info);
int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info);
int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 src, u64 dst);
int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 src, u64 dst);
int btrfs_create_qgroup(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 qgroupid,
char *name);
int btrfs_remove_qgroup(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 qgroupid);
int btrfs_limit_qgroup(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 qgroupid,
struct btrfs_qgroup_limit *limit);
int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info);
void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info);
struct btrfs_delayed_extent_op;
int btrfs_qgroup_record_ref(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 ref_root,
u64 bytenr, u64 num_bytes,
enum btrfs_qgroup_operation_type type,
int mod_seq);
int btrfs_delayed_qgroup_accounting(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
void btrfs_remove_qgroup_operation(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info,
struct btrfs_qgroup_operation *oper);
int btrfs_run_qgroups(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info);
int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid,
struct btrfs_qgroup_inherit *inherit);
int btrfs_qgroup_reserve(struct btrfs_root *root, u64 num_bytes);
void btrfs_qgroup_free(struct btrfs_root *root, u64 num_bytes);
void assert_qgroups_uptodate(struct btrfs_trans_handle *trans);
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid,
u64 rfer, u64 excl);
#endif
#endif /* __BTRFS_QGROUP__ */
...@@ -337,7 +337,7 @@ static void backref_tree_panic(struct rb_node *rb_node, int errno, u64 bytenr) ...@@ -337,7 +337,7 @@ static void backref_tree_panic(struct rb_node *rb_node, int errno, u64 bytenr)
if (bnode->root) if (bnode->root)
fs_info = bnode->root->fs_info; fs_info = bnode->root->fs_info;
btrfs_panic(fs_info, errno, "Inconsistency in backref cache " btrfs_panic(fs_info, errno, "Inconsistency in backref cache "
"found at offset %llu\n", bytenr); "found at offset %llu", bytenr);
} }
/* /*
...@@ -528,7 +528,7 @@ static int should_ignore_root(struct btrfs_root *root) ...@@ -528,7 +528,7 @@ static int should_ignore_root(struct btrfs_root *root)
{ {
struct btrfs_root *reloc_root; struct btrfs_root *reloc_root;
if (!root->ref_cows) if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))
return 0; return 0;
reloc_root = root->reloc_root; reloc_root = root->reloc_root;
...@@ -610,7 +610,7 @@ struct btrfs_root *find_tree_root(struct reloc_control *rc, ...@@ -610,7 +610,7 @@ struct btrfs_root *find_tree_root(struct reloc_control *rc,
root = read_fs_root(rc->extent_root->fs_info, root_objectid); root = read_fs_root(rc->extent_root->fs_info, root_objectid);
BUG_ON(IS_ERR(root)); BUG_ON(IS_ERR(root));
if (root->ref_cows && if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) &&
generation != btrfs_root_generation(&root->root_item)) generation != btrfs_root_generation(&root->root_item))
return NULL; return NULL;
...@@ -887,7 +887,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -887,7 +887,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
goto out; goto out;
} }
if (!root->ref_cows) if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))
cur->cowonly = 1; cur->cowonly = 1;
if (btrfs_root_level(&root->root_item) == cur->level) { if (btrfs_root_level(&root->root_item) == cur->level) {
...@@ -954,7 +954,8 @@ struct backref_node *build_backref_tree(struct reloc_control *rc, ...@@ -954,7 +954,8 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
upper->bytenr = eb->start; upper->bytenr = eb->start;
upper->owner = btrfs_header_owner(eb); upper->owner = btrfs_header_owner(eb);
upper->level = lower->level + 1; upper->level = lower->level + 1;
if (!root->ref_cows) if (!test_bit(BTRFS_ROOT_REF_COWS,
&root->state))
upper->cowonly = 1; upper->cowonly = 1;
/* /*
...@@ -1258,7 +1259,7 @@ static int __must_check __add_reloc_root(struct btrfs_root *root) ...@@ -1258,7 +1259,7 @@ static int __must_check __add_reloc_root(struct btrfs_root *root)
if (rb_node) { if (rb_node) {
btrfs_panic(root->fs_info, -EEXIST, "Duplicate root found " btrfs_panic(root->fs_info, -EEXIST, "Duplicate root found "
"for start=%llu while inserting into relocation " "for start=%llu while inserting into relocation "
"tree\n", node->bytenr); "tree", node->bytenr);
kfree(node); kfree(node);
return -EEXIST; return -EEXIST;
} }
...@@ -2441,7 +2442,7 @@ struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans, ...@@ -2441,7 +2442,7 @@ struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans,
next = walk_up_backref(next, edges, &index); next = walk_up_backref(next, edges, &index);
root = next->root; root = next->root;
BUG_ON(!root); BUG_ON(!root);
BUG_ON(!root->ref_cows); BUG_ON(!test_bit(BTRFS_ROOT_REF_COWS, &root->state));
if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) {
record_reloc_root_in_trans(trans, root); record_reloc_root_in_trans(trans, root);
...@@ -2506,7 +2507,7 @@ struct btrfs_root *select_one_root(struct btrfs_trans_handle *trans, ...@@ -2506,7 +2507,7 @@ struct btrfs_root *select_one_root(struct btrfs_trans_handle *trans,
BUG_ON(!root); BUG_ON(!root);
/* no other choice for non-references counted tree */ /* no other choice for non-references counted tree */
if (!root->ref_cows) if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))
return root; return root;
if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID)
...@@ -2893,14 +2894,14 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans, ...@@ -2893,14 +2894,14 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,
goto out; goto out;
} }
if (!root || root->ref_cows) { if (!root || test_bit(BTRFS_ROOT_REF_COWS, &root->state)) {
ret = reserve_metadata_space(trans, rc, node); ret = reserve_metadata_space(trans, rc, node);
if (ret) if (ret)
goto out; goto out;
} }
if (root) { if (root) {
if (root->ref_cows) { if (test_bit(BTRFS_ROOT_REF_COWS, &root->state)) {
BUG_ON(node->new_bytenr); BUG_ON(node->new_bytenr);
BUG_ON(!list_empty(&node->list)); BUG_ON(!list_empty(&node->list));
btrfs_record_root_in_trans(trans, root); btrfs_record_root_in_trans(trans, root);
......
...@@ -306,7 +306,7 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root) ...@@ -306,7 +306,7 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
break; break;
} }
root->orphan_item_inserted = 1; set_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state);
err = btrfs_insert_fs_root(root->fs_info, root); err = btrfs_insert_fs_root(root->fs_info, root);
if (err) { if (err) {
......
...@@ -588,8 +588,9 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock) ...@@ -588,8 +588,9 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
do { do {
ret = tree_backref_for_extent(&ptr, eb, ei, item_size, ret = tree_backref_for_extent(&ptr, eb, &found_key, ei,
&ref_root, &ref_level); item_size, &ref_root,
&ref_level);
printk_in_rcu(KERN_WARNING printk_in_rcu(KERN_WARNING
"BTRFS: %s at logical %llu on dev %s, " "BTRFS: %s at logical %llu on dev %s, "
"sector %llu: metadata %s (level %d) in tree " "sector %llu: metadata %s (level %d) in tree "
...@@ -717,7 +718,7 @@ static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx) ...@@ -717,7 +718,7 @@ static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx)
out: out:
if (page) if (page)
put_page(page); put_page(page);
if (inode)
iput(inode); iput(inode);
if (ret < 0) if (ret < 0)
......
This diff is collapsed.
...@@ -511,7 +511,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) ...@@ -511,7 +511,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
} else if (compress) { } else if (compress) {
if (!btrfs_test_opt(root, COMPRESS)) if (!btrfs_test_opt(root, COMPRESS))
btrfs_info(root->fs_info, btrfs_info(root->fs_info,
"btrfs: use %s compression\n", "btrfs: use %s compression",
compress_type); compress_type);
} }
break; break;
...@@ -580,8 +580,15 @@ int btrfs_parse_options(struct btrfs_root *root, char *options) ...@@ -580,8 +580,15 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
} }
break; break;
case Opt_acl: case Opt_acl:
#ifdef CONFIG_BTRFS_FS_POSIX_ACL
root->fs_info->sb->s_flags |= MS_POSIXACL; root->fs_info->sb->s_flags |= MS_POSIXACL;
break; break;
#else
btrfs_err(root->fs_info,
"support for ACL not compiled in!");
ret = -EINVAL;
goto out;
#endif
case Opt_noacl: case Opt_noacl:
root->fs_info->sb->s_flags &= ~MS_POSIXACL; root->fs_info->sb->s_flags &= ~MS_POSIXACL;
break; break;
...@@ -1413,6 +1420,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data) ...@@ -1413,6 +1420,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
* this also happens on 'umount -rf' or on shutdown, when * this also happens on 'umount -rf' or on shutdown, when
* the filesystem is busy. * the filesystem is busy.
*/ */
cancel_work_sync(&fs_info->async_reclaim_work);
/* wait for the uuid_scan task to finish */ /* wait for the uuid_scan task to finish */
down(&fs_info->uuid_tree_rescan_sem); down(&fs_info->uuid_tree_rescan_sem);
...@@ -1894,6 +1902,9 @@ static int btrfs_run_sanity_tests(void) ...@@ -1894,6 +1902,9 @@ static int btrfs_run_sanity_tests(void)
if (ret) if (ret)
goto out; goto out;
ret = btrfs_test_inodes(); ret = btrfs_test_inodes();
if (ret)
goto out;
ret = btrfs_test_qgroups();
out: out:
btrfs_destroy_test_fs(); btrfs_destroy_test_fs();
return ret; return ret;
......
...@@ -254,6 +254,7 @@ static ssize_t global_rsv_reserved_show(struct kobject *kobj, ...@@ -254,6 +254,7 @@ static ssize_t global_rsv_reserved_show(struct kobject *kobj,
BTRFS_ATTR(global_rsv_reserved, 0444, global_rsv_reserved_show); BTRFS_ATTR(global_rsv_reserved, 0444, global_rsv_reserved_show);
#define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj) #define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj)
#define to_raid_kobj(_kobj) container_of(_kobj, struct raid_kobject, kobj)
static ssize_t raid_bytes_show(struct kobject *kobj, static ssize_t raid_bytes_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf); struct kobj_attribute *attr, char *buf);
...@@ -266,7 +267,7 @@ static ssize_t raid_bytes_show(struct kobject *kobj, ...@@ -266,7 +267,7 @@ static ssize_t raid_bytes_show(struct kobject *kobj,
{ {
struct btrfs_space_info *sinfo = to_space_info(kobj->parent); struct btrfs_space_info *sinfo = to_space_info(kobj->parent);
struct btrfs_block_group_cache *block_group; struct btrfs_block_group_cache *block_group;
int index = kobj - sinfo->block_group_kobjs; int index = to_raid_kobj(kobj)->raid_type;
u64 val = 0; u64 val = 0;
down_read(&sinfo->groups_sem); down_read(&sinfo->groups_sem);
...@@ -288,7 +289,7 @@ static struct attribute *raid_attributes[] = { ...@@ -288,7 +289,7 @@ static struct attribute *raid_attributes[] = {
static void release_raid_kobj(struct kobject *kobj) static void release_raid_kobj(struct kobject *kobj)
{ {
kobject_put(kobj->parent); kfree(to_raid_kobj(kobj));
} }
struct kobj_type btrfs_raid_ktype = { struct kobj_type btrfs_raid_ktype = {
...@@ -374,11 +375,8 @@ static ssize_t btrfs_label_store(struct kobject *kobj, ...@@ -374,11 +375,8 @@ static ssize_t btrfs_label_store(struct kobject *kobj,
struct btrfs_root *root = fs_info->fs_root; struct btrfs_root *root = fs_info->fs_root;
int ret; int ret;
if (len >= BTRFS_LABEL_SIZE) { if (len >= BTRFS_LABEL_SIZE)
pr_err("BTRFS: unable to set label with more than %d bytes\n",
BTRFS_LABEL_SIZE - 1);
return -EINVAL; return -EINVAL;
}
trans = btrfs_start_transaction(root, 0); trans = btrfs_start_transaction(root, 0);
if (IS_ERR(trans)) if (IS_ERR(trans))
...@@ -396,8 +394,48 @@ static ssize_t btrfs_label_store(struct kobject *kobj, ...@@ -396,8 +394,48 @@ static ssize_t btrfs_label_store(struct kobject *kobj,
} }
BTRFS_ATTR_RW(label, 0644, btrfs_label_show, btrfs_label_store); BTRFS_ATTR_RW(label, 0644, btrfs_label_show, btrfs_label_store);
static ssize_t btrfs_no_store(struct kobject *kobj,
struct kobj_attribute *a,
const char *buf, size_t len)
{
return -EPERM;
}
static ssize_t btrfs_nodesize_show(struct kobject *kobj,
struct kobj_attribute *a, char *buf)
{
struct btrfs_fs_info *fs_info = to_fs_info(kobj);
return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->nodesize);
}
BTRFS_ATTR_RW(nodesize, 0444, btrfs_nodesize_show, btrfs_no_store);
static ssize_t btrfs_sectorsize_show(struct kobject *kobj,
struct kobj_attribute *a, char *buf)
{
struct btrfs_fs_info *fs_info = to_fs_info(kobj);
return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->sectorsize);
}
BTRFS_ATTR_RW(sectorsize, 0444, btrfs_sectorsize_show, btrfs_no_store);
static ssize_t btrfs_clone_alignment_show(struct kobject *kobj,
struct kobj_attribute *a, char *buf)
{
struct btrfs_fs_info *fs_info = to_fs_info(kobj);
return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->sectorsize);
}
BTRFS_ATTR_RW(clone_alignment, 0444, btrfs_clone_alignment_show, btrfs_no_store);
static struct attribute *btrfs_attrs[] = { static struct attribute *btrfs_attrs[] = {
BTRFS_ATTR_PTR(label), BTRFS_ATTR_PTR(label),
BTRFS_ATTR_PTR(nodesize),
BTRFS_ATTR_PTR(sectorsize),
BTRFS_ATTR_PTR(clone_alignment),
NULL, NULL,
}; };
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
#include <linux/magic.h> #include <linux/magic.h>
#include "btrfs-tests.h" #include "btrfs-tests.h"
#include "../ctree.h" #include "../ctree.h"
#include "../volumes.h"
#include "../disk-io.h"
#include "../qgroup.h"
static struct vfsmount *test_mnt = NULL; static struct vfsmount *test_mnt = NULL;
...@@ -72,3 +75,97 @@ void btrfs_destroy_test_fs(void) ...@@ -72,3 +75,97 @@ void btrfs_destroy_test_fs(void)
kern_unmount(test_mnt); kern_unmount(test_mnt);
unregister_filesystem(&test_type); unregister_filesystem(&test_type);
} }
struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void)
{
struct btrfs_fs_info *fs_info = kzalloc(sizeof(struct btrfs_fs_info),
GFP_NOFS);
if (!fs_info)
return fs_info;
fs_info->fs_devices = kzalloc(sizeof(struct btrfs_fs_devices),
GFP_NOFS);
if (!fs_info->fs_devices) {
kfree(fs_info);
return NULL;
}
fs_info->super_copy = kzalloc(sizeof(struct btrfs_super_block),
GFP_NOFS);
if (!fs_info->super_copy) {
kfree(fs_info->fs_devices);
kfree(fs_info);
return NULL;
}
if (init_srcu_struct(&fs_info->subvol_srcu)) {
kfree(fs_info->fs_devices);
kfree(fs_info->super_copy);
kfree(fs_info);
return NULL;
}
spin_lock_init(&fs_info->buffer_lock);
spin_lock_init(&fs_info->qgroup_lock);
spin_lock_init(&fs_info->qgroup_op_lock);
spin_lock_init(&fs_info->super_lock);
spin_lock_init(&fs_info->fs_roots_radix_lock);
spin_lock_init(&fs_info->tree_mod_seq_lock);
mutex_init(&fs_info->qgroup_ioctl_lock);
mutex_init(&fs_info->qgroup_rescan_lock);
rwlock_init(&fs_info->tree_mod_log_lock);
fs_info->running_transaction = NULL;
fs_info->qgroup_tree = RB_ROOT;
fs_info->qgroup_ulist = NULL;
atomic64_set(&fs_info->tree_mod_seq, 0);
INIT_LIST_HEAD(&fs_info->dirty_qgroups);
INIT_LIST_HEAD(&fs_info->dead_roots);
INIT_LIST_HEAD(&fs_info->tree_mod_seq_list);
INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC);
INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
return fs_info;
}
static void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
{
struct radix_tree_iter iter;
void **slot;
spin_lock(&fs_info->buffer_lock);
restart:
radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) {
struct extent_buffer *eb;
eb = radix_tree_deref_slot(slot);
if (!eb)
continue;
/* Shouldn't happen but that kind of thinking creates CVE's */
if (radix_tree_exception(eb)) {
if (radix_tree_deref_retry(eb))
goto restart;
continue;
}
spin_unlock(&fs_info->buffer_lock);
free_extent_buffer_stale(eb);
spin_lock(&fs_info->buffer_lock);
}
spin_unlock(&fs_info->buffer_lock);
btrfs_free_qgroup_config(fs_info);
btrfs_free_fs_roots(fs_info);
cleanup_srcu_struct(&fs_info->subvol_srcu);
kfree(fs_info->super_copy);
kfree(fs_info->fs_devices);
kfree(fs_info);
}
void btrfs_free_dummy_root(struct btrfs_root *root)
{
if (!root)
return;
if (root->node)
free_extent_buffer(root->node);
if (root->fs_info)
btrfs_free_dummy_fs_info(root->fs_info);
kfree(root);
}
...@@ -23,13 +23,18 @@ ...@@ -23,13 +23,18 @@
#define test_msg(fmt, ...) pr_info("BTRFS: selftest: " fmt, ##__VA_ARGS__) #define test_msg(fmt, ...) pr_info("BTRFS: selftest: " fmt, ##__VA_ARGS__)
struct btrfs_root;
int btrfs_test_free_space_cache(void); int btrfs_test_free_space_cache(void);
int btrfs_test_extent_buffer_operations(void); int btrfs_test_extent_buffer_operations(void);
int btrfs_test_extent_io(void); int btrfs_test_extent_io(void);
int btrfs_test_inodes(void); int btrfs_test_inodes(void);
int btrfs_test_qgroups(void);
int btrfs_init_test_fs(void); int btrfs_init_test_fs(void);
void btrfs_destroy_test_fs(void); void btrfs_destroy_test_fs(void);
struct inode *btrfs_new_test_inode(void); struct inode *btrfs_new_test_inode(void);
struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void);
void btrfs_free_dummy_root(struct btrfs_root *root);
#else #else
static inline int btrfs_test_free_space_cache(void) static inline int btrfs_test_free_space_cache(void)
{ {
...@@ -54,6 +59,10 @@ static inline int btrfs_test_inodes(void) ...@@ -54,6 +59,10 @@ static inline int btrfs_test_inodes(void)
{ {
return 0; return 0;
} }
static inline int btrfs_test_qgroups(void)
{
return 0;
}
#endif #endif
#endif #endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -69,6 +69,7 @@ struct btrfs_transaction { ...@@ -69,6 +69,7 @@ struct btrfs_transaction {
#define __TRANS_ATTACH (1U << 10) #define __TRANS_ATTACH (1U << 10)
#define __TRANS_JOIN (1U << 11) #define __TRANS_JOIN (1U << 11)
#define __TRANS_JOIN_NOLOCK (1U << 12) #define __TRANS_JOIN_NOLOCK (1U << 12)
#define __TRANS_DUMMY (1U << 13)
#define TRANS_USERSPACE (__TRANS_USERSPACE | __TRANS_FREEZABLE) #define TRANS_USERSPACE (__TRANS_USERSPACE | __TRANS_FREEZABLE)
#define TRANS_START (__TRANS_START | __TRANS_FREEZABLE) #define TRANS_START (__TRANS_START | __TRANS_FREEZABLE)
......
...@@ -49,7 +49,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, ...@@ -49,7 +49,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
goto out; goto out;
} }
if (root->ref_cows == 0) if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))
goto out; goto out;
if (btrfs_test_opt(root, SSD)) if (btrfs_test_opt(root, SSD))
......
This diff is collapsed.
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
#ifndef __TREE_LOG_ #ifndef __TREE_LOG_
#define __TREE_LOG_ #define __TREE_LOG_
#include "ctree.h"
#include "transaction.h"
/* return value for btrfs_log_dentry_safe that means we don't need to log it at all */ /* return value for btrfs_log_dentry_safe that means we don't need to log it at all */
#define BTRFS_NO_LOG_SYNC 256 #define BTRFS_NO_LOG_SYNC 256
...@@ -35,6 +38,19 @@ static inline void btrfs_init_log_ctx(struct btrfs_log_ctx *ctx) ...@@ -35,6 +38,19 @@ static inline void btrfs_init_log_ctx(struct btrfs_log_ctx *ctx)
INIT_LIST_HEAD(&ctx->list); INIT_LIST_HEAD(&ctx->list);
} }
static inline void btrfs_set_log_full_commit(struct btrfs_fs_info *fs_info,
struct btrfs_trans_handle *trans)
{
ACCESS_ONCE(fs_info->last_trans_log_full_commit) = trans->transid;
}
static inline int btrfs_need_log_full_commit(struct btrfs_fs_info *fs_info,
struct btrfs_trans_handle *trans)
{
return ACCESS_ONCE(fs_info->last_trans_log_full_commit) ==
trans->transid;
}
int btrfs_sync_log(struct btrfs_trans_handle *trans, int btrfs_sync_log(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_log_ctx *ctx); struct btrfs_root *root, struct btrfs_log_ctx *ctx);
int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root); int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root);
......
This diff is collapsed.
...@@ -255,6 +255,7 @@ struct map_lookup { ...@@ -255,6 +255,7 @@ struct map_lookup {
#define BTRFS_BALANCE_ARGS_DEVID (1ULL << 2) #define BTRFS_BALANCE_ARGS_DEVID (1ULL << 2)
#define BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3) #define BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3)
#define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4) #define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4)
#define BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5)
/* /*
* Profile changing flags. When SOFT is set we won't relocate chunk if * Profile changing flags. When SOFT is set we won't relocate chunk if
......
This diff is collapsed.
This diff is collapsed.
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