mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-28 23:24:50 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull btrfs update frm Chris Mason: "This is our usual merge window set of bug fixes, performance improvements and cleanups. Miao Xie has some really nice optimizations for writeback. Josef also expanded our sanity checks quite a bit; these make up a big chunk of the new lines" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (98 commits) Btrfs: rename btrfs_start_all_delalloc_inodes Btrfs: don't wait for the completion of all the ordered extents Btrfs: don't wait for all the async delalloc when shrinking delalloc Btrfs: fix the confusion between delalloc bytes and metadata bytes Btrfs: pick up the code for the item number calculation in flush_space() Btrfs: wait for the ordered extent only when we want Btrfs: remove unnecessary initialization and memory barrior in shrink_delalloc() Btrfs: avoid unnecessary scrub workers allocation Btrfs: check file extent type before anything else btrfs: Remove useless variable in write_ctree_super() btrfs: Fix checkpatch.pl warning of spacing issues btrfs: Replace kmalloc with kmalloc_array btrfs: Enclose macros with complex values within parenthesis btrfs: Use WARN_ON()'s return value in place of WARN_ON(1) btrfs: Remove redundant local zero structure btrfs: Pack struct btrfs_device btrfs: Replace multiple atomic_inc() with atomic_add() btrfs: Add helper function for free_root_pointers() Btrfs: fix a crash when running balance and defrag concurrently Btrfs: do not run snapshot-aware defragment on error ...
This commit is contained in:
commit
3aeb58ab62
49 changed files with 2600 additions and 973 deletions
|
@ -14,4 +14,6 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
|
||||||
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
|
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
|
||||||
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
|
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-io-tests.o tests/inode-tests.o
|
||||||
|
|
|
@ -229,7 +229,7 @@ int btrfs_init_acl(struct btrfs_trans_handle *trans,
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
/* we need an acl */
|
/* we need an acl */
|
||||||
ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS);
|
ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS);
|
||||||
} else {
|
} else if (ret < 0) {
|
||||||
cache_no_acl(inode);
|
cache_no_acl(inode);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -262,7 +262,7 @@ static struct btrfs_work *get_next_work(struct btrfs_worker_thread *worker,
|
||||||
struct btrfs_work *work = NULL;
|
struct btrfs_work *work = NULL;
|
||||||
struct list_head *cur = NULL;
|
struct list_head *cur = NULL;
|
||||||
|
|
||||||
if(!list_empty(prio_head))
|
if (!list_empty(prio_head))
|
||||||
cur = prio_head->next;
|
cur = prio_head->next;
|
||||||
|
|
||||||
smp_mb();
|
smp_mb();
|
||||||
|
|
|
@ -185,6 +185,9 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id,
|
||||||
{
|
{
|
||||||
struct __prelim_ref *ref;
|
struct __prelim_ref *ref;
|
||||||
|
|
||||||
|
if (root_id == BTRFS_DATA_RELOC_TREE_OBJECTID)
|
||||||
|
return 0;
|
||||||
|
|
||||||
ref = kmem_cache_alloc(btrfs_prelim_ref_cache, gfp_mask);
|
ref = kmem_cache_alloc(btrfs_prelim_ref_cache, gfp_mask);
|
||||||
if (!ref)
|
if (!ref)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -323,8 +326,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
|
||||||
|
|
||||||
eb = path->nodes[level];
|
eb = path->nodes[level];
|
||||||
while (!eb) {
|
while (!eb) {
|
||||||
if (!level) {
|
if (WARN_ON(!level)) {
|
||||||
WARN_ON(1);
|
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1619,7 +1621,7 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
|
||||||
btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
|
btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
item = btrfs_item_nr(eb, slot);
|
item = btrfs_item_nr(slot);
|
||||||
iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);
|
iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref);
|
||||||
|
|
||||||
for (cur = 0; cur < btrfs_item_size(eb, item); cur += len) {
|
for (cur = 0; cur < btrfs_item_size(eb, item); cur += len) {
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#ifndef __BTRFS_I__
|
#ifndef __BTRFS_I__
|
||||||
#define __BTRFS_I__
|
#define __BTRFS_I__
|
||||||
|
|
||||||
|
#include <linux/hash.h>
|
||||||
#include "extent_map.h"
|
#include "extent_map.h"
|
||||||
#include "extent_io.h"
|
#include "extent_io.h"
|
||||||
#include "ordered-data.h"
|
#include "ordered-data.h"
|
||||||
|
@ -179,6 +180,25 @@ static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
|
||||||
return container_of(inode, struct btrfs_inode, vfs_inode);
|
return container_of(inode, struct btrfs_inode, vfs_inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline unsigned long btrfs_inode_hash(u64 objectid,
|
||||||
|
const struct btrfs_root *root)
|
||||||
|
{
|
||||||
|
u64 h = objectid ^ (root->objectid * GOLDEN_RATIO_PRIME);
|
||||||
|
|
||||||
|
#if BITS_PER_LONG == 32
|
||||||
|
h = (h >> 32) ^ (h & 0xffffffff);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (unsigned long)h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void btrfs_insert_inode_hash(struct inode *inode)
|
||||||
|
{
|
||||||
|
unsigned long h = btrfs_inode_hash(inode->i_ino, BTRFS_I(inode)->root);
|
||||||
|
|
||||||
|
__insert_inode_hash(inode, h);
|
||||||
|
}
|
||||||
|
|
||||||
static inline u64 btrfs_ino(struct inode *inode)
|
static inline u64 btrfs_ino(struct inode *inode)
|
||||||
{
|
{
|
||||||
u64 ino = BTRFS_I(inode)->location.objectid;
|
u64 ino = BTRFS_I(inode)->location.objectid;
|
||||||
|
|
|
@ -1038,7 +1038,7 @@ static int btrfsic_process_metablock(
|
||||||
disk_item_offset,
|
disk_item_offset,
|
||||||
sizeof(struct btrfs_item));
|
sizeof(struct btrfs_item));
|
||||||
item_offset = btrfs_stack_item_offset(&disk_item);
|
item_offset = btrfs_stack_item_offset(&disk_item);
|
||||||
item_size = btrfs_stack_item_offset(&disk_item);
|
item_size = btrfs_stack_item_size(&disk_item);
|
||||||
disk_key = &disk_item.key;
|
disk_key = &disk_item.key;
|
||||||
type = btrfs_disk_key_type(disk_key);
|
type = btrfs_disk_key_type(disk_key);
|
||||||
|
|
||||||
|
@ -1900,7 +1900,9 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
|
||||||
dev_state,
|
dev_state,
|
||||||
dev_bytenr);
|
dev_bytenr);
|
||||||
}
|
}
|
||||||
if (block->logical_bytenr != bytenr) {
|
if (block->logical_bytenr != bytenr &&
|
||||||
|
!(!block->is_metadata &&
|
||||||
|
block->logical_bytenr == 0))
|
||||||
printk(KERN_INFO
|
printk(KERN_INFO
|
||||||
"Written block @%llu (%s/%llu/%d)"
|
"Written block @%llu (%s/%llu/%d)"
|
||||||
" found in hash table, %c,"
|
" found in hash table, %c,"
|
||||||
|
@ -1910,15 +1912,14 @@ static void btrfsic_process_written_block(struct btrfsic_dev_state *dev_state,
|
||||||
block->mirror_num,
|
block->mirror_num,
|
||||||
btrfsic_get_block_type(state, block),
|
btrfsic_get_block_type(state, block),
|
||||||
block->logical_bytenr);
|
block->logical_bytenr);
|
||||||
block->logical_bytenr = bytenr;
|
else if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
|
||||||
} else if (state->print_mask &
|
|
||||||
BTRFSIC_PRINT_MASK_VERBOSE)
|
|
||||||
printk(KERN_INFO
|
printk(KERN_INFO
|
||||||
"Written block @%llu (%s/%llu/%d)"
|
"Written block @%llu (%s/%llu/%d)"
|
||||||
" found in hash table, %c.\n",
|
" found in hash table, %c.\n",
|
||||||
bytenr, dev_state->name, dev_bytenr,
|
bytenr, dev_state->name, dev_bytenr,
|
||||||
block->mirror_num,
|
block->mirror_num,
|
||||||
btrfsic_get_block_type(state, block));
|
btrfsic_get_block_type(state, block));
|
||||||
|
block->logical_bytenr = bytenr;
|
||||||
} else {
|
} else {
|
||||||
if (num_pages * PAGE_CACHE_SIZE <
|
if (num_pages * PAGE_CACHE_SIZE <
|
||||||
state->datablock_size) {
|
state->datablock_size) {
|
||||||
|
@ -2463,10 +2464,8 @@ static int btrfsic_process_written_superblock(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 == btrfsic_check_all_ref_blocks(state, superblock, 0)) {
|
if (WARN_ON(-1 == btrfsic_check_all_ref_blocks(state, superblock, 0)))
|
||||||
WARN_ON(1);
|
|
||||||
btrfsic_dump_tree(state);
|
btrfsic_dump_tree(state);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2906,7 +2905,7 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
|
||||||
btrfsic_release_block_ctx(&block_ctx);
|
btrfsic_release_block_ctx(&block_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!match) {
|
if (WARN_ON(!match)) {
|
||||||
printk(KERN_INFO "btrfs: attempt to write M-block which contains logical bytenr that doesn't map to dev+physical bytenr of submit_bio,"
|
printk(KERN_INFO "btrfs: attempt to write M-block which contains logical bytenr that doesn't map to dev+physical bytenr of submit_bio,"
|
||||||
" buffer->log_bytenr=%llu, submit_bio(bdev=%s,"
|
" buffer->log_bytenr=%llu, submit_bio(bdev=%s,"
|
||||||
" phys_bytenr=%llu)!\n",
|
" phys_bytenr=%llu)!\n",
|
||||||
|
@ -2923,7 +2922,6 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
|
||||||
bytenr, block_ctx.dev->name,
|
bytenr, block_ctx.dev->name,
|
||||||
block_ctx.dev_bytenr, mirror_num);
|
block_ctx.dev_bytenr, mirror_num);
|
||||||
}
|
}
|
||||||
WARN_ON(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
#ifndef _COMPAT_H_
|
|
||||||
#define _COMPAT_H_
|
|
||||||
|
|
||||||
#define btrfs_drop_nlink(inode) drop_nlink(inode)
|
|
||||||
#define btrfs_inc_nlink(inode) inc_nlink(inode)
|
|
||||||
|
|
||||||
#endif /* _COMPAT_H_ */
|
|
|
@ -32,7 +32,6 @@
|
||||||
#include <linux/writeback.h>
|
#include <linux/writeback.h>
|
||||||
#include <linux/bit_spinlock.h>
|
#include <linux/bit_spinlock.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include "compat.h"
|
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
|
@ -360,7 +359,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
|
||||||
bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
|
bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
|
||||||
|
|
||||||
bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS);
|
bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS);
|
||||||
if(!bio) {
|
if (!bio) {
|
||||||
kfree(cb);
|
kfree(cb);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
|
@ -274,7 +274,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
|
||||||
else
|
else
|
||||||
btrfs_set_header_owner(cow, new_root_objectid);
|
btrfs_set_header_owner(cow, new_root_objectid);
|
||||||
|
|
||||||
write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(cow),
|
write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(),
|
||||||
BTRFS_FSID_SIZE);
|
BTRFS_FSID_SIZE);
|
||||||
|
|
||||||
WARN_ON(btrfs_header_generation(buf) > trans->transid);
|
WARN_ON(btrfs_header_generation(buf) > trans->transid);
|
||||||
|
@ -996,7 +996,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
||||||
else
|
else
|
||||||
btrfs_set_header_owner(cow, root->root_key.objectid);
|
btrfs_set_header_owner(cow, root->root_key.objectid);
|
||||||
|
|
||||||
write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(cow),
|
write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(),
|
||||||
BTRFS_FSID_SIZE);
|
BTRFS_FSID_SIZE);
|
||||||
|
|
||||||
ret = update_ref_for_cow(trans, root, buf, cow, &last_ref);
|
ret = update_ref_for_cow(trans, root, buf, cow, &last_ref);
|
||||||
|
@ -1285,11 +1285,10 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
|
||||||
free_extent_buffer(eb_root);
|
free_extent_buffer(eb_root);
|
||||||
blocksize = btrfs_level_size(root, old_root->level);
|
blocksize = btrfs_level_size(root, old_root->level);
|
||||||
old = read_tree_block(root, logical, blocksize, 0);
|
old = read_tree_block(root, logical, blocksize, 0);
|
||||||
if (!old || !extent_buffer_uptodate(old)) {
|
if (WARN_ON(!old || !extent_buffer_uptodate(old))) {
|
||||||
free_extent_buffer(old);
|
free_extent_buffer(old);
|
||||||
pr_warn("btrfs: failed to read tree block %llu from get_old_root\n",
|
pr_warn("btrfs: failed to read tree block %llu from get_old_root\n",
|
||||||
logical);
|
logical);
|
||||||
WARN_ON(1);
|
|
||||||
} else {
|
} else {
|
||||||
eb = btrfs_clone_extent_buffer(old);
|
eb = btrfs_clone_extent_buffer(old);
|
||||||
free_extent_buffer(old);
|
free_extent_buffer(old);
|
||||||
|
@ -2758,7 +2757,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
|
||||||
int level;
|
int level;
|
||||||
int lowest_unlock = 1;
|
int lowest_unlock = 1;
|
||||||
u8 lowest_level = 0;
|
u8 lowest_level = 0;
|
||||||
int prev_cmp;
|
int prev_cmp = -1;
|
||||||
|
|
||||||
lowest_level = p->lowest_level;
|
lowest_level = p->lowest_level;
|
||||||
WARN_ON(p->nodes[0] != NULL);
|
WARN_ON(p->nodes[0] != NULL);
|
||||||
|
@ -2769,7 +2768,6 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
|
||||||
}
|
}
|
||||||
|
|
||||||
again:
|
again:
|
||||||
prev_cmp = -1;
|
|
||||||
b = get_old_root(root, time_seq);
|
b = get_old_root(root, time_seq);
|
||||||
level = btrfs_header_level(b);
|
level = btrfs_header_level(b);
|
||||||
p->locks[level] = BTRFS_READ_LOCK;
|
p->locks[level] = BTRFS_READ_LOCK;
|
||||||
|
@ -2787,6 +2785,11 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
|
||||||
*/
|
*/
|
||||||
btrfs_unlock_up_safe(p, level + 1);
|
btrfs_unlock_up_safe(p, level + 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since we can unwind eb's we want to do a real search every
|
||||||
|
* time.
|
||||||
|
*/
|
||||||
|
prev_cmp = -1;
|
||||||
ret = key_search(b, key, level, &prev_cmp, &slot);
|
ret = key_search(b, key, level, &prev_cmp, &slot);
|
||||||
|
|
||||||
if (level != 0) {
|
if (level != 0) {
|
||||||
|
@ -3148,7 +3151,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
|
||||||
btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV);
|
btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV);
|
||||||
btrfs_set_header_owner(c, root->root_key.objectid);
|
btrfs_set_header_owner(c, root->root_key.objectid);
|
||||||
|
|
||||||
write_extent_buffer(c, root->fs_info->fsid, btrfs_header_fsid(c),
|
write_extent_buffer(c, root->fs_info->fsid, btrfs_header_fsid(),
|
||||||
BTRFS_FSID_SIZE);
|
BTRFS_FSID_SIZE);
|
||||||
|
|
||||||
write_extent_buffer(c, root->fs_info->chunk_tree_uuid,
|
write_extent_buffer(c, root->fs_info->chunk_tree_uuid,
|
||||||
|
@ -3287,7 +3290,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
|
||||||
btrfs_set_header_backref_rev(split, BTRFS_MIXED_BACKREF_REV);
|
btrfs_set_header_backref_rev(split, BTRFS_MIXED_BACKREF_REV);
|
||||||
btrfs_set_header_owner(split, root->root_key.objectid);
|
btrfs_set_header_owner(split, root->root_key.objectid);
|
||||||
write_extent_buffer(split, root->fs_info->fsid,
|
write_extent_buffer(split, root->fs_info->fsid,
|
||||||
btrfs_header_fsid(split), BTRFS_FSID_SIZE);
|
btrfs_header_fsid(), BTRFS_FSID_SIZE);
|
||||||
write_extent_buffer(split, root->fs_info->chunk_tree_uuid,
|
write_extent_buffer(split, root->fs_info->chunk_tree_uuid,
|
||||||
btrfs_header_chunk_tree_uuid(split),
|
btrfs_header_chunk_tree_uuid(split),
|
||||||
BTRFS_UUID_SIZE);
|
BTRFS_UUID_SIZE);
|
||||||
|
@ -3337,8 +3340,8 @@ static int leaf_space_used(struct extent_buffer *l, int start, int nr)
|
||||||
if (!nr)
|
if (!nr)
|
||||||
return 0;
|
return 0;
|
||||||
btrfs_init_map_token(&token);
|
btrfs_init_map_token(&token);
|
||||||
start_item = btrfs_item_nr(l, start);
|
start_item = btrfs_item_nr(start);
|
||||||
end_item = btrfs_item_nr(l, end);
|
end_item = btrfs_item_nr(end);
|
||||||
data_len = btrfs_token_item_offset(l, start_item, &token) +
|
data_len = btrfs_token_item_offset(l, start_item, &token) +
|
||||||
btrfs_token_item_size(l, start_item, &token);
|
btrfs_token_item_size(l, start_item, &token);
|
||||||
data_len = data_len - btrfs_token_item_offset(l, end_item, &token);
|
data_len = data_len - btrfs_token_item_offset(l, end_item, &token);
|
||||||
|
@ -3406,7 +3409,7 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
|
||||||
slot = path->slots[1];
|
slot = path->slots[1];
|
||||||
i = left_nritems - 1;
|
i = left_nritems - 1;
|
||||||
while (i >= nr) {
|
while (i >= nr) {
|
||||||
item = btrfs_item_nr(left, i);
|
item = btrfs_item_nr(i);
|
||||||
|
|
||||||
if (!empty && push_items > 0) {
|
if (!empty && push_items > 0) {
|
||||||
if (path->slots[0] > i)
|
if (path->slots[0] > i)
|
||||||
|
@ -3470,7 +3473,7 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
|
||||||
btrfs_set_header_nritems(right, right_nritems);
|
btrfs_set_header_nritems(right, right_nritems);
|
||||||
push_space = BTRFS_LEAF_DATA_SIZE(root);
|
push_space = BTRFS_LEAF_DATA_SIZE(root);
|
||||||
for (i = 0; i < right_nritems; i++) {
|
for (i = 0; i < right_nritems; i++) {
|
||||||
item = btrfs_item_nr(right, i);
|
item = btrfs_item_nr(i);
|
||||||
push_space -= btrfs_token_item_size(right, item, &token);
|
push_space -= btrfs_token_item_size(right, item, &token);
|
||||||
btrfs_set_token_item_offset(right, item, push_space, &token);
|
btrfs_set_token_item_offset(right, item, push_space, &token);
|
||||||
}
|
}
|
||||||
|
@ -3612,7 +3615,7 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
|
||||||
nr = min(right_nritems - 1, max_slot);
|
nr = min(right_nritems - 1, max_slot);
|
||||||
|
|
||||||
for (i = 0; i < nr; i++) {
|
for (i = 0; i < nr; i++) {
|
||||||
item = btrfs_item_nr(right, i);
|
item = btrfs_item_nr(i);
|
||||||
|
|
||||||
if (!empty && push_items > 0) {
|
if (!empty && push_items > 0) {
|
||||||
if (path->slots[0] < i)
|
if (path->slots[0] < i)
|
||||||
|
@ -3639,8 +3642,7 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!empty && push_items == btrfs_header_nritems(right))
|
WARN_ON(!empty && push_items == btrfs_header_nritems(right));
|
||||||
WARN_ON(1);
|
|
||||||
|
|
||||||
/* push data from right to left */
|
/* push data from right to left */
|
||||||
copy_extent_buffer(left, right,
|
copy_extent_buffer(left, right,
|
||||||
|
@ -3663,7 +3665,7 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
|
||||||
for (i = old_left_nritems; i < old_left_nritems + push_items; i++) {
|
for (i = old_left_nritems; i < old_left_nritems + push_items; i++) {
|
||||||
u32 ioff;
|
u32 ioff;
|
||||||
|
|
||||||
item = btrfs_item_nr(left, i);
|
item = btrfs_item_nr(i);
|
||||||
|
|
||||||
ioff = btrfs_token_item_offset(left, item, &token);
|
ioff = btrfs_token_item_offset(left, item, &token);
|
||||||
btrfs_set_token_item_offset(left, item,
|
btrfs_set_token_item_offset(left, item,
|
||||||
|
@ -3694,7 +3696,7 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
|
||||||
btrfs_set_header_nritems(right, right_nritems);
|
btrfs_set_header_nritems(right, right_nritems);
|
||||||
push_space = BTRFS_LEAF_DATA_SIZE(root);
|
push_space = BTRFS_LEAF_DATA_SIZE(root);
|
||||||
for (i = 0; i < right_nritems; i++) {
|
for (i = 0; i < right_nritems; i++) {
|
||||||
item = btrfs_item_nr(right, i);
|
item = btrfs_item_nr(i);
|
||||||
|
|
||||||
push_space = push_space - btrfs_token_item_size(right,
|
push_space = push_space - btrfs_token_item_size(right,
|
||||||
item, &token);
|
item, &token);
|
||||||
|
@ -3835,7 +3837,7 @@ static noinline void copy_for_split(struct btrfs_trans_handle *trans,
|
||||||
btrfs_item_end_nr(l, mid);
|
btrfs_item_end_nr(l, mid);
|
||||||
|
|
||||||
for (i = 0; i < nritems; i++) {
|
for (i = 0; i < nritems; i++) {
|
||||||
struct btrfs_item *item = btrfs_item_nr(right, i);
|
struct btrfs_item *item = btrfs_item_nr(i);
|
||||||
u32 ioff;
|
u32 ioff;
|
||||||
|
|
||||||
ioff = btrfs_token_item_offset(right, item, &token);
|
ioff = btrfs_token_item_offset(right, item, &token);
|
||||||
|
@ -4016,7 +4018,7 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
|
||||||
data_size > BTRFS_LEAF_DATA_SIZE(root)) {
|
data_size > BTRFS_LEAF_DATA_SIZE(root)) {
|
||||||
if (data_size && !tried_avoid_double)
|
if (data_size && !tried_avoid_double)
|
||||||
goto push_for_double;
|
goto push_for_double;
|
||||||
split = 2 ;
|
split = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4042,7 +4044,7 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
|
||||||
btrfs_set_header_owner(right, root->root_key.objectid);
|
btrfs_set_header_owner(right, root->root_key.objectid);
|
||||||
btrfs_set_header_level(right, 0);
|
btrfs_set_header_level(right, 0);
|
||||||
write_extent_buffer(right, root->fs_info->fsid,
|
write_extent_buffer(right, root->fs_info->fsid,
|
||||||
btrfs_header_fsid(right), BTRFS_FSID_SIZE);
|
btrfs_header_fsid(), BTRFS_FSID_SIZE);
|
||||||
|
|
||||||
write_extent_buffer(right, root->fs_info->chunk_tree_uuid,
|
write_extent_buffer(right, root->fs_info->chunk_tree_uuid,
|
||||||
btrfs_header_chunk_tree_uuid(right),
|
btrfs_header_chunk_tree_uuid(right),
|
||||||
|
@ -4177,7 +4179,7 @@ static noinline int split_item(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
btrfs_set_path_blocking(path);
|
btrfs_set_path_blocking(path);
|
||||||
|
|
||||||
item = btrfs_item_nr(leaf, path->slots[0]);
|
item = btrfs_item_nr(path->slots[0]);
|
||||||
orig_offset = btrfs_item_offset(leaf, item);
|
orig_offset = btrfs_item_offset(leaf, item);
|
||||||
item_size = btrfs_item_size(leaf, item);
|
item_size = btrfs_item_size(leaf, item);
|
||||||
|
|
||||||
|
@ -4200,7 +4202,7 @@ static noinline int split_item(struct btrfs_trans_handle *trans,
|
||||||
btrfs_cpu_key_to_disk(&disk_key, new_key);
|
btrfs_cpu_key_to_disk(&disk_key, new_key);
|
||||||
btrfs_set_item_key(leaf, &disk_key, slot);
|
btrfs_set_item_key(leaf, &disk_key, slot);
|
||||||
|
|
||||||
new_item = btrfs_item_nr(leaf, slot);
|
new_item = btrfs_item_nr(slot);
|
||||||
|
|
||||||
btrfs_set_item_offset(leaf, new_item, orig_offset);
|
btrfs_set_item_offset(leaf, new_item, orig_offset);
|
||||||
btrfs_set_item_size(leaf, new_item, item_size - split_offset);
|
btrfs_set_item_size(leaf, new_item, item_size - split_offset);
|
||||||
|
@ -4339,7 +4341,7 @@ void btrfs_truncate_item(struct btrfs_root *root, struct btrfs_path *path,
|
||||||
/* first correct the data pointers */
|
/* first correct the data pointers */
|
||||||
for (i = slot; i < nritems; i++) {
|
for (i = slot; i < nritems; i++) {
|
||||||
u32 ioff;
|
u32 ioff;
|
||||||
item = btrfs_item_nr(leaf, i);
|
item = btrfs_item_nr(i);
|
||||||
|
|
||||||
ioff = btrfs_token_item_offset(leaf, item, &token);
|
ioff = btrfs_token_item_offset(leaf, item, &token);
|
||||||
btrfs_set_token_item_offset(leaf, item,
|
btrfs_set_token_item_offset(leaf, item,
|
||||||
|
@ -4387,7 +4389,7 @@ void btrfs_truncate_item(struct btrfs_root *root, struct btrfs_path *path,
|
||||||
fixup_low_keys(root, path, &disk_key, 1);
|
fixup_low_keys(root, path, &disk_key, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
item = btrfs_item_nr(leaf, slot);
|
item = btrfs_item_nr(slot);
|
||||||
btrfs_set_item_size(leaf, item, new_size);
|
btrfs_set_item_size(leaf, item, new_size);
|
||||||
btrfs_mark_buffer_dirty(leaf);
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
|
|
||||||
|
@ -4441,7 +4443,7 @@ void btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
|
||||||
/* first correct the data pointers */
|
/* first correct the data pointers */
|
||||||
for (i = slot; i < nritems; i++) {
|
for (i = slot; i < nritems; i++) {
|
||||||
u32 ioff;
|
u32 ioff;
|
||||||
item = btrfs_item_nr(leaf, i);
|
item = btrfs_item_nr(i);
|
||||||
|
|
||||||
ioff = btrfs_token_item_offset(leaf, item, &token);
|
ioff = btrfs_token_item_offset(leaf, item, &token);
|
||||||
btrfs_set_token_item_offset(leaf, item,
|
btrfs_set_token_item_offset(leaf, item,
|
||||||
|
@ -4455,7 +4457,7 @@ void btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
|
||||||
|
|
||||||
data_end = old_data;
|
data_end = old_data;
|
||||||
old_size = btrfs_item_size_nr(leaf, slot);
|
old_size = btrfs_item_size_nr(leaf, slot);
|
||||||
item = btrfs_item_nr(leaf, slot);
|
item = btrfs_item_nr(slot);
|
||||||
btrfs_set_item_size(leaf, item, old_size + data_size);
|
btrfs_set_item_size(leaf, item, old_size + data_size);
|
||||||
btrfs_mark_buffer_dirty(leaf);
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
|
|
||||||
|
@ -4514,7 +4516,7 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
|
||||||
for (i = slot; i < nritems; i++) {
|
for (i = slot; i < nritems; i++) {
|
||||||
u32 ioff;
|
u32 ioff;
|
||||||
|
|
||||||
item = btrfs_item_nr(leaf, i);
|
item = btrfs_item_nr( i);
|
||||||
ioff = btrfs_token_item_offset(leaf, item, &token);
|
ioff = btrfs_token_item_offset(leaf, item, &token);
|
||||||
btrfs_set_token_item_offset(leaf, item,
|
btrfs_set_token_item_offset(leaf, item,
|
||||||
ioff - total_data, &token);
|
ioff - total_data, &token);
|
||||||
|
@ -4535,7 +4537,7 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
|
||||||
for (i = 0; i < nr; i++) {
|
for (i = 0; i < nr; i++) {
|
||||||
btrfs_cpu_key_to_disk(&disk_key, cpu_key + i);
|
btrfs_cpu_key_to_disk(&disk_key, cpu_key + i);
|
||||||
btrfs_set_item_key(leaf, &disk_key, slot + i);
|
btrfs_set_item_key(leaf, &disk_key, slot + i);
|
||||||
item = btrfs_item_nr(leaf, slot + i);
|
item = btrfs_item_nr(slot + i);
|
||||||
btrfs_set_token_item_offset(leaf, item,
|
btrfs_set_token_item_offset(leaf, item,
|
||||||
data_end - data_size[i], &token);
|
data_end - data_size[i], &token);
|
||||||
data_end -= data_size[i];
|
data_end -= data_size[i];
|
||||||
|
@ -4730,7 +4732,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||||
for (i = slot + nr; i < nritems; i++) {
|
for (i = slot + nr; i < nritems; i++) {
|
||||||
u32 ioff;
|
u32 ioff;
|
||||||
|
|
||||||
item = btrfs_item_nr(leaf, i);
|
item = btrfs_item_nr(i);
|
||||||
ioff = btrfs_token_item_offset(leaf, item, &token);
|
ioff = btrfs_token_item_offset(leaf, item, &token);
|
||||||
btrfs_set_token_item_offset(leaf, item,
|
btrfs_set_token_item_offset(leaf, item,
|
||||||
ioff + dsize, &token);
|
ioff + dsize, &token);
|
||||||
|
@ -4823,14 +4825,18 @@ static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
|
||||||
|
|
||||||
btrfs_item_key_to_cpu(path->nodes[0], &key, 0);
|
btrfs_item_key_to_cpu(path->nodes[0], &key, 0);
|
||||||
|
|
||||||
if (key.offset > 0)
|
if (key.offset > 0) {
|
||||||
key.offset--;
|
key.offset--;
|
||||||
else if (key.type > 0)
|
} else if (key.type > 0) {
|
||||||
key.type--;
|
key.type--;
|
||||||
else if (key.objectid > 0)
|
key.offset = (u64)-1;
|
||||||
|
} else if (key.objectid > 0) {
|
||||||
key.objectid--;
|
key.objectid--;
|
||||||
else
|
key.type = (u8)-1;
|
||||||
|
key.offset = (u64)-1;
|
||||||
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||||
|
@ -4866,7 +4872,6 @@ static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
|
||||||
* was nothing in the tree that matched the search criteria.
|
* was nothing in the tree that matched the search criteria.
|
||||||
*/
|
*/
|
||||||
int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
|
int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
|
||||||
struct btrfs_key *max_key,
|
|
||||||
struct btrfs_path *path,
|
struct btrfs_path *path,
|
||||||
u64 min_trans)
|
u64 min_trans)
|
||||||
{
|
{
|
||||||
|
@ -4911,10 +4916,8 @@ int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
|
||||||
* If it is too old, old, skip to the next one.
|
* If it is too old, old, skip to the next one.
|
||||||
*/
|
*/
|
||||||
while (slot < nritems) {
|
while (slot < nritems) {
|
||||||
u64 blockptr;
|
|
||||||
u64 gen;
|
u64 gen;
|
||||||
|
|
||||||
blockptr = btrfs_node_blockptr(cur, slot);
|
|
||||||
gen = btrfs_node_ptr_generation(cur, slot);
|
gen = btrfs_node_ptr_generation(cur, slot);
|
||||||
if (gen < min_trans) {
|
if (gen < min_trans) {
|
||||||
slot++;
|
slot++;
|
||||||
|
|
|
@ -47,6 +47,12 @@ extern struct kmem_cache *btrfs_path_cachep;
|
||||||
extern struct kmem_cache *btrfs_free_space_cachep;
|
extern struct kmem_cache *btrfs_free_space_cachep;
|
||||||
struct btrfs_ordered_sum;
|
struct btrfs_ordered_sum;
|
||||||
|
|
||||||
|
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
|
||||||
|
#define STATIC noinline
|
||||||
|
#else
|
||||||
|
#define STATIC static noinline
|
||||||
|
#endif
|
||||||
|
|
||||||
#define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */
|
#define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */
|
||||||
|
|
||||||
#define BTRFS_MAX_MIRRORS 3
|
#define BTRFS_MAX_MIRRORS 3
|
||||||
|
@ -1580,7 +1586,6 @@ struct btrfs_fs_info {
|
||||||
atomic_t scrubs_paused;
|
atomic_t scrubs_paused;
|
||||||
atomic_t scrub_cancel_req;
|
atomic_t scrub_cancel_req;
|
||||||
wait_queue_head_t scrub_pause_wait;
|
wait_queue_head_t scrub_pause_wait;
|
||||||
struct rw_semaphore scrub_super_lock;
|
|
||||||
int scrub_workers_refcnt;
|
int scrub_workers_refcnt;
|
||||||
struct btrfs_workers scrub_workers;
|
struct btrfs_workers scrub_workers;
|
||||||
struct btrfs_workers scrub_wr_completion_workers;
|
struct btrfs_workers scrub_wr_completion_workers;
|
||||||
|
@ -1724,7 +1729,9 @@ struct btrfs_root {
|
||||||
int ref_cows;
|
int ref_cows;
|
||||||
int track_dirty;
|
int track_dirty;
|
||||||
int in_radix;
|
int in_radix;
|
||||||
|
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
|
||||||
|
int dummy_root;
|
||||||
|
#endif
|
||||||
u64 defrag_trans_start;
|
u64 defrag_trans_start;
|
||||||
struct btrfs_key defrag_progress;
|
struct btrfs_key defrag_progress;
|
||||||
struct btrfs_key defrag_max;
|
struct btrfs_key defrag_max;
|
||||||
|
@ -2461,8 +2468,7 @@ static inline unsigned long btrfs_item_nr_offset(int nr)
|
||||||
sizeof(struct btrfs_item) * nr;
|
sizeof(struct btrfs_item) * nr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct btrfs_item *btrfs_item_nr(struct extent_buffer *eb,
|
static inline struct btrfs_item *btrfs_item_nr(int nr)
|
||||||
int nr)
|
|
||||||
{
|
{
|
||||||
return (struct btrfs_item *)btrfs_item_nr_offset(nr);
|
return (struct btrfs_item *)btrfs_item_nr_offset(nr);
|
||||||
}
|
}
|
||||||
|
@ -2475,30 +2481,30 @@ static inline u32 btrfs_item_end(struct extent_buffer *eb,
|
||||||
|
|
||||||
static inline u32 btrfs_item_end_nr(struct extent_buffer *eb, int nr)
|
static inline u32 btrfs_item_end_nr(struct extent_buffer *eb, int nr)
|
||||||
{
|
{
|
||||||
return btrfs_item_end(eb, btrfs_item_nr(eb, nr));
|
return btrfs_item_end(eb, btrfs_item_nr(nr));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr)
|
static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr)
|
||||||
{
|
{
|
||||||
return btrfs_item_offset(eb, btrfs_item_nr(eb, nr));
|
return btrfs_item_offset(eb, btrfs_item_nr(nr));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 btrfs_item_size_nr(struct extent_buffer *eb, int nr)
|
static inline u32 btrfs_item_size_nr(struct extent_buffer *eb, int nr)
|
||||||
{
|
{
|
||||||
return btrfs_item_size(eb, btrfs_item_nr(eb, nr));
|
return btrfs_item_size(eb, btrfs_item_nr(nr));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void btrfs_item_key(struct extent_buffer *eb,
|
static inline void btrfs_item_key(struct extent_buffer *eb,
|
||||||
struct btrfs_disk_key *disk_key, int nr)
|
struct btrfs_disk_key *disk_key, int nr)
|
||||||
{
|
{
|
||||||
struct btrfs_item *item = btrfs_item_nr(eb, nr);
|
struct btrfs_item *item = btrfs_item_nr(nr);
|
||||||
read_eb_member(eb, item, struct btrfs_item, key, disk_key);
|
read_eb_member(eb, item, struct btrfs_item, key, disk_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void btrfs_set_item_key(struct extent_buffer *eb,
|
static inline void btrfs_set_item_key(struct extent_buffer *eb,
|
||||||
struct btrfs_disk_key *disk_key, int nr)
|
struct btrfs_disk_key *disk_key, int nr)
|
||||||
{
|
{
|
||||||
struct btrfs_item *item = btrfs_item_nr(eb, nr);
|
struct btrfs_item *item = btrfs_item_nr(nr);
|
||||||
write_eb_member(eb, item, struct btrfs_item, key, disk_key);
|
write_eb_member(eb, item, struct btrfs_item, key, disk_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2666,7 +2672,7 @@ static inline void btrfs_set_header_backref_rev(struct extent_buffer *eb,
|
||||||
btrfs_set_header_flags(eb, flags);
|
btrfs_set_header_flags(eb, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long btrfs_header_fsid(struct extent_buffer *eb)
|
static inline unsigned long btrfs_header_fsid(void)
|
||||||
{
|
{
|
||||||
return offsetof(struct btrfs_header, fsid);
|
return offsetof(struct btrfs_header, fsid);
|
||||||
}
|
}
|
||||||
|
@ -3308,7 +3314,6 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path,
|
||||||
struct btrfs_key *key, int lowest_level,
|
struct btrfs_key *key, int lowest_level,
|
||||||
u64 min_trans);
|
u64 min_trans);
|
||||||
int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
|
int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key,
|
||||||
struct btrfs_key *max_key,
|
|
||||||
struct btrfs_path *path,
|
struct btrfs_path *path,
|
||||||
u64 min_trans);
|
u64 min_trans);
|
||||||
enum btrfs_compare_tree_result {
|
enum btrfs_compare_tree_result {
|
||||||
|
@ -3675,8 +3680,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
|
||||||
u32 min_type);
|
u32 min_type);
|
||||||
|
|
||||||
int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
|
int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
|
||||||
int btrfs_start_all_delalloc_inodes(struct btrfs_fs_info *fs_info,
|
int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput);
|
||||||
int delay_iput);
|
|
||||||
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
|
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
|
||||||
struct extent_state **cached_state);
|
struct extent_state **cached_state);
|
||||||
int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
|
int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
|
||||||
|
@ -3944,9 +3948,7 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
|
||||||
u64 end, struct btrfs_scrub_progress *progress,
|
u64 end, struct btrfs_scrub_progress *progress,
|
||||||
int readonly, int is_dev_replace);
|
int readonly, int is_dev_replace);
|
||||||
void btrfs_scrub_pause(struct btrfs_root *root);
|
void btrfs_scrub_pause(struct btrfs_root *root);
|
||||||
void btrfs_scrub_pause_super(struct btrfs_root *root);
|
|
||||||
void btrfs_scrub_continue(struct btrfs_root *root);
|
void btrfs_scrub_continue(struct btrfs_root *root);
|
||||||
void btrfs_scrub_continue_super(struct btrfs_root *root);
|
|
||||||
int btrfs_scrub_cancel(struct btrfs_fs_info *info);
|
int btrfs_scrub_cancel(struct btrfs_fs_info *info);
|
||||||
int btrfs_scrub_cancel_dev(struct btrfs_fs_info *info,
|
int btrfs_scrub_cancel_dev(struct btrfs_fs_info *info,
|
||||||
struct btrfs_device *dev);
|
struct btrfs_device *dev);
|
||||||
|
@ -4028,5 +4030,9 @@ static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info)
|
||||||
return signal_pending(current);
|
return signal_pending(current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sanity test specific functions */
|
||||||
|
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
|
||||||
|
void btrfs_test_destroy_inode(struct inode *inode);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -108,8 +108,8 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(struct inode *inode)
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
btrfs_inode->delayed_node = node;
|
btrfs_inode->delayed_node = node;
|
||||||
atomic_inc(&node->refs); /* can be accessed */
|
/* can be accessed and cached in the inode */
|
||||||
atomic_inc(&node->refs); /* cached in the inode */
|
atomic_add(2, &node->refs);
|
||||||
spin_unlock(&root->inode_lock);
|
spin_unlock(&root->inode_lock);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
@ -138,8 +138,8 @@ static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
btrfs_init_delayed_node(node, root, ino);
|
btrfs_init_delayed_node(node, root, ino);
|
||||||
|
|
||||||
atomic_inc(&node->refs); /* cached in the btrfs inode */
|
/* cached in the btrfs inode and can be accessed */
|
||||||
atomic_inc(&node->refs); /* can be accessed */
|
atomic_add(2, &node->refs);
|
||||||
|
|
||||||
ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
|
ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -649,14 +649,13 @@ static int btrfs_delayed_inode_reserve_metadata(
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
|
ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
|
||||||
if (!ret)
|
if (!WARN_ON(ret))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ok this is a problem, let's just steal from the global rsv
|
* Ok this is a problem, let's just steal from the global rsv
|
||||||
* since this really shouldn't happen that often.
|
* since this really shouldn't happen that often.
|
||||||
*/
|
*/
|
||||||
WARN_ON(1);
|
|
||||||
ret = btrfs_block_rsv_migrate(&root->fs_info->global_block_rsv,
|
ret = btrfs_block_rsv_migrate(&root->fs_info->global_block_rsv,
|
||||||
dst_rsv, num_bytes);
|
dst_rsv, num_bytes);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -771,13 +770,13 @@ static int btrfs_batch_insert_items(struct btrfs_root *root,
|
||||||
*/
|
*/
|
||||||
btrfs_set_path_blocking(path);
|
btrfs_set_path_blocking(path);
|
||||||
|
|
||||||
keys = kmalloc(sizeof(struct btrfs_key) * nitems, GFP_NOFS);
|
keys = kmalloc_array(nitems, sizeof(struct btrfs_key), GFP_NOFS);
|
||||||
if (!keys) {
|
if (!keys) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
data_size = kmalloc(sizeof(u32) * nitems, GFP_NOFS);
|
data_size = kmalloc_array(nitems, sizeof(u32), GFP_NOFS);
|
||||||
if (!data_size) {
|
if (!data_size) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -1174,8 +1173,10 @@ int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
|
||||||
mutex_unlock(&delayed_node->mutex);
|
mutex_unlock(&delayed_node->mutex);
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path) {
|
||||||
|
btrfs_release_delayed_node(delayed_node);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
path->leave_spinning = 1;
|
path->leave_spinning = 1;
|
||||||
|
|
||||||
block_rsv = trans->block_rsv;
|
block_rsv = trans->block_rsv;
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <linux/math64.h>
|
#include <linux/math64.h>
|
||||||
#include <asm/div64.h>
|
#include <asm/div64.h>
|
||||||
#include "compat.h"
|
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "extent_map.h"
|
#include "extent_map.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
|
@ -38,7 +37,6 @@
|
||||||
#include "rcu-string.h"
|
#include "rcu-string.h"
|
||||||
#include "dev-replace.h"
|
#include "dev-replace.h"
|
||||||
|
|
||||||
static u64 btrfs_get_seconds_since_1970(void);
|
|
||||||
static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
|
static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
|
||||||
int scrub_ret);
|
int scrub_ret);
|
||||||
static void btrfs_dev_replace_update_device_in_mapping_tree(
|
static void btrfs_dev_replace_update_device_in_mapping_tree(
|
||||||
|
@ -296,13 +294,6 @@ void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info)
|
||||||
dev_replace->cursor_left_last_write_of_item;
|
dev_replace->cursor_left_last_write_of_item;
|
||||||
}
|
}
|
||||||
|
|
||||||
static u64 btrfs_get_seconds_since_1970(void)
|
|
||||||
{
|
|
||||||
struct timespec t = CURRENT_TIME_SEC;
|
|
||||||
|
|
||||||
return t.tv_sec;
|
|
||||||
}
|
|
||||||
|
|
||||||
int btrfs_dev_replace_start(struct btrfs_root *root,
|
int btrfs_dev_replace_start(struct btrfs_root *root,
|
||||||
struct btrfs_ioctl_dev_replace_args *args)
|
struct btrfs_ioctl_dev_replace_args *args)
|
||||||
{
|
{
|
||||||
|
@ -390,7 +381,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
|
||||||
* go to the tgtdev as well (refer to btrfs_map_block()).
|
* go to the tgtdev as well (refer to btrfs_map_block()).
|
||||||
*/
|
*/
|
||||||
dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED;
|
dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED;
|
||||||
dev_replace->time_started = btrfs_get_seconds_since_1970();
|
dev_replace->time_started = get_seconds();
|
||||||
dev_replace->cursor_left = 0;
|
dev_replace->cursor_left = 0;
|
||||||
dev_replace->committed_cursor_left = 0;
|
dev_replace->committed_cursor_left = 0;
|
||||||
dev_replace->cursor_left_last_write_of_item = 0;
|
dev_replace->cursor_left_last_write_of_item = 0;
|
||||||
|
@ -400,7 +391,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
|
||||||
args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
|
args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
|
||||||
btrfs_dev_replace_unlock(dev_replace);
|
btrfs_dev_replace_unlock(dev_replace);
|
||||||
|
|
||||||
btrfs_wait_all_ordered_extents(root->fs_info);
|
btrfs_wait_ordered_roots(root->fs_info, -1);
|
||||||
|
|
||||||
/* force writing the updated state information to disk */
|
/* force writing the updated state information to disk */
|
||||||
trans = btrfs_start_transaction(root, 0);
|
trans = btrfs_start_transaction(root, 0);
|
||||||
|
@ -470,12 +461,12 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
|
||||||
* flush all outstanding I/O and inode extent mappings before the
|
* flush all outstanding I/O and inode extent mappings before the
|
||||||
* copy operation is declared as being finished
|
* copy operation is declared as being finished
|
||||||
*/
|
*/
|
||||||
ret = btrfs_start_all_delalloc_inodes(root->fs_info, 0);
|
ret = btrfs_start_delalloc_roots(root->fs_info, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
|
mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
btrfs_wait_all_ordered_extents(root->fs_info);
|
btrfs_wait_ordered_roots(root->fs_info, -1);
|
||||||
|
|
||||||
trans = btrfs_start_transaction(root, 0);
|
trans = btrfs_start_transaction(root, 0);
|
||||||
if (IS_ERR(trans)) {
|
if (IS_ERR(trans)) {
|
||||||
|
@ -493,7 +484,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
|
||||||
: BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED;
|
: BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED;
|
||||||
dev_replace->tgtdev = NULL;
|
dev_replace->tgtdev = NULL;
|
||||||
dev_replace->srcdev = NULL;
|
dev_replace->srcdev = NULL;
|
||||||
dev_replace->time_stopped = btrfs_get_seconds_since_1970();
|
dev_replace->time_stopped = get_seconds();
|
||||||
dev_replace->item_needs_writeback = 1;
|
dev_replace->item_needs_writeback = 1;
|
||||||
|
|
||||||
if (scrub_ret) {
|
if (scrub_ret) {
|
||||||
|
@ -650,6 +641,9 @@ static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
|
||||||
u64 result;
|
u64 result;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (fs_info->sb->s_flags & MS_RDONLY)
|
||||||
|
return -EROFS;
|
||||||
|
|
||||||
mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
|
mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
|
||||||
btrfs_dev_replace_lock(dev_replace);
|
btrfs_dev_replace_lock(dev_replace);
|
||||||
switch (dev_replace->replace_state) {
|
switch (dev_replace->replace_state) {
|
||||||
|
@ -668,7 +662,7 @@ static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED;
|
dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED;
|
||||||
dev_replace->time_stopped = btrfs_get_seconds_since_1970();
|
dev_replace->time_stopped = get_seconds();
|
||||||
dev_replace->item_needs_writeback = 1;
|
dev_replace->item_needs_writeback = 1;
|
||||||
btrfs_dev_replace_unlock(dev_replace);
|
btrfs_dev_replace_unlock(dev_replace);
|
||||||
btrfs_scrub_cancel(fs_info);
|
btrfs_scrub_cancel(fs_info);
|
||||||
|
@ -703,7 +697,7 @@ void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info)
|
||||||
case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
|
case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
|
||||||
dev_replace->replace_state =
|
dev_replace->replace_state =
|
||||||
BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED;
|
BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED;
|
||||||
dev_replace->time_stopped = btrfs_get_seconds_since_1970();
|
dev_replace->time_stopped = get_seconds();
|
||||||
dev_replace->item_needs_writeback = 1;
|
dev_replace->item_needs_writeback = 1;
|
||||||
pr_info("btrfs: suspending dev_replace for unmount\n");
|
pr_info("btrfs: suspending dev_replace for unmount\n");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -58,7 +58,7 @@ static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
WARN_ON(ret > 0);
|
WARN_ON(ret > 0);
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
item = btrfs_item_nr(leaf, path->slots[0]);
|
item = btrfs_item_nr(path->slots[0]);
|
||||||
ptr = btrfs_item_ptr(leaf, path->slots[0], char);
|
ptr = btrfs_item_ptr(leaf, path->slots[0], char);
|
||||||
BUG_ON(data_size > btrfs_item_size(leaf, item));
|
BUG_ON(data_size > btrfs_item_size(leaf, item));
|
||||||
ptr += btrfs_item_size(leaf, item) - data_size;
|
ptr += btrfs_item_size(leaf, item) - data_size;
|
||||||
|
@ -474,8 +474,10 @@ int verify_dir_item(struct btrfs_root *root,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BTRFS_MAX_XATTR_SIZE is the same for all dir items */
|
/* BTRFS_MAX_XATTR_SIZE is the same for all dir items */
|
||||||
if (btrfs_dir_data_len(leaf, dir_item) > BTRFS_MAX_XATTR_SIZE(root)) {
|
if ((btrfs_dir_data_len(leaf, dir_item) +
|
||||||
printk(KERN_CRIT "btrfs: invalid dir item data len: %u\n",
|
btrfs_dir_name_len(leaf, dir_item)) > BTRFS_MAX_XATTR_SIZE(root)) {
|
||||||
|
printk(KERN_CRIT "btrfs: invalid dir item name + data len: %u + %u\n",
|
||||||
|
(unsigned)btrfs_dir_name_len(leaf, dir_item),
|
||||||
(unsigned)btrfs_dir_data_len(leaf, dir_item));
|
(unsigned)btrfs_dir_data_len(leaf, dir_item));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#include <linux/uuid.h>
|
#include <linux/uuid.h>
|
||||||
#include <linux/semaphore.h>
|
#include <linux/semaphore.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
#include "compat.h"
|
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
|
@ -64,7 +63,6 @@ static void btrfs_destroy_ordered_operations(struct btrfs_transaction *t,
|
||||||
static void btrfs_destroy_ordered_extents(struct btrfs_root *root);
|
static void btrfs_destroy_ordered_extents(struct btrfs_root *root);
|
||||||
static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||||
struct btrfs_root *root);
|
struct btrfs_root *root);
|
||||||
static void btrfs_evict_pending_snapshots(struct btrfs_transaction *t);
|
|
||||||
static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root);
|
static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root);
|
||||||
static int btrfs_destroy_marked_extents(struct btrfs_root *root,
|
static int btrfs_destroy_marked_extents(struct btrfs_root *root,
|
||||||
struct extent_io_tree *dirty_pages,
|
struct extent_io_tree *dirty_pages,
|
||||||
|
@ -477,14 +475,8 @@ static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
|
||||||
if (page != eb->pages[0])
|
if (page != eb->pages[0])
|
||||||
return 0;
|
return 0;
|
||||||
found_start = btrfs_header_bytenr(eb);
|
found_start = btrfs_header_bytenr(eb);
|
||||||
if (found_start != start) {
|
if (WARN_ON(found_start != start || !PageUptodate(page)))
|
||||||
WARN_ON(1);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
if (!PageUptodate(page)) {
|
|
||||||
WARN_ON(1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
csum_tree_block(root, eb, 0);
|
csum_tree_block(root, eb, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -496,7 +488,7 @@ static int check_tree_block_fsid(struct btrfs_root *root,
|
||||||
u8 fsid[BTRFS_UUID_SIZE];
|
u8 fsid[BTRFS_UUID_SIZE];
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
|
||||||
read_extent_buffer(eb, fsid, btrfs_header_fsid(eb), BTRFS_FSID_SIZE);
|
read_extent_buffer(eb, fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE);
|
||||||
while (fs_devices) {
|
while (fs_devices) {
|
||||||
if (!memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE)) {
|
if (!memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE)) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -1105,8 +1097,7 @@ struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
|
||||||
{
|
{
|
||||||
struct inode *btree_inode = root->fs_info->btree_inode;
|
struct inode *btree_inode = root->fs_info->btree_inode;
|
||||||
struct extent_buffer *eb;
|
struct extent_buffer *eb;
|
||||||
eb = find_extent_buffer(&BTRFS_I(btree_inode)->io_tree,
|
eb = find_extent_buffer(&BTRFS_I(btree_inode)->io_tree, bytenr);
|
||||||
bytenr, blocksize);
|
|
||||||
return eb;
|
return eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1229,14 +1220,18 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
|
||||||
atomic_set(&root->refs, 1);
|
atomic_set(&root->refs, 1);
|
||||||
root->log_transid = 0;
|
root->log_transid = 0;
|
||||||
root->last_log_commit = 0;
|
root->last_log_commit = 0;
|
||||||
extent_io_tree_init(&root->dirty_log_pages,
|
if (fs_info)
|
||||||
fs_info->btree_inode->i_mapping);
|
extent_io_tree_init(&root->dirty_log_pages,
|
||||||
|
fs_info->btree_inode->i_mapping);
|
||||||
|
|
||||||
memset(&root->root_key, 0, sizeof(root->root_key));
|
memset(&root->root_key, 0, sizeof(root->root_key));
|
||||||
memset(&root->root_item, 0, sizeof(root->root_item));
|
memset(&root->root_item, 0, sizeof(root->root_item));
|
||||||
memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
|
memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
|
||||||
memset(&root->root_kobj, 0, sizeof(root->root_kobj));
|
memset(&root->root_kobj, 0, sizeof(root->root_kobj));
|
||||||
root->defrag_trans_start = fs_info->generation;
|
if (fs_info)
|
||||||
|
root->defrag_trans_start = fs_info->generation;
|
||||||
|
else
|
||||||
|
root->defrag_trans_start = 0;
|
||||||
init_completion(&root->kobj_unregister);
|
init_completion(&root->kobj_unregister);
|
||||||
root->defrag_running = 0;
|
root->defrag_running = 0;
|
||||||
root->root_key.objectid = objectid;
|
root->root_key.objectid = objectid;
|
||||||
|
@ -1253,6 +1248,22 @@ static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info)
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
|
||||||
|
/* Should only be used by the testing infrastructure */
|
||||||
|
struct btrfs_root *btrfs_alloc_dummy_root(void)
|
||||||
|
{
|
||||||
|
struct btrfs_root *root;
|
||||||
|
|
||||||
|
root = btrfs_alloc_root(NULL);
|
||||||
|
if (!root)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
__setup_root(4096, 4096, 4096, 4096, root, NULL, 1);
|
||||||
|
root->dummy_root = 1;
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
|
struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_fs_info *fs_info,
|
struct btrfs_fs_info *fs_info,
|
||||||
u64 objectid)
|
u64 objectid)
|
||||||
|
@ -1292,7 +1303,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
|
||||||
btrfs_set_header_owner(leaf, objectid);
|
btrfs_set_header_owner(leaf, objectid);
|
||||||
root->node = leaf;
|
root->node = leaf;
|
||||||
|
|
||||||
write_extent_buffer(leaf, fs_info->fsid, btrfs_header_fsid(leaf),
|
write_extent_buffer(leaf, fs_info->fsid, btrfs_header_fsid(),
|
||||||
BTRFS_FSID_SIZE);
|
BTRFS_FSID_SIZE);
|
||||||
write_extent_buffer(leaf, fs_info->chunk_tree_uuid,
|
write_extent_buffer(leaf, fs_info->chunk_tree_uuid,
|
||||||
btrfs_header_chunk_tree_uuid(leaf),
|
btrfs_header_chunk_tree_uuid(leaf),
|
||||||
|
@ -1379,7 +1390,7 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
|
||||||
root->node = leaf;
|
root->node = leaf;
|
||||||
|
|
||||||
write_extent_buffer(root->node, root->fs_info->fsid,
|
write_extent_buffer(root->node, root->fs_info->fsid,
|
||||||
btrfs_header_fsid(root->node), BTRFS_FSID_SIZE);
|
btrfs_header_fsid(), BTRFS_FSID_SIZE);
|
||||||
btrfs_mark_buffer_dirty(root->node);
|
btrfs_mark_buffer_dirty(root->node);
|
||||||
btrfs_tree_unlock(root->node);
|
btrfs_tree_unlock(root->node);
|
||||||
return root;
|
return root;
|
||||||
|
@ -1780,6 +1791,9 @@ static int transaction_kthread(void *arg)
|
||||||
wake_up_process(root->fs_info->cleaner_kthread);
|
wake_up_process(root->fs_info->cleaner_kthread);
|
||||||
mutex_unlock(&root->fs_info->transaction_kthread_mutex);
|
mutex_unlock(&root->fs_info->transaction_kthread_mutex);
|
||||||
|
|
||||||
|
if (unlikely(test_bit(BTRFS_FS_STATE_ERROR,
|
||||||
|
&root->fs_info->fs_state)))
|
||||||
|
btrfs_cleanup_transaction(root);
|
||||||
if (!try_to_freeze()) {
|
if (!try_to_freeze()) {
|
||||||
set_current_state(TASK_INTERRUPTIBLE);
|
set_current_state(TASK_INTERRUPTIBLE);
|
||||||
if (!kthread_should_stop() &&
|
if (!kthread_should_stop() &&
|
||||||
|
@ -2013,50 +2027,28 @@ static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info)
|
||||||
btrfs_stop_workers(&fs_info->qgroup_rescan_workers);
|
btrfs_stop_workers(&fs_info->qgroup_rescan_workers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_root_extent_buffers(struct btrfs_root *root)
|
||||||
|
{
|
||||||
|
if (root) {
|
||||||
|
free_extent_buffer(root->node);
|
||||||
|
free_extent_buffer(root->commit_root);
|
||||||
|
root->node = NULL;
|
||||||
|
root->commit_root = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* helper to cleanup tree roots */
|
/* helper to cleanup tree roots */
|
||||||
static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
|
static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
|
||||||
{
|
{
|
||||||
free_extent_buffer(info->tree_root->node);
|
free_root_extent_buffers(info->tree_root);
|
||||||
free_extent_buffer(info->tree_root->commit_root);
|
|
||||||
info->tree_root->node = NULL;
|
|
||||||
info->tree_root->commit_root = NULL;
|
|
||||||
|
|
||||||
if (info->dev_root) {
|
free_root_extent_buffers(info->dev_root);
|
||||||
free_extent_buffer(info->dev_root->node);
|
free_root_extent_buffers(info->extent_root);
|
||||||
free_extent_buffer(info->dev_root->commit_root);
|
free_root_extent_buffers(info->csum_root);
|
||||||
info->dev_root->node = NULL;
|
free_root_extent_buffers(info->quota_root);
|
||||||
info->dev_root->commit_root = NULL;
|
free_root_extent_buffers(info->uuid_root);
|
||||||
}
|
if (chunk_root)
|
||||||
if (info->extent_root) {
|
free_root_extent_buffers(info->chunk_root);
|
||||||
free_extent_buffer(info->extent_root->node);
|
|
||||||
free_extent_buffer(info->extent_root->commit_root);
|
|
||||||
info->extent_root->node = NULL;
|
|
||||||
info->extent_root->commit_root = NULL;
|
|
||||||
}
|
|
||||||
if (info->csum_root) {
|
|
||||||
free_extent_buffer(info->csum_root->node);
|
|
||||||
free_extent_buffer(info->csum_root->commit_root);
|
|
||||||
info->csum_root->node = NULL;
|
|
||||||
info->csum_root->commit_root = NULL;
|
|
||||||
}
|
|
||||||
if (info->quota_root) {
|
|
||||||
free_extent_buffer(info->quota_root->node);
|
|
||||||
free_extent_buffer(info->quota_root->commit_root);
|
|
||||||
info->quota_root->node = NULL;
|
|
||||||
info->quota_root->commit_root = NULL;
|
|
||||||
}
|
|
||||||
if (info->uuid_root) {
|
|
||||||
free_extent_buffer(info->uuid_root->node);
|
|
||||||
free_extent_buffer(info->uuid_root->commit_root);
|
|
||||||
info->uuid_root->node = NULL;
|
|
||||||
info->uuid_root->commit_root = NULL;
|
|
||||||
}
|
|
||||||
if (chunk_root) {
|
|
||||||
free_extent_buffer(info->chunk_root->node);
|
|
||||||
free_extent_buffer(info->chunk_root->commit_root);
|
|
||||||
info->chunk_root->node = NULL;
|
|
||||||
info->chunk_root->commit_root = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void del_fs_roots(struct btrfs_fs_info *fs_info)
|
static void del_fs_roots(struct btrfs_fs_info *fs_info)
|
||||||
|
@ -2230,7 +2222,6 @@ int open_ctree(struct super_block *sb,
|
||||||
atomic_set(&fs_info->scrubs_paused, 0);
|
atomic_set(&fs_info->scrubs_paused, 0);
|
||||||
atomic_set(&fs_info->scrub_cancel_req, 0);
|
atomic_set(&fs_info->scrub_cancel_req, 0);
|
||||||
init_waitqueue_head(&fs_info->scrub_pause_wait);
|
init_waitqueue_head(&fs_info->scrub_pause_wait);
|
||||||
init_rwsem(&fs_info->scrub_super_lock);
|
|
||||||
fs_info->scrub_workers_refcnt = 0;
|
fs_info->scrub_workers_refcnt = 0;
|
||||||
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
|
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
|
||||||
fs_info->check_integrity_print_mask = 0;
|
fs_info->check_integrity_print_mask = 0;
|
||||||
|
@ -2272,7 +2263,7 @@ int open_ctree(struct super_block *sb,
|
||||||
sizeof(struct btrfs_key));
|
sizeof(struct btrfs_key));
|
||||||
set_bit(BTRFS_INODE_DUMMY,
|
set_bit(BTRFS_INODE_DUMMY,
|
||||||
&BTRFS_I(fs_info->btree_inode)->runtime_flags);
|
&BTRFS_I(fs_info->btree_inode)->runtime_flags);
|
||||||
insert_inode_hash(fs_info->btree_inode);
|
btrfs_insert_inode_hash(fs_info->btree_inode);
|
||||||
|
|
||||||
spin_lock_init(&fs_info->block_group_cache_lock);
|
spin_lock_init(&fs_info->block_group_cache_lock);
|
||||||
fs_info->block_group_cache_tree = RB_ROOT;
|
fs_info->block_group_cache_tree = RB_ROOT;
|
||||||
|
@ -2670,6 +2661,7 @@ int open_ctree(struct super_block *sb,
|
||||||
|
|
||||||
btrfs_set_root_node(&tree_root->root_item, tree_root->node);
|
btrfs_set_root_node(&tree_root->root_item, tree_root->node);
|
||||||
tree_root->commit_root = btrfs_root_node(tree_root);
|
tree_root->commit_root = btrfs_root_node(tree_root);
|
||||||
|
btrfs_set_root_refs(&tree_root->root_item, 1);
|
||||||
|
|
||||||
location.objectid = BTRFS_EXTENT_TREE_OBJECTID;
|
location.objectid = BTRFS_EXTENT_TREE_OBJECTID;
|
||||||
location.type = BTRFS_ROOT_ITEM_KEY;
|
location.type = BTRFS_ROOT_ITEM_KEY;
|
||||||
|
@ -3448,10 +3440,7 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
|
||||||
int write_ctree_super(struct btrfs_trans_handle *trans,
|
int write_ctree_super(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, int max_mirrors)
|
struct btrfs_root *root, int max_mirrors)
|
||||||
{
|
{
|
||||||
int ret;
|
return write_all_supers(root, max_mirrors);
|
||||||
|
|
||||||
ret = write_all_supers(root, max_mirrors);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Drop a fs root from the radix tree and free it. */
|
/* Drop a fs root from the radix tree and free it. */
|
||||||
|
@ -3614,12 +3603,12 @@ int close_ctree(struct btrfs_root *root)
|
||||||
percpu_counter_sum(&fs_info->delalloc_bytes));
|
percpu_counter_sum(&fs_info->delalloc_bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
del_fs_roots(fs_info);
|
||||||
|
|
||||||
btrfs_free_block_groups(fs_info);
|
btrfs_free_block_groups(fs_info);
|
||||||
|
|
||||||
btrfs_stop_all_workers(fs_info);
|
btrfs_stop_all_workers(fs_info);
|
||||||
|
|
||||||
del_fs_roots(fs_info);
|
|
||||||
|
|
||||||
free_root_pointers(fs_info, 1);
|
free_root_pointers(fs_info, 1);
|
||||||
|
|
||||||
iput(fs_info->btree_inode);
|
iput(fs_info->btree_inode);
|
||||||
|
@ -3669,10 +3658,20 @@ int btrfs_set_buffer_uptodate(struct extent_buffer *buf)
|
||||||
|
|
||||||
void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
|
void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
|
||||||
{
|
{
|
||||||
struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root;
|
struct btrfs_root *root;
|
||||||
u64 transid = btrfs_header_generation(buf);
|
u64 transid = btrfs_header_generation(buf);
|
||||||
int was_dirty;
|
int was_dirty;
|
||||||
|
|
||||||
|
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
|
||||||
|
/*
|
||||||
|
* This is a fast path so only do this check if we have sanity tests
|
||||||
|
* enabled. Normal people shouldn't be marking dummy buffers as dirty
|
||||||
|
* outside of the sanity tests.
|
||||||
|
*/
|
||||||
|
if (unlikely(test_bit(EXTENT_BUFFER_DUMMY, &buf->bflags)))
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
root = BTRFS_I(buf->pages[0]->mapping->host)->root;
|
||||||
btrfs_assert_tree_locked(buf);
|
btrfs_assert_tree_locked(buf);
|
||||||
if (transid != root->fs_info->generation)
|
if (transid != root->fs_info->generation)
|
||||||
WARN(1, KERN_CRIT "btrfs transid mismatch buffer %llu, "
|
WARN(1, KERN_CRIT "btrfs transid mismatch buffer %llu, "
|
||||||
|
@ -3802,7 +3801,8 @@ static void btrfs_destroy_all_ordered_extents(struct btrfs_fs_info *fs_info)
|
||||||
while (!list_empty(&splice)) {
|
while (!list_empty(&splice)) {
|
||||||
root = list_first_entry(&splice, struct btrfs_root,
|
root = list_first_entry(&splice, struct btrfs_root,
|
||||||
ordered_root);
|
ordered_root);
|
||||||
list_del_init(&root->ordered_root);
|
list_move_tail(&root->ordered_root,
|
||||||
|
&fs_info->ordered_roots);
|
||||||
|
|
||||||
btrfs_destroy_ordered_extents(root);
|
btrfs_destroy_ordered_extents(root);
|
||||||
|
|
||||||
|
@ -3880,24 +3880,6 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void btrfs_evict_pending_snapshots(struct btrfs_transaction *t)
|
|
||||||
{
|
|
||||||
struct btrfs_pending_snapshot *snapshot;
|
|
||||||
struct list_head splice;
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&splice);
|
|
||||||
|
|
||||||
list_splice_init(&t->pending_snapshots, &splice);
|
|
||||||
|
|
||||||
while (!list_empty(&splice)) {
|
|
||||||
snapshot = list_entry(splice.next,
|
|
||||||
struct btrfs_pending_snapshot,
|
|
||||||
list);
|
|
||||||
snapshot->error = -ECANCELED;
|
|
||||||
list_del_init(&snapshot->list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
|
static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root)
|
||||||
{
|
{
|
||||||
struct btrfs_inode *btrfs_inode;
|
struct btrfs_inode *btrfs_inode;
|
||||||
|
@ -4027,15 +4009,13 @@ static int btrfs_destroy_pinned_extent(struct btrfs_root *root,
|
||||||
void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
|
void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
|
||||||
struct btrfs_root *root)
|
struct btrfs_root *root)
|
||||||
{
|
{
|
||||||
|
btrfs_destroy_ordered_operations(cur_trans, root);
|
||||||
|
|
||||||
btrfs_destroy_delayed_refs(cur_trans, root);
|
btrfs_destroy_delayed_refs(cur_trans, root);
|
||||||
btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv,
|
|
||||||
cur_trans->dirty_pages.dirty_bytes);
|
|
||||||
|
|
||||||
cur_trans->state = TRANS_STATE_COMMIT_START;
|
cur_trans->state = TRANS_STATE_COMMIT_START;
|
||||||
wake_up(&root->fs_info->transaction_blocked_wait);
|
wake_up(&root->fs_info->transaction_blocked_wait);
|
||||||
|
|
||||||
btrfs_evict_pending_snapshots(cur_trans);
|
|
||||||
|
|
||||||
cur_trans->state = TRANS_STATE_UNBLOCKED;
|
cur_trans->state = TRANS_STATE_UNBLOCKED;
|
||||||
wake_up(&root->fs_info->transaction_wait);
|
wake_up(&root->fs_info->transaction_wait);
|
||||||
|
|
||||||
|
@ -4059,63 +4039,51 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans,
|
||||||
static int btrfs_cleanup_transaction(struct btrfs_root *root)
|
static int btrfs_cleanup_transaction(struct btrfs_root *root)
|
||||||
{
|
{
|
||||||
struct btrfs_transaction *t;
|
struct btrfs_transaction *t;
|
||||||
LIST_HEAD(list);
|
|
||||||
|
|
||||||
mutex_lock(&root->fs_info->transaction_kthread_mutex);
|
mutex_lock(&root->fs_info->transaction_kthread_mutex);
|
||||||
|
|
||||||
spin_lock(&root->fs_info->trans_lock);
|
spin_lock(&root->fs_info->trans_lock);
|
||||||
list_splice_init(&root->fs_info->trans_list, &list);
|
while (!list_empty(&root->fs_info->trans_list)) {
|
||||||
root->fs_info->running_transaction = NULL;
|
t = list_first_entry(&root->fs_info->trans_list,
|
||||||
spin_unlock(&root->fs_info->trans_lock);
|
struct btrfs_transaction, list);
|
||||||
|
if (t->state >= TRANS_STATE_COMMIT_START) {
|
||||||
|
atomic_inc(&t->use_count);
|
||||||
|
spin_unlock(&root->fs_info->trans_lock);
|
||||||
|
btrfs_wait_for_commit(root, t->transid);
|
||||||
|
btrfs_put_transaction(t);
|
||||||
|
spin_lock(&root->fs_info->trans_lock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (t == root->fs_info->running_transaction) {
|
||||||
|
t->state = TRANS_STATE_COMMIT_DOING;
|
||||||
|
spin_unlock(&root->fs_info->trans_lock);
|
||||||
|
/*
|
||||||
|
* We wait for 0 num_writers since we don't hold a trans
|
||||||
|
* handle open currently for this transaction.
|
||||||
|
*/
|
||||||
|
wait_event(t->writer_wait,
|
||||||
|
atomic_read(&t->num_writers) == 0);
|
||||||
|
} else {
|
||||||
|
spin_unlock(&root->fs_info->trans_lock);
|
||||||
|
}
|
||||||
|
btrfs_cleanup_one_transaction(t, root);
|
||||||
|
|
||||||
while (!list_empty(&list)) {
|
spin_lock(&root->fs_info->trans_lock);
|
||||||
t = list_entry(list.next, struct btrfs_transaction, list);
|
if (t == root->fs_info->running_transaction)
|
||||||
|
root->fs_info->running_transaction = NULL;
|
||||||
btrfs_destroy_ordered_operations(t, root);
|
|
||||||
|
|
||||||
btrfs_destroy_all_ordered_extents(root->fs_info);
|
|
||||||
|
|
||||||
btrfs_destroy_delayed_refs(t, root);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: cleanup wait for commit
|
|
||||||
* We needn't acquire the lock here, because we are during
|
|
||||||
* the umount, there is no other task which will change it.
|
|
||||||
*/
|
|
||||||
t->state = TRANS_STATE_COMMIT_START;
|
|
||||||
smp_mb();
|
|
||||||
if (waitqueue_active(&root->fs_info->transaction_blocked_wait))
|
|
||||||
wake_up(&root->fs_info->transaction_blocked_wait);
|
|
||||||
|
|
||||||
btrfs_evict_pending_snapshots(t);
|
|
||||||
|
|
||||||
t->state = TRANS_STATE_UNBLOCKED;
|
|
||||||
smp_mb();
|
|
||||||
if (waitqueue_active(&root->fs_info->transaction_wait))
|
|
||||||
wake_up(&root->fs_info->transaction_wait);
|
|
||||||
|
|
||||||
btrfs_destroy_delayed_inodes(root);
|
|
||||||
btrfs_assert_delayed_root_empty(root);
|
|
||||||
|
|
||||||
btrfs_destroy_all_delalloc_inodes(root->fs_info);
|
|
||||||
|
|
||||||
btrfs_destroy_marked_extents(root, &t->dirty_pages,
|
|
||||||
EXTENT_DIRTY);
|
|
||||||
|
|
||||||
btrfs_destroy_pinned_extent(root,
|
|
||||||
root->fs_info->pinned_extents);
|
|
||||||
|
|
||||||
t->state = TRANS_STATE_COMPLETED;
|
|
||||||
smp_mb();
|
|
||||||
if (waitqueue_active(&t->commit_wait))
|
|
||||||
wake_up(&t->commit_wait);
|
|
||||||
|
|
||||||
atomic_set(&t->use_count, 0);
|
|
||||||
list_del_init(&t->list);
|
list_del_init(&t->list);
|
||||||
memset(t, 0, sizeof(*t));
|
spin_unlock(&root->fs_info->trans_lock);
|
||||||
kmem_cache_free(btrfs_transaction_cachep, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
btrfs_put_transaction(t);
|
||||||
|
trace_btrfs_transaction_commit(root);
|
||||||
|
spin_lock(&root->fs_info->trans_lock);
|
||||||
|
}
|
||||||
|
spin_unlock(&root->fs_info->trans_lock);
|
||||||
|
btrfs_destroy_all_ordered_extents(root->fs_info);
|
||||||
|
btrfs_destroy_delayed_inodes(root);
|
||||||
|
btrfs_assert_delayed_root_empty(root);
|
||||||
|
btrfs_destroy_pinned_extent(root, root->fs_info->pinned_extents);
|
||||||
|
btrfs_destroy_all_delalloc_inodes(root->fs_info);
|
||||||
mutex_unlock(&root->fs_info->transaction_kthread_mutex);
|
mutex_unlock(&root->fs_info->transaction_kthread_mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -86,6 +86,10 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
|
||||||
struct btrfs_root *root);
|
struct btrfs_root *root);
|
||||||
void btrfs_free_fs_root(struct btrfs_root *root);
|
void btrfs_free_fs_root(struct btrfs_root *root);
|
||||||
|
|
||||||
|
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
|
||||||
|
struct btrfs_root *btrfs_alloc_dummy_root(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is used to grab the root, and avoid it is freed when we
|
* This function is used to grab the root, and avoid it is freed when we
|
||||||
* access it. But it doesn't ensure that the tree is not dropped.
|
* access it. But it doesn't ensure that the tree is not dropped.
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "print-tree.h"
|
#include "print-tree.h"
|
||||||
#include "export.h"
|
#include "export.h"
|
||||||
#include "compat.h"
|
|
||||||
|
|
||||||
#define BTRFS_FID_SIZE_NON_CONNECTABLE (offsetof(struct btrfs_fid, \
|
#define BTRFS_FID_SIZE_NON_CONNECTABLE (offsetof(struct btrfs_fid, \
|
||||||
parent_objectid) / 4)
|
parent_objectid) / 4)
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/ratelimit.h>
|
#include <linux/ratelimit.h>
|
||||||
#include <linux/percpu_counter.h>
|
#include <linux/percpu_counter.h>
|
||||||
#include "compat.h"
|
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
|
@ -1551,9 +1550,8 @@ int lookup_inline_extent_backref(struct btrfs_trans_handle *trans,
|
||||||
if (ret && !insert) {
|
if (ret && !insert) {
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
goto out;
|
goto out;
|
||||||
} else if (ret) {
|
} else if (WARN_ON(ret)) {
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
WARN_ON(1);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1979,7 +1977,6 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_extent_item *item;
|
struct btrfs_extent_item *item;
|
||||||
u64 refs;
|
u64 refs;
|
||||||
int ret;
|
int ret;
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path)
|
||||||
|
@ -1992,14 +1989,9 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
||||||
path, bytenr, num_bytes, parent,
|
path, bytenr, num_bytes, parent,
|
||||||
root_objectid, owner, offset,
|
root_objectid, owner, offset,
|
||||||
refs_to_add, extent_op);
|
refs_to_add, extent_op);
|
||||||
if (ret == 0)
|
if (ret != -EAGAIN)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (ret != -EAGAIN) {
|
|
||||||
err = ret;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
|
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
|
||||||
refs = btrfs_extent_refs(leaf, item);
|
refs = btrfs_extent_refs(leaf, item);
|
||||||
|
@ -2021,7 +2013,7 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
||||||
btrfs_abort_transaction(trans, root, ret);
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
out:
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return err;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
|
static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
|
||||||
|
@ -2137,15 +2129,28 @@ static int run_delayed_extent_op(struct btrfs_trans_handle *trans,
|
||||||
}
|
}
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
if (metadata) {
|
if (metadata) {
|
||||||
btrfs_release_path(path);
|
if (path->slots[0] > 0) {
|
||||||
metadata = 0;
|
path->slots[0]--;
|
||||||
|
btrfs_item_key_to_cpu(path->nodes[0], &key,
|
||||||
|
path->slots[0]);
|
||||||
|
if (key.objectid == node->bytenr &&
|
||||||
|
key.type == BTRFS_EXTENT_ITEM_KEY &&
|
||||||
|
key.offset == node->num_bytes)
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
if (ret > 0) {
|
||||||
|
btrfs_release_path(path);
|
||||||
|
metadata = 0;
|
||||||
|
|
||||||
key.offset = node->num_bytes;
|
key.objectid = node->bytenr;
|
||||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
key.offset = node->num_bytes;
|
||||||
goto again;
|
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = -EIO;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
err = -EIO;
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
|
@ -2234,8 +2239,12 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (trans->aborted)
|
if (trans->aborted) {
|
||||||
|
if (insert_reserved)
|
||||||
|
btrfs_pin_extent(root, node->bytenr,
|
||||||
|
node->num_bytes, 1);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (btrfs_delayed_ref_is_head(node)) {
|
if (btrfs_delayed_ref_is_head(node)) {
|
||||||
struct btrfs_delayed_ref_head *head;
|
struct btrfs_delayed_ref_head *head;
|
||||||
|
@ -2411,6 +2420,14 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
|
||||||
btrfs_free_delayed_extent_op(extent_op);
|
btrfs_free_delayed_extent_op(extent_op);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
/*
|
||||||
|
* Need to reset must_insert_reserved if
|
||||||
|
* there was an error so the abort stuff
|
||||||
|
* can cleanup the reserved space
|
||||||
|
* properly.
|
||||||
|
*/
|
||||||
|
if (must_insert_reserved)
|
||||||
|
locked_ref->must_insert_reserved = 1;
|
||||||
btrfs_debug(fs_info, "run_delayed_extent_op returned %d", ret);
|
btrfs_debug(fs_info, "run_delayed_extent_op returned %d", ret);
|
||||||
spin_lock(&delayed_refs->lock);
|
spin_lock(&delayed_refs->lock);
|
||||||
btrfs_delayed_ref_unlock(locked_ref);
|
btrfs_delayed_ref_unlock(locked_ref);
|
||||||
|
@ -3197,8 +3214,7 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_put;
|
goto out_put;
|
||||||
|
|
||||||
ret = btrfs_truncate_free_space_cache(root, trans, path,
|
ret = btrfs_truncate_free_space_cache(root, trans, inode);
|
||||||
inode);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_put;
|
goto out_put;
|
||||||
}
|
}
|
||||||
|
@ -3318,10 +3334,9 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
|
||||||
last = cache->key.objectid + cache->key.offset;
|
last = cache->key.objectid + cache->key.offset;
|
||||||
|
|
||||||
err = write_one_cache_group(trans, root, path, cache);
|
err = write_one_cache_group(trans, root, path, cache);
|
||||||
|
btrfs_put_block_group(cache);
|
||||||
if (err) /* File system offline */
|
if (err) /* File system offline */
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
btrfs_put_block_group(cache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -3605,10 +3620,9 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes)
|
||||||
/* make sure bytes are sectorsize aligned */
|
/* make sure bytes are sectorsize aligned */
|
||||||
bytes = ALIGN(bytes, root->sectorsize);
|
bytes = ALIGN(bytes, root->sectorsize);
|
||||||
|
|
||||||
if (root == root->fs_info->tree_root ||
|
if (btrfs_is_free_space_inode(inode)) {
|
||||||
BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID) {
|
|
||||||
alloc_chunk = 0;
|
|
||||||
committed = 1;
|
committed = 1;
|
||||||
|
ASSERT(current->journal_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
data_sinfo = fs_info->data_sinfo;
|
data_sinfo = fs_info->data_sinfo;
|
||||||
|
@ -3636,6 +3650,16 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes)
|
||||||
spin_unlock(&data_sinfo->lock);
|
spin_unlock(&data_sinfo->lock);
|
||||||
alloc:
|
alloc:
|
||||||
alloc_target = btrfs_get_alloc_profile(root, 1);
|
alloc_target = btrfs_get_alloc_profile(root, 1);
|
||||||
|
/*
|
||||||
|
* It is ugly that we don't call nolock join
|
||||||
|
* transaction for the free space inode case here.
|
||||||
|
* But it is safe because we only do the data space
|
||||||
|
* reservation for the free space cache in the
|
||||||
|
* transaction context, the common join transaction
|
||||||
|
* just increase the counter of the current transaction
|
||||||
|
* handler, doesn't try to acquire the trans_lock of
|
||||||
|
* the fs.
|
||||||
|
*/
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
if (IS_ERR(trans))
|
if (IS_ERR(trans))
|
||||||
return PTR_ERR(trans);
|
return PTR_ERR(trans);
|
||||||
|
@ -3681,6 +3705,9 @@ int btrfs_check_data_free_space(struct inode *inode, u64 bytes)
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trace_btrfs_space_reservation(root->fs_info,
|
||||||
|
"space_info:enospc",
|
||||||
|
data_sinfo->flags, bytes, 1);
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
}
|
}
|
||||||
data_sinfo->bytes_may_use += bytes;
|
data_sinfo->bytes_may_use += bytes;
|
||||||
|
@ -3989,12 +4016,26 @@ static void btrfs_writeback_inodes_sb_nr(struct btrfs_root *root,
|
||||||
* the filesystem is readonly(all dirty pages are written to
|
* the filesystem is readonly(all dirty pages are written to
|
||||||
* the disk).
|
* the disk).
|
||||||
*/
|
*/
|
||||||
btrfs_start_all_delalloc_inodes(root->fs_info, 0);
|
btrfs_start_delalloc_roots(root->fs_info, 0);
|
||||||
if (!current->journal_info)
|
if (!current->journal_info)
|
||||||
btrfs_wait_all_ordered_extents(root->fs_info);
|
btrfs_wait_ordered_roots(root->fs_info, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int calc_reclaim_items_nr(struct btrfs_root *root, u64 to_reclaim)
|
||||||
|
{
|
||||||
|
u64 bytes;
|
||||||
|
int nr;
|
||||||
|
|
||||||
|
bytes = btrfs_calc_trans_metadata_size(root, 1);
|
||||||
|
nr = (int)div64_u64(to_reclaim, bytes);
|
||||||
|
if (!nr)
|
||||||
|
nr = 1;
|
||||||
|
return nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXTENT_SIZE_PER_ITEM (256 * 1024)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* shrink metadata reservation for delalloc
|
* shrink metadata reservation for delalloc
|
||||||
*/
|
*/
|
||||||
|
@ -4007,24 +4048,30 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
|
||||||
u64 delalloc_bytes;
|
u64 delalloc_bytes;
|
||||||
u64 max_reclaim;
|
u64 max_reclaim;
|
||||||
long time_left;
|
long time_left;
|
||||||
unsigned long nr_pages = (2 * 1024 * 1024) >> PAGE_CACHE_SHIFT;
|
unsigned long nr_pages;
|
||||||
int loops = 0;
|
int loops;
|
||||||
|
int items;
|
||||||
enum btrfs_reserve_flush_enum flush;
|
enum btrfs_reserve_flush_enum flush;
|
||||||
|
|
||||||
|
/* Calc the number of the pages we need flush for space reservation */
|
||||||
|
items = calc_reclaim_items_nr(root, to_reclaim);
|
||||||
|
to_reclaim = items * EXTENT_SIZE_PER_ITEM;
|
||||||
|
|
||||||
trans = (struct btrfs_trans_handle *)current->journal_info;
|
trans = (struct btrfs_trans_handle *)current->journal_info;
|
||||||
block_rsv = &root->fs_info->delalloc_block_rsv;
|
block_rsv = &root->fs_info->delalloc_block_rsv;
|
||||||
space_info = block_rsv->space_info;
|
space_info = block_rsv->space_info;
|
||||||
|
|
||||||
smp_mb();
|
|
||||||
delalloc_bytes = percpu_counter_sum_positive(
|
delalloc_bytes = percpu_counter_sum_positive(
|
||||||
&root->fs_info->delalloc_bytes);
|
&root->fs_info->delalloc_bytes);
|
||||||
if (delalloc_bytes == 0) {
|
if (delalloc_bytes == 0) {
|
||||||
if (trans)
|
if (trans)
|
||||||
return;
|
return;
|
||||||
btrfs_wait_all_ordered_extents(root->fs_info);
|
if (wait_ordered)
|
||||||
|
btrfs_wait_ordered_roots(root->fs_info, items);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loops = 0;
|
||||||
while (delalloc_bytes && loops < 3) {
|
while (delalloc_bytes && loops < 3) {
|
||||||
max_reclaim = min(delalloc_bytes, to_reclaim);
|
max_reclaim = min(delalloc_bytes, to_reclaim);
|
||||||
nr_pages = max_reclaim >> PAGE_CACHE_SHIFT;
|
nr_pages = max_reclaim >> PAGE_CACHE_SHIFT;
|
||||||
|
@ -4033,9 +4080,19 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
|
||||||
* We need to wait for the async pages to actually start before
|
* We need to wait for the async pages to actually start before
|
||||||
* we do anything.
|
* we do anything.
|
||||||
*/
|
*/
|
||||||
wait_event(root->fs_info->async_submit_wait,
|
max_reclaim = atomic_read(&root->fs_info->async_delalloc_pages);
|
||||||
!atomic_read(&root->fs_info->async_delalloc_pages));
|
if (!max_reclaim)
|
||||||
|
goto skip_async;
|
||||||
|
|
||||||
|
if (max_reclaim <= nr_pages)
|
||||||
|
max_reclaim = 0;
|
||||||
|
else
|
||||||
|
max_reclaim -= nr_pages;
|
||||||
|
|
||||||
|
wait_event(root->fs_info->async_submit_wait,
|
||||||
|
atomic_read(&root->fs_info->async_delalloc_pages) <=
|
||||||
|
(int)max_reclaim);
|
||||||
|
skip_async:
|
||||||
if (!trans)
|
if (!trans)
|
||||||
flush = BTRFS_RESERVE_FLUSH_ALL;
|
flush = BTRFS_RESERVE_FLUSH_ALL;
|
||||||
else
|
else
|
||||||
|
@ -4049,13 +4106,12 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
|
||||||
|
|
||||||
loops++;
|
loops++;
|
||||||
if (wait_ordered && !trans) {
|
if (wait_ordered && !trans) {
|
||||||
btrfs_wait_all_ordered_extents(root->fs_info);
|
btrfs_wait_ordered_roots(root->fs_info, items);
|
||||||
} else {
|
} else {
|
||||||
time_left = schedule_timeout_killable(1);
|
time_left = schedule_timeout_killable(1);
|
||||||
if (time_left)
|
if (time_left)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
smp_mb();
|
|
||||||
delalloc_bytes = percpu_counter_sum_positive(
|
delalloc_bytes = percpu_counter_sum_positive(
|
||||||
&root->fs_info->delalloc_bytes);
|
&root->fs_info->delalloc_bytes);
|
||||||
}
|
}
|
||||||
|
@ -4140,16 +4196,11 @@ static int flush_space(struct btrfs_root *root,
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case FLUSH_DELAYED_ITEMS_NR:
|
case FLUSH_DELAYED_ITEMS_NR:
|
||||||
case FLUSH_DELAYED_ITEMS:
|
case FLUSH_DELAYED_ITEMS:
|
||||||
if (state == FLUSH_DELAYED_ITEMS_NR) {
|
if (state == FLUSH_DELAYED_ITEMS_NR)
|
||||||
u64 bytes = btrfs_calc_trans_metadata_size(root, 1);
|
nr = calc_reclaim_items_nr(root, num_bytes) * 2;
|
||||||
|
else
|
||||||
nr = (int)div64_u64(num_bytes, bytes);
|
|
||||||
if (!nr)
|
|
||||||
nr = 1;
|
|
||||||
nr *= 2;
|
|
||||||
} else {
|
|
||||||
nr = -1;
|
nr = -1;
|
||||||
}
|
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
if (IS_ERR(trans)) {
|
if (IS_ERR(trans)) {
|
||||||
ret = PTR_ERR(trans);
|
ret = PTR_ERR(trans);
|
||||||
|
@ -4332,6 +4383,10 @@ static int reserve_metadata_bytes(struct btrfs_root *root,
|
||||||
!block_rsv_use_bytes(global_rsv, orig_bytes))
|
!block_rsv_use_bytes(global_rsv, orig_bytes))
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
if (ret == -ENOSPC)
|
||||||
|
trace_btrfs_space_reservation(root->fs_info,
|
||||||
|
"space_info:enospc",
|
||||||
|
space_info->flags, orig_bytes, 1);
|
||||||
if (flushing) {
|
if (flushing) {
|
||||||
spin_lock(&space_info->lock);
|
spin_lock(&space_info->lock);
|
||||||
space_info->flush = 0;
|
space_info->flush = 0;
|
||||||
|
@ -4986,7 +5041,7 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
|
||||||
mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
|
mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
|
||||||
|
|
||||||
if (to_reserve)
|
if (to_reserve)
|
||||||
trace_btrfs_space_reservation(root->fs_info,"delalloc",
|
trace_btrfs_space_reservation(root->fs_info, "delalloc",
|
||||||
btrfs_ino(inode), to_reserve, 1);
|
btrfs_ino(inode), to_reserve, 1);
|
||||||
block_rsv_add_bytes(block_rsv, to_reserve, 1);
|
block_rsv_add_bytes(block_rsv, to_reserve, 1);
|
||||||
|
|
||||||
|
@ -5264,6 +5319,8 @@ static int pin_down_extent(struct btrfs_root *root,
|
||||||
|
|
||||||
set_extent_dirty(root->fs_info->pinned_extents, bytenr,
|
set_extent_dirty(root->fs_info->pinned_extents, bytenr,
|
||||||
bytenr + num_bytes - 1, GFP_NOFS | __GFP_NOFAIL);
|
bytenr + num_bytes - 1, GFP_NOFS | __GFP_NOFAIL);
|
||||||
|
if (reserved)
|
||||||
|
trace_btrfs_reserved_extent_free(root, bytenr, num_bytes);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5718,9 +5775,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||||
}
|
}
|
||||||
extent_slot = path->slots[0];
|
extent_slot = path->slots[0];
|
||||||
}
|
}
|
||||||
} else if (ret == -ENOENT) {
|
} else if (WARN_ON(ret == -ENOENT)) {
|
||||||
btrfs_print_leaf(extent_root, path->nodes[0]);
|
btrfs_print_leaf(extent_root, path->nodes[0]);
|
||||||
WARN_ON(1);
|
|
||||||
btrfs_err(info,
|
btrfs_err(info,
|
||||||
"unable to find ref byte nr %llu parent %llu root %llu owner %llu offset %llu",
|
"unable to find ref byte nr %llu parent %llu root %llu owner %llu offset %llu",
|
||||||
bytenr, parent, root_objectid, owner_objectid,
|
bytenr, parent, root_objectid, owner_objectid,
|
||||||
|
@ -5967,6 +6023,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
btrfs_add_free_space(cache, buf->start, buf->len);
|
btrfs_add_free_space(cache, buf->start, buf->len);
|
||||||
btrfs_update_reserved_bytes(cache, buf->len, RESERVE_FREE);
|
btrfs_update_reserved_bytes(cache, buf->len, RESERVE_FREE);
|
||||||
|
trace_btrfs_reserved_extent_free(root, buf->start, buf->len);
|
||||||
pin = 0;
|
pin = 0;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
@ -6594,8 +6651,6 @@ int btrfs_reserve_extent(struct btrfs_root *root,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trace_btrfs_reserved_extent_alloc(root, ins->objectid, ins->offset);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6707,6 +6762,7 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
|
||||||
ins->objectid, ins->offset);
|
ins->objectid, ins->offset);
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
trace_btrfs_reserved_extent_alloc(root, ins->objectid, ins->offset);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6731,13 +6787,18 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
|
||||||
size += sizeof(*block_info);
|
size += sizeof(*block_info);
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path) {
|
||||||
|
btrfs_free_and_pin_reserved_extent(root, ins->objectid,
|
||||||
|
root->leafsize);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
path->leave_spinning = 1;
|
path->leave_spinning = 1;
|
||||||
ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
|
ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path,
|
||||||
ins, size);
|
ins, size);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
btrfs_free_and_pin_reserved_extent(root, ins->objectid,
|
||||||
|
root->leafsize);
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -6779,6 +6840,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
|
||||||
ins->objectid, ins->offset);
|
ins->objectid, ins->offset);
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trace_btrfs_reserved_extent_alloc(root, ins->objectid, root->leafsize);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7983,7 +8046,7 @@ u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo)
|
||||||
|
|
||||||
spin_lock(&sinfo->lock);
|
spin_lock(&sinfo->lock);
|
||||||
|
|
||||||
for(i = 0; i < BTRFS_NR_RAID_TYPES; i++)
|
for (i = 0; i < BTRFS_NR_RAID_TYPES; i++)
|
||||||
if (!list_empty(&sinfo->block_groups[i]))
|
if (!list_empty(&sinfo->block_groups[i]))
|
||||||
free_bytes += __btrfs_get_ro_block_group_free_space(
|
free_bytes += __btrfs_get_ro_block_group_free_space(
|
||||||
&sinfo->block_groups[i]);
|
&sinfo->block_groups[i]);
|
||||||
|
@ -8271,15 +8334,14 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
|
||||||
|
|
||||||
release_global_block_rsv(info);
|
release_global_block_rsv(info);
|
||||||
|
|
||||||
while(!list_empty(&info->space_info)) {
|
while (!list_empty(&info->space_info)) {
|
||||||
space_info = list_entry(info->space_info.next,
|
space_info = list_entry(info->space_info.next,
|
||||||
struct btrfs_space_info,
|
struct btrfs_space_info,
|
||||||
list);
|
list);
|
||||||
if (btrfs_test_opt(info->tree_root, ENOSPC_DEBUG)) {
|
if (btrfs_test_opt(info->tree_root, ENOSPC_DEBUG)) {
|
||||||
if (space_info->bytes_pinned > 0 ||
|
if (WARN_ON(space_info->bytes_pinned > 0 ||
|
||||||
space_info->bytes_reserved > 0 ||
|
space_info->bytes_reserved > 0 ||
|
||||||
space_info->bytes_may_use > 0) {
|
space_info->bytes_may_use > 0)) {
|
||||||
WARN_ON(1);
|
|
||||||
dump_space_info(space_info, 0, 0);
|
dump_space_info(space_info, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,13 +13,13 @@
|
||||||
#include <linux/cleancache.h>
|
#include <linux/cleancache.h>
|
||||||
#include "extent_io.h"
|
#include "extent_io.h"
|
||||||
#include "extent_map.h"
|
#include "extent_map.h"
|
||||||
#include "compat.h"
|
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "btrfs_inode.h"
|
#include "btrfs_inode.h"
|
||||||
#include "volumes.h"
|
#include "volumes.h"
|
||||||
#include "check-integrity.h"
|
#include "check-integrity.h"
|
||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
#include "rcu-string.h"
|
#include "rcu-string.h"
|
||||||
|
#include "backref.h"
|
||||||
|
|
||||||
static struct kmem_cache *extent_state_cache;
|
static struct kmem_cache *extent_state_cache;
|
||||||
static struct kmem_cache *extent_buffer_cache;
|
static struct kmem_cache *extent_buffer_cache;
|
||||||
|
@ -1597,11 +1597,10 @@ static noinline int lock_delalloc_pages(struct inode *inode,
|
||||||
*
|
*
|
||||||
* 1 is returned if we find something, 0 if nothing was in the tree
|
* 1 is returned if we find something, 0 if nothing was in the tree
|
||||||
*/
|
*/
|
||||||
static noinline u64 find_lock_delalloc_range(struct inode *inode,
|
STATIC u64 find_lock_delalloc_range(struct inode *inode,
|
||||||
struct extent_io_tree *tree,
|
struct extent_io_tree *tree,
|
||||||
struct page *locked_page,
|
struct page *locked_page, u64 *start,
|
||||||
u64 *start, u64 *end,
|
u64 *end, u64 max_bytes)
|
||||||
u64 max_bytes)
|
|
||||||
{
|
{
|
||||||
u64 delalloc_start;
|
u64 delalloc_start;
|
||||||
u64 delalloc_end;
|
u64 delalloc_end;
|
||||||
|
@ -1740,10 +1739,8 @@ u64 count_range_bits(struct extent_io_tree *tree,
|
||||||
u64 last = 0;
|
u64 last = 0;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
||||||
if (search_end <= cur_start) {
|
if (WARN_ON(search_end <= cur_start))
|
||||||
WARN_ON(1);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock(&tree->lock);
|
spin_lock(&tree->lock);
|
||||||
if (cur_start == 0 && bits == EXTENT_DIRTY) {
|
if (cur_start == 0 && bits == EXTENT_DIRTY) {
|
||||||
|
@ -3569,9 +3566,8 @@ int btree_write_cache_pages(struct address_space *mapping,
|
||||||
* but no sense in crashing the users box for something
|
* but no sense in crashing the users box for something
|
||||||
* we can survive anyway.
|
* we can survive anyway.
|
||||||
*/
|
*/
|
||||||
if (!eb) {
|
if (WARN_ON(!eb)) {
|
||||||
spin_unlock(&mapping->private_lock);
|
spin_unlock(&mapping->private_lock);
|
||||||
WARN_ON(1);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4038,7 +4034,7 @@ static struct extent_map *get_extent_skip_holes(struct inode *inode,
|
||||||
if (offset >= last)
|
if (offset >= last)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
len = last - offset;
|
len = last - offset;
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
break;
|
break;
|
||||||
|
@ -4062,6 +4058,19 @@ static struct extent_map *get_extent_skip_holes(struct inode *inode,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static noinline int count_ext_ref(u64 inum, u64 offset, u64 root_id, void *ctx)
|
||||||
|
{
|
||||||
|
unsigned long cnt = *((unsigned long *)ctx);
|
||||||
|
|
||||||
|
cnt++;
|
||||||
|
*((unsigned long *)ctx) = cnt;
|
||||||
|
|
||||||
|
/* Now we're sure that the extent is shared. */
|
||||||
|
if (cnt > 1)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||||
__u64 start, __u64 len, get_extent_t *get_extent)
|
__u64 start, __u64 len, get_extent_t *get_extent)
|
||||||
{
|
{
|
||||||
|
@ -4128,7 +4137,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||||
last = found_key.offset;
|
last = found_key.offset;
|
||||||
last_for_get_extent = last + 1;
|
last_for_get_extent = last + 1;
|
||||||
}
|
}
|
||||||
btrfs_free_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we might have some extents allocated but more delalloc past those
|
* we might have some extents allocated but more delalloc past those
|
||||||
|
@ -4198,7 +4207,24 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||||
flags |= (FIEMAP_EXTENT_DELALLOC |
|
flags |= (FIEMAP_EXTENT_DELALLOC |
|
||||||
FIEMAP_EXTENT_UNKNOWN);
|
FIEMAP_EXTENT_UNKNOWN);
|
||||||
} else {
|
} else {
|
||||||
|
unsigned long ref_cnt = 0;
|
||||||
|
|
||||||
disko = em->block_start + offset_in_extent;
|
disko = em->block_start + offset_in_extent;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As btrfs supports shared space, this information
|
||||||
|
* can be exported to userspace tools via
|
||||||
|
* flag FIEMAP_EXTENT_SHARED.
|
||||||
|
*/
|
||||||
|
ret = iterate_inodes_from_logical(
|
||||||
|
em->block_start,
|
||||||
|
BTRFS_I(inode)->root->fs_info,
|
||||||
|
path, count_ext_ref, &ref_cnt);
|
||||||
|
if (ret < 0 && ret != -ENOENT)
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
if (ref_cnt > 1)
|
||||||
|
flags |= FIEMAP_EXTENT_SHARED;
|
||||||
}
|
}
|
||||||
if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
|
if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
|
||||||
flags |= FIEMAP_EXTENT_ENCODED;
|
flags |= FIEMAP_EXTENT_ENCODED;
|
||||||
|
@ -4230,6 +4256,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||||
out_free:
|
out_free:
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
out:
|
out:
|
||||||
|
btrfs_free_path(path);
|
||||||
unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, start + len - 1,
|
unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, start + len - 1,
|
||||||
&cached_state, GFP_NOFS);
|
&cached_state, GFP_NOFS);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -4455,6 +4482,23 @@ static void mark_extent_buffer_accessed(struct extent_buffer *eb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
|
||||||
|
u64 start)
|
||||||
|
{
|
||||||
|
struct extent_buffer *eb;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
|
||||||
|
if (eb && atomic_inc_not_zero(&eb->refs)) {
|
||||||
|
rcu_read_unlock();
|
||||||
|
mark_extent_buffer_accessed(eb);
|
||||||
|
return eb;
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
|
struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
|
||||||
u64 start, unsigned long len)
|
u64 start, unsigned long len)
|
||||||
{
|
{
|
||||||
|
@ -4468,14 +4512,10 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
|
||||||
int uptodate = 1;
|
int uptodate = 1;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
|
eb = find_extent_buffer(tree, start);
|
||||||
if (eb && atomic_inc_not_zero(&eb->refs)) {
|
if (eb)
|
||||||
rcu_read_unlock();
|
|
||||||
mark_extent_buffer_accessed(eb);
|
|
||||||
return eb;
|
return eb;
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
eb = __alloc_extent_buffer(tree, start, len, GFP_NOFS);
|
eb = __alloc_extent_buffer(tree, start, len, GFP_NOFS);
|
||||||
if (!eb)
|
if (!eb)
|
||||||
|
@ -4534,24 +4574,17 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
|
||||||
|
|
||||||
spin_lock(&tree->buffer_lock);
|
spin_lock(&tree->buffer_lock);
|
||||||
ret = radix_tree_insert(&tree->buffer, start >> PAGE_CACHE_SHIFT, eb);
|
ret = radix_tree_insert(&tree->buffer, start >> PAGE_CACHE_SHIFT, eb);
|
||||||
|
spin_unlock(&tree->buffer_lock);
|
||||||
|
radix_tree_preload_end();
|
||||||
if (ret == -EEXIST) {
|
if (ret == -EEXIST) {
|
||||||
exists = radix_tree_lookup(&tree->buffer,
|
exists = find_extent_buffer(tree, start);
|
||||||
start >> PAGE_CACHE_SHIFT);
|
if (exists)
|
||||||
if (!atomic_inc_not_zero(&exists->refs)) {
|
goto free_eb;
|
||||||
spin_unlock(&tree->buffer_lock);
|
else
|
||||||
radix_tree_preload_end();
|
|
||||||
exists = NULL;
|
|
||||||
goto again;
|
goto again;
|
||||||
}
|
|
||||||
spin_unlock(&tree->buffer_lock);
|
|
||||||
radix_tree_preload_end();
|
|
||||||
mark_extent_buffer_accessed(exists);
|
|
||||||
goto free_eb;
|
|
||||||
}
|
}
|
||||||
/* add one reference for the tree */
|
/* add one reference for the tree */
|
||||||
check_buffer_tree_ref(eb);
|
check_buffer_tree_ref(eb);
|
||||||
spin_unlock(&tree->buffer_lock);
|
|
||||||
radix_tree_preload_end();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* there is a race where release page may have
|
* there is a race where release page may have
|
||||||
|
@ -4582,23 +4615,6 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
|
||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
|
|
||||||
u64 start, unsigned long len)
|
|
||||||
{
|
|
||||||
struct extent_buffer *eb;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
|
|
||||||
if (eb && atomic_inc_not_zero(&eb->refs)) {
|
|
||||||
rcu_read_unlock();
|
|
||||||
mark_extent_buffer_accessed(eb);
|
|
||||||
return eb;
|
|
||||||
}
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head)
|
static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head)
|
||||||
{
|
{
|
||||||
struct extent_buffer *eb =
|
struct extent_buffer *eb =
|
||||||
|
@ -5062,23 +5078,6 @@ void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void move_pages(struct page *dst_page, struct page *src_page,
|
|
||||||
unsigned long dst_off, unsigned long src_off,
|
|
||||||
unsigned long len)
|
|
||||||
{
|
|
||||||
char *dst_kaddr = page_address(dst_page);
|
|
||||||
if (dst_page == src_page) {
|
|
||||||
memmove(dst_kaddr + dst_off, dst_kaddr + src_off, len);
|
|
||||||
} else {
|
|
||||||
char *src_kaddr = page_address(src_page);
|
|
||||||
char *p = dst_kaddr + dst_off + len;
|
|
||||||
char *s = src_kaddr + src_off + len;
|
|
||||||
|
|
||||||
while (len--)
|
|
||||||
*--p = *--s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len)
|
static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len)
|
||||||
{
|
{
|
||||||
unsigned long distance = (src > dst) ? src - dst : dst - src;
|
unsigned long distance = (src > dst) ? src - dst : dst - src;
|
||||||
|
@ -5189,7 +5188,7 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
|
||||||
|
|
||||||
cur = min_t(unsigned long, len, src_off_in_page + 1);
|
cur = min_t(unsigned long, len, src_off_in_page + 1);
|
||||||
cur = min(cur, dst_off_in_page + 1);
|
cur = min(cur, dst_off_in_page + 1);
|
||||||
move_pages(extent_buffer_page(dst, dst_i),
|
copy_pages(extent_buffer_page(dst, dst_i),
|
||||||
extent_buffer_page(dst, src_i),
|
extent_buffer_page(dst, src_i),
|
||||||
dst_off_in_page - cur + 1,
|
dst_off_in_page - cur + 1,
|
||||||
src_off_in_page - cur + 1, cur);
|
src_off_in_page - cur + 1, cur);
|
||||||
|
|
|
@ -271,7 +271,7 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
|
||||||
struct extent_buffer *alloc_dummy_extent_buffer(u64 start, unsigned long len);
|
struct extent_buffer *alloc_dummy_extent_buffer(u64 start, unsigned long len);
|
||||||
struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src);
|
struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src);
|
||||||
struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
|
struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
|
||||||
u64 start, unsigned long len);
|
u64 start);
|
||||||
void free_extent_buffer(struct extent_buffer *eb);
|
void free_extent_buffer(struct extent_buffer *eb);
|
||||||
void free_extent_buffer_stale(struct extent_buffer *eb);
|
void free_extent_buffer_stale(struct extent_buffer *eb);
|
||||||
#define WAIT_NONE 0
|
#define WAIT_NONE 0
|
||||||
|
@ -345,4 +345,10 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
|
||||||
int end_extent_writepage(struct page *page, int err, u64 start, u64 end);
|
int end_extent_writepage(struct page *page, int err, u64 start, u64 end);
|
||||||
int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
|
int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
|
||||||
int mirror_num);
|
int mirror_num);
|
||||||
|
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
|
||||||
|
noinline u64 find_lock_delalloc_range(struct inode *inode,
|
||||||
|
struct extent_io_tree *tree,
|
||||||
|
struct page *locked_page, u64 *start,
|
||||||
|
u64 *end, u64 max_bytes);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,10 +3,10 @@
|
||||||
|
|
||||||
#include <linux/rbtree.h>
|
#include <linux/rbtree.h>
|
||||||
|
|
||||||
#define EXTENT_MAP_LAST_BYTE (u64)-4
|
#define EXTENT_MAP_LAST_BYTE ((u64)-4)
|
||||||
#define EXTENT_MAP_HOLE (u64)-3
|
#define EXTENT_MAP_HOLE ((u64)-3)
|
||||||
#define EXTENT_MAP_INLINE (u64)-2
|
#define EXTENT_MAP_INLINE ((u64)-2)
|
||||||
#define EXTENT_MAP_DELALLOC (u64)-1
|
#define EXTENT_MAP_DELALLOC ((u64)-1)
|
||||||
|
|
||||||
/* bits for the flags field */
|
/* bits for the flags field */
|
||||||
#define EXTENT_FLAG_PINNED 0 /* this entry not yet on disk, don't free it */
|
#define EXTENT_FLAG_PINNED 0 /* this entry not yet on disk, don't free it */
|
||||||
|
|
|
@ -329,6 +329,9 @@ int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
|
||||||
u64 csum_end;
|
u64 csum_end;
|
||||||
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
|
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
|
||||||
|
|
||||||
|
ASSERT(start == ALIGN(start, root->sectorsize) &&
|
||||||
|
(end + 1) == ALIGN(end + 1, root->sectorsize));
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
if (!path)
|
if (!path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -846,10 +849,8 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
|
||||||
path->leave_spinning = 0;
|
path->leave_spinning = 0;
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto fail_unlock;
|
goto fail_unlock;
|
||||||
if (ret != 0) {
|
if (WARN_ON(ret != 0))
|
||||||
WARN_ON(1);
|
|
||||||
goto fail_unlock;
|
goto fail_unlock;
|
||||||
}
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
csum:
|
csum:
|
||||||
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
|
item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
|
||||||
|
|
163
fs/btrfs/file.c
163
fs/btrfs/file.c
|
@ -39,7 +39,6 @@
|
||||||
#include "print-tree.h"
|
#include "print-tree.h"
|
||||||
#include "tree-log.h"
|
#include "tree-log.h"
|
||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
#include "compat.h"
|
|
||||||
#include "volumes.h"
|
#include "volumes.h"
|
||||||
|
|
||||||
static struct kmem_cache *btrfs_inode_defrag_cachep;
|
static struct kmem_cache *btrfs_inode_defrag_cachep;
|
||||||
|
@ -370,7 +369,7 @@ int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info)
|
||||||
u64 root_objectid = 0;
|
u64 root_objectid = 0;
|
||||||
|
|
||||||
atomic_inc(&fs_info->defrag_running);
|
atomic_inc(&fs_info->defrag_running);
|
||||||
while(1) {
|
while (1) {
|
||||||
/* Pause the auto defragger. */
|
/* Pause the auto defragger. */
|
||||||
if (test_bit(BTRFS_FS_STATE_REMOUNTING,
|
if (test_bit(BTRFS_FS_STATE_REMOUNTING,
|
||||||
&fs_info->fs_state))
|
&fs_info->fs_state))
|
||||||
|
@ -1281,6 +1280,7 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
|
||||||
}
|
}
|
||||||
wait_on_page_writeback(pages[i]);
|
wait_on_page_writeback(pages[i]);
|
||||||
}
|
}
|
||||||
|
faili = num_pages - 1;
|
||||||
err = 0;
|
err = 0;
|
||||||
if (start_pos < inode->i_size) {
|
if (start_pos < inode->i_size) {
|
||||||
struct btrfs_ordered_extent *ordered;
|
struct btrfs_ordered_extent *ordered;
|
||||||
|
@ -1299,8 +1299,10 @@ static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
|
||||||
unlock_page(pages[i]);
|
unlock_page(pages[i]);
|
||||||
page_cache_release(pages[i]);
|
page_cache_release(pages[i]);
|
||||||
}
|
}
|
||||||
btrfs_wait_ordered_range(inode, start_pos,
|
err = btrfs_wait_ordered_range(inode, start_pos,
|
||||||
last_pos - start_pos);
|
last_pos - start_pos);
|
||||||
|
if (err)
|
||||||
|
goto fail;
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
if (ordered)
|
if (ordered)
|
||||||
|
@ -1809,8 +1811,13 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
||||||
atomic_inc(&root->log_batch);
|
atomic_inc(&root->log_batch);
|
||||||
full_sync = test_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
|
full_sync = test_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
|
||||||
&BTRFS_I(inode)->runtime_flags);
|
&BTRFS_I(inode)->runtime_flags);
|
||||||
if (full_sync)
|
if (full_sync) {
|
||||||
btrfs_wait_ordered_range(inode, start, end - start + 1);
|
ret = btrfs_wait_ordered_range(inode, start, end - start + 1);
|
||||||
|
if (ret) {
|
||||||
|
mutex_unlock(&inode->i_mutex);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
atomic_inc(&root->log_batch);
|
atomic_inc(&root->log_batch);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1876,27 +1883,20 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
||||||
mutex_unlock(&inode->i_mutex);
|
mutex_unlock(&inode->i_mutex);
|
||||||
|
|
||||||
if (ret != BTRFS_NO_LOG_SYNC) {
|
if (ret != BTRFS_NO_LOG_SYNC) {
|
||||||
if (ret > 0) {
|
if (!ret) {
|
||||||
/*
|
|
||||||
* If we didn't already wait for ordered extents we need
|
|
||||||
* to do that now.
|
|
||||||
*/
|
|
||||||
if (!full_sync)
|
|
||||||
btrfs_wait_ordered_range(inode, start,
|
|
||||||
end - start + 1);
|
|
||||||
ret = btrfs_commit_transaction(trans, root);
|
|
||||||
} else {
|
|
||||||
ret = btrfs_sync_log(trans, root);
|
ret = btrfs_sync_log(trans, root);
|
||||||
if (ret == 0) {
|
if (!ret) {
|
||||||
ret = btrfs_end_transaction(trans, root);
|
ret = btrfs_end_transaction(trans, root);
|
||||||
} else {
|
goto out;
|
||||||
if (!full_sync)
|
|
||||||
btrfs_wait_ordered_range(inode, start,
|
|
||||||
end -
|
|
||||||
start + 1);
|
|
||||||
ret = btrfs_commit_transaction(trans, root);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!full_sync) {
|
||||||
|
ret = btrfs_wait_ordered_range(inode, start,
|
||||||
|
end - start + 1);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = btrfs_commit_transaction(trans, root);
|
||||||
} else {
|
} else {
|
||||||
ret = btrfs_end_transaction(trans, root);
|
ret = btrfs_end_transaction(trans, root);
|
||||||
}
|
}
|
||||||
|
@ -2067,7 +2067,9 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
|
||||||
bool same_page = ((offset >> PAGE_CACHE_SHIFT) ==
|
bool same_page = ((offset >> PAGE_CACHE_SHIFT) ==
|
||||||
((offset + len - 1) >> PAGE_CACHE_SHIFT));
|
((offset + len - 1) >> PAGE_CACHE_SHIFT));
|
||||||
|
|
||||||
btrfs_wait_ordered_range(inode, offset, len);
|
ret = btrfs_wait_ordered_range(inode, offset, len);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
mutex_lock(&inode->i_mutex);
|
mutex_lock(&inode->i_mutex);
|
||||||
/*
|
/*
|
||||||
|
@ -2136,8 +2138,12 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart,
|
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart,
|
||||||
lockend, &cached_state, GFP_NOFS);
|
lockend, &cached_state, GFP_NOFS);
|
||||||
btrfs_wait_ordered_range(inode, lockstart,
|
ret = btrfs_wait_ordered_range(inode, lockstart,
|
||||||
lockend - lockstart + 1);
|
lockend - lockstart + 1);
|
||||||
|
if (ret) {
|
||||||
|
mutex_unlock(&inode->i_mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
path = btrfs_alloc_path();
|
||||||
|
@ -2308,7 +2314,10 @@ static long btrfs_fallocate(struct file *file, int mode,
|
||||||
* wait for ordered IO before we have any locks. We'll loop again
|
* wait for ordered IO before we have any locks. We'll loop again
|
||||||
* below with the locks held.
|
* below with the locks held.
|
||||||
*/
|
*/
|
||||||
btrfs_wait_ordered_range(inode, alloc_start, alloc_end - alloc_start);
|
ret = btrfs_wait_ordered_range(inode, alloc_start,
|
||||||
|
alloc_end - alloc_start);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
locked_end = alloc_end - 1;
|
locked_end = alloc_end - 1;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -2332,8 +2341,10 @@ static long btrfs_fallocate(struct file *file, int mode,
|
||||||
* we can't wait on the range with the transaction
|
* we can't wait on the range with the transaction
|
||||||
* running or with the extent lock held
|
* running or with the extent lock held
|
||||||
*/
|
*/
|
||||||
btrfs_wait_ordered_range(inode, alloc_start,
|
ret = btrfs_wait_ordered_range(inode, alloc_start,
|
||||||
alloc_end - alloc_start);
|
alloc_end - alloc_start);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
if (ordered)
|
if (ordered)
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
|
@ -2405,14 +2416,12 @@ static long btrfs_fallocate(struct file *file, int mode,
|
||||||
static int find_desired_extent(struct inode *inode, loff_t *offset, int whence)
|
static int find_desired_extent(struct inode *inode, loff_t *offset, int whence)
|
||||||
{
|
{
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct extent_map *em;
|
struct extent_map *em = NULL;
|
||||||
struct extent_state *cached_state = NULL;
|
struct extent_state *cached_state = NULL;
|
||||||
u64 lockstart = *offset;
|
u64 lockstart = *offset;
|
||||||
u64 lockend = i_size_read(inode);
|
u64 lockend = i_size_read(inode);
|
||||||
u64 start = *offset;
|
u64 start = *offset;
|
||||||
u64 orig_start = *offset;
|
|
||||||
u64 len = i_size_read(inode);
|
u64 len = i_size_read(inode);
|
||||||
u64 last_end = 0;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
lockend = max_t(u64, root->sectorsize, lockend);
|
lockend = max_t(u64, root->sectorsize, lockend);
|
||||||
|
@ -2429,89 +2438,35 @@ static int find_desired_extent(struct inode *inode, loff_t *offset, int whence)
|
||||||
lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, 0,
|
lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, 0,
|
||||||
&cached_state);
|
&cached_state);
|
||||||
|
|
||||||
/*
|
while (start < inode->i_size) {
|
||||||
* Delalloc is such a pain. If we have a hole and we have pending
|
|
||||||
* delalloc for a portion of the hole we will get back a hole that
|
|
||||||
* exists for the entire range since it hasn't been actually written
|
|
||||||
* yet. So to take care of this case we need to look for an extent just
|
|
||||||
* before the position we want in case there is outstanding delalloc
|
|
||||||
* going on here.
|
|
||||||
*/
|
|
||||||
if (whence == SEEK_HOLE && start != 0) {
|
|
||||||
if (start <= root->sectorsize)
|
|
||||||
em = btrfs_get_extent_fiemap(inode, NULL, 0, 0,
|
|
||||||
root->sectorsize, 0);
|
|
||||||
else
|
|
||||||
em = btrfs_get_extent_fiemap(inode, NULL, 0,
|
|
||||||
start - root->sectorsize,
|
|
||||||
root->sectorsize, 0);
|
|
||||||
if (IS_ERR(em)) {
|
|
||||||
ret = PTR_ERR(em);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
last_end = em->start + em->len;
|
|
||||||
if (em->block_start == EXTENT_MAP_DELALLOC)
|
|
||||||
last_end = min_t(u64, last_end, inode->i_size);
|
|
||||||
free_extent_map(em);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
em = btrfs_get_extent_fiemap(inode, NULL, 0, start, len, 0);
|
em = btrfs_get_extent_fiemap(inode, NULL, 0, start, len, 0);
|
||||||
if (IS_ERR(em)) {
|
if (IS_ERR(em)) {
|
||||||
ret = PTR_ERR(em);
|
ret = PTR_ERR(em);
|
||||||
|
em = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (em->block_start == EXTENT_MAP_HOLE) {
|
if (whence == SEEK_HOLE &&
|
||||||
if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
|
(em->block_start == EXTENT_MAP_HOLE ||
|
||||||
if (last_end <= orig_start) {
|
test_bit(EXTENT_FLAG_PREALLOC, &em->flags)))
|
||||||
free_extent_map(em);
|
break;
|
||||||
ret = -ENXIO;
|
else if (whence == SEEK_DATA &&
|
||||||
break;
|
(em->block_start != EXTENT_MAP_HOLE &&
|
||||||
}
|
!test_bit(EXTENT_FLAG_PREALLOC, &em->flags)))
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (whence == SEEK_HOLE) {
|
|
||||||
*offset = start;
|
|
||||||
free_extent_map(em);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (whence == SEEK_DATA) {
|
|
||||||
if (em->block_start == EXTENT_MAP_DELALLOC) {
|
|
||||||
if (start >= inode->i_size) {
|
|
||||||
free_extent_map(em);
|
|
||||||
ret = -ENXIO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!test_bit(EXTENT_FLAG_PREALLOC,
|
|
||||||
&em->flags)) {
|
|
||||||
*offset = start;
|
|
||||||
free_extent_map(em);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
start = em->start + em->len;
|
start = em->start + em->len;
|
||||||
last_end = em->start + em->len;
|
|
||||||
|
|
||||||
if (em->block_start == EXTENT_MAP_DELALLOC)
|
|
||||||
last_end = min_t(u64, last_end, inode->i_size);
|
|
||||||
|
|
||||||
if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
|
|
||||||
free_extent_map(em);
|
|
||||||
ret = -ENXIO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
free_extent_map(em);
|
free_extent_map(em);
|
||||||
|
em = NULL;
|
||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
if (!ret)
|
free_extent_map(em);
|
||||||
*offset = min(*offset, inode->i_size);
|
if (!ret) {
|
||||||
out:
|
if (whence == SEEK_DATA && start >= inode->i_size)
|
||||||
|
ret = -ENXIO;
|
||||||
|
else
|
||||||
|
*offset = min_t(loff_t, start, inode->i_size);
|
||||||
|
}
|
||||||
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);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -218,7 +218,6 @@ int btrfs_check_trunc_cache_free_space(struct btrfs_root *root,
|
||||||
|
|
||||||
int btrfs_truncate_free_space_cache(struct btrfs_root *root,
|
int btrfs_truncate_free_space_cache(struct btrfs_root *root,
|
||||||
struct btrfs_trans_handle *trans,
|
struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_path *path,
|
|
||||||
struct inode *inode)
|
struct inode *inode)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -1009,8 +1008,13 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
ret = btrfs_wait_ordered_range(inode, 0, (u64)-1);
|
||||||
btrfs_wait_ordered_range(inode, 0, (u64)-1);
|
if (ret) {
|
||||||
|
clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1,
|
||||||
|
EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL,
|
||||||
|
GFP_NOFS);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
|
key.objectid = BTRFS_FREE_SPACE_OBJECTID;
|
||||||
key.offset = offset;
|
key.offset = offset;
|
||||||
|
@ -2276,7 +2280,7 @@ u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
entry = rb_entry(node, struct btrfs_free_space, offset_index);
|
entry = rb_entry(node, struct btrfs_free_space, offset_index);
|
||||||
while(1) {
|
while (1) {
|
||||||
if (entry->bytes < bytes && entry->bytes > *max_extent_size)
|
if (entry->bytes < bytes && entry->bytes > *max_extent_size)
|
||||||
*max_extent_size = entry->bytes;
|
*max_extent_size = entry->bytes;
|
||||||
|
|
||||||
|
@ -2967,19 +2971,15 @@ int load_free_ino_cache(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
|
||||||
|
|
||||||
int btrfs_write_out_ino_cache(struct btrfs_root *root,
|
int btrfs_write_out_ino_cache(struct btrfs_root *root,
|
||||||
struct btrfs_trans_handle *trans,
|
struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_path *path)
|
struct btrfs_path *path,
|
||||||
|
struct inode *inode)
|
||||||
{
|
{
|
||||||
struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
|
struct btrfs_free_space_ctl *ctl = root->free_ino_ctl;
|
||||||
struct inode *inode;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!btrfs_test_opt(root, INODE_MAP_CACHE))
|
if (!btrfs_test_opt(root, INODE_MAP_CACHE))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
inode = lookup_free_ino_inode(root, path);
|
|
||||||
if (IS_ERR(inode))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ret = __btrfs_write_out_cache(root, inode, ctl, NULL, trans, path, 0);
|
ret = __btrfs_write_out_cache(root, inode, ctl, NULL, trans, path, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
btrfs_delalloc_release_metadata(inode, inode->i_size);
|
btrfs_delalloc_release_metadata(inode, inode->i_size);
|
||||||
|
@ -2990,7 +2990,6 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
iput(inode);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,6 @@ int btrfs_check_trunc_cache_free_space(struct btrfs_root *root,
|
||||||
struct btrfs_block_rsv *rsv);
|
struct btrfs_block_rsv *rsv);
|
||||||
int btrfs_truncate_free_space_cache(struct btrfs_root *root,
|
int btrfs_truncate_free_space_cache(struct btrfs_root *root,
|
||||||
struct btrfs_trans_handle *trans,
|
struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_path *path,
|
|
||||||
struct inode *inode);
|
struct inode *inode);
|
||||||
int load_free_space_cache(struct btrfs_fs_info *fs_info,
|
int load_free_space_cache(struct btrfs_fs_info *fs_info,
|
||||||
struct btrfs_block_group_cache *block_group);
|
struct btrfs_block_group_cache *block_group);
|
||||||
|
@ -76,7 +75,8 @@ int load_free_ino_cache(struct btrfs_fs_info *fs_info,
|
||||||
struct btrfs_root *root);
|
struct btrfs_root *root);
|
||||||
int btrfs_write_out_ino_cache(struct btrfs_root *root,
|
int btrfs_write_out_ino_cache(struct btrfs_root *root,
|
||||||
struct btrfs_trans_handle *trans,
|
struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_path *path);
|
struct btrfs_path *path,
|
||||||
|
struct inode *inode);
|
||||||
|
|
||||||
void btrfs_init_free_space_ctl(struct btrfs_block_group_cache *block_group);
|
void btrfs_init_free_space_ctl(struct btrfs_block_group_cache *block_group);
|
||||||
int __btrfs_add_free_space(struct btrfs_free_space_ctl *ctl,
|
int __btrfs_add_free_space(struct btrfs_free_space_ctl *ctl,
|
||||||
|
|
|
@ -369,7 +369,7 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
item = btrfs_item_nr(leaf, path->slots[0]);
|
item = btrfs_item_nr(path->slots[0]);
|
||||||
ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char);
|
ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char);
|
||||||
ptr += btrfs_item_size(leaf, item) - ins_len;
|
ptr += btrfs_item_size(leaf, item) - ins_len;
|
||||||
extref = (struct btrfs_inode_extref *)ptr;
|
extref = (struct btrfs_inode_extref *)ptr;
|
||||||
|
|
|
@ -78,10 +78,8 @@ static int caching_kthread(void *data)
|
||||||
btrfs_transaction_in_commit(fs_info)) {
|
btrfs_transaction_in_commit(fs_info)) {
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
|
|
||||||
if (btrfs_header_nritems(leaf) == 0) {
|
if (WARN_ON(btrfs_header_nritems(leaf) == 0))
|
||||||
WARN_ON(1);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save the key so we can advances forward
|
* Save the key so we can advances forward
|
||||||
|
@ -237,7 +235,7 @@ void btrfs_return_ino(struct btrfs_root *root, u64 objectid)
|
||||||
start_caching(root);
|
start_caching(root);
|
||||||
|
|
||||||
if (objectid <= root->cache_progress ||
|
if (objectid <= root->cache_progress ||
|
||||||
objectid > root->highest_objectid)
|
objectid >= root->highest_objectid)
|
||||||
__btrfs_add_free_space(ctl, objectid, 1);
|
__btrfs_add_free_space(ctl, objectid, 1);
|
||||||
else
|
else
|
||||||
__btrfs_add_free_space(pinned, objectid, 1);
|
__btrfs_add_free_space(pinned, objectid, 1);
|
||||||
|
@ -412,8 +410,7 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Don't save inode cache if we are deleting this root */
|
/* Don't save inode cache if we are deleting this root */
|
||||||
if (btrfs_root_refs(&root->root_item) == 0 &&
|
if (btrfs_root_refs(&root->root_item) == 0)
|
||||||
root != root->fs_info->tree_root)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!btrfs_test_opt(root, INODE_MAP_CACHE))
|
if (!btrfs_test_opt(root, INODE_MAP_CACHE))
|
||||||
|
@ -467,7 +464,7 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i_size_read(inode) > 0) {
|
if (i_size_read(inode) > 0) {
|
||||||
ret = btrfs_truncate_free_space_cache(root, trans, path, inode);
|
ret = btrfs_truncate_free_space_cache(root, trans, inode);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret != -ENOSPC)
|
if (ret != -ENOSPC)
|
||||||
btrfs_abort_transaction(trans, root, ret);
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
|
@ -504,7 +501,7 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
|
||||||
}
|
}
|
||||||
btrfs_free_reserved_data_space(inode, prealloc);
|
btrfs_free_reserved_data_space(inode, prealloc);
|
||||||
|
|
||||||
ret = btrfs_write_out_ino_cache(root, trans, path);
|
ret = btrfs_write_out_ino_cache(root, trans, path, inode);
|
||||||
out_put:
|
out_put:
|
||||||
iput(inode);
|
iput(inode);
|
||||||
out_release:
|
out_release:
|
||||||
|
|
207
fs/btrfs/inode.c
207
fs/btrfs/inode.c
|
@ -43,7 +43,6 @@
|
||||||
#include <linux/btrfs.h>
|
#include <linux/btrfs.h>
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
#include <linux/posix_acl_xattr.h>
|
#include <linux/posix_acl_xattr.h>
|
||||||
#include "compat.h"
|
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
|
@ -844,7 +843,10 @@ static noinline int cow_file_range(struct inode *inode,
|
||||||
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
|
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
BUG_ON(btrfs_is_free_space_inode(inode));
|
if (btrfs_is_free_space_inode(inode)) {
|
||||||
|
WARN_ON_ONCE(1);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
num_bytes = ALIGN(end - start + 1, blocksize);
|
num_bytes = ALIGN(end - start + 1, blocksize);
|
||||||
num_bytes = max(blocksize, num_bytes);
|
num_bytes = max(blocksize, num_bytes);
|
||||||
|
@ -1178,10 +1180,8 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = btrfs_lookup_file_extent(trans, root, path, ino,
|
ret = btrfs_lookup_file_extent(trans, root, path, ino,
|
||||||
cur_offset, 0);
|
cur_offset, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
btrfs_abort_transaction(trans, root, ret);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
if (ret > 0 && path->slots[0] > 0 && check_prev) {
|
if (ret > 0 && path->slots[0] > 0 && check_prev) {
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
btrfs_item_key_to_cpu(leaf, &found_key,
|
btrfs_item_key_to_cpu(leaf, &found_key,
|
||||||
|
@ -1195,10 +1195,8 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
||||||
ret = btrfs_next_leaf(root, path);
|
ret = btrfs_next_leaf(root, path);
|
||||||
if (ret < 0) {
|
if (ret < 0)
|
||||||
btrfs_abort_transaction(trans, root, ret);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
break;
|
break;
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
|
@ -1289,10 +1287,8 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||||
ret = cow_file_range(inode, locked_page,
|
ret = cow_file_range(inode, locked_page,
|
||||||
cow_start, found_key.offset - 1,
|
cow_start, found_key.offset - 1,
|
||||||
page_started, nr_written, 1);
|
page_started, nr_written, 1);
|
||||||
if (ret) {
|
if (ret)
|
||||||
btrfs_abort_transaction(trans, root, ret);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
cow_start = (u64)-1;
|
cow_start = (u64)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1339,10 +1335,8 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||||
BTRFS_DATA_RELOC_TREE_OBJECTID) {
|
BTRFS_DATA_RELOC_TREE_OBJECTID) {
|
||||||
ret = btrfs_reloc_clone_csums(inode, cur_offset,
|
ret = btrfs_reloc_clone_csums(inode, cur_offset,
|
||||||
num_bytes);
|
num_bytes);
|
||||||
if (ret) {
|
if (ret)
|
||||||
btrfs_abort_transaction(trans, root, ret);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extent_clear_unlock_delalloc(inode, cur_offset,
|
extent_clear_unlock_delalloc(inode, cur_offset,
|
||||||
|
@ -1364,10 +1358,8 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||||
if (cow_start != (u64)-1) {
|
if (cow_start != (u64)-1) {
|
||||||
ret = cow_file_range(inode, locked_page, cow_start, end,
|
ret = cow_file_range(inode, locked_page, cow_start, end,
|
||||||
page_started, nr_written, 1);
|
page_started, nr_written, 1);
|
||||||
if (ret) {
|
if (ret)
|
||||||
btrfs_abort_transaction(trans, root, ret);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -1551,7 +1543,13 @@ static void btrfs_clear_bit_hook(struct inode *inode,
|
||||||
spin_unlock(&BTRFS_I(inode)->lock);
|
spin_unlock(&BTRFS_I(inode)->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*bits & EXTENT_DO_ACCOUNTING)
|
/*
|
||||||
|
* We don't reserve metadata space for space cache inodes so we
|
||||||
|
* don't need to call dellalloc_release_metadata if there is an
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
|
if (*bits & EXTENT_DO_ACCOUNTING &&
|
||||||
|
root != root->fs_info->tree_root)
|
||||||
btrfs_delalloc_release_metadata(inode, len);
|
btrfs_delalloc_release_metadata(inode, len);
|
||||||
|
|
||||||
if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID
|
if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID
|
||||||
|
@ -2041,10 +2039,8 @@ static noinline int record_one_backref(u64 inum, u64 offset, u64 root_id,
|
||||||
key.offset = offset;
|
key.offset = offset;
|
||||||
|
|
||||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||||
if (ret < 0) {
|
if (WARN_ON(ret < 0))
|
||||||
WARN_ON(1);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -2367,10 +2363,23 @@ static noinline int relink_extent_backref(struct btrfs_path *path,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_sa_defrag_extent(struct new_sa_defrag_extent *new)
|
||||||
|
{
|
||||||
|
struct old_sa_defrag_extent *old, *tmp;
|
||||||
|
|
||||||
|
if (!new)
|
||||||
|
return;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(old, tmp, &new->head, list) {
|
||||||
|
list_del(&old->list);
|
||||||
|
kfree(old);
|
||||||
|
}
|
||||||
|
kfree(new);
|
||||||
|
}
|
||||||
|
|
||||||
static void relink_file_extents(struct new_sa_defrag_extent *new)
|
static void relink_file_extents(struct new_sa_defrag_extent *new)
|
||||||
{
|
{
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
struct old_sa_defrag_extent *old, *tmp;
|
|
||||||
struct sa_defrag_extent_backref *backref;
|
struct sa_defrag_extent_backref *backref;
|
||||||
struct sa_defrag_extent_backref *prev = NULL;
|
struct sa_defrag_extent_backref *prev = NULL;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
@ -2413,16 +2422,11 @@ static void relink_file_extents(struct new_sa_defrag_extent *new)
|
||||||
kfree(prev);
|
kfree(prev);
|
||||||
|
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
|
|
||||||
list_for_each_entry_safe(old, tmp, &new->head, list) {
|
|
||||||
list_del(&old->list);
|
|
||||||
kfree(old);
|
|
||||||
}
|
|
||||||
out:
|
out:
|
||||||
|
free_sa_defrag_extent(new);
|
||||||
|
|
||||||
atomic_dec(&root->fs_info->defrag_running);
|
atomic_dec(&root->fs_info->defrag_running);
|
||||||
wake_up(&root->fs_info->transaction_wait);
|
wake_up(&root->fs_info->transaction_wait);
|
||||||
|
|
||||||
kfree(new);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct new_sa_defrag_extent *
|
static struct new_sa_defrag_extent *
|
||||||
|
@ -2432,7 +2436,7 @@ record_old_file_extents(struct inode *inode,
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct old_sa_defrag_extent *old, *tmp;
|
struct old_sa_defrag_extent *old;
|
||||||
struct new_sa_defrag_extent *new;
|
struct new_sa_defrag_extent *new;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -2480,7 +2484,7 @@ record_old_file_extents(struct inode *inode,
|
||||||
if (slot >= btrfs_header_nritems(l)) {
|
if (slot >= btrfs_header_nritems(l)) {
|
||||||
ret = btrfs_next_leaf(root, path);
|
ret = btrfs_next_leaf(root, path);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_free_list;
|
goto out_free_path;
|
||||||
else if (ret > 0)
|
else if (ret > 0)
|
||||||
break;
|
break;
|
||||||
continue;
|
continue;
|
||||||
|
@ -2509,7 +2513,7 @@ record_old_file_extents(struct inode *inode,
|
||||||
|
|
||||||
old = kmalloc(sizeof(*old), GFP_NOFS);
|
old = kmalloc(sizeof(*old), GFP_NOFS);
|
||||||
if (!old)
|
if (!old)
|
||||||
goto out_free_list;
|
goto out_free_path;
|
||||||
|
|
||||||
offset = max(new->file_pos, key.offset);
|
offset = max(new->file_pos, key.offset);
|
||||||
end = min(new->file_pos + new->len, key.offset + num_bytes);
|
end = min(new->file_pos + new->len, key.offset + num_bytes);
|
||||||
|
@ -2531,15 +2535,10 @@ record_old_file_extents(struct inode *inode,
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
|
|
||||||
out_free_list:
|
|
||||||
list_for_each_entry_safe(old, tmp, &new->head, list) {
|
|
||||||
list_del(&old->list);
|
|
||||||
kfree(old);
|
|
||||||
}
|
|
||||||
out_free_path:
|
out_free_path:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
out_kfree:
|
out_kfree:
|
||||||
kfree(new);
|
free_sa_defrag_extent(new);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2710,8 +2709,14 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
|
||||||
btrfs_remove_ordered_extent(inode, ordered_extent);
|
btrfs_remove_ordered_extent(inode, ordered_extent);
|
||||||
|
|
||||||
/* for snapshot-aware defrag */
|
/* for snapshot-aware defrag */
|
||||||
if (new)
|
if (new) {
|
||||||
relink_file_extents(new);
|
if (ret) {
|
||||||
|
free_sa_defrag_extent(new);
|
||||||
|
atomic_dec(&root->fs_info->defrag_running);
|
||||||
|
} else {
|
||||||
|
relink_file_extents(new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* once for us */
|
/* once for us */
|
||||||
btrfs_put_ordered_extent(ordered_extent);
|
btrfs_put_ordered_extent(ordered_extent);
|
||||||
|
@ -2969,6 +2974,7 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
|
||||||
if (insert >= 1) {
|
if (insert >= 1) {
|
||||||
ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
|
ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
atomic_dec(&root->orphan_inodes);
|
||||||
if (reserve) {
|
if (reserve) {
|
||||||
clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
|
clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
|
||||||
&BTRFS_I(inode)->runtime_flags);
|
&BTRFS_I(inode)->runtime_flags);
|
||||||
|
@ -3018,14 +3024,16 @@ static int btrfs_orphan_del(struct btrfs_trans_handle *trans,
|
||||||
release_rsv = 1;
|
release_rsv = 1;
|
||||||
spin_unlock(&root->orphan_lock);
|
spin_unlock(&root->orphan_lock);
|
||||||
|
|
||||||
if (trans && delete_item)
|
if (delete_item) {
|
||||||
ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode));
|
|
||||||
|
|
||||||
if (release_rsv) {
|
|
||||||
btrfs_orphan_release_metadata(inode);
|
|
||||||
atomic_dec(&root->orphan_inodes);
|
atomic_dec(&root->orphan_inodes);
|
||||||
|
if (trans)
|
||||||
|
ret = btrfs_del_orphan_item(trans, root,
|
||||||
|
btrfs_ino(inode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (release_rsv)
|
||||||
|
btrfs_orphan_release_metadata(inode);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3172,8 +3180,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||||
|
|
||||||
/* if we have links, this was a truncate, lets do that */
|
/* if we have links, this was a truncate, lets do that */
|
||||||
if (inode->i_nlink) {
|
if (inode->i_nlink) {
|
||||||
if (!S_ISREG(inode->i_mode)) {
|
if (WARN_ON(!S_ISREG(inode->i_mode))) {
|
||||||
WARN_ON(1);
|
|
||||||
iput(inode);
|
iput(inode);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -3636,7 +3643,7 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
|
||||||
int ret;
|
int ret;
|
||||||
ret = __btrfs_unlink_inode(trans, root, dir, inode, name, name_len);
|
ret = __btrfs_unlink_inode(trans, root, dir, inode, name, name_len);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
btrfs_drop_nlink(inode);
|
drop_nlink(inode);
|
||||||
ret = btrfs_update_inode(trans, root, inode);
|
ret = btrfs_update_inode(trans, root, inode);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -4230,15 +4237,16 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
struct btrfs_ordered_extent *ordered;
|
struct btrfs_ordered_extent *ordered;
|
||||||
btrfs_wait_ordered_range(inode, hole_start,
|
|
||||||
block_end - hole_start);
|
|
||||||
lock_extent_bits(io_tree, hole_start, block_end - 1, 0,
|
lock_extent_bits(io_tree, hole_start, block_end - 1, 0,
|
||||||
&cached_state);
|
&cached_state);
|
||||||
ordered = btrfs_lookup_ordered_extent(inode, hole_start);
|
ordered = btrfs_lookup_ordered_range(inode, hole_start,
|
||||||
|
block_end - hole_start);
|
||||||
if (!ordered)
|
if (!ordered)
|
||||||
break;
|
break;
|
||||||
unlock_extent_cached(io_tree, hole_start, block_end - 1,
|
unlock_extent_cached(io_tree, hole_start, block_end - 1,
|
||||||
&cached_state, GFP_NOFS);
|
&cached_state, GFP_NOFS);
|
||||||
|
btrfs_start_ordered_extent(inode, ordered, 1);
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4472,8 +4480,10 @@ void btrfs_evict_inode(struct inode *inode)
|
||||||
trace_btrfs_inode_evict(inode);
|
trace_btrfs_inode_evict(inode);
|
||||||
|
|
||||||
truncate_inode_pages(&inode->i_data, 0);
|
truncate_inode_pages(&inode->i_data, 0);
|
||||||
if (inode->i_nlink && (btrfs_root_refs(&root->root_item) != 0 ||
|
if (inode->i_nlink &&
|
||||||
btrfs_is_free_space_inode(inode)))
|
((btrfs_root_refs(&root->root_item) != 0 &&
|
||||||
|
root->root_key.objectid != BTRFS_ROOT_TREE_OBJECTID) ||
|
||||||
|
btrfs_is_free_space_inode(inode)))
|
||||||
goto no_delete;
|
goto no_delete;
|
||||||
|
|
||||||
if (is_bad_inode(inode)) {
|
if (is_bad_inode(inode)) {
|
||||||
|
@ -4490,7 +4500,8 @@ void btrfs_evict_inode(struct inode *inode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inode->i_nlink > 0) {
|
if (inode->i_nlink > 0) {
|
||||||
BUG_ON(btrfs_root_refs(&root->root_item) != 0);
|
BUG_ON(btrfs_root_refs(&root->root_item) != 0 &&
|
||||||
|
root->root_key.objectid != BTRFS_ROOT_TREE_OBJECTID);
|
||||||
goto no_delete;
|
goto no_delete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4731,14 +4742,7 @@ static void inode_tree_del(struct inode *inode)
|
||||||
}
|
}
|
||||||
spin_unlock(&root->inode_lock);
|
spin_unlock(&root->inode_lock);
|
||||||
|
|
||||||
/*
|
if (empty && btrfs_root_refs(&root->root_item) == 0) {
|
||||||
* Free space cache has inodes in the tree root, but the tree root has a
|
|
||||||
* root_refs of 0, so this could end up dropping the tree root as a
|
|
||||||
* snapshot, so we need the extra !root->fs_info->tree_root check to
|
|
||||||
* make sure we don't drop it.
|
|
||||||
*/
|
|
||||||
if (empty && btrfs_root_refs(&root->root_item) == 0 &&
|
|
||||||
root != root->fs_info->tree_root) {
|
|
||||||
synchronize_srcu(&root->fs_info->subvol_srcu);
|
synchronize_srcu(&root->fs_info->subvol_srcu);
|
||||||
spin_lock(&root->inode_lock);
|
spin_lock(&root->inode_lock);
|
||||||
empty = RB_EMPTY_ROOT(&root->inode_tree);
|
empty = RB_EMPTY_ROOT(&root->inode_tree);
|
||||||
|
@ -4831,10 +4835,12 @@ static struct inode *btrfs_iget_locked(struct super_block *s,
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct btrfs_iget_args args;
|
struct btrfs_iget_args args;
|
||||||
|
unsigned long hashval = btrfs_inode_hash(objectid, root);
|
||||||
|
|
||||||
args.ino = objectid;
|
args.ino = objectid;
|
||||||
args.root = root;
|
args.root = root;
|
||||||
|
|
||||||
inode = iget5_locked(s, objectid, btrfs_find_actor,
|
inode = iget5_locked(s, hashval, btrfs_find_actor,
|
||||||
btrfs_init_locked_inode,
|
btrfs_init_locked_inode,
|
||||||
(void *)&args);
|
(void *)&args);
|
||||||
return inode;
|
return inode;
|
||||||
|
@ -5048,7 +5054,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
item = btrfs_item_nr(leaf, slot);
|
item = btrfs_item_nr(slot);
|
||||||
btrfs_item_key_to_cpu(leaf, &found_key, slot);
|
btrfs_item_key_to_cpu(leaf, &found_key, slot);
|
||||||
|
|
||||||
if (found_key.objectid != key.objectid)
|
if (found_key.objectid != key.objectid)
|
||||||
|
@ -5454,7 +5460,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
||||||
BTRFS_INODE_NODATASUM;
|
BTRFS_INODE_NODATASUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
insert_inode_hash(inode);
|
btrfs_insert_inode_hash(inode);
|
||||||
inode_tree_add(inode);
|
inode_tree_add(inode);
|
||||||
|
|
||||||
trace_btrfs_inode_new(inode);
|
trace_btrfs_inode_new(inode);
|
||||||
|
@ -5730,7 +5736,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_inc_nlink(inode);
|
inc_nlink(inode);
|
||||||
inode_inc_iversion(inode);
|
inode_inc_iversion(inode);
|
||||||
inode->i_ctime = CURRENT_TIME;
|
inode->i_ctime = CURRENT_TIME;
|
||||||
ihold(inode);
|
ihold(inode);
|
||||||
|
@ -5860,7 +5866,7 @@ static noinline int uncompress_inline(struct btrfs_path *path,
|
||||||
compress_type = btrfs_file_extent_compression(leaf, item);
|
compress_type = btrfs_file_extent_compression(leaf, item);
|
||||||
max_size = btrfs_file_extent_ram_bytes(leaf, item);
|
max_size = btrfs_file_extent_ram_bytes(leaf, item);
|
||||||
inline_size = btrfs_file_extent_inline_item_len(leaf,
|
inline_size = btrfs_file_extent_inline_item_len(leaf,
|
||||||
btrfs_item_nr(leaf, path->slots[0]));
|
btrfs_item_nr(path->slots[0]));
|
||||||
tmp = kmalloc(inline_size, GFP_NOFS);
|
tmp = kmalloc(inline_size, GFP_NOFS);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -5974,7 +5980,14 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
|
||||||
found_type = btrfs_key_type(&found_key);
|
found_type = btrfs_key_type(&found_key);
|
||||||
if (found_key.objectid != objectid ||
|
if (found_key.objectid != objectid ||
|
||||||
found_type != BTRFS_EXTENT_DATA_KEY) {
|
found_type != BTRFS_EXTENT_DATA_KEY) {
|
||||||
goto not_found;
|
/*
|
||||||
|
* If we backup past the first extent we want to move forward
|
||||||
|
* and see if there is an extent in front of us, otherwise we'll
|
||||||
|
* say there is a hole for our whole search range which can
|
||||||
|
* cause problems.
|
||||||
|
*/
|
||||||
|
extent_end = start;
|
||||||
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
found_type = btrfs_file_extent_type(leaf, item);
|
found_type = btrfs_file_extent_type(leaf, item);
|
||||||
|
@ -5989,7 +6002,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
|
||||||
size = btrfs_file_extent_inline_len(leaf, item);
|
size = btrfs_file_extent_inline_len(leaf, item);
|
||||||
extent_end = ALIGN(extent_start + size, root->sectorsize);
|
extent_end = ALIGN(extent_start + size, root->sectorsize);
|
||||||
}
|
}
|
||||||
|
next:
|
||||||
if (start >= extent_end) {
|
if (start >= extent_end) {
|
||||||
path->slots[0]++;
|
path->slots[0]++;
|
||||||
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
|
||||||
|
@ -6249,7 +6262,7 @@ struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *pag
|
||||||
/* adjust the range_start to make sure it doesn't
|
/* adjust the range_start to make sure it doesn't
|
||||||
* go backwards from the start they passed in
|
* go backwards from the start they passed in
|
||||||
*/
|
*/
|
||||||
range_start = max(start,range_start);
|
range_start = max(start, range_start);
|
||||||
found = found_end - range_start;
|
found = found_end - range_start;
|
||||||
|
|
||||||
if (found > 0) {
|
if (found > 0) {
|
||||||
|
@ -7053,7 +7066,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
submit_len += bvec->bv_len;
|
submit_len += bvec->bv_len;
|
||||||
nr_pages ++;
|
nr_pages++;
|
||||||
bvec++;
|
bvec++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7222,7 +7235,9 @@ static ssize_t btrfs_direct_IO(int rw, struct kiocb *iocb,
|
||||||
* outstanding dirty pages are on disk.
|
* outstanding dirty pages are on disk.
|
||||||
*/
|
*/
|
||||||
count = iov_length(iov, nr_segs);
|
count = iov_length(iov, nr_segs);
|
||||||
btrfs_wait_ordered_range(inode, offset, count);
|
ret = btrfs_wait_ordered_range(inode, offset, count);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (rw & WRITE) {
|
if (rw & WRITE) {
|
||||||
/*
|
/*
|
||||||
|
@ -7563,7 +7578,10 @@ static int btrfs_truncate(struct inode *inode)
|
||||||
u64 mask = root->sectorsize - 1;
|
u64 mask = root->sectorsize - 1;
|
||||||
u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
|
u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
|
||||||
|
|
||||||
btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
|
ret = btrfs_wait_ordered_range(inode, inode->i_size & (~mask),
|
||||||
|
(u64)-1);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Yes ladies and gentelment, this is indeed ugly. The fact is we have
|
* Yes ladies and gentelment, this is indeed ugly. The fact is we have
|
||||||
|
@ -7787,6 +7805,14 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
|
||||||
return inode;
|
return inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
|
||||||
|
void btrfs_test_destroy_inode(struct inode *inode)
|
||||||
|
{
|
||||||
|
btrfs_drop_extent_cache(inode, 0, (u64)-1, 0);
|
||||||
|
kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void btrfs_i_callback(struct rcu_head *head)
|
static void btrfs_i_callback(struct rcu_head *head)
|
||||||
{
|
{
|
||||||
struct inode *inode = container_of(head, struct inode, i_rcu);
|
struct inode *inode = container_of(head, struct inode, i_rcu);
|
||||||
|
@ -7857,8 +7883,7 @@ int btrfs_drop_inode(struct inode *inode)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* the snap/subvol tree is on deleting */
|
/* the snap/subvol tree is on deleting */
|
||||||
if (btrfs_root_refs(&root->root_item) == 0 &&
|
if (btrfs_root_refs(&root->root_item) == 0)
|
||||||
root != root->fs_info->tree_root)
|
|
||||||
return 1;
|
return 1;
|
||||||
else
|
else
|
||||||
return generic_drop_inode(inode);
|
return generic_drop_inode(inode);
|
||||||
|
@ -7995,8 +8020,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
if (ret == -EEXIST) {
|
if (ret == -EEXIST) {
|
||||||
/* we shouldn't get
|
/* we shouldn't get
|
||||||
* eexist without a new_inode */
|
* eexist without a new_inode */
|
||||||
if (!new_inode) {
|
if (WARN_ON(!new_inode)) {
|
||||||
WARN_ON(1);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -8144,18 +8168,24 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||||
static void btrfs_run_delalloc_work(struct btrfs_work *work)
|
static void btrfs_run_delalloc_work(struct btrfs_work *work)
|
||||||
{
|
{
|
||||||
struct btrfs_delalloc_work *delalloc_work;
|
struct btrfs_delalloc_work *delalloc_work;
|
||||||
|
struct inode *inode;
|
||||||
|
|
||||||
delalloc_work = container_of(work, struct btrfs_delalloc_work,
|
delalloc_work = container_of(work, struct btrfs_delalloc_work,
|
||||||
work);
|
work);
|
||||||
if (delalloc_work->wait)
|
inode = delalloc_work->inode;
|
||||||
btrfs_wait_ordered_range(delalloc_work->inode, 0, (u64)-1);
|
if (delalloc_work->wait) {
|
||||||
else
|
btrfs_wait_ordered_range(inode, 0, (u64)-1);
|
||||||
filemap_flush(delalloc_work->inode->i_mapping);
|
} else {
|
||||||
|
filemap_flush(inode->i_mapping);
|
||||||
|
if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
|
||||||
|
&BTRFS_I(inode)->runtime_flags))
|
||||||
|
filemap_flush(inode->i_mapping);
|
||||||
|
}
|
||||||
|
|
||||||
if (delalloc_work->delay_iput)
|
if (delalloc_work->delay_iput)
|
||||||
btrfs_add_delayed_iput(delalloc_work->inode);
|
btrfs_add_delayed_iput(inode);
|
||||||
else
|
else
|
||||||
iput(delalloc_work->inode);
|
iput(inode);
|
||||||
complete(&delalloc_work->completion);
|
complete(&delalloc_work->completion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8276,8 +8306,7 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_start_all_delalloc_inodes(struct btrfs_fs_info *fs_info,
|
int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput)
|
||||||
int delay_iput)
|
|
||||||
{
|
{
|
||||||
struct btrfs_root *root;
|
struct btrfs_root *root;
|
||||||
struct list_head splice;
|
struct list_head splice;
|
||||||
|
@ -8337,14 +8366,14 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
|
||||||
int err;
|
int err;
|
||||||
int drop_inode = 0;
|
int drop_inode = 0;
|
||||||
u64 objectid;
|
u64 objectid;
|
||||||
u64 index = 0 ;
|
u64 index = 0;
|
||||||
int name_len;
|
int name_len;
|
||||||
int datasize;
|
int datasize;
|
||||||
unsigned long ptr;
|
unsigned long ptr;
|
||||||
struct btrfs_file_extent_item *ei;
|
struct btrfs_file_extent_item *ei;
|
||||||
struct extent_buffer *leaf;
|
struct extent_buffer *leaf;
|
||||||
|
|
||||||
name_len = strlen(symname) + 1;
|
name_len = strlen(symname);
|
||||||
if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root))
|
if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root))
|
||||||
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
||||||
|
|
||||||
|
@ -8432,7 +8461,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
|
||||||
inode->i_mapping->a_ops = &btrfs_symlink_aops;
|
inode->i_mapping->a_ops = &btrfs_symlink_aops;
|
||||||
inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
|
inode->i_mapping->backing_dev_info = &root->fs_info->bdi;
|
||||||
inode_set_bytes(inode, name_len);
|
inode_set_bytes(inode, name_len);
|
||||||
btrfs_i_size_write(inode, name_len - 1);
|
btrfs_i_size_write(inode, name_len);
|
||||||
err = btrfs_update_inode(trans, root, inode);
|
err = btrfs_update_inode(trans, root, inode);
|
||||||
if (err)
|
if (err)
|
||||||
drop_inode = 1;
|
drop_inode = 1;
|
||||||
|
@ -8491,6 +8520,8 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
|
||||||
ins.offset, 0, 0, 0,
|
ins.offset, 0, 0, 0,
|
||||||
BTRFS_FILE_EXTENT_PREALLOC);
|
BTRFS_FILE_EXTENT_PREALLOC);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
btrfs_free_reserved_extent(root, ins.objectid,
|
||||||
|
ins.offset);
|
||||||
btrfs_abort_transaction(trans, root, ret);
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
if (own_trans)
|
if (own_trans)
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
|
|
|
@ -44,7 +44,6 @@
|
||||||
#include <linux/uuid.h>
|
#include <linux/uuid.h>
|
||||||
#include <linux/btrfs.h>
|
#include <linux/btrfs.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include "compat.h"
|
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
#include "transaction.h"
|
#include "transaction.h"
|
||||||
|
@ -369,9 +368,8 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
|
||||||
|
|
||||||
int btrfs_is_empty_uuid(u8 *uuid)
|
int btrfs_is_empty_uuid(u8 *uuid)
|
||||||
{
|
{
|
||||||
static char empty_uuid[BTRFS_UUID_SIZE] = {0};
|
BUILD_BUG_ON(BTRFS_UUID_SIZE > PAGE_SIZE);
|
||||||
|
return !memcmp(uuid, empty_zero_page, BTRFS_UUID_SIZE);
|
||||||
return !memcmp(uuid, empty_uuid, BTRFS_UUID_SIZE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline int create_subvol(struct inode *dir,
|
static noinline int create_subvol(struct inode *dir,
|
||||||
|
@ -436,7 +434,7 @@ static noinline int create_subvol(struct inode *dir,
|
||||||
btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV);
|
btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV);
|
||||||
btrfs_set_header_owner(leaf, objectid);
|
btrfs_set_header_owner(leaf, objectid);
|
||||||
|
|
||||||
write_extent_buffer(leaf, root->fs_info->fsid, btrfs_header_fsid(leaf),
|
write_extent_buffer(leaf, root->fs_info->fsid, btrfs_header_fsid(),
|
||||||
BTRFS_FSID_SIZE);
|
BTRFS_FSID_SIZE);
|
||||||
write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid,
|
write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid,
|
||||||
btrfs_header_chunk_tree_uuid(leaf),
|
btrfs_header_chunk_tree_uuid(leaf),
|
||||||
|
@ -574,7 +572,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
btrfs_wait_ordered_extents(root);
|
btrfs_wait_ordered_extents(root, -1);
|
||||||
|
|
||||||
pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS);
|
pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS);
|
||||||
if (!pending_snapshot)
|
if (!pending_snapshot)
|
||||||
|
@ -688,7 +686,7 @@ static inline int btrfs_check_sticky(struct inode *dir, struct inode *inode)
|
||||||
* nfs_async_unlink().
|
* nfs_async_unlink().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int btrfs_may_delete(struct inode *dir,struct dentry *victim,int isdir)
|
static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
@ -842,7 +840,6 @@ static int find_new_extents(struct btrfs_root *root,
|
||||||
{
|
{
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
struct btrfs_key min_key;
|
struct btrfs_key min_key;
|
||||||
struct btrfs_key max_key;
|
|
||||||
struct extent_buffer *leaf;
|
struct extent_buffer *leaf;
|
||||||
struct btrfs_file_extent_item *extent;
|
struct btrfs_file_extent_item *extent;
|
||||||
int type;
|
int type;
|
||||||
|
@ -857,15 +854,10 @@ static int find_new_extents(struct btrfs_root *root,
|
||||||
min_key.type = BTRFS_EXTENT_DATA_KEY;
|
min_key.type = BTRFS_EXTENT_DATA_KEY;
|
||||||
min_key.offset = *off;
|
min_key.offset = *off;
|
||||||
|
|
||||||
max_key.objectid = ino;
|
|
||||||
max_key.type = (u8)-1;
|
|
||||||
max_key.offset = (u64)-1;
|
|
||||||
|
|
||||||
path->keep_locks = 1;
|
path->keep_locks = 1;
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
ret = btrfs_search_forward(root, &min_key, &max_key,
|
ret = btrfs_search_forward(root, &min_key, path, newer_than);
|
||||||
path, newer_than);
|
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto none;
|
goto none;
|
||||||
if (min_key.objectid != ino)
|
if (min_key.objectid != ino)
|
||||||
|
@ -1206,7 +1198,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
|
||||||
ra = &file->f_ra;
|
ra = &file->f_ra;
|
||||||
}
|
}
|
||||||
|
|
||||||
pages = kmalloc(sizeof(struct page *) * max_cluster,
|
pages = kmalloc_array(max_cluster, sizeof(struct page *),
|
||||||
GFP_NOFS);
|
GFP_NOFS);
|
||||||
if (!pages) {
|
if (!pages) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
@ -1893,7 +1885,6 @@ static noinline int search_ioctl(struct inode *inode,
|
||||||
{
|
{
|
||||||
struct btrfs_root *root;
|
struct btrfs_root *root;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct btrfs_key max_key;
|
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
struct btrfs_ioctl_search_key *sk = &args->key;
|
struct btrfs_ioctl_search_key *sk = &args->key;
|
||||||
struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info;
|
struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info;
|
||||||
|
@ -1925,15 +1916,10 @@ static noinline int search_ioctl(struct inode *inode,
|
||||||
key.type = sk->min_type;
|
key.type = sk->min_type;
|
||||||
key.offset = sk->min_offset;
|
key.offset = sk->min_offset;
|
||||||
|
|
||||||
max_key.objectid = sk->max_objectid;
|
|
||||||
max_key.type = sk->max_type;
|
|
||||||
max_key.offset = sk->max_offset;
|
|
||||||
|
|
||||||
path->keep_locks = 1;
|
path->keep_locks = 1;
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
ret = btrfs_search_forward(root, &key, &max_key, path,
|
ret = btrfs_search_forward(root, &key, path, sk->min_transid);
|
||||||
sk->min_transid);
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -2018,7 +2004,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
|
||||||
key.type = BTRFS_INODE_REF_KEY;
|
key.type = BTRFS_INODE_REF_KEY;
|
||||||
key.offset = (u64)-1;
|
key.offset = (u64)-1;
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -2047,7 +2033,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
|
||||||
}
|
}
|
||||||
|
|
||||||
*(ptr + len) = '/';
|
*(ptr + len) = '/';
|
||||||
read_extent_buffer(l, ptr,(unsigned long)(iref + 1), len);
|
read_extent_buffer(l, ptr, (unsigned long)(iref + 1), len);
|
||||||
|
|
||||||
if (key.offset == BTRFS_FIRST_FREE_OBJECTID)
|
if (key.offset == BTRFS_FIRST_FREE_OBJECTID)
|
||||||
break;
|
break;
|
||||||
|
@ -2058,7 +2044,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
|
||||||
dirid = key.objectid;
|
dirid = key.objectid;
|
||||||
}
|
}
|
||||||
memmove(name, ptr, total_len);
|
memmove(name, ptr, total_len);
|
||||||
name[total_len]='\0';
|
name[total_len] = '\0';
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
|
@ -2144,7 +2130,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
|
||||||
|
|
||||||
inode = dentry->d_inode;
|
inode = dentry->d_inode;
|
||||||
dest = BTRFS_I(inode)->root;
|
dest = BTRFS_I(inode)->root;
|
||||||
if (!capable(CAP_SYS_ADMIN)){
|
if (!capable(CAP_SYS_ADMIN)) {
|
||||||
/*
|
/*
|
||||||
* Regular user. Only allow this with a special mount
|
* Regular user. Only allow this with a special mount
|
||||||
* option, when the user has write+exec access to the
|
* option, when the user has write+exec access to the
|
||||||
|
@ -2727,15 +2713,10 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
|
||||||
size = sizeof(tmp) +
|
size = sizeof(tmp) +
|
||||||
tmp.dest_count * sizeof(struct btrfs_ioctl_same_extent_info);
|
tmp.dest_count * sizeof(struct btrfs_ioctl_same_extent_info);
|
||||||
|
|
||||||
same = kmalloc(size, GFP_NOFS);
|
same = memdup_user((struct btrfs_ioctl_same_args __user *)argp, size);
|
||||||
if (!same) {
|
|
||||||
ret = -EFAULT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy_from_user(same,
|
if (IS_ERR(same)) {
|
||||||
(struct btrfs_ioctl_same_args __user *)argp, size)) {
|
ret = PTR_ERR(same);
|
||||||
ret = -EFAULT;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3679,9 +3660,10 @@ static long btrfs_ioctl_dev_replace(struct btrfs_root *root, void __user *arg)
|
||||||
|
|
||||||
switch (p->cmd) {
|
switch (p->cmd) {
|
||||||
case BTRFS_IOCTL_DEV_REPLACE_CMD_START:
|
case BTRFS_IOCTL_DEV_REPLACE_CMD_START:
|
||||||
if (root->fs_info->sb->s_flags & MS_RDONLY)
|
if (root->fs_info->sb->s_flags & MS_RDONLY) {
|
||||||
return -EROFS;
|
ret = -EROFS;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
if (atomic_xchg(
|
if (atomic_xchg(
|
||||||
&root->fs_info->mutually_exclusive_operation_running,
|
&root->fs_info->mutually_exclusive_operation_running,
|
||||||
1)) {
|
1)) {
|
||||||
|
@ -3707,7 +3689,7 @@ static long btrfs_ioctl_dev_replace(struct btrfs_root *root, void __user *arg)
|
||||||
|
|
||||||
if (copy_to_user(arg, p, sizeof(*p)))
|
if (copy_to_user(arg, p, sizeof(*p)))
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
|
out:
|
||||||
kfree(p);
|
kfree(p);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -4557,9 +4539,15 @@ long btrfs_ioctl(struct file *file, unsigned int
|
||||||
return btrfs_ioctl_logical_to_ino(root, argp);
|
return btrfs_ioctl_logical_to_ino(root, argp);
|
||||||
case BTRFS_IOC_SPACE_INFO:
|
case BTRFS_IOC_SPACE_INFO:
|
||||||
return btrfs_ioctl_space_info(root, argp);
|
return btrfs_ioctl_space_info(root, argp);
|
||||||
case BTRFS_IOC_SYNC:
|
case BTRFS_IOC_SYNC: {
|
||||||
btrfs_sync_fs(file->f_dentry->d_sb, 1);
|
int ret;
|
||||||
return 0;
|
|
||||||
|
ret = btrfs_start_delalloc_roots(root->fs_info, 0);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
ret = btrfs_sync_fs(file->f_dentry->d_sb, 1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
case BTRFS_IOC_START_SYNC:
|
case BTRFS_IOC_START_SYNC:
|
||||||
return btrfs_ioctl_start_sync(root, argp);
|
return btrfs_ioctl_start_sync(root, argp);
|
||||||
case BTRFS_IOC_WAIT_SYNC:
|
case BTRFS_IOC_WAIT_SYNC:
|
||||||
|
|
|
@ -537,7 +537,9 @@ void btrfs_remove_ordered_extent(struct inode *inode,
|
||||||
*/
|
*/
|
||||||
if (RB_EMPTY_ROOT(&tree->tree) &&
|
if (RB_EMPTY_ROOT(&tree->tree) &&
|
||||||
!mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) {
|
!mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) {
|
||||||
|
spin_lock(&root->fs_info->ordered_root_lock);
|
||||||
list_del_init(&BTRFS_I(inode)->ordered_operations);
|
list_del_init(&BTRFS_I(inode)->ordered_operations);
|
||||||
|
spin_unlock(&root->fs_info->ordered_root_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!root->nr_ordered_extents) {
|
if (!root->nr_ordered_extents) {
|
||||||
|
@ -563,10 +565,11 @@ static void btrfs_run_ordered_extent_work(struct btrfs_work *work)
|
||||||
* wait for all the ordered extents in a root. This is done when balancing
|
* wait for all the ordered extents in a root. This is done when balancing
|
||||||
* space between drives.
|
* space between drives.
|
||||||
*/
|
*/
|
||||||
void btrfs_wait_ordered_extents(struct btrfs_root *root)
|
int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr)
|
||||||
{
|
{
|
||||||
struct list_head splice, works;
|
struct list_head splice, works;
|
||||||
struct btrfs_ordered_extent *ordered, *next;
|
struct btrfs_ordered_extent *ordered, *next;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&splice);
|
INIT_LIST_HEAD(&splice);
|
||||||
INIT_LIST_HEAD(&works);
|
INIT_LIST_HEAD(&works);
|
||||||
|
@ -574,7 +577,7 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root)
|
||||||
mutex_lock(&root->fs_info->ordered_operations_mutex);
|
mutex_lock(&root->fs_info->ordered_operations_mutex);
|
||||||
spin_lock(&root->ordered_extent_lock);
|
spin_lock(&root->ordered_extent_lock);
|
||||||
list_splice_init(&root->ordered_extents, &splice);
|
list_splice_init(&root->ordered_extents, &splice);
|
||||||
while (!list_empty(&splice)) {
|
while (!list_empty(&splice) && nr) {
|
||||||
ordered = list_first_entry(&splice, struct btrfs_ordered_extent,
|
ordered = list_first_entry(&splice, struct btrfs_ordered_extent,
|
||||||
root_extent_list);
|
root_extent_list);
|
||||||
list_move_tail(&ordered->root_extent_list,
|
list_move_tail(&ordered->root_extent_list,
|
||||||
|
@ -589,7 +592,11 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root)
|
||||||
|
|
||||||
cond_resched();
|
cond_resched();
|
||||||
spin_lock(&root->ordered_extent_lock);
|
spin_lock(&root->ordered_extent_lock);
|
||||||
|
if (nr != -1)
|
||||||
|
nr--;
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
list_splice_tail(&splice, &root->ordered_extents);
|
||||||
spin_unlock(&root->ordered_extent_lock);
|
spin_unlock(&root->ordered_extent_lock);
|
||||||
|
|
||||||
list_for_each_entry_safe(ordered, next, &works, work_list) {
|
list_for_each_entry_safe(ordered, next, &works, work_list) {
|
||||||
|
@ -599,18 +606,21 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root)
|
||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
mutex_unlock(&root->fs_info->ordered_operations_mutex);
|
mutex_unlock(&root->fs_info->ordered_operations_mutex);
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void btrfs_wait_all_ordered_extents(struct btrfs_fs_info *fs_info)
|
void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr)
|
||||||
{
|
{
|
||||||
struct btrfs_root *root;
|
struct btrfs_root *root;
|
||||||
struct list_head splice;
|
struct list_head splice;
|
||||||
|
int done;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&splice);
|
INIT_LIST_HEAD(&splice);
|
||||||
|
|
||||||
spin_lock(&fs_info->ordered_root_lock);
|
spin_lock(&fs_info->ordered_root_lock);
|
||||||
list_splice_init(&fs_info->ordered_roots, &splice);
|
list_splice_init(&fs_info->ordered_roots, &splice);
|
||||||
while (!list_empty(&splice)) {
|
while (!list_empty(&splice) && nr) {
|
||||||
root = list_first_entry(&splice, struct btrfs_root,
|
root = list_first_entry(&splice, struct btrfs_root,
|
||||||
ordered_root);
|
ordered_root);
|
||||||
root = btrfs_grab_fs_root(root);
|
root = btrfs_grab_fs_root(root);
|
||||||
|
@ -619,10 +629,14 @@ void btrfs_wait_all_ordered_extents(struct btrfs_fs_info *fs_info)
|
||||||
&fs_info->ordered_roots);
|
&fs_info->ordered_roots);
|
||||||
spin_unlock(&fs_info->ordered_root_lock);
|
spin_unlock(&fs_info->ordered_root_lock);
|
||||||
|
|
||||||
btrfs_wait_ordered_extents(root);
|
done = btrfs_wait_ordered_extents(root, nr);
|
||||||
btrfs_put_fs_root(root);
|
btrfs_put_fs_root(root);
|
||||||
|
|
||||||
spin_lock(&fs_info->ordered_root_lock);
|
spin_lock(&fs_info->ordered_root_lock);
|
||||||
|
if (nr != -1) {
|
||||||
|
nr -= done;
|
||||||
|
WARN_ON(nr < 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
spin_unlock(&fs_info->ordered_root_lock);
|
spin_unlock(&fs_info->ordered_root_lock);
|
||||||
}
|
}
|
||||||
|
@ -734,8 +748,9 @@ void btrfs_start_ordered_extent(struct inode *inode,
|
||||||
/*
|
/*
|
||||||
* Used to wait on ordered extents across a large range of bytes.
|
* Used to wait on ordered extents across a large range of bytes.
|
||||||
*/
|
*/
|
||||||
void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
|
int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
u64 end;
|
u64 end;
|
||||||
u64 orig_end;
|
u64 orig_end;
|
||||||
struct btrfs_ordered_extent *ordered;
|
struct btrfs_ordered_extent *ordered;
|
||||||
|
@ -751,8 +766,9 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
|
||||||
/* start IO across the range first to instantiate any delalloc
|
/* start IO across the range first to instantiate any delalloc
|
||||||
* extents
|
* extents
|
||||||
*/
|
*/
|
||||||
filemap_fdatawrite_range(inode->i_mapping, start, orig_end);
|
ret = filemap_fdatawrite_range(inode->i_mapping, start, orig_end);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
/*
|
/*
|
||||||
* So with compression we will find and lock a dirty page and clear the
|
* So with compression we will find and lock a dirty page and clear the
|
||||||
* first one as dirty, setup an async extent, and immediately return
|
* first one as dirty, setup an async extent, and immediately return
|
||||||
|
@ -768,10 +784,15 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
|
||||||
* right and you are wrong.
|
* right and you are wrong.
|
||||||
*/
|
*/
|
||||||
if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
|
if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
|
||||||
&BTRFS_I(inode)->runtime_flags))
|
&BTRFS_I(inode)->runtime_flags)) {
|
||||||
filemap_fdatawrite_range(inode->i_mapping, start, orig_end);
|
ret = filemap_fdatawrite_range(inode->i_mapping, start,
|
||||||
|
orig_end);
|
||||||
filemap_fdatawait_range(inode->i_mapping, start, orig_end);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = filemap_fdatawait_range(inode->i_mapping, start, orig_end);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
end = orig_end;
|
end = orig_end;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -788,11 +809,14 @@ void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len)
|
||||||
}
|
}
|
||||||
btrfs_start_ordered_extent(inode, ordered, 1);
|
btrfs_start_ordered_extent(inode, ordered, 1);
|
||||||
end = ordered->file_offset;
|
end = ordered->file_offset;
|
||||||
|
if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags))
|
||||||
|
ret = -EIO;
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
if (end == 0 || end == start)
|
if (ret || end == 0 || end == start)
|
||||||
break;
|
break;
|
||||||
end--;
|
end--;
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1076,7 +1100,7 @@ void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
|
||||||
* if this file hasn't been changed since the last transaction
|
* if this file hasn't been changed since the last transaction
|
||||||
* commit, we can safely return without doing anything
|
* commit, we can safely return without doing anything
|
||||||
*/
|
*/
|
||||||
if (last_mod < root->fs_info->last_trans_committed)
|
if (last_mod <= root->fs_info->last_trans_committed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
spin_lock(&root->fs_info->ordered_root_lock);
|
spin_lock(&root->fs_info->ordered_root_lock);
|
||||||
|
|
|
@ -180,7 +180,7 @@ struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode,
|
||||||
u64 file_offset);
|
u64 file_offset);
|
||||||
void btrfs_start_ordered_extent(struct inode *inode,
|
void btrfs_start_ordered_extent(struct inode *inode,
|
||||||
struct btrfs_ordered_extent *entry, int wait);
|
struct btrfs_ordered_extent *entry, int wait);
|
||||||
void btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
|
int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len);
|
||||||
struct btrfs_ordered_extent *
|
struct btrfs_ordered_extent *
|
||||||
btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset);
|
btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset);
|
||||||
struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode,
|
struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode,
|
||||||
|
@ -195,8 +195,8 @@ int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans,
|
||||||
void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
|
void btrfs_add_ordered_operation(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct inode *inode);
|
struct inode *inode);
|
||||||
void btrfs_wait_ordered_extents(struct btrfs_root *root);
|
int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr);
|
||||||
void btrfs_wait_all_ordered_extents(struct btrfs_fs_info *fs_info);
|
void btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr);
|
||||||
void btrfs_get_logged_extents(struct btrfs_root *log, struct inode *inode);
|
void btrfs_get_logged_extents(struct btrfs_root *log, struct inode *inode);
|
||||||
void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid);
|
void btrfs_wait_logged_extents(struct btrfs_root *log, u64 transid);
|
||||||
void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid);
|
void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid);
|
||||||
|
|
|
@ -193,7 +193,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
|
||||||
btrfs_info(root->fs_info, "leaf %llu total ptrs %d free space %d",
|
btrfs_info(root->fs_info, "leaf %llu total ptrs %d free space %d",
|
||||||
btrfs_header_bytenr(l), nr, btrfs_leaf_free_space(root, l));
|
btrfs_header_bytenr(l), nr, btrfs_leaf_free_space(root, l));
|
||||||
for (i = 0 ; i < nr ; i++) {
|
for (i = 0 ; i < nr ; i++) {
|
||||||
item = btrfs_item_nr(l, i);
|
item = btrfs_item_nr(i);
|
||||||
btrfs_item_key_to_cpu(l, &key, i);
|
btrfs_item_key_to_cpu(l, &key, i);
|
||||||
type = btrfs_key_type(&key);
|
type = btrfs_key_type(&key);
|
||||||
printk(KERN_INFO "\titem %d key (%llu %u %llu) itemoff %d "
|
printk(KERN_INFO "\titem %d key (%llu %u %llu) itemoff %d "
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
#include <linux/raid/xor.h>
|
#include <linux/raid/xor.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
#include <asm/div64.h>
|
#include <asm/div64.h>
|
||||||
#include "compat.h"
|
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "extent_map.h"
|
#include "extent_map.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
|
|
|
@ -1383,6 +1383,7 @@ int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,
|
||||||
{
|
{
|
||||||
struct btrfs_root *reloc_root;
|
struct btrfs_root *reloc_root;
|
||||||
struct reloc_control *rc = root->fs_info->reloc_ctl;
|
struct reloc_control *rc = root->fs_info->reloc_ctl;
|
||||||
|
struct btrfs_block_rsv *rsv;
|
||||||
int clear_rsv = 0;
|
int clear_rsv = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1396,13 +1397,14 @@ int btrfs_init_reloc_root(struct btrfs_trans_handle *trans,
|
||||||
root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID)
|
root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!trans->block_rsv) {
|
if (!trans->reloc_reserved) {
|
||||||
|
rsv = trans->block_rsv;
|
||||||
trans->block_rsv = rc->block_rsv;
|
trans->block_rsv = rc->block_rsv;
|
||||||
clear_rsv = 1;
|
clear_rsv = 1;
|
||||||
}
|
}
|
||||||
reloc_root = create_reloc_root(trans, root, root->root_key.objectid);
|
reloc_root = create_reloc_root(trans, root, root->root_key.objectid);
|
||||||
if (clear_rsv)
|
if (clear_rsv)
|
||||||
trans->block_rsv = NULL;
|
trans->block_rsv = rsv;
|
||||||
|
|
||||||
ret = __add_reloc_root(reloc_root);
|
ret = __add_reloc_root(reloc_root);
|
||||||
BUG_ON(ret < 0);
|
BUG_ON(ret < 0);
|
||||||
|
@ -1775,8 +1777,7 @@ int replace_path(struct btrfs_trans_handle *trans,
|
||||||
new_ptr_gen = 0;
|
new_ptr_gen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_bytenr > 0 && new_bytenr == old_bytenr) {
|
if (WARN_ON(new_bytenr > 0 && new_bytenr == old_bytenr)) {
|
||||||
WARN_ON(1);
|
|
||||||
ret = level;
|
ret = level;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2058,7 +2059,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
|
||||||
LIST_HEAD(inode_list);
|
LIST_HEAD(inode_list);
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct btrfs_key next_key;
|
struct btrfs_key next_key;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans = NULL;
|
||||||
struct btrfs_root *reloc_root;
|
struct btrfs_root *reloc_root;
|
||||||
struct btrfs_root_item *root_item;
|
struct btrfs_root_item *root_item;
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
|
@ -2107,18 +2108,19 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
|
||||||
memset(&next_key, 0, sizeof(next_key));
|
memset(&next_key, 0, sizeof(next_key));
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
trans = btrfs_start_transaction(root, 0);
|
|
||||||
BUG_ON(IS_ERR(trans));
|
|
||||||
trans->block_rsv = rc->block_rsv;
|
|
||||||
|
|
||||||
ret = btrfs_block_rsv_refill(root, rc->block_rsv, min_reserved,
|
ret = btrfs_block_rsv_refill(root, rc->block_rsv, min_reserved,
|
||||||
BTRFS_RESERVE_FLUSH_ALL);
|
BTRFS_RESERVE_FLUSH_ALL);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
BUG_ON(ret != -EAGAIN);
|
err = ret;
|
||||||
ret = btrfs_commit_transaction(trans, root);
|
goto out;
|
||||||
BUG_ON(ret);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
trans = btrfs_start_transaction(root, 0);
|
||||||
|
if (IS_ERR(trans)) {
|
||||||
|
err = PTR_ERR(trans);
|
||||||
|
trans = NULL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
trans->block_rsv = rc->block_rsv;
|
||||||
|
|
||||||
replaced = 0;
|
replaced = 0;
|
||||||
max_level = level;
|
max_level = level;
|
||||||
|
@ -2164,6 +2166,7 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
|
||||||
root_item->drop_level = level;
|
root_item->drop_level = level;
|
||||||
|
|
||||||
btrfs_end_transaction_throttle(trans, root);
|
btrfs_end_transaction_throttle(trans, root);
|
||||||
|
trans = NULL;
|
||||||
|
|
||||||
btrfs_btree_balance_dirty(root);
|
btrfs_btree_balance_dirty(root);
|
||||||
|
|
||||||
|
@ -2192,7 +2195,8 @@ static noinline_for_stack int merge_reloc_root(struct reloc_control *rc,
|
||||||
btrfs_update_reloc_root(trans, root);
|
btrfs_update_reloc_root(trans, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_end_transaction_throttle(trans, root);
|
if (trans)
|
||||||
|
btrfs_end_transaction_throttle(trans, root);
|
||||||
|
|
||||||
btrfs_btree_balance_dirty(root);
|
btrfs_btree_balance_dirty(root);
|
||||||
|
|
||||||
|
@ -3258,7 +3262,7 @@ static int add_tree_block(struct reloc_control *rc,
|
||||||
struct rb_node *rb_node;
|
struct rb_node *rb_node;
|
||||||
u32 item_size;
|
u32 item_size;
|
||||||
int level = -1;
|
int level = -1;
|
||||||
int generation;
|
u64 generation;
|
||||||
|
|
||||||
eb = path->nodes[0];
|
eb = path->nodes[0];
|
||||||
item_size = btrfs_item_size_nr(eb, path->slots[0]);
|
item_size = btrfs_item_size_nr(eb, path->slots[0]);
|
||||||
|
@ -3407,7 +3411,6 @@ static int delete_block_group_cache(struct btrfs_fs_info *fs_info,
|
||||||
struct inode *inode, u64 ino)
|
struct inode *inode, u64 ino)
|
||||||
{
|
{
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct btrfs_path *path;
|
|
||||||
struct btrfs_root *root = fs_info->tree_root;
|
struct btrfs_root *root = fs_info->tree_root;
|
||||||
struct btrfs_trans_handle *trans;
|
struct btrfs_trans_handle *trans;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -3432,22 +3435,14 @@ static int delete_block_group_cache(struct btrfs_fs_info *fs_info,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
path = btrfs_alloc_path();
|
|
||||||
if (!path) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
trans = btrfs_join_transaction(root);
|
trans = btrfs_join_transaction(root);
|
||||||
if (IS_ERR(trans)) {
|
if (IS_ERR(trans)) {
|
||||||
btrfs_free_path(path);
|
|
||||||
ret = PTR_ERR(trans);
|
ret = PTR_ERR(trans);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_truncate_free_space_cache(root, trans, path, inode);
|
ret = btrfs_truncate_free_space_cache(root, trans, inode);
|
||||||
|
|
||||||
btrfs_free_path(path);
|
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
btrfs_btree_balance_dirty(root);
|
btrfs_btree_balance_dirty(root);
|
||||||
out:
|
out:
|
||||||
|
@ -3549,10 +3544,8 @@ static int find_data_references(struct reloc_control *rc,
|
||||||
err = ret;
|
err = ret;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (ret > 0) {
|
if (WARN_ON(ret > 0))
|
||||||
WARN_ON(1);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
nritems = btrfs_header_nritems(leaf);
|
nritems = btrfs_header_nritems(leaf);
|
||||||
|
@ -3572,11 +3565,9 @@ static int find_data_references(struct reloc_control *rc,
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
|
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
|
||||||
if (key.objectid != ref_objectid ||
|
if (WARN_ON(key.objectid != ref_objectid ||
|
||||||
key.type != BTRFS_EXTENT_DATA_KEY) {
|
key.type != BTRFS_EXTENT_DATA_KEY))
|
||||||
WARN_ON(1);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
fi = btrfs_item_ptr(leaf, path->slots[0],
|
fi = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
struct btrfs_file_extent_item);
|
struct btrfs_file_extent_item);
|
||||||
|
@ -4001,16 +3992,6 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_block_rsv_check(rc->extent_root, rc->block_rsv, 5);
|
|
||||||
if (ret < 0) {
|
|
||||||
if (ret != -ENOSPC) {
|
|
||||||
err = ret;
|
|
||||||
WARN_ON(1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
rc->commit_transaction = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc->commit_transaction) {
|
if (rc->commit_transaction) {
|
||||||
rc->commit_transaction = 0;
|
rc->commit_transaction = 0;
|
||||||
ret = btrfs_commit_transaction(trans, rc->extent_root);
|
ret = btrfs_commit_transaction(trans, rc->extent_root);
|
||||||
|
@ -4241,12 +4222,12 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
|
||||||
printk(KERN_INFO "btrfs: relocating block group %llu flags %llu\n",
|
printk(KERN_INFO "btrfs: relocating block group %llu flags %llu\n",
|
||||||
rc->block_group->key.objectid, rc->block_group->flags);
|
rc->block_group->key.objectid, rc->block_group->flags);
|
||||||
|
|
||||||
ret = btrfs_start_all_delalloc_inodes(fs_info, 0);
|
ret = btrfs_start_delalloc_roots(fs_info, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
err = ret;
|
err = ret;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
btrfs_wait_all_ordered_extents(fs_info);
|
btrfs_wait_ordered_roots(fs_info, -1);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
mutex_lock(&fs_info->cleaner_mutex);
|
mutex_lock(&fs_info->cleaner_mutex);
|
||||||
|
@ -4264,7 +4245,12 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
|
||||||
rc->extents_found);
|
rc->extents_found);
|
||||||
|
|
||||||
if (rc->stage == MOVE_DATA_EXTENTS && rc->found_file_extent) {
|
if (rc->stage == MOVE_DATA_EXTENTS && rc->found_file_extent) {
|
||||||
btrfs_wait_ordered_range(rc->data_inode, 0, (u64)-1);
|
ret = btrfs_wait_ordered_range(rc->data_inode, 0,
|
||||||
|
(u64)-1);
|
||||||
|
if (ret) {
|
||||||
|
err = ret;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
invalidate_mapping_pages(rc->data_inode->i_mapping,
|
invalidate_mapping_pages(rc->data_inode->i_mapping,
|
||||||
0, -1);
|
0, -1);
|
||||||
rc->stage = UPDATE_DATA_PTRS;
|
rc->stage = UPDATE_DATA_PTRS;
|
||||||
|
@ -4481,6 +4467,7 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
int ret;
|
int ret;
|
||||||
u64 disk_bytenr;
|
u64 disk_bytenr;
|
||||||
|
u64 new_bytenr;
|
||||||
LIST_HEAD(list);
|
LIST_HEAD(list);
|
||||||
|
|
||||||
ordered = btrfs_lookup_ordered_extent(inode, file_pos);
|
ordered = btrfs_lookup_ordered_extent(inode, file_pos);
|
||||||
|
@ -4492,13 +4479,24 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
disk_bytenr = ordered->start;
|
|
||||||
while (!list_empty(&list)) {
|
while (!list_empty(&list)) {
|
||||||
sums = list_entry(list.next, struct btrfs_ordered_sum, list);
|
sums = list_entry(list.next, struct btrfs_ordered_sum, list);
|
||||||
list_del_init(&sums->list);
|
list_del_init(&sums->list);
|
||||||
|
|
||||||
sums->bytenr = disk_bytenr;
|
/*
|
||||||
disk_bytenr += sums->len;
|
* We need to offset the new_bytenr based on where the csum is.
|
||||||
|
* We need to do this because we will read in entire prealloc
|
||||||
|
* extents but we may have written to say the middle of the
|
||||||
|
* prealloc extent, so we need to make sure the csum goes with
|
||||||
|
* the right disk offset.
|
||||||
|
*
|
||||||
|
* We can do this because the data reloc inode refers strictly
|
||||||
|
* to the on disk bytes, so we don't have to worry about
|
||||||
|
* disk_len vs real len like with real inodes since it's all
|
||||||
|
* disk length.
|
||||||
|
*/
|
||||||
|
new_bytenr = ordered->start + (sums->bytenr - disk_bytenr);
|
||||||
|
sums->bytenr = new_bytenr;
|
||||||
|
|
||||||
btrfs_add_ordered_sum(inode, ordered, sums);
|
btrfs_add_ordered_sum(inode, ordered, sums);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2717,8 +2717,6 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
|
||||||
mutex_unlock(&fs_info->scrub_lock);
|
mutex_unlock(&fs_info->scrub_lock);
|
||||||
wake_up(&fs_info->scrub_pause_wait);
|
wake_up(&fs_info->scrub_pause_wait);
|
||||||
|
|
||||||
dev_replace->cursor_left = dev_replace->cursor_right;
|
|
||||||
dev_replace->item_needs_writeback = 1;
|
|
||||||
btrfs_put_block_group(cache);
|
btrfs_put_block_group(cache);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
|
@ -2732,6 +2730,9 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev_replace->cursor_left = dev_replace->cursor_right;
|
||||||
|
dev_replace->item_needs_writeback = 1;
|
||||||
|
|
||||||
key.offset = found_key.offset + length;
|
key.offset = found_key.offset + length;
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
}
|
}
|
||||||
|
@ -2783,7 +2784,6 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&fs_info->scrub_lock);
|
|
||||||
if (fs_info->scrub_workers_refcnt == 0) {
|
if (fs_info->scrub_workers_refcnt == 0) {
|
||||||
if (is_dev_replace)
|
if (is_dev_replace)
|
||||||
btrfs_init_workers(&fs_info->scrub_workers, "scrub", 1,
|
btrfs_init_workers(&fs_info->scrub_workers, "scrub", 1,
|
||||||
|
@ -2813,21 +2813,17 @@ static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info,
|
||||||
}
|
}
|
||||||
++fs_info->scrub_workers_refcnt;
|
++fs_info->scrub_workers_refcnt;
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&fs_info->scrub_lock);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info)
|
static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info)
|
||||||
{
|
{
|
||||||
mutex_lock(&fs_info->scrub_lock);
|
|
||||||
if (--fs_info->scrub_workers_refcnt == 0) {
|
if (--fs_info->scrub_workers_refcnt == 0) {
|
||||||
btrfs_stop_workers(&fs_info->scrub_workers);
|
btrfs_stop_workers(&fs_info->scrub_workers);
|
||||||
btrfs_stop_workers(&fs_info->scrub_wr_completion_workers);
|
btrfs_stop_workers(&fs_info->scrub_wr_completion_workers);
|
||||||
btrfs_stop_workers(&fs_info->scrub_nocow_workers);
|
btrfs_stop_workers(&fs_info->scrub_nocow_workers);
|
||||||
}
|
}
|
||||||
WARN_ON(fs_info->scrub_workers_refcnt < 0);
|
WARN_ON(fs_info->scrub_workers_refcnt < 0);
|
||||||
mutex_unlock(&fs_info->scrub_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
|
int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
|
||||||
|
@ -2888,23 +2884,18 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = scrub_workers_get(fs_info, is_dev_replace);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
mutex_lock(&fs_info->fs_devices->device_list_mutex);
|
mutex_lock(&fs_info->fs_devices->device_list_mutex);
|
||||||
dev = btrfs_find_device(fs_info, devid, NULL, NULL);
|
dev = btrfs_find_device(fs_info, devid, NULL, NULL);
|
||||||
if (!dev || (dev->missing && !is_dev_replace)) {
|
if (!dev || (dev->missing && !is_dev_replace)) {
|
||||||
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
||||||
scrub_workers_put(fs_info);
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
mutex_lock(&fs_info->scrub_lock);
|
|
||||||
|
|
||||||
|
mutex_lock(&fs_info->scrub_lock);
|
||||||
if (!dev->in_fs_metadata || dev->is_tgtdev_for_dev_replace) {
|
if (!dev->in_fs_metadata || dev->is_tgtdev_for_dev_replace) {
|
||||||
mutex_unlock(&fs_info->scrub_lock);
|
mutex_unlock(&fs_info->scrub_lock);
|
||||||
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
||||||
scrub_workers_put(fs_info);
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2915,10 +2906,17 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
|
||||||
btrfs_dev_replace_unlock(&fs_info->dev_replace);
|
btrfs_dev_replace_unlock(&fs_info->dev_replace);
|
||||||
mutex_unlock(&fs_info->scrub_lock);
|
mutex_unlock(&fs_info->scrub_lock);
|
||||||
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
||||||
scrub_workers_put(fs_info);
|
|
||||||
return -EINPROGRESS;
|
return -EINPROGRESS;
|
||||||
}
|
}
|
||||||
btrfs_dev_replace_unlock(&fs_info->dev_replace);
|
btrfs_dev_replace_unlock(&fs_info->dev_replace);
|
||||||
|
|
||||||
|
ret = scrub_workers_get(fs_info, is_dev_replace);
|
||||||
|
if (ret) {
|
||||||
|
mutex_unlock(&fs_info->scrub_lock);
|
||||||
|
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
sctx = scrub_setup_ctx(dev, is_dev_replace);
|
sctx = scrub_setup_ctx(dev, is_dev_replace);
|
||||||
if (IS_ERR(sctx)) {
|
if (IS_ERR(sctx)) {
|
||||||
mutex_unlock(&fs_info->scrub_lock);
|
mutex_unlock(&fs_info->scrub_lock);
|
||||||
|
@ -2931,13 +2929,15 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
|
||||||
|
|
||||||
atomic_inc(&fs_info->scrubs_running);
|
atomic_inc(&fs_info->scrubs_running);
|
||||||
mutex_unlock(&fs_info->scrub_lock);
|
mutex_unlock(&fs_info->scrub_lock);
|
||||||
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
|
||||||
|
|
||||||
if (!is_dev_replace) {
|
if (!is_dev_replace) {
|
||||||
down_read(&fs_info->scrub_super_lock);
|
/*
|
||||||
|
* by holding device list mutex, we can
|
||||||
|
* kick off writing super in log tree sync.
|
||||||
|
*/
|
||||||
ret = scrub_supers(sctx, dev);
|
ret = scrub_supers(sctx, dev);
|
||||||
up_read(&fs_info->scrub_super_lock);
|
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&fs_info->fs_devices->device_list_mutex);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = scrub_enumerate_chunks(sctx, dev, start, end,
|
ret = scrub_enumerate_chunks(sctx, dev, start, end,
|
||||||
|
@ -2954,10 +2954,10 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
|
||||||
|
|
||||||
mutex_lock(&fs_info->scrub_lock);
|
mutex_lock(&fs_info->scrub_lock);
|
||||||
dev->scrub_device = NULL;
|
dev->scrub_device = NULL;
|
||||||
|
scrub_workers_put(fs_info);
|
||||||
mutex_unlock(&fs_info->scrub_lock);
|
mutex_unlock(&fs_info->scrub_lock);
|
||||||
|
|
||||||
scrub_free_ctx(sctx);
|
scrub_free_ctx(sctx);
|
||||||
scrub_workers_put(fs_info);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2987,16 +2987,6 @@ void btrfs_scrub_continue(struct btrfs_root *root)
|
||||||
wake_up(&fs_info->scrub_pause_wait);
|
wake_up(&fs_info->scrub_pause_wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
void btrfs_scrub_pause_super(struct btrfs_root *root)
|
|
||||||
{
|
|
||||||
down_write(&root->fs_info->scrub_super_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
void btrfs_scrub_continue_super(struct btrfs_root *root)
|
|
||||||
{
|
|
||||||
up_write(&root->fs_info->scrub_super_lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
int btrfs_scrub_cancel(struct btrfs_fs_info *fs_info)
|
int btrfs_scrub_cancel(struct btrfs_fs_info *fs_info)
|
||||||
{
|
{
|
||||||
mutex_lock(&fs_info->scrub_lock);
|
mutex_lock(&fs_info->scrub_lock);
|
||||||
|
|
193
fs/btrfs/send.c
193
fs/btrfs/send.c
|
@ -121,7 +121,6 @@ struct send_ctx {
|
||||||
struct list_head name_cache_list;
|
struct list_head name_cache_list;
|
||||||
int name_cache_size;
|
int name_cache_size;
|
||||||
|
|
||||||
struct file *cur_inode_filp;
|
|
||||||
char *read_buf;
|
char *read_buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -565,10 +564,8 @@ static int begin_cmd(struct send_ctx *sctx, int cmd)
|
||||||
{
|
{
|
||||||
struct btrfs_cmd_header *hdr;
|
struct btrfs_cmd_header *hdr;
|
||||||
|
|
||||||
if (!sctx->send_buf) {
|
if (WARN_ON(!sctx->send_buf))
|
||||||
WARN_ON(1);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
BUG_ON(sctx->send_size);
|
BUG_ON(sctx->send_size);
|
||||||
|
|
||||||
|
@ -791,7 +788,7 @@ static int iterate_inode_ref(struct btrfs_root *root, struct btrfs_path *path,
|
||||||
if (found_key->type == BTRFS_INODE_REF_KEY) {
|
if (found_key->type == BTRFS_INODE_REF_KEY) {
|
||||||
ptr = (unsigned long)btrfs_item_ptr(eb, slot,
|
ptr = (unsigned long)btrfs_item_ptr(eb, slot,
|
||||||
struct btrfs_inode_ref);
|
struct btrfs_inode_ref);
|
||||||
item = btrfs_item_nr(eb, slot);
|
item = btrfs_item_nr(slot);
|
||||||
total = btrfs_item_size(eb, item);
|
total = btrfs_item_size(eb, item);
|
||||||
elem_size = sizeof(*iref);
|
elem_size = sizeof(*iref);
|
||||||
} else {
|
} else {
|
||||||
|
@ -905,7 +902,7 @@ static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path,
|
||||||
|
|
||||||
eb = path->nodes[0];
|
eb = path->nodes[0];
|
||||||
slot = path->slots[0];
|
slot = path->slots[0];
|
||||||
item = btrfs_item_nr(eb, slot);
|
item = btrfs_item_nr(slot);
|
||||||
di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
|
di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
|
||||||
cur = 0;
|
cur = 0;
|
||||||
len = 0;
|
len = 0;
|
||||||
|
@ -2119,77 +2116,6 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Called for regular files when sending extents data. Opens a struct file
|
|
||||||
* to read from the file.
|
|
||||||
*/
|
|
||||||
static int open_cur_inode_file(struct send_ctx *sctx)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
struct btrfs_key key;
|
|
||||||
struct path path;
|
|
||||||
struct inode *inode;
|
|
||||||
struct dentry *dentry;
|
|
||||||
struct file *filp;
|
|
||||||
int new = 0;
|
|
||||||
|
|
||||||
if (sctx->cur_inode_filp)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
key.objectid = sctx->cur_ino;
|
|
||||||
key.type = BTRFS_INODE_ITEM_KEY;
|
|
||||||
key.offset = 0;
|
|
||||||
|
|
||||||
inode = btrfs_iget(sctx->send_root->fs_info->sb, &key, sctx->send_root,
|
|
||||||
&new);
|
|
||||||
if (IS_ERR(inode)) {
|
|
||||||
ret = PTR_ERR(inode);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
dentry = d_obtain_alias(inode);
|
|
||||||
inode = NULL;
|
|
||||||
if (IS_ERR(dentry)) {
|
|
||||||
ret = PTR_ERR(dentry);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
path.mnt = sctx->mnt;
|
|
||||||
path.dentry = dentry;
|
|
||||||
filp = dentry_open(&path, O_RDONLY | O_LARGEFILE, current_cred());
|
|
||||||
dput(dentry);
|
|
||||||
dentry = NULL;
|
|
||||||
if (IS_ERR(filp)) {
|
|
||||||
ret = PTR_ERR(filp);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
sctx->cur_inode_filp = filp;
|
|
||||||
|
|
||||||
out:
|
|
||||||
/*
|
|
||||||
* no xxxput required here as every vfs op
|
|
||||||
* does it by itself on failure
|
|
||||||
*/
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Closes the struct file that was created in open_cur_inode_file
|
|
||||||
*/
|
|
||||||
static int close_cur_inode_file(struct send_ctx *sctx)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (!sctx->cur_inode_filp)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = filp_close(sctx->cur_inode_filp, NULL);
|
|
||||||
sctx->cur_inode_filp = NULL;
|
|
||||||
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sends a BTRFS_SEND_C_SUBVOL command/item to userspace
|
* Sends a BTRFS_SEND_C_SUBVOL command/item to userspace
|
||||||
*/
|
*/
|
||||||
|
@ -3622,6 +3548,72 @@ static int process_all_new_xattrs(struct send_ctx *sctx)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t fill_read_buf(struct send_ctx *sctx, u64 offset, u32 len)
|
||||||
|
{
|
||||||
|
struct btrfs_root *root = sctx->send_root;
|
||||||
|
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||||
|
struct inode *inode;
|
||||||
|
struct page *page;
|
||||||
|
char *addr;
|
||||||
|
struct btrfs_key key;
|
||||||
|
pgoff_t index = offset >> PAGE_CACHE_SHIFT;
|
||||||
|
pgoff_t last_index;
|
||||||
|
unsigned pg_offset = offset & ~PAGE_CACHE_MASK;
|
||||||
|
ssize_t ret = 0;
|
||||||
|
|
||||||
|
key.objectid = sctx->cur_ino;
|
||||||
|
key.type = BTRFS_INODE_ITEM_KEY;
|
||||||
|
key.offset = 0;
|
||||||
|
|
||||||
|
inode = btrfs_iget(fs_info->sb, &key, root, NULL);
|
||||||
|
if (IS_ERR(inode))
|
||||||
|
return PTR_ERR(inode);
|
||||||
|
|
||||||
|
if (offset + len > i_size_read(inode)) {
|
||||||
|
if (offset > i_size_read(inode))
|
||||||
|
len = 0;
|
||||||
|
else
|
||||||
|
len = offset - i_size_read(inode);
|
||||||
|
}
|
||||||
|
if (len == 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
last_index = (offset + len - 1) >> PAGE_CACHE_SHIFT;
|
||||||
|
while (index <= last_index) {
|
||||||
|
unsigned cur_len = min_t(unsigned, len,
|
||||||
|
PAGE_CACHE_SIZE - pg_offset);
|
||||||
|
page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
|
||||||
|
if (!page) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PageUptodate(page)) {
|
||||||
|
btrfs_readpage(NULL, page);
|
||||||
|
lock_page(page);
|
||||||
|
if (!PageUptodate(page)) {
|
||||||
|
unlock_page(page);
|
||||||
|
page_cache_release(page);
|
||||||
|
ret = -EIO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addr = kmap(page);
|
||||||
|
memcpy(sctx->read_buf + ret, addr + pg_offset, cur_len);
|
||||||
|
kunmap(page);
|
||||||
|
unlock_page(page);
|
||||||
|
page_cache_release(page);
|
||||||
|
index++;
|
||||||
|
pg_offset = 0;
|
||||||
|
len -= cur_len;
|
||||||
|
ret += cur_len;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
iput(inode);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read some bytes from the current inode/file and send a write command to
|
* Read some bytes from the current inode/file and send a write command to
|
||||||
* user space.
|
* user space.
|
||||||
|
@ -3630,35 +3622,20 @@ static int send_write(struct send_ctx *sctx, u64 offset, u32 len)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct fs_path *p;
|
struct fs_path *p;
|
||||||
loff_t pos = offset;
|
ssize_t num_read = 0;
|
||||||
int num_read = 0;
|
|
||||||
mm_segment_t old_fs;
|
|
||||||
|
|
||||||
p = fs_path_alloc();
|
p = fs_path_alloc();
|
||||||
if (!p)
|
if (!p)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
/*
|
|
||||||
* vfs normally only accepts user space buffers for security reasons.
|
|
||||||
* we only read from the file and also only provide the read_buf buffer
|
|
||||||
* to vfs. As this buffer does not come from a user space call, it's
|
|
||||||
* ok to temporary allow kernel space buffers.
|
|
||||||
*/
|
|
||||||
old_fs = get_fs();
|
|
||||||
set_fs(KERNEL_DS);
|
|
||||||
|
|
||||||
verbose_printk("btrfs: send_write offset=%llu, len=%d\n", offset, len);
|
verbose_printk("btrfs: send_write offset=%llu, len=%d\n", offset, len);
|
||||||
|
|
||||||
ret = open_cur_inode_file(sctx);
|
num_read = fill_read_buf(sctx, offset, len);
|
||||||
if (ret < 0)
|
if (num_read <= 0) {
|
||||||
goto out;
|
if (num_read < 0)
|
||||||
|
ret = num_read;
|
||||||
ret = vfs_read(sctx->cur_inode_filp, sctx->read_buf, len, &pos);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out;
|
|
||||||
num_read = ret;
|
|
||||||
if (!num_read)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE);
|
ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -3677,7 +3654,6 @@ verbose_printk("btrfs: send_write offset=%llu, len=%d\n", offset, len);
|
||||||
tlv_put_failure:
|
tlv_put_failure:
|
||||||
out:
|
out:
|
||||||
fs_path_free(p);
|
fs_path_free(p);
|
||||||
set_fs(old_fs);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
return num_read;
|
return num_read;
|
||||||
|
@ -3926,16 +3902,16 @@ static int is_extent_unchanged(struct send_ctx *sctx,
|
||||||
while (key.offset < ekey->offset + left_len) {
|
while (key.offset < ekey->offset + left_len) {
|
||||||
ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
|
ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
|
||||||
right_type = btrfs_file_extent_type(eb, ei);
|
right_type = btrfs_file_extent_type(eb, ei);
|
||||||
right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
|
|
||||||
right_len = btrfs_file_extent_num_bytes(eb, ei);
|
|
||||||
right_offset = btrfs_file_extent_offset(eb, ei);
|
|
||||||
right_gen = btrfs_file_extent_generation(eb, ei);
|
|
||||||
|
|
||||||
if (right_type != BTRFS_FILE_EXTENT_REG) {
|
if (right_type != BTRFS_FILE_EXTENT_REG) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
|
||||||
|
right_len = btrfs_file_extent_num_bytes(eb, ei);
|
||||||
|
right_offset = btrfs_file_extent_offset(eb, ei);
|
||||||
|
right_gen = btrfs_file_extent_generation(eb, ei);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Are we at extent 8? If yes, we know the extent is changed.
|
* Are we at extent 8? If yes, we know the extent is changed.
|
||||||
* This may only happen on the first iteration.
|
* This may only happen on the first iteration.
|
||||||
|
@ -4222,10 +4198,6 @@ static int changed_inode(struct send_ctx *sctx,
|
||||||
u64 left_gen = 0;
|
u64 left_gen = 0;
|
||||||
u64 right_gen = 0;
|
u64 right_gen = 0;
|
||||||
|
|
||||||
ret = close_cur_inode_file(sctx);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
sctx->cur_ino = key->objectid;
|
sctx->cur_ino = key->objectid;
|
||||||
sctx->cur_inode_new_gen = 0;
|
sctx->cur_inode_new_gen = 0;
|
||||||
|
|
||||||
|
@ -4686,11 +4658,6 @@ static int send_subvol(struct send_ctx *sctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (!ret)
|
|
||||||
ret = close_cur_inode_file(sctx);
|
|
||||||
else
|
|
||||||
close_cur_inode_file(sctx);
|
|
||||||
|
|
||||||
free_recorded_refs(sctx);
|
free_recorded_refs(sctx);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
#include <linux/cleancache.h>
|
#include <linux/cleancache.h>
|
||||||
#include <linux/ratelimit.h>
|
#include <linux/ratelimit.h>
|
||||||
#include <linux/btrfs.h>
|
#include <linux/btrfs.h>
|
||||||
#include "compat.h"
|
|
||||||
#include "delayed-inode.h"
|
#include "delayed-inode.h"
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
|
@ -921,7 +920,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_wait_all_ordered_extents(fs_info);
|
btrfs_wait_ordered_roots(fs_info, -1);
|
||||||
|
|
||||||
trans = btrfs_attach_transaction_barrier(root);
|
trans = btrfs_attach_transaction_barrier(root);
|
||||||
if (IS_ERR(trans)) {
|
if (IS_ERR(trans)) {
|
||||||
|
@ -1330,6 +1329,12 @@ 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* wait for the uuid_scan task to finish */
|
||||||
|
down(&fs_info->uuid_tree_rescan_sem);
|
||||||
|
/* avoid complains from lockdep et al. */
|
||||||
|
up(&fs_info->uuid_tree_rescan_sem);
|
||||||
|
|
||||||
sb->s_flags |= MS_RDONLY;
|
sb->s_flags |= MS_RDONLY;
|
||||||
|
|
||||||
btrfs_dev_replace_suspend_for_unmount(fs_info);
|
btrfs_dev_replace_suspend_for_unmount(fs_info);
|
||||||
|
@ -1465,7 +1470,7 @@ static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes)
|
||||||
nr_devices = fs_info->fs_devices->open_devices;
|
nr_devices = fs_info->fs_devices->open_devices;
|
||||||
BUG_ON(!nr_devices);
|
BUG_ON(!nr_devices);
|
||||||
|
|
||||||
devices_info = kmalloc(sizeof(*devices_info) * nr_devices,
|
devices_info = kmalloc_array(nr_devices, sizeof(*devices_info),
|
||||||
GFP_NOFS);
|
GFP_NOFS);
|
||||||
if (!devices_info)
|
if (!devices_info)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -1789,7 +1794,25 @@ static void btrfs_print_info(void)
|
||||||
|
|
||||||
static int btrfs_run_sanity_tests(void)
|
static int btrfs_run_sanity_tests(void)
|
||||||
{
|
{
|
||||||
return btrfs_test_free_space_cache();
|
int ret;
|
||||||
|
|
||||||
|
ret = btrfs_init_test_fs();
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = btrfs_test_free_space_cache();
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
ret = btrfs_test_extent_buffer_operations();
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
ret = btrfs_test_extent_io();
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
ret = btrfs_test_inodes();
|
||||||
|
out:
|
||||||
|
btrfs_destroy_test_fs();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init init_btrfs_fs(void)
|
static int __init init_btrfs_fs(void)
|
||||||
|
|
74
fs/btrfs/tests/btrfs-tests.c
Normal file
74
fs/btrfs/tests/btrfs-tests.c
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Fusion IO. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/mount.h>
|
||||||
|
#include <linux/magic.h>
|
||||||
|
#include "btrfs-tests.h"
|
||||||
|
#include "../ctree.h"
|
||||||
|
|
||||||
|
static struct vfsmount *test_mnt = NULL;
|
||||||
|
|
||||||
|
static const struct super_operations btrfs_test_super_ops = {
|
||||||
|
.alloc_inode = btrfs_alloc_inode,
|
||||||
|
.destroy_inode = btrfs_test_destroy_inode,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct dentry *btrfs_test_mount(struct file_system_type *fs_type,
|
||||||
|
int flags, const char *dev_name,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
return mount_pseudo(fs_type, "btrfs_test:", &btrfs_test_super_ops,
|
||||||
|
NULL, BTRFS_TEST_MAGIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct file_system_type test_type = {
|
||||||
|
.name = "btrfs_test_fs",
|
||||||
|
.mount = btrfs_test_mount,
|
||||||
|
.kill_sb = kill_anon_super,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct inode *btrfs_new_test_inode(void)
|
||||||
|
{
|
||||||
|
return new_inode(test_mnt->mnt_sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
int btrfs_init_test_fs(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = register_filesystem(&test_type);
|
||||||
|
if (ret) {
|
||||||
|
printk(KERN_ERR "btrfs: cannot register test file system\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_mnt = kern_mount(&test_type);
|
||||||
|
if (IS_ERR(test_mnt)) {
|
||||||
|
printk(KERN_ERR "btrfs: cannot mount test file system\n");
|
||||||
|
unregister_filesystem(&test_type);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void btrfs_destroy_test_fs(void)
|
||||||
|
{
|
||||||
|
kern_unmount(test_mnt);
|
||||||
|
unregister_filesystem(&test_type);
|
||||||
|
}
|
|
@ -24,11 +24,36 @@
|
||||||
#define test_msg(fmt, ...) pr_info("btrfs: selftest: " fmt, ##__VA_ARGS__)
|
#define test_msg(fmt, ...) pr_info("btrfs: selftest: " fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
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_io(void);
|
||||||
|
int btrfs_test_inodes(void);
|
||||||
|
int btrfs_init_test_fs(void);
|
||||||
|
void btrfs_destroy_test_fs(void);
|
||||||
|
struct inode *btrfs_new_test_inode(void);
|
||||||
#else
|
#else
|
||||||
static inline int btrfs_test_free_space_cache(void)
|
static inline int btrfs_test_free_space_cache(void)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
static inline int btrfs_test_extent_buffer_operations(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int btrfs_init_test_fs(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline void btrfs_destroy_test_fs(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static inline int btrfs_test_extent_io(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int btrfs_test_inodes(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
229
fs/btrfs/tests/extent-buffer-tests.c
Normal file
229
fs/btrfs/tests/extent-buffer-tests.c
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Fusion IO. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include "btrfs-tests.h"
|
||||||
|
#include "../ctree.h"
|
||||||
|
#include "../extent_io.h"
|
||||||
|
#include "../disk-io.h"
|
||||||
|
|
||||||
|
static int test_btrfs_split_item(void)
|
||||||
|
{
|
||||||
|
struct btrfs_path *path;
|
||||||
|
struct btrfs_root *root;
|
||||||
|
struct extent_buffer *eb;
|
||||||
|
struct btrfs_item *item;
|
||||||
|
char *value = "mary had a little lamb";
|
||||||
|
char *split1 = "mary had a little";
|
||||||
|
char *split2 = " lamb";
|
||||||
|
char *split3 = "mary";
|
||||||
|
char *split4 = " had a little";
|
||||||
|
char buf[32];
|
||||||
|
struct btrfs_key key;
|
||||||
|
u32 value_len = strlen(value);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
test_msg("Running btrfs_split_item tests\n");
|
||||||
|
|
||||||
|
root = btrfs_alloc_dummy_root();
|
||||||
|
if (IS_ERR(root)) {
|
||||||
|
test_msg("Could not allocate root\n");
|
||||||
|
return PTR_ERR(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
path = btrfs_alloc_path();
|
||||||
|
if (!path) {
|
||||||
|
test_msg("Could not allocate path\n");
|
||||||
|
kfree(root);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
path->nodes[0] = eb = alloc_dummy_extent_buffer(0, 4096);
|
||||||
|
if (!eb) {
|
||||||
|
test_msg("Could not allocate dummy buffer\n");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
path->slots[0] = 0;
|
||||||
|
|
||||||
|
key.objectid = 0;
|
||||||
|
key.type = BTRFS_EXTENT_CSUM_KEY;
|
||||||
|
key.offset = 0;
|
||||||
|
|
||||||
|
setup_items_for_insert(root, path, &key, &value_len, value_len,
|
||||||
|
value_len + sizeof(struct btrfs_item), 1);
|
||||||
|
item = btrfs_item_nr(0);
|
||||||
|
write_extent_buffer(eb, value, btrfs_item_ptr_offset(eb, 0),
|
||||||
|
value_len);
|
||||||
|
|
||||||
|
key.offset = 3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Passing NULL trans here should be safe because we have plenty of
|
||||||
|
* space in this leaf to split the item without having to split the
|
||||||
|
* leaf.
|
||||||
|
*/
|
||||||
|
ret = btrfs_split_item(NULL, root, path, &key, 17);
|
||||||
|
if (ret) {
|
||||||
|
test_msg("Split item failed %d\n", ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the first slot, it should have the original key and contain only
|
||||||
|
* 'mary had a little'
|
||||||
|
*/
|
||||||
|
btrfs_item_key_to_cpu(eb, &key, 0);
|
||||||
|
if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
|
||||||
|
key.offset != 0) {
|
||||||
|
test_msg("Invalid key at slot 0\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
item = btrfs_item_nr(0);
|
||||||
|
if (btrfs_item_size(eb, item) != strlen(split1)) {
|
||||||
|
test_msg("Invalid len in the first split\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 0),
|
||||||
|
strlen(split1));
|
||||||
|
if (memcmp(buf, split1, strlen(split1))) {
|
||||||
|
test_msg("Data in the buffer doesn't match what it should "
|
||||||
|
"in the first split have='%.*s' want '%s'\n",
|
||||||
|
(int)strlen(split1), buf, split1);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
btrfs_item_key_to_cpu(eb, &key, 1);
|
||||||
|
if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
|
||||||
|
key.offset != 3) {
|
||||||
|
test_msg("Invalid key at slot 1\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
item = btrfs_item_nr(1);
|
||||||
|
if (btrfs_item_size(eb, item) != strlen(split2)) {
|
||||||
|
test_msg("Invalid len in the second split\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 1),
|
||||||
|
strlen(split2));
|
||||||
|
if (memcmp(buf, split2, strlen(split2))) {
|
||||||
|
test_msg("Data in the buffer doesn't match what it should "
|
||||||
|
"in the second split\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
key.offset = 1;
|
||||||
|
/* Do it again so we test memmoving the other items in the leaf */
|
||||||
|
ret = btrfs_split_item(NULL, root, path, &key, 4);
|
||||||
|
if (ret) {
|
||||||
|
test_msg("Second split item failed %d\n", ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
btrfs_item_key_to_cpu(eb, &key, 0);
|
||||||
|
if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
|
||||||
|
key.offset != 0) {
|
||||||
|
test_msg("Invalid key at slot 0\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
item = btrfs_item_nr(0);
|
||||||
|
if (btrfs_item_size(eb, item) != strlen(split3)) {
|
||||||
|
test_msg("Invalid len in the first split\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 0),
|
||||||
|
strlen(split3));
|
||||||
|
if (memcmp(buf, split3, strlen(split3))) {
|
||||||
|
test_msg("Data in the buffer doesn't match what it should "
|
||||||
|
"in the third split");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
btrfs_item_key_to_cpu(eb, &key, 1);
|
||||||
|
if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
|
||||||
|
key.offset != 1) {
|
||||||
|
test_msg("Invalid key at slot 1\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
item = btrfs_item_nr(1);
|
||||||
|
if (btrfs_item_size(eb, item) != strlen(split4)) {
|
||||||
|
test_msg("Invalid len in the second split\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 1),
|
||||||
|
strlen(split4));
|
||||||
|
if (memcmp(buf, split4, strlen(split4))) {
|
||||||
|
test_msg("Data in the buffer doesn't match what it should "
|
||||||
|
"in the fourth split\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
btrfs_item_key_to_cpu(eb, &key, 2);
|
||||||
|
if (key.objectid != 0 || key.type != BTRFS_EXTENT_CSUM_KEY ||
|
||||||
|
key.offset != 3) {
|
||||||
|
test_msg("Invalid key at slot 2\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
item = btrfs_item_nr(2);
|
||||||
|
if (btrfs_item_size(eb, item) != strlen(split2)) {
|
||||||
|
test_msg("Invalid len in the second split\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
read_extent_buffer(eb, buf, btrfs_item_ptr_offset(eb, 2),
|
||||||
|
strlen(split2));
|
||||||
|
if (memcmp(buf, split2, strlen(split2))) {
|
||||||
|
test_msg("Data in the buffer doesn't match what it should "
|
||||||
|
"in the last chunk\n");
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
btrfs_free_path(path);
|
||||||
|
kfree(root);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int btrfs_test_extent_buffer_operations(void)
|
||||||
|
{
|
||||||
|
test_msg("Running extent buffer operation tests");
|
||||||
|
return test_btrfs_split_item();
|
||||||
|
}
|
276
fs/btrfs/tests/extent-io-tests.c
Normal file
276
fs/btrfs/tests/extent-io-tests.c
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Fusion IO. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/pagemap.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include "btrfs-tests.h"
|
||||||
|
#include "../extent_io.h"
|
||||||
|
|
||||||
|
#define PROCESS_UNLOCK (1 << 0)
|
||||||
|
#define PROCESS_RELEASE (1 << 1)
|
||||||
|
#define PROCESS_TEST_LOCKED (1 << 2)
|
||||||
|
|
||||||
|
static noinline int process_page_range(struct inode *inode, u64 start, u64 end,
|
||||||
|
unsigned long flags)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct page *pages[16];
|
||||||
|
unsigned long index = start >> PAGE_CACHE_SHIFT;
|
||||||
|
unsigned long end_index = end >> PAGE_CACHE_SHIFT;
|
||||||
|
unsigned long nr_pages = end_index - index + 1;
|
||||||
|
int i;
|
||||||
|
int count = 0;
|
||||||
|
int loops = 0;
|
||||||
|
|
||||||
|
while (nr_pages > 0) {
|
||||||
|
ret = find_get_pages_contig(inode->i_mapping, index,
|
||||||
|
min_t(unsigned long, nr_pages,
|
||||||
|
ARRAY_SIZE(pages)), pages);
|
||||||
|
for (i = 0; i < ret; i++) {
|
||||||
|
if (flags & PROCESS_TEST_LOCKED &&
|
||||||
|
!PageLocked(pages[i]))
|
||||||
|
count++;
|
||||||
|
if (flags & PROCESS_UNLOCK && PageLocked(pages[i]))
|
||||||
|
unlock_page(pages[i]);
|
||||||
|
page_cache_release(pages[i]);
|
||||||
|
if (flags & PROCESS_RELEASE)
|
||||||
|
page_cache_release(pages[i]);
|
||||||
|
}
|
||||||
|
nr_pages -= ret;
|
||||||
|
index += ret;
|
||||||
|
cond_resched();
|
||||||
|
loops++;
|
||||||
|
if (loops > 100000) {
|
||||||
|
printk(KERN_ERR "stuck in a loop, start %Lu, end %Lu, nr_pages %lu, ret %d\n", start, end, nr_pages, ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_find_delalloc(void)
|
||||||
|
{
|
||||||
|
struct inode *inode;
|
||||||
|
struct extent_io_tree tmp;
|
||||||
|
struct page *page;
|
||||||
|
struct page *locked_page = NULL;
|
||||||
|
unsigned long index = 0;
|
||||||
|
u64 total_dirty = 256 * 1024 * 1024;
|
||||||
|
u64 max_bytes = 128 * 1024 * 1024;
|
||||||
|
u64 start, end, test_start;
|
||||||
|
u64 found;
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
inode = btrfs_new_test_inode();
|
||||||
|
if (!inode) {
|
||||||
|
test_msg("Failed to allocate test inode\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
extent_io_tree_init(&tmp, &inode->i_data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First go through and create and mark all of our pages dirty, we pin
|
||||||
|
* everything to make sure our pages don't get evicted and screw up our
|
||||||
|
* test.
|
||||||
|
*/
|
||||||
|
for (index = 0; index < (total_dirty >> PAGE_CACHE_SHIFT); index++) {
|
||||||
|
page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
|
||||||
|
if (!page) {
|
||||||
|
test_msg("Failed to allocate test page\n");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
SetPageDirty(page);
|
||||||
|
if (index) {
|
||||||
|
unlock_page(page);
|
||||||
|
} else {
|
||||||
|
page_cache_get(page);
|
||||||
|
locked_page = page;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test this scenario
|
||||||
|
* |--- delalloc ---|
|
||||||
|
* |--- search ---|
|
||||||
|
*/
|
||||||
|
set_extent_delalloc(&tmp, 0, 4095, NULL, GFP_NOFS);
|
||||||
|
start = 0;
|
||||||
|
end = 0;
|
||||||
|
found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
|
||||||
|
&end, max_bytes);
|
||||||
|
if (!found) {
|
||||||
|
test_msg("Should have found at least one delalloc\n");
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
if (start != 0 || end != 4095) {
|
||||||
|
test_msg("Expected start 0 end 4095, got start %Lu end %Lu\n",
|
||||||
|
start, end);
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
unlock_extent(&tmp, start, end);
|
||||||
|
unlock_page(locked_page);
|
||||||
|
page_cache_release(locked_page);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test this scenario
|
||||||
|
*
|
||||||
|
* |--- delalloc ---|
|
||||||
|
* |--- search ---|
|
||||||
|
*/
|
||||||
|
test_start = 64 * 1024 * 1024;
|
||||||
|
locked_page = find_lock_page(inode->i_mapping,
|
||||||
|
test_start >> PAGE_CACHE_SHIFT);
|
||||||
|
if (!locked_page) {
|
||||||
|
test_msg("Couldn't find the locked page\n");
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
set_extent_delalloc(&tmp, 4096, max_bytes - 1, NULL, GFP_NOFS);
|
||||||
|
start = test_start;
|
||||||
|
end = 0;
|
||||||
|
found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
|
||||||
|
&end, max_bytes);
|
||||||
|
if (!found) {
|
||||||
|
test_msg("Couldn't find delalloc in our range\n");
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
if (start != test_start || end != max_bytes - 1) {
|
||||||
|
test_msg("Expected start %Lu end %Lu, got start %Lu, end "
|
||||||
|
"%Lu\n", test_start, max_bytes - 1, start, end);
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
if (process_page_range(inode, start, end,
|
||||||
|
PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) {
|
||||||
|
test_msg("There were unlocked pages in the range\n");
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
unlock_extent(&tmp, start, end);
|
||||||
|
/* locked_page was unlocked above */
|
||||||
|
page_cache_release(locked_page);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test this scenario
|
||||||
|
* |--- delalloc ---|
|
||||||
|
* |--- search ---|
|
||||||
|
*/
|
||||||
|
test_start = max_bytes + 4096;
|
||||||
|
locked_page = find_lock_page(inode->i_mapping, test_start >>
|
||||||
|
PAGE_CACHE_SHIFT);
|
||||||
|
if (!locked_page) {
|
||||||
|
test_msg("Could'nt find the locked page\n");
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
start = test_start;
|
||||||
|
end = 0;
|
||||||
|
found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
|
||||||
|
&end, max_bytes);
|
||||||
|
if (found) {
|
||||||
|
test_msg("Found range when we shouldn't have\n");
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
if (end != (u64)-1) {
|
||||||
|
test_msg("Did not return the proper end offset\n");
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test this scenario
|
||||||
|
* [------- delalloc -------|
|
||||||
|
* [max_bytes]|-- search--|
|
||||||
|
*
|
||||||
|
* We are re-using our test_start from above since it works out well.
|
||||||
|
*/
|
||||||
|
set_extent_delalloc(&tmp, max_bytes, total_dirty - 1, NULL, GFP_NOFS);
|
||||||
|
start = test_start;
|
||||||
|
end = 0;
|
||||||
|
found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
|
||||||
|
&end, max_bytes);
|
||||||
|
if (!found) {
|
||||||
|
test_msg("Didn't find our range\n");
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
if (start != test_start || end != total_dirty - 1) {
|
||||||
|
test_msg("Expected start %Lu end %Lu, got start %Lu end %Lu\n",
|
||||||
|
test_start, total_dirty - 1, start, end);
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
if (process_page_range(inode, start, end,
|
||||||
|
PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) {
|
||||||
|
test_msg("Pages in range were not all locked\n");
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
unlock_extent(&tmp, start, end);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now to test where we run into a page that is no longer dirty in the
|
||||||
|
* range we want to find.
|
||||||
|
*/
|
||||||
|
page = find_get_page(inode->i_mapping, (max_bytes + (1 * 1024 * 1024))
|
||||||
|
>> PAGE_CACHE_SHIFT);
|
||||||
|
if (!page) {
|
||||||
|
test_msg("Couldn't find our page\n");
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
ClearPageDirty(page);
|
||||||
|
page_cache_release(page);
|
||||||
|
|
||||||
|
/* We unlocked it in the previous test */
|
||||||
|
lock_page(locked_page);
|
||||||
|
start = test_start;
|
||||||
|
end = 0;
|
||||||
|
/*
|
||||||
|
* Currently if we fail to find dirty pages in the delalloc range we
|
||||||
|
* will adjust max_bytes down to PAGE_CACHE_SIZE and then re-search. If
|
||||||
|
* this changes at any point in the future we will need to fix this
|
||||||
|
* tests expected behavior.
|
||||||
|
*/
|
||||||
|
found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
|
||||||
|
&end, max_bytes);
|
||||||
|
if (!found) {
|
||||||
|
test_msg("Didn't find our range\n");
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
if (start != test_start && end != test_start + PAGE_CACHE_SIZE - 1) {
|
||||||
|
test_msg("Expected start %Lu end %Lu, got start %Lu end %Lu\n",
|
||||||
|
test_start, test_start + PAGE_CACHE_SIZE - 1, start,
|
||||||
|
end);
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
if (process_page_range(inode, start, end, PROCESS_TEST_LOCKED |
|
||||||
|
PROCESS_UNLOCK)) {
|
||||||
|
test_msg("Pages in range were not all locked\n");
|
||||||
|
goto out_bits;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
out_bits:
|
||||||
|
clear_extent_bits(&tmp, 0, total_dirty - 1,
|
||||||
|
(unsigned long)-1, GFP_NOFS);
|
||||||
|
out:
|
||||||
|
if (locked_page)
|
||||||
|
page_cache_release(locked_page);
|
||||||
|
process_page_range(inode, 0, total_dirty - 1,
|
||||||
|
PROCESS_UNLOCK | PROCESS_RELEASE);
|
||||||
|
iput(inode);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int btrfs_test_extent_io(void)
|
||||||
|
{
|
||||||
|
test_msg("Running find delalloc tests\n");
|
||||||
|
return test_find_delalloc();
|
||||||
|
}
|
955
fs/btrfs/tests/inode-tests.c
Normal file
955
fs/btrfs/tests/inode-tests.c
Normal file
|
@ -0,0 +1,955 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2013 Fusion IO. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "btrfs-tests.h"
|
||||||
|
#include "../ctree.h"
|
||||||
|
#include "../btrfs_inode.h"
|
||||||
|
#include "../disk-io.h"
|
||||||
|
#include "../extent_io.h"
|
||||||
|
#include "../volumes.h"
|
||||||
|
|
||||||
|
static struct btrfs_fs_info *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;
|
||||||
|
}
|
||||||
|
return fs_info;
|
||||||
|
}
|
||||||
|
static void free_dummy_root(struct btrfs_root *root)
|
||||||
|
{
|
||||||
|
if (!root)
|
||||||
|
return;
|
||||||
|
if (root->fs_info) {
|
||||||
|
kfree(root->fs_info->fs_devices);
|
||||||
|
kfree(root->fs_info);
|
||||||
|
}
|
||||||
|
if (root->node)
|
||||||
|
free_extent_buffer(root->node);
|
||||||
|
kfree(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert_extent(struct btrfs_root *root, u64 start, u64 len,
|
||||||
|
u64 ram_bytes, u64 offset, u64 disk_bytenr,
|
||||||
|
u64 disk_len, u32 type, u8 compression, int slot)
|
||||||
|
{
|
||||||
|
struct btrfs_path path;
|
||||||
|
struct btrfs_file_extent_item *fi;
|
||||||
|
struct extent_buffer *leaf = root->node;
|
||||||
|
struct btrfs_key key;
|
||||||
|
u32 value_len = sizeof(struct btrfs_file_extent_item);
|
||||||
|
|
||||||
|
if (type == BTRFS_FILE_EXTENT_INLINE)
|
||||||
|
value_len += len;
|
||||||
|
memset(&path, 0, sizeof(path));
|
||||||
|
|
||||||
|
path.nodes[0] = leaf;
|
||||||
|
path.slots[0] = slot;
|
||||||
|
|
||||||
|
key.objectid = BTRFS_FIRST_FREE_OBJECTID;
|
||||||
|
key.type = BTRFS_EXTENT_DATA_KEY;
|
||||||
|
key.offset = start;
|
||||||
|
|
||||||
|
setup_items_for_insert(root, &path, &key, &value_len, value_len,
|
||||||
|
value_len + sizeof(struct btrfs_item), 1);
|
||||||
|
fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
|
||||||
|
btrfs_set_file_extent_generation(leaf, fi, 1);
|
||||||
|
btrfs_set_file_extent_type(leaf, fi, type);
|
||||||
|
btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr);
|
||||||
|
btrfs_set_file_extent_disk_num_bytes(leaf, fi, disk_len);
|
||||||
|
btrfs_set_file_extent_offset(leaf, fi, offset);
|
||||||
|
btrfs_set_file_extent_num_bytes(leaf, fi, len);
|
||||||
|
btrfs_set_file_extent_ram_bytes(leaf, fi, ram_bytes);
|
||||||
|
btrfs_set_file_extent_compression(leaf, fi, compression);
|
||||||
|
btrfs_set_file_extent_encryption(leaf, fi, 0);
|
||||||
|
btrfs_set_file_extent_other_encoding(leaf, fi, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert_inode_item_key(struct btrfs_root *root)
|
||||||
|
{
|
||||||
|
struct btrfs_path path;
|
||||||
|
struct extent_buffer *leaf = root->node;
|
||||||
|
struct btrfs_key key;
|
||||||
|
u32 value_len = 0;
|
||||||
|
|
||||||
|
memset(&path, 0, sizeof(path));
|
||||||
|
|
||||||
|
path.nodes[0] = leaf;
|
||||||
|
path.slots[0] = 0;
|
||||||
|
|
||||||
|
key.objectid = BTRFS_INODE_ITEM_KEY;
|
||||||
|
key.type = BTRFS_INODE_ITEM_KEY;
|
||||||
|
key.offset = 0;
|
||||||
|
|
||||||
|
setup_items_for_insert(root, &path, &key, &value_len, value_len,
|
||||||
|
value_len + sizeof(struct btrfs_item), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Build the most complicated map of extents the earth has ever seen. We want
|
||||||
|
* this so we can test all of the corner cases of btrfs_get_extent. Here is a
|
||||||
|
* diagram of how the extents will look though this may not be possible we still
|
||||||
|
* want to make sure everything acts normally (the last number is not inclusive)
|
||||||
|
*
|
||||||
|
* [0 - 5][5 - 6][6 - 10][10 - 4096][ 4096 - 8192 ][8192 - 12288]
|
||||||
|
* [hole ][inline][ hole ][ regular ][regular1 split][ hole ]
|
||||||
|
*
|
||||||
|
* [ 12288 - 20480][20480 - 24576][ 24576 - 28672 ][28672 - 36864][36864 - 45056]
|
||||||
|
* [regular1 split][ prealloc1 ][prealloc1 written][ prealloc1 ][ compressed ]
|
||||||
|
*
|
||||||
|
* [45056 - 49152][49152-53248][53248-61440][61440-65536][ 65536+81920 ]
|
||||||
|
* [ compressed1 ][ regular ][compressed1][ regular ][ hole but no extent]
|
||||||
|
*
|
||||||
|
* [81920-86016]
|
||||||
|
* [ regular ]
|
||||||
|
*/
|
||||||
|
static void setup_file_extents(struct btrfs_root *root)
|
||||||
|
{
|
||||||
|
int slot = 0;
|
||||||
|
u64 disk_bytenr = 1 * 1024 * 1024;
|
||||||
|
u64 offset = 0;
|
||||||
|
|
||||||
|
/* First we want a hole */
|
||||||
|
insert_extent(root, offset, 5, 5, 0, 0, 0, BTRFS_FILE_EXTENT_REG, 0,
|
||||||
|
slot);
|
||||||
|
slot++;
|
||||||
|
offset += 5;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we want an inline extent, I don't think this is possible but hey
|
||||||
|
* why not? Also keep in mind if we have an inline extent it counts as
|
||||||
|
* the whole first page. If we were to expand it we would have to cow
|
||||||
|
* and we wouldn't have an inline extent anymore.
|
||||||
|
*/
|
||||||
|
insert_extent(root, offset, 1, 1, 0, 0, 0, BTRFS_FILE_EXTENT_INLINE, 0,
|
||||||
|
slot);
|
||||||
|
slot++;
|
||||||
|
offset = 4096;
|
||||||
|
|
||||||
|
/* Now another hole */
|
||||||
|
insert_extent(root, offset, 4, 4, 0, 0, 0, BTRFS_FILE_EXTENT_REG, 0,
|
||||||
|
slot);
|
||||||
|
slot++;
|
||||||
|
offset += 4;
|
||||||
|
|
||||||
|
/* Now for a regular extent */
|
||||||
|
insert_extent(root, offset, 4095, 4095, 0, disk_bytenr, 4096,
|
||||||
|
BTRFS_FILE_EXTENT_REG, 0, slot);
|
||||||
|
slot++;
|
||||||
|
disk_bytenr += 4096;
|
||||||
|
offset += 4095;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now for 3 extents that were split from a hole punch so we test
|
||||||
|
* offsets properly.
|
||||||
|
*/
|
||||||
|
insert_extent(root, offset, 4096, 16384, 0, disk_bytenr, 16384,
|
||||||
|
BTRFS_FILE_EXTENT_REG, 0, slot);
|
||||||
|
slot++;
|
||||||
|
offset += 4096;
|
||||||
|
insert_extent(root, offset, 4096, 4096, 0, 0, 0, BTRFS_FILE_EXTENT_REG,
|
||||||
|
0, slot);
|
||||||
|
slot++;
|
||||||
|
offset += 4096;
|
||||||
|
insert_extent(root, offset, 8192, 16384, 8192, disk_bytenr, 16384,
|
||||||
|
BTRFS_FILE_EXTENT_REG, 0, slot);
|
||||||
|
slot++;
|
||||||
|
offset += 8192;
|
||||||
|
disk_bytenr += 16384;
|
||||||
|
|
||||||
|
/* Now for a unwritten prealloc extent */
|
||||||
|
insert_extent(root, offset, 4096, 4096, 0, disk_bytenr, 4096,
|
||||||
|
BTRFS_FILE_EXTENT_PREALLOC, 0, slot);
|
||||||
|
slot++;
|
||||||
|
offset += 4096;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We want to jack up disk_bytenr a little more so the em stuff doesn't
|
||||||
|
* merge our records.
|
||||||
|
*/
|
||||||
|
disk_bytenr += 8192;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now for a partially written prealloc extent, basically the same as
|
||||||
|
* the hole punch example above. Ram_bytes never changes when you mark
|
||||||
|
* extents written btw.
|
||||||
|
*/
|
||||||
|
insert_extent(root, offset, 4096, 16384, 0, disk_bytenr, 16384,
|
||||||
|
BTRFS_FILE_EXTENT_PREALLOC, 0, slot);
|
||||||
|
slot++;
|
||||||
|
offset += 4096;
|
||||||
|
insert_extent(root, offset, 4096, 16384, 4096, disk_bytenr, 16384,
|
||||||
|
BTRFS_FILE_EXTENT_REG, 0, slot);
|
||||||
|
slot++;
|
||||||
|
offset += 4096;
|
||||||
|
insert_extent(root, offset, 8192, 16384, 8192, disk_bytenr, 16384,
|
||||||
|
BTRFS_FILE_EXTENT_PREALLOC, 0, slot);
|
||||||
|
slot++;
|
||||||
|
offset += 8192;
|
||||||
|
disk_bytenr += 16384;
|
||||||
|
|
||||||
|
/* Now a normal compressed extent */
|
||||||
|
insert_extent(root, offset, 8192, 8192, 0, disk_bytenr, 4096,
|
||||||
|
BTRFS_FILE_EXTENT_REG, BTRFS_COMPRESS_ZLIB, slot);
|
||||||
|
slot++;
|
||||||
|
offset += 8192;
|
||||||
|
/* No merges */
|
||||||
|
disk_bytenr += 8192;
|
||||||
|
|
||||||
|
/* Now a split compressed extent */
|
||||||
|
insert_extent(root, offset, 4096, 16384, 0, disk_bytenr, 4096,
|
||||||
|
BTRFS_FILE_EXTENT_REG, BTRFS_COMPRESS_ZLIB, slot);
|
||||||
|
slot++;
|
||||||
|
offset += 4096;
|
||||||
|
insert_extent(root, offset, 4096, 4096, 0, disk_bytenr + 4096, 4096,
|
||||||
|
BTRFS_FILE_EXTENT_REG, 0, slot);
|
||||||
|
slot++;
|
||||||
|
offset += 4096;
|
||||||
|
insert_extent(root, offset, 8192, 16384, 8192, disk_bytenr, 4096,
|
||||||
|
BTRFS_FILE_EXTENT_REG, BTRFS_COMPRESS_ZLIB, slot);
|
||||||
|
slot++;
|
||||||
|
offset += 8192;
|
||||||
|
disk_bytenr += 8192;
|
||||||
|
|
||||||
|
/* Now extents that have a hole but no hole extent */
|
||||||
|
insert_extent(root, offset, 4096, 4096, 0, disk_bytenr, 4096,
|
||||||
|
BTRFS_FILE_EXTENT_REG, 0, slot);
|
||||||
|
slot++;
|
||||||
|
offset += 16384;
|
||||||
|
disk_bytenr += 4096;
|
||||||
|
insert_extent(root, offset, 4096, 4096, 0, disk_bytenr, 4096,
|
||||||
|
BTRFS_FILE_EXTENT_REG, 0, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long prealloc_only = 0;
|
||||||
|
static unsigned long compressed_only = 0;
|
||||||
|
static unsigned long vacancy_only = 0;
|
||||||
|
|
||||||
|
static noinline int test_btrfs_get_extent(void)
|
||||||
|
{
|
||||||
|
struct inode *inode = NULL;
|
||||||
|
struct btrfs_root *root = NULL;
|
||||||
|
struct extent_map *em = NULL;
|
||||||
|
u64 orig_start;
|
||||||
|
u64 disk_bytenr;
|
||||||
|
u64 offset;
|
||||||
|
int ret = -ENOMEM;
|
||||||
|
|
||||||
|
inode = btrfs_new_test_inode();
|
||||||
|
if (!inode) {
|
||||||
|
test_msg("Couldn't allocate inode\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY;
|
||||||
|
BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID;
|
||||||
|
BTRFS_I(inode)->location.offset = 0;
|
||||||
|
|
||||||
|
root = btrfs_alloc_dummy_root();
|
||||||
|
if (IS_ERR(root)) {
|
||||||
|
test_msg("Couldn't allocate root\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We do this since btrfs_get_extent wants to assign em->bdev to
|
||||||
|
* root->fs_info->fs_devices->latest_bdev.
|
||||||
|
*/
|
||||||
|
root->fs_info = alloc_dummy_fs_info();
|
||||||
|
if (!root->fs_info) {
|
||||||
|
test_msg("Couldn't allocate dummy fs info\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
root->node = alloc_dummy_extent_buffer(0, 4096);
|
||||||
|
if (!root->node) {
|
||||||
|
test_msg("Couldn't allocate dummy buffer\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We will just free a dummy node if it's ref count is 2 so we need an
|
||||||
|
* extra ref so our searches don't accidently release our page.
|
||||||
|
*/
|
||||||
|
extent_buffer_get(root->node);
|
||||||
|
btrfs_set_header_nritems(root->node, 0);
|
||||||
|
btrfs_set_header_level(root->node, 0);
|
||||||
|
ret = -EINVAL;
|
||||||
|
|
||||||
|
/* First with no extents */
|
||||||
|
BTRFS_I(inode)->root = root;
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, 0, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
em = NULL;
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start != EXTENT_MAP_HOLE) {
|
||||||
|
test_msg("Expected a hole, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (!test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
|
||||||
|
test_msg("Vacancy flag wasn't set properly\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
free_extent_map(em);
|
||||||
|
btrfs_drop_extent_cache(inode, 0, (u64)-1, 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* All of the magic numbers are based on the mapping setup in
|
||||||
|
* setup_file_extents, so if you change anything there you need to
|
||||||
|
* update the comment and update the expected values below.
|
||||||
|
*/
|
||||||
|
setup_file_extents(root);
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, 0, (u64)-1, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start != EXTENT_MAP_HOLE) {
|
||||||
|
test_msg("Expected a hole, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != 0 || em->len != 5) {
|
||||||
|
test_msg("Unexpected extent wanted start 0 len 5, got start "
|
||||||
|
"%llu len %llu\n", em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != 0) {
|
||||||
|
test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start != EXTENT_MAP_INLINE) {
|
||||||
|
test_msg("Expected an inline, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 4091) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 1, got start "
|
||||||
|
"%llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != 0) {
|
||||||
|
test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We don't test anything else for inline since it doesn't get set
|
||||||
|
* unless we have a page for it to write into. Maybe we should change
|
||||||
|
* this?
|
||||||
|
*/
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start != EXTENT_MAP_HOLE) {
|
||||||
|
test_msg("Expected a hole, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 4) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 4, got start "
|
||||||
|
"%llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != 0) {
|
||||||
|
test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
/* Regular extent */
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 4095) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 4095, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != 0) {
|
||||||
|
test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != em->start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
|
||||||
|
em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
/* The next 3 are split extents */
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 4096) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 4096, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != 0) {
|
||||||
|
test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != em->start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
|
||||||
|
em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
disk_bytenr = em->block_start;
|
||||||
|
orig_start = em->start;
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start != EXTENT_MAP_HOLE) {
|
||||||
|
test_msg("Expected a hole, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 4096) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 4096, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != 0) {
|
||||||
|
test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 8192) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 8192, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != 0) {
|
||||||
|
test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != orig_start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n",
|
||||||
|
orig_start, em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
disk_bytenr += (em->start - orig_start);
|
||||||
|
if (em->block_start != disk_bytenr) {
|
||||||
|
test_msg("Wrong block start, want %llu, have %llu\n",
|
||||||
|
disk_bytenr, em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
/* Prealloc extent */
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 4096) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 4096, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != prealloc_only) {
|
||||||
|
test_msg("Unexpected flags set, want %lu have %lu\n",
|
||||||
|
prealloc_only, em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != em->start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
|
||||||
|
em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
/* The next 3 are a half written prealloc extent */
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 4096) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 4096, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != prealloc_only) {
|
||||||
|
test_msg("Unexpected flags set, want %lu have %lu\n",
|
||||||
|
prealloc_only, em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != em->start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
|
||||||
|
em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
disk_bytenr = em->block_start;
|
||||||
|
orig_start = em->start;
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start >= EXTENT_MAP_HOLE) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 4096) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 4096, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != 0) {
|
||||||
|
test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != orig_start) {
|
||||||
|
test_msg("Unexpected orig offset, wanted %llu, have %llu\n",
|
||||||
|
orig_start, em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start != (disk_bytenr + (em->start - em->orig_start))) {
|
||||||
|
test_msg("Unexpected block start, wanted %llu, have %llu\n",
|
||||||
|
disk_bytenr + (em->start - em->orig_start),
|
||||||
|
em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 8192) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 8192, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != prealloc_only) {
|
||||||
|
test_msg("Unexpected flags set, want %lu have %lu\n",
|
||||||
|
prealloc_only, em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != orig_start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n", orig_start,
|
||||||
|
em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start != (disk_bytenr + (em->start - em->orig_start))) {
|
||||||
|
test_msg("Unexpected block start, wanted %llu, have %llu\n",
|
||||||
|
disk_bytenr + (em->start - em->orig_start),
|
||||||
|
em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
/* Now for the compressed extent */
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 8192) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 8192, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != compressed_only) {
|
||||||
|
test_msg("Unexpected flags set, want %lu have %lu\n",
|
||||||
|
compressed_only, em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != em->start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n",
|
||||||
|
em->start, em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->compress_type != BTRFS_COMPRESS_ZLIB) {
|
||||||
|
test_msg("Unexpected compress type, wanted %d, got %d\n",
|
||||||
|
BTRFS_COMPRESS_ZLIB, em->compress_type);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
/* Split compressed extent */
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 4096) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 4096, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != compressed_only) {
|
||||||
|
test_msg("Unexpected flags set, want %lu have %lu\n",
|
||||||
|
compressed_only, em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != em->start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n",
|
||||||
|
em->start, em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->compress_type != BTRFS_COMPRESS_ZLIB) {
|
||||||
|
test_msg("Unexpected compress type, wanted %d, got %d\n",
|
||||||
|
BTRFS_COMPRESS_ZLIB, em->compress_type);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
disk_bytenr = em->block_start;
|
||||||
|
orig_start = em->start;
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 4096) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 4096, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != 0) {
|
||||||
|
test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != em->start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
|
||||||
|
em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start != disk_bytenr) {
|
||||||
|
test_msg("Block start does not match, want %llu got %llu\n",
|
||||||
|
disk_bytenr, em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 8192) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 8192, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != compressed_only) {
|
||||||
|
test_msg("Unexpected flags set, want %lu have %lu\n",
|
||||||
|
compressed_only, em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != orig_start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n",
|
||||||
|
em->start, orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->compress_type != BTRFS_COMPRESS_ZLIB) {
|
||||||
|
test_msg("Unexpected compress type, wanted %d, got %d\n",
|
||||||
|
BTRFS_COMPRESS_ZLIB, em->compress_type);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
/* A hole between regular extents but no hole extent */
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset + 6, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 4096) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 4096, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != 0) {
|
||||||
|
test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != em->start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
|
||||||
|
em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096 * 1024, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start != EXTENT_MAP_HOLE) {
|
||||||
|
test_msg("Expected a hole extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Currently we just return a length that we requested rather than the
|
||||||
|
* length of the actual hole, if this changes we'll have to change this
|
||||||
|
* test.
|
||||||
|
*/
|
||||||
|
if (em->start != offset || em->len != 12288) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 12288, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != vacancy_only) {
|
||||||
|
test_msg("Unexpected flags set, want %lu have %lu\n",
|
||||||
|
vacancy_only, em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != em->start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
|
||||||
|
em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
offset = em->start + em->len;
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, offset, 4096, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start >= EXTENT_MAP_LAST_BYTE) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != offset || em->len != 4096) {
|
||||||
|
test_msg("Unexpected extent wanted start %llu len 4096, got "
|
||||||
|
"start %llu len %llu\n", offset, em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != 0) {
|
||||||
|
test_msg("Unexpected flags set, want 0 have %lu\n", em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->orig_start != em->start) {
|
||||||
|
test_msg("Wrong orig offset, want %llu, have %llu\n", em->start,
|
||||||
|
em->orig_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
|
if (!IS_ERR(em))
|
||||||
|
free_extent_map(em);
|
||||||
|
iput(inode);
|
||||||
|
free_dummy_root(root);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_hole_first(void)
|
||||||
|
{
|
||||||
|
struct inode *inode = NULL;
|
||||||
|
struct btrfs_root *root = NULL;
|
||||||
|
struct extent_map *em = NULL;
|
||||||
|
int ret = -ENOMEM;
|
||||||
|
|
||||||
|
inode = btrfs_new_test_inode();
|
||||||
|
if (!inode) {
|
||||||
|
test_msg("Couldn't allocate inode\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY;
|
||||||
|
BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID;
|
||||||
|
BTRFS_I(inode)->location.offset = 0;
|
||||||
|
|
||||||
|
root = btrfs_alloc_dummy_root();
|
||||||
|
if (IS_ERR(root)) {
|
||||||
|
test_msg("Couldn't allocate root\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
root->fs_info = alloc_dummy_fs_info();
|
||||||
|
if (!root->fs_info) {
|
||||||
|
test_msg("Couldn't allocate dummy fs info\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
root->node = alloc_dummy_extent_buffer(0, 4096);
|
||||||
|
if (!root->node) {
|
||||||
|
test_msg("Couldn't allocate dummy buffer\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
extent_buffer_get(root->node);
|
||||||
|
btrfs_set_header_nritems(root->node, 0);
|
||||||
|
btrfs_set_header_level(root->node, 0);
|
||||||
|
BTRFS_I(inode)->root = root;
|
||||||
|
ret = -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need a blank inode item here just so we don't confuse
|
||||||
|
* btrfs_get_extent.
|
||||||
|
*/
|
||||||
|
insert_inode_item_key(root);
|
||||||
|
insert_extent(root, 4096, 4096, 4096, 0, 4096, 4096,
|
||||||
|
BTRFS_FILE_EXTENT_REG, 0, 1);
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, 0, 8192, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start != EXTENT_MAP_HOLE) {
|
||||||
|
test_msg("Expected a hole, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != 0 || em->len != 4096) {
|
||||||
|
test_msg("Unexpected extent wanted start 0 len 4096, got start "
|
||||||
|
"%llu len %llu\n", em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != vacancy_only) {
|
||||||
|
test_msg("Wrong flags, wanted %lu, have %lu\n", vacancy_only,
|
||||||
|
em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
free_extent_map(em);
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, 4096, 8192, 0);
|
||||||
|
if (IS_ERR(em)) {
|
||||||
|
test_msg("Got an error when we shouldn't have\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->block_start != 4096) {
|
||||||
|
test_msg("Expected a real extent, got %llu\n", em->block_start);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->start != 4096 || em->len != 4096) {
|
||||||
|
test_msg("Unexpected extent wanted start 4096 len 4096, got "
|
||||||
|
"start %llu len %llu\n", em->start, em->len);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (em->flags != 0) {
|
||||||
|
test_msg("Unexpected flags set, wanted 0 got %lu\n",
|
||||||
|
em->flags);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
out:
|
||||||
|
if (!IS_ERR(em))
|
||||||
|
free_extent_map(em);
|
||||||
|
iput(inode);
|
||||||
|
free_dummy_root(root);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int btrfs_test_inodes(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
set_bit(EXTENT_FLAG_COMPRESSED, &compressed_only);
|
||||||
|
set_bit(EXTENT_FLAG_VACANCY, &vacancy_only);
|
||||||
|
set_bit(EXTENT_FLAG_PREALLOC, &prealloc_only);
|
||||||
|
|
||||||
|
test_msg("Running btrfs_get_extent tests\n");
|
||||||
|
ret = test_btrfs_get_extent();
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
test_msg("Running hole first btrfs_get_extent test\n");
|
||||||
|
return test_hole_first();
|
||||||
|
}
|
|
@ -57,7 +57,7 @@ static unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = {
|
||||||
__TRANS_JOIN_NOLOCK),
|
__TRANS_JOIN_NOLOCK),
|
||||||
};
|
};
|
||||||
|
|
||||||
static void put_transaction(struct btrfs_transaction *transaction)
|
void btrfs_put_transaction(struct btrfs_transaction *transaction)
|
||||||
{
|
{
|
||||||
WARN_ON(atomic_read(&transaction->use_count) == 0);
|
WARN_ON(atomic_read(&transaction->use_count) == 0);
|
||||||
if (atomic_dec_and_test(&transaction->use_count)) {
|
if (atomic_dec_and_test(&transaction->use_count)) {
|
||||||
|
@ -332,7 +332,7 @@ static void wait_current_trans(struct btrfs_root *root)
|
||||||
wait_event(root->fs_info->transaction_wait,
|
wait_event(root->fs_info->transaction_wait,
|
||||||
cur_trans->state >= TRANS_STATE_UNBLOCKED ||
|
cur_trans->state >= TRANS_STATE_UNBLOCKED ||
|
||||||
cur_trans->aborted);
|
cur_trans->aborted);
|
||||||
put_transaction(cur_trans);
|
btrfs_put_transaction(cur_trans);
|
||||||
} else {
|
} else {
|
||||||
spin_unlock(&root->fs_info->trans_lock);
|
spin_unlock(&root->fs_info->trans_lock);
|
||||||
}
|
}
|
||||||
|
@ -353,6 +353,17 @@ static int may_wait_transaction(struct btrfs_root *root, int type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool need_reserve_reloc_root(struct btrfs_root *root)
|
||||||
|
{
|
||||||
|
if (!root->fs_info->reloc_ctl ||
|
||||||
|
!root->ref_cows ||
|
||||||
|
root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID ||
|
||||||
|
root->reloc_root)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static struct btrfs_trans_handle *
|
static struct btrfs_trans_handle *
|
||||||
start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
|
start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
|
||||||
enum btrfs_reserve_flush_enum flush)
|
enum btrfs_reserve_flush_enum flush)
|
||||||
|
@ -360,8 +371,9 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
|
||||||
struct btrfs_trans_handle *h;
|
struct btrfs_trans_handle *h;
|
||||||
struct btrfs_transaction *cur_trans;
|
struct btrfs_transaction *cur_trans;
|
||||||
u64 num_bytes = 0;
|
u64 num_bytes = 0;
|
||||||
int ret;
|
|
||||||
u64 qgroup_reserved = 0;
|
u64 qgroup_reserved = 0;
|
||||||
|
bool reloc_reserved = false;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
|
if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
|
||||||
return ERR_PTR(-EROFS);
|
return ERR_PTR(-EROFS);
|
||||||
|
@ -390,6 +402,14 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
|
||||||
}
|
}
|
||||||
|
|
||||||
num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
|
num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
|
||||||
|
/*
|
||||||
|
* Do the reservation for the relocation root creation
|
||||||
|
*/
|
||||||
|
if (unlikely(need_reserve_reloc_root(root))) {
|
||||||
|
num_bytes += root->nodesize;
|
||||||
|
reloc_reserved = true;
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_block_rsv_add(root,
|
ret = btrfs_block_rsv_add(root,
|
||||||
&root->fs_info->trans_block_rsv,
|
&root->fs_info->trans_block_rsv,
|
||||||
num_bytes, flush);
|
num_bytes, flush);
|
||||||
|
@ -451,6 +471,7 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
|
||||||
h->delayed_ref_elem.seq = 0;
|
h->delayed_ref_elem.seq = 0;
|
||||||
h->type = type;
|
h->type = type;
|
||||||
h->allocating_chunk = false;
|
h->allocating_chunk = false;
|
||||||
|
h->reloc_reserved = false;
|
||||||
INIT_LIST_HEAD(&h->qgroup_ref_list);
|
INIT_LIST_HEAD(&h->qgroup_ref_list);
|
||||||
INIT_LIST_HEAD(&h->new_bgs);
|
INIT_LIST_HEAD(&h->new_bgs);
|
||||||
|
|
||||||
|
@ -466,6 +487,7 @@ start_transaction(struct btrfs_root *root, u64 num_items, unsigned int type,
|
||||||
h->transid, num_bytes, 1);
|
h->transid, num_bytes, 1);
|
||||||
h->block_rsv = &root->fs_info->trans_block_rsv;
|
h->block_rsv = &root->fs_info->trans_block_rsv;
|
||||||
h->bytes_reserved = num_bytes;
|
h->bytes_reserved = num_bytes;
|
||||||
|
h->reloc_reserved = reloc_reserved;
|
||||||
}
|
}
|
||||||
h->qgroup_reserved = qgroup_reserved;
|
h->qgroup_reserved = qgroup_reserved;
|
||||||
|
|
||||||
|
@ -610,7 +632,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid)
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_for_commit(root, cur_trans);
|
wait_for_commit(root, cur_trans);
|
||||||
put_transaction(cur_trans);
|
btrfs_put_transaction(cur_trans);
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -735,7 +757,7 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
|
||||||
smp_mb();
|
smp_mb();
|
||||||
if (waitqueue_active(&cur_trans->writer_wait))
|
if (waitqueue_active(&cur_trans->writer_wait))
|
||||||
wake_up(&cur_trans->writer_wait);
|
wake_up(&cur_trans->writer_wait);
|
||||||
put_transaction(cur_trans);
|
btrfs_put_transaction(cur_trans);
|
||||||
|
|
||||||
if (current->journal_info == trans)
|
if (current->journal_info == trans)
|
||||||
current->journal_info = NULL;
|
current->journal_info = NULL;
|
||||||
|
@ -744,8 +766,10 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
|
||||||
btrfs_run_delayed_iputs(root);
|
btrfs_run_delayed_iputs(root);
|
||||||
|
|
||||||
if (trans->aborted ||
|
if (trans->aborted ||
|
||||||
test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
|
test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) {
|
||||||
|
wake_up_process(info->transaction_kthread);
|
||||||
err = -EIO;
|
err = -EIO;
|
||||||
|
}
|
||||||
assert_qgroups_uptodate(trans);
|
assert_qgroups_uptodate(trans);
|
||||||
|
|
||||||
kmem_cache_free(btrfs_trans_handle_cachep, trans);
|
kmem_cache_free(btrfs_trans_handle_cachep, trans);
|
||||||
|
@ -948,16 +972,19 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = btrfs_run_dev_stats(trans, root->fs_info);
|
ret = btrfs_run_dev_stats(trans, root->fs_info);
|
||||||
WARN_ON(ret);
|
if (ret)
|
||||||
|
return ret;
|
||||||
ret = btrfs_run_dev_replace(trans, root->fs_info);
|
ret = btrfs_run_dev_replace(trans, root->fs_info);
|
||||||
WARN_ON(ret);
|
if (ret)
|
||||||
|
return ret;
|
||||||
ret = btrfs_run_qgroups(trans, root->fs_info);
|
ret = btrfs_run_qgroups(trans, root->fs_info);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* run_qgroups might have added some more refs */
|
/* run_qgroups might have added some more refs */
|
||||||
ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
|
ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1);
|
||||||
BUG_ON(ret);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
while (!list_empty(&fs_info->dirty_cowonly_roots)) {
|
while (!list_empty(&fs_info->dirty_cowonly_roots)) {
|
||||||
next = fs_info->dirty_cowonly_roots.next;
|
next = fs_info->dirty_cowonly_roots.next;
|
||||||
|
@ -1510,7 +1537,7 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
|
||||||
if (current->journal_info == trans)
|
if (current->journal_info == trans)
|
||||||
current->journal_info = NULL;
|
current->journal_info = NULL;
|
||||||
|
|
||||||
put_transaction(cur_trans);
|
btrfs_put_transaction(cur_trans);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1552,8 +1579,10 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans,
|
||||||
root->fs_info->running_transaction = NULL;
|
root->fs_info->running_transaction = NULL;
|
||||||
spin_unlock(&root->fs_info->trans_lock);
|
spin_unlock(&root->fs_info->trans_lock);
|
||||||
|
|
||||||
put_transaction(cur_trans);
|
if (trans->type & __TRANS_FREEZABLE)
|
||||||
put_transaction(cur_trans);
|
sb_end_intwrite(root->fs_info->sb);
|
||||||
|
btrfs_put_transaction(cur_trans);
|
||||||
|
btrfs_put_transaction(cur_trans);
|
||||||
|
|
||||||
trace_btrfs_transaction_commit(root);
|
trace_btrfs_transaction_commit(root);
|
||||||
|
|
||||||
|
@ -1571,15 +1600,19 @@ static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = btrfs_run_delayed_items(trans, root);
|
ret = btrfs_run_delayed_items(trans, root);
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* running the delayed items may have added new refs. account
|
* running the delayed items may have added new refs. account
|
||||||
* them now so that they hinder processing of more delayed refs
|
* them now so that they hinder processing of more delayed refs
|
||||||
* as little as possible.
|
* as little as possible.
|
||||||
*/
|
*/
|
||||||
btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
|
if (ret) {
|
||||||
|
btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* rename don't use btrfs_join_transaction, so, once we
|
* rename don't use btrfs_join_transaction, so, once we
|
||||||
|
@ -1596,14 +1629,14 @@ static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans,
|
||||||
static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
|
static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
|
||||||
{
|
{
|
||||||
if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
|
if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
|
||||||
return btrfs_start_all_delalloc_inodes(fs_info, 1);
|
return btrfs_start_delalloc_roots(fs_info, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
|
static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
|
||||||
{
|
{
|
||||||
if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
|
if (btrfs_test_opt(fs_info->tree_root, FLUSHONCOMMIT))
|
||||||
btrfs_wait_all_ordered_extents(fs_info);
|
btrfs_wait_ordered_roots(fs_info, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||||
|
@ -1669,7 +1702,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
wait_for_commit(root, cur_trans);
|
wait_for_commit(root, cur_trans);
|
||||||
|
|
||||||
put_transaction(cur_trans);
|
btrfs_put_transaction(cur_trans);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1686,7 +1719,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
wait_for_commit(root, prev_trans);
|
wait_for_commit(root, prev_trans);
|
||||||
|
|
||||||
put_transaction(prev_trans);
|
btrfs_put_transaction(prev_trans);
|
||||||
} else {
|
} else {
|
||||||
spin_unlock(&root->fs_info->trans_lock);
|
spin_unlock(&root->fs_info->trans_lock);
|
||||||
}
|
}
|
||||||
|
@ -1885,8 +1918,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||||
list_del_init(&cur_trans->list);
|
list_del_init(&cur_trans->list);
|
||||||
spin_unlock(&root->fs_info->trans_lock);
|
spin_unlock(&root->fs_info->trans_lock);
|
||||||
|
|
||||||
put_transaction(cur_trans);
|
btrfs_put_transaction(cur_trans);
|
||||||
put_transaction(cur_trans);
|
btrfs_put_transaction(cur_trans);
|
||||||
|
|
||||||
if (trans->type & __TRANS_FREEZABLE)
|
if (trans->type & __TRANS_FREEZABLE)
|
||||||
sb_end_intwrite(root->fs_info->sb);
|
sb_end_intwrite(root->fs_info->sb);
|
||||||
|
|
|
@ -92,6 +92,7 @@ struct btrfs_trans_handle {
|
||||||
short aborted;
|
short aborted;
|
||||||
short adding_csums;
|
short adding_csums;
|
||||||
bool allocating_chunk;
|
bool allocating_chunk;
|
||||||
|
bool reloc_reserved;
|
||||||
unsigned int type;
|
unsigned int type;
|
||||||
/*
|
/*
|
||||||
* this root is only needed to validate that the root passed to
|
* this root is only needed to validate that the root passed to
|
||||||
|
@ -166,4 +167,5 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
|
||||||
struct extent_io_tree *dirty_pages, int mark);
|
struct extent_io_tree *dirty_pages, int mark);
|
||||||
int btrfs_transaction_blocked(struct btrfs_fs_info *info);
|
int btrfs_transaction_blocked(struct btrfs_fs_info *info);
|
||||||
int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
|
int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
|
||||||
|
void btrfs_put_transaction(struct btrfs_transaction *transaction);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -37,7 +37,6 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int wret;
|
int wret;
|
||||||
int level;
|
int level;
|
||||||
int is_extent = 0;
|
|
||||||
int next_key_ret = 0;
|
int next_key_ret = 0;
|
||||||
u64 last_ret = 0;
|
u64 last_ret = 0;
|
||||||
u64 min_trans = 0;
|
u64 min_trans = 0;
|
||||||
|
@ -50,7 +49,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root->ref_cows == 0 && !is_extent)
|
if (root->ref_cows == 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (btrfs_test_opt(root, SSD))
|
if (btrfs_test_opt(root, SSD))
|
||||||
|
@ -85,7 +84,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
path->keep_locks = 1;
|
path->keep_locks = 1;
|
||||||
|
|
||||||
ret = btrfs_search_forward(root, &key, NULL, path, min_trans);
|
ret = btrfs_search_forward(root, &key, path, min_trans);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include "locking.h"
|
#include "locking.h"
|
||||||
#include "print-tree.h"
|
#include "print-tree.h"
|
||||||
#include "backref.h"
|
#include "backref.h"
|
||||||
#include "compat.h"
|
|
||||||
#include "tree-log.h"
|
#include "tree-log.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
|
||||||
|
@ -936,7 +935,7 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
|
||||||
parent_objectid,
|
parent_objectid,
|
||||||
victim_name,
|
victim_name,
|
||||||
victim_name_len)) {
|
victim_name_len)) {
|
||||||
btrfs_inc_nlink(inode);
|
inc_nlink(inode);
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
ret = btrfs_unlink_inode(trans, root, dir,
|
ret = btrfs_unlink_inode(trans, root, dir,
|
||||||
|
@ -1006,7 +1005,7 @@ static inline int __add_inode_ref(struct btrfs_trans_handle *trans,
|
||||||
victim_parent = read_one_inode(root,
|
victim_parent = read_one_inode(root,
|
||||||
parent_objectid);
|
parent_objectid);
|
||||||
if (victim_parent) {
|
if (victim_parent) {
|
||||||
btrfs_inc_nlink(inode);
|
inc_nlink(inode);
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
ret = btrfs_unlink_inode(trans, root,
|
ret = btrfs_unlink_inode(trans, root,
|
||||||
|
@ -1113,11 +1112,11 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||||
struct extent_buffer *eb, int slot,
|
struct extent_buffer *eb, int slot,
|
||||||
struct btrfs_key *key)
|
struct btrfs_key *key)
|
||||||
{
|
{
|
||||||
struct inode *dir;
|
struct inode *dir = NULL;
|
||||||
struct inode *inode;
|
struct inode *inode = NULL;
|
||||||
unsigned long ref_ptr;
|
unsigned long ref_ptr;
|
||||||
unsigned long ref_end;
|
unsigned long ref_end;
|
||||||
char *name;
|
char *name = NULL;
|
||||||
int namelen;
|
int namelen;
|
||||||
int ret;
|
int ret;
|
||||||
int search_done = 0;
|
int search_done = 0;
|
||||||
|
@ -1150,13 +1149,15 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||||
* care of the rest
|
* care of the rest
|
||||||
*/
|
*/
|
||||||
dir = read_one_inode(root, parent_objectid);
|
dir = read_one_inode(root, parent_objectid);
|
||||||
if (!dir)
|
if (!dir) {
|
||||||
return -ENOENT;
|
ret = -ENOENT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
inode = read_one_inode(root, inode_objectid);
|
inode = read_one_inode(root, inode_objectid);
|
||||||
if (!inode) {
|
if (!inode) {
|
||||||
iput(dir);
|
ret = -EIO;
|
||||||
return -EIO;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ref_ptr < ref_end) {
|
while (ref_ptr < ref_end) {
|
||||||
|
@ -1169,14 +1170,16 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||||
*/
|
*/
|
||||||
if (!dir)
|
if (!dir)
|
||||||
dir = read_one_inode(root, parent_objectid);
|
dir = read_one_inode(root, parent_objectid);
|
||||||
if (!dir)
|
if (!dir) {
|
||||||
return -ENOENT;
|
ret = -ENOENT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ret = ref_get_fields(eb, ref_ptr, &namelen, &name,
|
ret = ref_get_fields(eb, ref_ptr, &namelen, &name,
|
||||||
&ref_index);
|
&ref_index);
|
||||||
}
|
}
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out;
|
||||||
|
|
||||||
/* if we already have a perfect match, we're done */
|
/* if we already have a perfect match, we're done */
|
||||||
if (!inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode),
|
if (!inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode),
|
||||||
|
@ -1196,12 +1199,11 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||||
parent_objectid,
|
parent_objectid,
|
||||||
ref_index, name, namelen,
|
ref_index, name, namelen,
|
||||||
&search_done);
|
&search_done);
|
||||||
if (ret == 1) {
|
if (ret) {
|
||||||
ret = 0;
|
if (ret == 1)
|
||||||
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* insert our name */
|
/* insert our name */
|
||||||
|
@ -1215,6 +1217,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + namelen;
|
ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + namelen;
|
||||||
kfree(name);
|
kfree(name);
|
||||||
|
name = NULL;
|
||||||
if (log_ref_ver) {
|
if (log_ref_ver) {
|
||||||
iput(dir);
|
iput(dir);
|
||||||
dir = NULL;
|
dir = NULL;
|
||||||
|
@ -1225,6 +1228,7 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
|
||||||
ret = overwrite_item(trans, root, path, eb, slot, key);
|
ret = overwrite_item(trans, root, path, eb, slot, key);
|
||||||
out:
|
out:
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
kfree(name);
|
||||||
iput(dir);
|
iput(dir);
|
||||||
iput(inode);
|
iput(inode);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1307,6 +1311,7 @@ static int count_inode_refs(struct btrfs_root *root,
|
||||||
break;
|
break;
|
||||||
path->slots[0]--;
|
path->slots[0]--;
|
||||||
}
|
}
|
||||||
|
process_slot:
|
||||||
btrfs_item_key_to_cpu(path->nodes[0], &key,
|
btrfs_item_key_to_cpu(path->nodes[0], &key,
|
||||||
path->slots[0]);
|
path->slots[0]);
|
||||||
if (key.objectid != ino ||
|
if (key.objectid != ino ||
|
||||||
|
@ -1327,6 +1332,10 @@ static int count_inode_refs(struct btrfs_root *root,
|
||||||
|
|
||||||
if (key.offset == 0)
|
if (key.offset == 0)
|
||||||
break;
|
break;
|
||||||
|
if (path->slots[0] > 0) {
|
||||||
|
path->slots[0]--;
|
||||||
|
goto process_slot;
|
||||||
|
}
|
||||||
key.offset--;
|
key.offset--;
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
}
|
}
|
||||||
|
@ -1480,7 +1489,7 @@ static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans,
|
||||||
if (!inode->i_nlink)
|
if (!inode->i_nlink)
|
||||||
set_nlink(inode, 1);
|
set_nlink(inode, 1);
|
||||||
else
|
else
|
||||||
btrfs_inc_nlink(inode);
|
inc_nlink(inode);
|
||||||
ret = btrfs_update_inode(trans, root, inode);
|
ret = btrfs_update_inode(trans, root, inode);
|
||||||
} else if (ret == -EEXIST) {
|
} else if (ret == -EEXIST) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -1823,7 +1832,7 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
|
||||||
dir_key->offset,
|
dir_key->offset,
|
||||||
name, name_len, 0);
|
name, name_len, 0);
|
||||||
}
|
}
|
||||||
if (IS_ERR_OR_NULL(log_di)) {
|
if (!log_di || (IS_ERR(log_di) && PTR_ERR(log_di) == -ENOENT)) {
|
||||||
btrfs_dir_item_key_to_cpu(eb, di, &location);
|
btrfs_dir_item_key_to_cpu(eb, di, &location);
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
btrfs_release_path(log_path);
|
btrfs_release_path(log_path);
|
||||||
|
@ -1841,7 +1850,7 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_inc_nlink(inode);
|
inc_nlink(inode);
|
||||||
ret = btrfs_unlink_inode(trans, root, dir, inode,
|
ret = btrfs_unlink_inode(trans, root, dir, inode,
|
||||||
name, name_len);
|
name, name_len);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
@ -1860,6 +1869,9 @@ static noinline int check_item_in_log(struct btrfs_trans_handle *trans,
|
||||||
goto again;
|
goto again;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto out;
|
goto out;
|
||||||
|
} else if (IS_ERR(log_di)) {
|
||||||
|
kfree(name);
|
||||||
|
return PTR_ERR(log_di);
|
||||||
}
|
}
|
||||||
btrfs_release_path(log_path);
|
btrfs_release_path(log_path);
|
||||||
kfree(name);
|
kfree(name);
|
||||||
|
@ -2118,8 +2130,7 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
|
||||||
WARN_ON(*level >= BTRFS_MAX_LEVEL);
|
WARN_ON(*level >= BTRFS_MAX_LEVEL);
|
||||||
cur = path->nodes[*level];
|
cur = path->nodes[*level];
|
||||||
|
|
||||||
if (btrfs_header_level(cur) != *level)
|
WARN_ON(btrfs_header_level(cur) != *level);
|
||||||
WARN_ON(1);
|
|
||||||
|
|
||||||
if (path->slots[*level] >=
|
if (path->slots[*level] >=
|
||||||
btrfs_header_nritems(cur))
|
btrfs_header_nritems(cur))
|
||||||
|
@ -2151,11 +2162,13 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_tree_lock(next);
|
if (trans) {
|
||||||
btrfs_set_lock_blocking(next);
|
btrfs_tree_lock(next);
|
||||||
clean_tree_block(trans, root, next);
|
btrfs_set_lock_blocking(next);
|
||||||
btrfs_wait_tree_block_writeback(next);
|
clean_tree_block(trans, root, next);
|
||||||
btrfs_tree_unlock(next);
|
btrfs_wait_tree_block_writeback(next);
|
||||||
|
btrfs_tree_unlock(next);
|
||||||
|
}
|
||||||
|
|
||||||
WARN_ON(root_owner !=
|
WARN_ON(root_owner !=
|
||||||
BTRFS_TREE_LOG_OBJECTID);
|
BTRFS_TREE_LOG_OBJECTID);
|
||||||
|
@ -2227,11 +2240,13 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
next = path->nodes[*level];
|
next = path->nodes[*level];
|
||||||
|
|
||||||
btrfs_tree_lock(next);
|
if (trans) {
|
||||||
btrfs_set_lock_blocking(next);
|
btrfs_tree_lock(next);
|
||||||
clean_tree_block(trans, root, next);
|
btrfs_set_lock_blocking(next);
|
||||||
btrfs_wait_tree_block_writeback(next);
|
clean_tree_block(trans, root, next);
|
||||||
btrfs_tree_unlock(next);
|
btrfs_wait_tree_block_writeback(next);
|
||||||
|
btrfs_tree_unlock(next);
|
||||||
|
}
|
||||||
|
|
||||||
WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
|
WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
|
||||||
ret = btrfs_free_and_pin_reserved_extent(root,
|
ret = btrfs_free_and_pin_reserved_extent(root,
|
||||||
|
@ -2301,11 +2316,13 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
next = path->nodes[orig_level];
|
next = path->nodes[orig_level];
|
||||||
|
|
||||||
btrfs_tree_lock(next);
|
if (trans) {
|
||||||
btrfs_set_lock_blocking(next);
|
btrfs_tree_lock(next);
|
||||||
clean_tree_block(trans, log, next);
|
btrfs_set_lock_blocking(next);
|
||||||
btrfs_wait_tree_block_writeback(next);
|
clean_tree_block(trans, log, next);
|
||||||
btrfs_tree_unlock(next);
|
btrfs_wait_tree_block_writeback(next);
|
||||||
|
btrfs_tree_unlock(next);
|
||||||
|
}
|
||||||
|
|
||||||
WARN_ON(log->root_key.objectid !=
|
WARN_ON(log->root_key.objectid !=
|
||||||
BTRFS_TREE_LOG_OBJECTID);
|
BTRFS_TREE_LOG_OBJECTID);
|
||||||
|
@ -2571,9 +2588,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
||||||
* the running transaction open, so a full commit can't hop
|
* the running transaction open, so a full commit can't hop
|
||||||
* in and cause problems either.
|
* in and cause problems either.
|
||||||
*/
|
*/
|
||||||
btrfs_scrub_pause_super(root);
|
|
||||||
ret = write_ctree_super(trans, root->fs_info->tree_root, 1);
|
ret = write_ctree_super(trans, root->fs_info->tree_root, 1);
|
||||||
btrfs_scrub_continue_super(root);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
btrfs_abort_transaction(trans, root, ret);
|
btrfs_abort_transaction(trans, root, ret);
|
||||||
goto out_wake_log_root;
|
goto out_wake_log_root;
|
||||||
|
@ -2608,13 +2623,10 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
|
||||||
.process_func = process_one_buffer
|
.process_func = process_one_buffer
|
||||||
};
|
};
|
||||||
|
|
||||||
if (trans) {
|
ret = walk_log_tree(trans, log, &wc);
|
||||||
ret = walk_log_tree(trans, log, &wc);
|
/* I don't think this can happen but just in case */
|
||||||
|
if (ret)
|
||||||
/* I don't think this can happen but just in case */
|
btrfs_abort_transaction(trans, log, ret);
|
||||||
if (ret)
|
|
||||||
btrfs_abort_transaction(trans, log, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = find_first_extent_bit(&log->dirty_log_pages,
|
ret = find_first_extent_bit(&log->dirty_log_pages,
|
||||||
|
@ -2867,7 +2879,6 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
|
||||||
u64 min_offset, u64 *last_offset_ret)
|
u64 min_offset, u64 *last_offset_ret)
|
||||||
{
|
{
|
||||||
struct btrfs_key min_key;
|
struct btrfs_key min_key;
|
||||||
struct btrfs_key max_key;
|
|
||||||
struct btrfs_root *log = root->log_root;
|
struct btrfs_root *log = root->log_root;
|
||||||
struct extent_buffer *src;
|
struct extent_buffer *src;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
@ -2879,9 +2890,6 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
|
||||||
u64 ino = btrfs_ino(inode);
|
u64 ino = btrfs_ino(inode);
|
||||||
|
|
||||||
log = root->log_root;
|
log = root->log_root;
|
||||||
max_key.objectid = ino;
|
|
||||||
max_key.offset = (u64)-1;
|
|
||||||
max_key.type = key_type;
|
|
||||||
|
|
||||||
min_key.objectid = ino;
|
min_key.objectid = ino;
|
||||||
min_key.type = key_type;
|
min_key.type = key_type;
|
||||||
|
@ -2889,8 +2897,7 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
path->keep_locks = 1;
|
path->keep_locks = 1;
|
||||||
|
|
||||||
ret = btrfs_search_forward(root, &min_key, &max_key,
|
ret = btrfs_search_forward(root, &min_key, path, trans->transid);
|
||||||
path, trans->transid);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we didn't find anything from this transaction, see if there
|
* we didn't find anything from this transaction, see if there
|
||||||
|
@ -2943,10 +2950,8 @@ static noinline int log_dir_items(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
/* find the first key from this transaction again */
|
/* find the first key from this transaction again */
|
||||||
ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0);
|
ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0);
|
||||||
if (ret != 0) {
|
if (WARN_ON(ret != 0))
|
||||||
WARN_ON(1);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we have a block from this transaction, log every item in it
|
* we have a block from this transaction, log every item in it
|
||||||
|
@ -3172,11 +3177,10 @@ static int log_inode_item(struct btrfs_trans_handle *trans,
|
||||||
struct inode *inode)
|
struct inode *inode)
|
||||||
{
|
{
|
||||||
struct btrfs_inode_item *inode_item;
|
struct btrfs_inode_item *inode_item;
|
||||||
struct btrfs_key key;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memcpy(&key, &BTRFS_I(inode)->location, sizeof(key));
|
ret = btrfs_insert_empty_item(trans, log, path,
|
||||||
ret = btrfs_insert_empty_item(trans, log, path, &key,
|
&BTRFS_I(inode)->location,
|
||||||
sizeof(*inode_item));
|
sizeof(*inode_item));
|
||||||
if (ret && ret != -EEXIST)
|
if (ret && ret != -EEXIST)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -3375,7 +3379,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
|
||||||
btrfs_set_token_file_extent_type(leaf, fi,
|
btrfs_set_token_file_extent_type(leaf, fi,
|
||||||
BTRFS_FILE_EXTENT_REG,
|
BTRFS_FILE_EXTENT_REG,
|
||||||
&token);
|
&token);
|
||||||
if (em->block_start == 0)
|
if (em->block_start == EXTENT_MAP_HOLE)
|
||||||
skip_csum = true;
|
skip_csum = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3417,11 +3421,6 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
|
||||||
if (skip_csum)
|
if (skip_csum)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (em->compress_type) {
|
|
||||||
csum_offset = 0;
|
|
||||||
csum_len = block_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First check and see if our csums are on our outstanding ordered
|
* First check and see if our csums are on our outstanding ordered
|
||||||
* extents.
|
* extents.
|
||||||
|
@ -3505,8 +3504,13 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
|
||||||
if (!mod_len || ret)
|
if (!mod_len || ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
csum_offset = mod_start - em->start;
|
if (em->compress_type) {
|
||||||
csum_len = mod_len;
|
csum_offset = 0;
|
||||||
|
csum_len = block_len;
|
||||||
|
} else {
|
||||||
|
csum_offset = mod_start - em->start;
|
||||||
|
csum_len = mod_len;
|
||||||
|
}
|
||||||
|
|
||||||
/* block start is already adjusted for the file extent offset. */
|
/* block start is already adjusted for the file extent offset. */
|
||||||
ret = btrfs_lookup_csums_range(log->fs_info->csum_root,
|
ret = btrfs_lookup_csums_range(log->fs_info->csum_root,
|
||||||
|
@ -3719,7 +3723,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ins_nr = 0;
|
ins_nr = 0;
|
||||||
ret = btrfs_search_forward(root, &min_key, &max_key,
|
ret = btrfs_search_forward(root, &min_key,
|
||||||
path, trans->transid);
|
path, trans->transid);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
break;
|
break;
|
||||||
|
@ -3769,14 +3773,14 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
|
||||||
}
|
}
|
||||||
btrfs_release_path(path);
|
btrfs_release_path(path);
|
||||||
|
|
||||||
if (min_key.offset < (u64)-1)
|
if (min_key.offset < (u64)-1) {
|
||||||
min_key.offset++;
|
min_key.offset++;
|
||||||
else if (min_key.type < (u8)-1)
|
} else if (min_key.type < max_key.type) {
|
||||||
min_key.type++;
|
min_key.type++;
|
||||||
else if (min_key.objectid < (u64)-1)
|
min_key.offset = 0;
|
||||||
min_key.objectid++;
|
} else {
|
||||||
else
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ins_nr) {
|
if (ins_nr) {
|
||||||
ret = copy_items(trans, inode, dst_path, src, ins_start_slot,
|
ret = copy_items(trans, inode, dst_path, src, ins_start_slot,
|
||||||
|
|
|
@ -260,7 +260,6 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
|
||||||
{
|
{
|
||||||
struct btrfs_root *root = fs_info->uuid_root;
|
struct btrfs_root *root = fs_info->uuid_root;
|
||||||
struct btrfs_key key;
|
struct btrfs_key key;
|
||||||
struct btrfs_key max_key;
|
|
||||||
struct btrfs_path *path;
|
struct btrfs_path *path;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct extent_buffer *leaf;
|
struct extent_buffer *leaf;
|
||||||
|
@ -277,13 +276,10 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
|
||||||
key.objectid = 0;
|
key.objectid = 0;
|
||||||
key.type = 0;
|
key.type = 0;
|
||||||
key.offset = 0;
|
key.offset = 0;
|
||||||
max_key.objectid = (u64)-1;
|
|
||||||
max_key.type = (u8)-1;
|
|
||||||
max_key.offset = (u64)-1;
|
|
||||||
|
|
||||||
again_search_slot:
|
again_search_slot:
|
||||||
path->keep_locks = 1;
|
path->keep_locks = 1;
|
||||||
ret = btrfs_search_forward(root, &key, &max_key, path, 0);
|
ret = btrfs_search_forward(root, &key, path, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
#include <linux/raid/pq.h>
|
#include <linux/raid/pq.h>
|
||||||
#include <linux/semaphore.h>
|
#include <linux/semaphore.h>
|
||||||
#include <asm/div64.h>
|
#include <asm/div64.h>
|
||||||
#include "compat.h"
|
|
||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "extent_map.h"
|
#include "extent_map.h"
|
||||||
#include "disk-io.h"
|
#include "disk-io.h"
|
||||||
|
@ -666,7 +665,8 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
|
||||||
if (device->bdev)
|
if (device->bdev)
|
||||||
fs_devices->open_devices--;
|
fs_devices->open_devices--;
|
||||||
|
|
||||||
if (device->writeable && !device->is_tgtdev_for_dev_replace) {
|
if (device->writeable &&
|
||||||
|
device->devid != BTRFS_DEV_REPLACE_DEVID) {
|
||||||
list_del_init(&device->dev_alloc_list);
|
list_del_init(&device->dev_alloc_list);
|
||||||
fs_devices->rw_devices--;
|
fs_devices->rw_devices--;
|
||||||
}
|
}
|
||||||
|
@ -2041,6 +2041,7 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
|
||||||
device->in_fs_metadata = 1;
|
device->in_fs_metadata = 1;
|
||||||
device->is_tgtdev_for_dev_replace = 0;
|
device->is_tgtdev_for_dev_replace = 0;
|
||||||
device->mode = FMODE_EXCL;
|
device->mode = FMODE_EXCL;
|
||||||
|
device->dev_stats_valid = 1;
|
||||||
set_blocksize(device->bdev, 4096);
|
set_blocksize(device->bdev, 4096);
|
||||||
|
|
||||||
if (seeding_dev) {
|
if (seeding_dev) {
|
||||||
|
@ -2208,6 +2209,7 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
|
||||||
device->in_fs_metadata = 1;
|
device->in_fs_metadata = 1;
|
||||||
device->is_tgtdev_for_dev_replace = 1;
|
device->is_tgtdev_for_dev_replace = 1;
|
||||||
device->mode = FMODE_EXCL;
|
device->mode = FMODE_EXCL;
|
||||||
|
device->dev_stats_valid = 1;
|
||||||
set_blocksize(device->bdev, 4096);
|
set_blocksize(device->bdev, 4096);
|
||||||
device->fs_devices = fs_info->fs_devices;
|
device->fs_devices = fs_info->fs_devices;
|
||||||
list_add(&device->dev_list, &fs_info->fs_devices->devices);
|
list_add(&device->dev_list, &fs_info->fs_devices->devices);
|
||||||
|
@ -2550,8 +2552,7 @@ static int btrfs_relocate_sys_chunks(struct btrfs_root *root)
|
||||||
failed = 0;
|
failed = 0;
|
||||||
retried = true;
|
retried = true;
|
||||||
goto again;
|
goto again;
|
||||||
} else if (failed && retried) {
|
} else if (WARN_ON(failed && retried)) {
|
||||||
WARN_ON(1);
|
|
||||||
ret = -ENOSPC;
|
ret = -ENOSPC;
|
||||||
}
|
}
|
||||||
error:
|
error:
|
||||||
|
@ -3423,6 +3424,9 @@ int btrfs_pause_balance(struct btrfs_fs_info *fs_info)
|
||||||
|
|
||||||
int btrfs_cancel_balance(struct btrfs_fs_info *fs_info)
|
int btrfs_cancel_balance(struct btrfs_fs_info *fs_info)
|
||||||
{
|
{
|
||||||
|
if (fs_info->sb->s_flags & MS_RDONLY)
|
||||||
|
return -EROFS;
|
||||||
|
|
||||||
mutex_lock(&fs_info->balance_mutex);
|
mutex_lock(&fs_info->balance_mutex);
|
||||||
if (!fs_info->balance_ctl) {
|
if (!fs_info->balance_ctl) {
|
||||||
mutex_unlock(&fs_info->balance_mutex);
|
mutex_unlock(&fs_info->balance_mutex);
|
||||||
|
@ -3488,7 +3492,7 @@ static int btrfs_uuid_scan_kthread(void *data)
|
||||||
path->keep_locks = 1;
|
path->keep_locks = 1;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ret = btrfs_search_forward(root, &key, &max_key, path, 0);
|
ret = btrfs_search_forward(root, &key, path, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret > 0)
|
if (ret > 0)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -4488,6 +4492,7 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
|
||||||
btrfs_crit(fs_info, "Invalid mapping for %Lu-%Lu, got "
|
btrfs_crit(fs_info, "Invalid mapping for %Lu-%Lu, got "
|
||||||
"%Lu-%Lu\n", logical, logical+len, em->start,
|
"%Lu-%Lu\n", logical, logical+len, em->start,
|
||||||
em->start + em->len);
|
em->start + em->len);
|
||||||
|
free_extent_map(em);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4668,6 +4673,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
|
||||||
btrfs_crit(fs_info, "found a bad mapping, wanted %Lu, "
|
btrfs_crit(fs_info, "found a bad mapping, wanted %Lu, "
|
||||||
"found %Lu-%Lu\n", logical, em->start,
|
"found %Lu-%Lu\n", logical, em->start,
|
||||||
em->start + em->len);
|
em->start + em->len);
|
||||||
|
free_extent_map(em);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4895,7 +4901,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
|
||||||
num_stripes = map->num_stripes;
|
num_stripes = map->num_stripes;
|
||||||
max_errors = nr_parity_stripes(map);
|
max_errors = nr_parity_stripes(map);
|
||||||
|
|
||||||
raid_map = kmalloc(sizeof(u64) * num_stripes,
|
raid_map = kmalloc_array(num_stripes, sizeof(u64),
|
||||||
GFP_NOFS);
|
GFP_NOFS);
|
||||||
if (!raid_map) {
|
if (!raid_map) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
@ -5395,10 +5401,8 @@ static int bio_size_ok(struct block_device *bdev, struct bio *bio,
|
||||||
.bi_rw = bio->bi_rw,
|
.bi_rw = bio->bi_rw,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (bio->bi_vcnt == 0) {
|
if (WARN_ON(bio->bi_vcnt == 0))
|
||||||
WARN_ON(1);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
prev = &bio->bi_io_vec[bio->bi_vcnt - 1];
|
prev = &bio->bi_io_vec[bio->bi_vcnt - 1];
|
||||||
if (bio_sectors(bio) > max_sectors)
|
if (bio_sectors(bio) > max_sectors)
|
||||||
|
@ -5631,10 +5635,8 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
|
||||||
struct btrfs_device *dev;
|
struct btrfs_device *dev;
|
||||||
u64 tmp;
|
u64 tmp;
|
||||||
|
|
||||||
if (!devid && !fs_info) {
|
if (WARN_ON(!devid && !fs_info))
|
||||||
WARN_ON(1);
|
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
|
||||||
|
|
||||||
dev = __alloc_device();
|
dev = __alloc_device();
|
||||||
if (IS_ERR(dev))
|
if (IS_ERR(dev))
|
||||||
|
|
|
@ -43,9 +43,8 @@ struct btrfs_device {
|
||||||
/* WRITE_SYNC bios */
|
/* WRITE_SYNC bios */
|
||||||
struct btrfs_pending_bios pending_sync_bios;
|
struct btrfs_pending_bios pending_sync_bios;
|
||||||
|
|
||||||
int running_pending;
|
|
||||||
u64 generation;
|
u64 generation;
|
||||||
|
int running_pending;
|
||||||
int writeable;
|
int writeable;
|
||||||
int in_fs_metadata;
|
int in_fs_metadata;
|
||||||
int missing;
|
int missing;
|
||||||
|
@ -53,11 +52,11 @@ struct btrfs_device {
|
||||||
int is_tgtdev_for_dev_replace;
|
int is_tgtdev_for_dev_replace;
|
||||||
|
|
||||||
spinlock_t io_lock;
|
spinlock_t io_lock;
|
||||||
|
/* the mode sent to blkdev_get */
|
||||||
|
fmode_t mode;
|
||||||
|
|
||||||
struct block_device *bdev;
|
struct block_device *bdev;
|
||||||
|
|
||||||
/* the mode sent to blkdev_get */
|
|
||||||
fmode_t mode;
|
|
||||||
|
|
||||||
struct rcu_string *name;
|
struct rcu_string *name;
|
||||||
|
|
||||||
|
@ -78,16 +77,21 @@ struct btrfs_device {
|
||||||
|
|
||||||
/* optimal io width for this device */
|
/* optimal io width for this device */
|
||||||
u32 io_width;
|
u32 io_width;
|
||||||
|
/* type and info about this device */
|
||||||
|
u64 type;
|
||||||
|
|
||||||
/* minimal io size for this device */
|
/* minimal io size for this device */
|
||||||
u32 sector_size;
|
u32 sector_size;
|
||||||
|
|
||||||
/* type and info about this device */
|
|
||||||
u64 type;
|
|
||||||
|
|
||||||
/* physical drive uuid (or lvm uuid) */
|
/* physical drive uuid (or lvm uuid) */
|
||||||
u8 uuid[BTRFS_UUID_SIZE];
|
u8 uuid[BTRFS_UUID_SIZE];
|
||||||
|
|
||||||
|
/* for sending down flush barriers */
|
||||||
|
int nobarriers;
|
||||||
|
struct bio *flush_bio;
|
||||||
|
struct completion flush_wait;
|
||||||
|
|
||||||
/* per-device scrub information */
|
/* per-device scrub information */
|
||||||
struct scrub_ctx *scrub_device;
|
struct scrub_ctx *scrub_device;
|
||||||
|
|
||||||
|
@ -103,10 +107,6 @@ struct btrfs_device {
|
||||||
struct radix_tree_root reada_zones;
|
struct radix_tree_root reada_zones;
|
||||||
struct radix_tree_root reada_extents;
|
struct radix_tree_root reada_extents;
|
||||||
|
|
||||||
/* for sending down flush barriers */
|
|
||||||
struct bio *flush_bio;
|
|
||||||
struct completion flush_wait;
|
|
||||||
int nobarriers;
|
|
||||||
|
|
||||||
/* disk I/O failure stats. For detailed description refer to
|
/* disk I/O failure stats. For detailed description refer to
|
||||||
* enum btrfs_dev_stat_values in ioctl.h */
|
* enum btrfs_dev_stat_values in ioctl.h */
|
||||||
|
@ -132,7 +132,9 @@ struct btrfs_fs_devices {
|
||||||
|
|
||||||
/* all of the devices in the FS, protected by a mutex
|
/* all of the devices in the FS, protected by a mutex
|
||||||
* so we can safely walk it to write out the supers without
|
* so we can safely walk it to write out the supers without
|
||||||
* worrying about add/remove by the multi-device code
|
* worrying about add/remove by the multi-device code.
|
||||||
|
* Scrubbing super can kick off supers writing by holding
|
||||||
|
* this mutex lock.
|
||||||
*/
|
*/
|
||||||
struct mutex device_list_mutex;
|
struct mutex device_list_mutex;
|
||||||
struct list_head devices;
|
struct list_head devices;
|
||||||
|
|
|
@ -71,6 +71,6 @@
|
||||||
#define USBDEVICE_SUPER_MAGIC 0x9fa2
|
#define USBDEVICE_SUPER_MAGIC 0x9fa2
|
||||||
#define MTD_INODE_FS_MAGIC 0x11307854
|
#define MTD_INODE_FS_MAGIC 0x11307854
|
||||||
#define ANON_INODE_FS_MAGIC 0x09041934
|
#define ANON_INODE_FS_MAGIC 0x09041934
|
||||||
|
#define BTRFS_TEST_MAGIC 0x73727279
|
||||||
|
|
||||||
#endif /* __LINUX_MAGIC_H__ */
|
#endif /* __LINUX_MAGIC_H__ */
|
||||||
|
|
Loading…
Reference in a new issue