You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull btrfs update from Chris Mason: "A big set of fixes and features. In terms of line count, most of the code comes from Stefan, who added the ability to replace a single drive in place. This is different from how btrfs normally replaces drives, and is much much much faster. Josef is plowing through our synchronous write performance. This pull request does not include the DIO_OWN_WAITING patch that was discussed on the list, but it has a number of other improvements to cut down our latencies and CPU time during fsync/O_DIRECT writes. Miao Xie has a big series of fixes and is spreading out ordered operations over more CPUs. This improves performance and reduces contention. I've put in fixes for error handling around hash collisions. These are going back to individual stable kernels as I test against them. Otherwise we have a lot of fixes and cleanups, thanks everyone! raid5/6 is being rebased against the device replacement code. I'll have it posted this Friday along with a nice series of benchmarks." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (115 commits) Btrfs: fix a bug of per-file nocow Btrfs: fix hash overflow handling Btrfs: don't take inode delalloc mutex if we're a free space inode Btrfs: fix autodefrag and umount lockup Btrfs: fix permissions of empty files not affected by umask Btrfs: put raid properties into global table Btrfs: fix BUG() in scrub when first superblock reading gives EIO Btrfs: do not call file_update_time in aio_write Btrfs: only unlock and relock if we have to Btrfs: use tokens where we can in the tree log Btrfs: optimize leaf_space_used Btrfs: don't memset new tokens Btrfs: only clear dirty on the buffer if it is marked as dirty Btrfs: move checks in set_page_dirty under DEBUG Btrfs: log changed inodes based on the extent map tree Btrfs: add path->really_keep_locks Btrfs: do not mark ems as prealloc if we are writing to them Btrfs: keep track of the extents original block length Btrfs: inline csums if we're fsyncing Btrfs: don't bother copying if we're only logging the inode ...
This commit is contained in:
+1
-1
@@ -8,7 +8,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
|
||||
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
|
||||
export.o tree-log.o free-space-cache.o zlib.o lzo.o \
|
||||
compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
|
||||
reada.o backref.o ulist.o qgroup.o send.o
|
||||
reada.o backref.o ulist.o qgroup.o send.o dev-replace.o
|
||||
|
||||
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
|
||||
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
|
||||
|
||||
@@ -121,6 +121,8 @@ static int btrfs_set_acl(struct btrfs_trans_handle *trans,
|
||||
ret = posix_acl_equiv_mode(acl, &inode->i_mode);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret == 0)
|
||||
acl = NULL;
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
+12
-4
@@ -461,6 +461,7 @@ static int __merge_refs(struct list_head *head, int mode)
|
||||
pos2 = n2, n2 = pos2->next) {
|
||||
struct __prelim_ref *ref2;
|
||||
struct __prelim_ref *xchg;
|
||||
struct extent_inode_elem *eie;
|
||||
|
||||
ref2 = list_entry(pos2, struct __prelim_ref, list);
|
||||
|
||||
@@ -472,12 +473,20 @@ static int __merge_refs(struct list_head *head, int mode)
|
||||
ref1 = ref2;
|
||||
ref2 = xchg;
|
||||
}
|
||||
ref1->count += ref2->count;
|
||||
} else {
|
||||
if (ref1->parent != ref2->parent)
|
||||
continue;
|
||||
ref1->count += ref2->count;
|
||||
}
|
||||
|
||||
eie = ref1->inode_list;
|
||||
while (eie && eie->next)
|
||||
eie = eie->next;
|
||||
if (eie)
|
||||
eie->next = ref2->inode_list;
|
||||
else
|
||||
ref1->inode_list = ref2->inode_list;
|
||||
ref1->count += ref2->count;
|
||||
|
||||
list_del(&ref2->list);
|
||||
kfree(ref2);
|
||||
}
|
||||
@@ -890,8 +899,7 @@ again:
|
||||
while (!list_empty(&prefs)) {
|
||||
ref = list_first_entry(&prefs, struct __prelim_ref, list);
|
||||
list_del(&ref->list);
|
||||
if (ref->count < 0)
|
||||
WARN_ON(1);
|
||||
WARN_ON(ref->count < 0);
|
||||
if (ref->count && ref->root_id && ref->parent == 0) {
|
||||
/* no parent == root of tree */
|
||||
ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS);
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#define BTRFS_INODE_HAS_ORPHAN_ITEM 5
|
||||
#define BTRFS_INODE_HAS_ASYNC_EXTENT 6
|
||||
#define BTRFS_INODE_NEEDS_FULL_SYNC 7
|
||||
#define BTRFS_INODE_COPY_EVERYTHING 8
|
||||
|
||||
/* in memory btrfs inode */
|
||||
struct btrfs_inode {
|
||||
@@ -90,6 +91,9 @@ struct btrfs_inode {
|
||||
|
||||
unsigned long runtime_flags;
|
||||
|
||||
/* Keep track of who's O_SYNC/fsycing currently */
|
||||
atomic_t sync_writers;
|
||||
|
||||
/* full 64 bit generation number, struct vfs_inode doesn't have a big
|
||||
* enough field for this.
|
||||
*/
|
||||
|
||||
+21
-10
@@ -137,7 +137,7 @@ struct btrfsic_block {
|
||||
unsigned int never_written:1; /* block was added because it was
|
||||
* referenced, not because it was
|
||||
* written */
|
||||
unsigned int mirror_num:2; /* large enough to hold
|
||||
unsigned int mirror_num; /* large enough to hold
|
||||
* BTRFS_SUPER_MIRROR_MAX */
|
||||
struct btrfsic_dev_state *dev_state;
|
||||
u64 dev_bytenr; /* key, physical byte num on disk */
|
||||
@@ -723,7 +723,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
|
||||
}
|
||||
|
||||
num_copies =
|
||||
btrfs_num_copies(&state->root->fs_info->mapping_tree,
|
||||
btrfs_num_copies(state->root->fs_info,
|
||||
next_bytenr, state->metablock_size);
|
||||
if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
|
||||
printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
|
||||
@@ -903,7 +903,7 @@ static int btrfsic_process_superblock_dev_mirror(
|
||||
}
|
||||
|
||||
num_copies =
|
||||
btrfs_num_copies(&state->root->fs_info->mapping_tree,
|
||||
btrfs_num_copies(state->root->fs_info,
|
||||
next_bytenr, state->metablock_size);
|
||||
if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
|
||||
printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
|
||||
@@ -1287,7 +1287,7 @@ static int btrfsic_create_link_to_next_block(
|
||||
*next_blockp = NULL;
|
||||
if (0 == *num_copiesp) {
|
||||
*num_copiesp =
|
||||
btrfs_num_copies(&state->root->fs_info->mapping_tree,
|
||||
btrfs_num_copies(state->root->fs_info,
|
||||
next_bytenr, state->metablock_size);
|
||||
if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
|
||||
printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
|
||||
@@ -1489,7 +1489,7 @@ static int btrfsic_handle_extent_data(
|
||||
chunk_len = num_bytes;
|
||||
|
||||
num_copies =
|
||||
btrfs_num_copies(&state->root->fs_info->mapping_tree,
|
||||
btrfs_num_copies(state->root->fs_info,
|
||||
next_bytenr, state->datablock_size);
|
||||
if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
|
||||
printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
|
||||
@@ -1582,9 +1582,21 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len,
|
||||
struct btrfs_device *device;
|
||||
|
||||
length = len;
|
||||
ret = btrfs_map_block(&state->root->fs_info->mapping_tree, READ,
|
||||
ret = btrfs_map_block(state->root->fs_info, READ,
|
||||
bytenr, &length, &multi, mirror_num);
|
||||
|
||||
if (ret) {
|
||||
block_ctx_out->start = 0;
|
||||
block_ctx_out->dev_bytenr = 0;
|
||||
block_ctx_out->len = 0;
|
||||
block_ctx_out->dev = NULL;
|
||||
block_ctx_out->datav = NULL;
|
||||
block_ctx_out->pagev = NULL;
|
||||
block_ctx_out->mem_to_free = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
device = multi->stripes[0].dev;
|
||||
block_ctx_out->dev = btrfsic_dev_state_lookup(device->bdev);
|
||||
block_ctx_out->dev_bytenr = multi->stripes[0].physical;
|
||||
@@ -1594,8 +1606,7 @@ static int btrfsic_map_block(struct btrfsic_state *state, u64 bytenr, u32 len,
|
||||
block_ctx_out->pagev = NULL;
|
||||
block_ctx_out->mem_to_free = NULL;
|
||||
|
||||
if (0 == ret)
|
||||
kfree(multi);
|
||||
kfree(multi);
|
||||
if (NULL == block_ctx_out->dev) {
|
||||
ret = -ENXIO;
|
||||
printk(KERN_INFO "btrfsic: error, cannot lookup dev (#1)!\n");
|
||||
@@ -2463,7 +2474,7 @@ static int btrfsic_process_written_superblock(
|
||||
}
|
||||
|
||||
num_copies =
|
||||
btrfs_num_copies(&state->root->fs_info->mapping_tree,
|
||||
btrfs_num_copies(state->root->fs_info,
|
||||
next_bytenr, BTRFS_SUPER_INFO_SIZE);
|
||||
if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
|
||||
printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
|
||||
@@ -2960,7 +2971,7 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
|
||||
struct btrfsic_block_data_ctx block_ctx;
|
||||
int match = 0;
|
||||
|
||||
num_copies = btrfs_num_copies(&state->root->fs_info->mapping_tree,
|
||||
num_copies = btrfs_num_copies(state->root->fs_info,
|
||||
bytenr, state->metablock_size);
|
||||
|
||||
for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
|
||||
|
||||
@@ -687,7 +687,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
||||
|
||||
ret = btrfs_map_bio(root, READ, comp_bio,
|
||||
mirror_num, 0);
|
||||
BUG_ON(ret); /* -ENOMEM */
|
||||
if (ret)
|
||||
bio_endio(comp_bio, ret);
|
||||
|
||||
bio_put(comp_bio);
|
||||
|
||||
@@ -712,7 +713,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
||||
}
|
||||
|
||||
ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0);
|
||||
BUG_ON(ret); /* -ENOMEM */
|
||||
if (ret)
|
||||
bio_endio(comp_bio, ret);
|
||||
|
||||
bio_put(comp_bio);
|
||||
return 0;
|
||||
|
||||
+189
-52
@@ -38,8 +38,7 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
|
||||
struct extent_buffer *dst_buf,
|
||||
struct extent_buffer *src_buf);
|
||||
static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_path *path, int level, int slot,
|
||||
int tree_mod_log);
|
||||
struct btrfs_path *path, int level, int slot);
|
||||
static void tree_mod_log_free_eb(struct btrfs_fs_info *fs_info,
|
||||
struct extent_buffer *eb);
|
||||
struct extent_buffer *read_old_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
@@ -776,8 +775,7 @@ tree_mod_log_eb_move(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
|
||||
|
||||
static noinline void
|
||||
tree_mod_log_set_node_key(struct btrfs_fs_info *fs_info,
|
||||
struct extent_buffer *eb,
|
||||
struct btrfs_disk_key *disk_key, int slot, int atomic)
|
||||
struct extent_buffer *eb, int slot, int atomic)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -1140,13 +1138,13 @@ __tree_mod_log_rewind(struct extent_buffer *eb, u64 time_seq,
|
||||
switch (tm->op) {
|
||||
case MOD_LOG_KEY_REMOVE_WHILE_FREEING:
|
||||
BUG_ON(tm->slot < n);
|
||||
case MOD_LOG_KEY_REMOVE_WHILE_MOVING:
|
||||
case MOD_LOG_KEY_REMOVE:
|
||||
n++;
|
||||
case MOD_LOG_KEY_REMOVE_WHILE_MOVING:
|
||||
btrfs_set_node_key(eb, &tm->key, tm->slot);
|
||||
btrfs_set_node_blockptr(eb, tm->slot, tm->blockptr);
|
||||
btrfs_set_node_ptr_generation(eb, tm->slot,
|
||||
tm->generation);
|
||||
n++;
|
||||
break;
|
||||
case MOD_LOG_KEY_REPLACE:
|
||||
BUG_ON(tm->slot >= n);
|
||||
@@ -1361,19 +1359,16 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
|
||||
u64 search_start;
|
||||
int ret;
|
||||
|
||||
if (trans->transaction != root->fs_info->running_transaction) {
|
||||
printk(KERN_CRIT "trans %llu running %llu\n",
|
||||
if (trans->transaction != root->fs_info->running_transaction)
|
||||
WARN(1, KERN_CRIT "trans %llu running %llu\n",
|
||||
(unsigned long long)trans->transid,
|
||||
(unsigned long long)
|
||||
root->fs_info->running_transaction->transid);
|
||||
WARN_ON(1);
|
||||
}
|
||||
if (trans->transid != root->fs_info->generation) {
|
||||
printk(KERN_CRIT "trans %llu running %llu\n",
|
||||
|
||||
if (trans->transid != root->fs_info->generation)
|
||||
WARN(1, KERN_CRIT "trans %llu running %llu\n",
|
||||
(unsigned long long)trans->transid,
|
||||
(unsigned long long)root->fs_info->generation);
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
if (!should_cow_block(trans, root, buf)) {
|
||||
*cow_ret = buf;
|
||||
@@ -1469,10 +1464,8 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
|
||||
if (cache_only && parent_level != 1)
|
||||
return 0;
|
||||
|
||||
if (trans->transaction != root->fs_info->running_transaction)
|
||||
WARN_ON(1);
|
||||
if (trans->transid != root->fs_info->generation)
|
||||
WARN_ON(1);
|
||||
WARN_ON(trans->transaction != root->fs_info->running_transaction);
|
||||
WARN_ON(trans->transid != root->fs_info->generation);
|
||||
|
||||
parent_nritems = btrfs_header_nritems(parent);
|
||||
blocksize = btrfs_level_size(root, parent_level - 1);
|
||||
@@ -1827,7 +1820,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
||||
if (btrfs_header_nritems(right) == 0) {
|
||||
clean_tree_block(trans, root, right);
|
||||
btrfs_tree_unlock(right);
|
||||
del_ptr(trans, root, path, level + 1, pslot + 1, 1);
|
||||
del_ptr(trans, root, path, level + 1, pslot + 1);
|
||||
root_sub_used(root, right->len);
|
||||
btrfs_free_tree_block(trans, root, right, 0, 1);
|
||||
free_extent_buffer_stale(right);
|
||||
@@ -1836,7 +1829,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_disk_key right_key;
|
||||
btrfs_node_key(right, &right_key, 0);
|
||||
tree_mod_log_set_node_key(root->fs_info, parent,
|
||||
&right_key, pslot + 1, 0);
|
||||
pslot + 1, 0);
|
||||
btrfs_set_node_key(parent, &right_key, pslot + 1);
|
||||
btrfs_mark_buffer_dirty(parent);
|
||||
}
|
||||
@@ -1871,7 +1864,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
||||
if (btrfs_header_nritems(mid) == 0) {
|
||||
clean_tree_block(trans, root, mid);
|
||||
btrfs_tree_unlock(mid);
|
||||
del_ptr(trans, root, path, level + 1, pslot, 1);
|
||||
del_ptr(trans, root, path, level + 1, pslot);
|
||||
root_sub_used(root, mid->len);
|
||||
btrfs_free_tree_block(trans, root, mid, 0, 1);
|
||||
free_extent_buffer_stale(mid);
|
||||
@@ -1880,7 +1873,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
||||
/* update the parent key to reflect our changes */
|
||||
struct btrfs_disk_key mid_key;
|
||||
btrfs_node_key(mid, &mid_key, 0);
|
||||
tree_mod_log_set_node_key(root->fs_info, parent, &mid_key,
|
||||
tree_mod_log_set_node_key(root->fs_info, parent,
|
||||
pslot, 0);
|
||||
btrfs_set_node_key(parent, &mid_key, pslot);
|
||||
btrfs_mark_buffer_dirty(parent);
|
||||
@@ -1980,7 +1973,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
|
||||
orig_slot += left_nr;
|
||||
btrfs_node_key(mid, &disk_key, 0);
|
||||
tree_mod_log_set_node_key(root->fs_info, parent,
|
||||
&disk_key, pslot, 0);
|
||||
pslot, 0);
|
||||
btrfs_set_node_key(parent, &disk_key, pslot);
|
||||
btrfs_mark_buffer_dirty(parent);
|
||||
if (btrfs_header_nritems(left) > orig_slot) {
|
||||
@@ -2033,7 +2026,7 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
|
||||
|
||||
btrfs_node_key(right, &disk_key, 0);
|
||||
tree_mod_log_set_node_key(root->fs_info, parent,
|
||||
&disk_key, pslot + 1, 0);
|
||||
pslot + 1, 0);
|
||||
btrfs_set_node_key(parent, &disk_key, pslot + 1);
|
||||
btrfs_mark_buffer_dirty(parent);
|
||||
|
||||
@@ -2219,6 +2212,9 @@ static noinline void unlock_up(struct btrfs_path *path, int level,
|
||||
int no_skips = 0;
|
||||
struct extent_buffer *t;
|
||||
|
||||
if (path->really_keep_locks)
|
||||
return;
|
||||
|
||||
for (i = level; i < BTRFS_MAX_LEVEL; i++) {
|
||||
if (!path->nodes[i])
|
||||
break;
|
||||
@@ -2266,7 +2262,7 @@ noinline void btrfs_unlock_up_safe(struct btrfs_path *path, int level)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (path->keep_locks)
|
||||
if (path->keep_locks || path->really_keep_locks)
|
||||
return;
|
||||
|
||||
for (i = level; i < BTRFS_MAX_LEVEL; i++) {
|
||||
@@ -2499,7 +2495,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
if (!cow)
|
||||
write_lock_level = -1;
|
||||
|
||||
if (cow && (p->keep_locks || p->lowest_level))
|
||||
if (cow && (p->really_keep_locks || p->keep_locks || p->lowest_level))
|
||||
write_lock_level = BTRFS_MAX_LEVEL;
|
||||
|
||||
min_write_lock_level = write_lock_level;
|
||||
@@ -2568,7 +2564,10 @@ again:
|
||||
* must have write locks on this node and the
|
||||
* parent
|
||||
*/
|
||||
if (level + 1 > write_lock_level) {
|
||||
if (level > write_lock_level ||
|
||||
(level + 1 > write_lock_level &&
|
||||
level + 1 < BTRFS_MAX_LEVEL &&
|
||||
p->nodes[level + 1])) {
|
||||
write_lock_level = level + 1;
|
||||
btrfs_release_path(p);
|
||||
goto again;
|
||||
@@ -2917,7 +2916,7 @@ static void fixup_low_keys(struct btrfs_trans_handle *trans,
|
||||
if (!path->nodes[i])
|
||||
break;
|
||||
t = path->nodes[i];
|
||||
tree_mod_log_set_node_key(root->fs_info, t, key, tslot, 1);
|
||||
tree_mod_log_set_node_key(root->fs_info, t, tslot, 1);
|
||||
btrfs_set_node_key(t, key, tslot);
|
||||
btrfs_mark_buffer_dirty(path->nodes[i]);
|
||||
if (tslot != 0)
|
||||
@@ -3302,14 +3301,21 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
|
||||
*/
|
||||
static int leaf_space_used(struct extent_buffer *l, int start, int nr)
|
||||
{
|
||||
struct btrfs_item *start_item;
|
||||
struct btrfs_item *end_item;
|
||||
struct btrfs_map_token token;
|
||||
int data_len;
|
||||
int nritems = btrfs_header_nritems(l);
|
||||
int end = min(nritems, start + nr) - 1;
|
||||
|
||||
if (!nr)
|
||||
return 0;
|
||||
data_len = btrfs_item_end_nr(l, start);
|
||||
data_len = data_len - btrfs_item_offset_nr(l, end);
|
||||
btrfs_init_map_token(&token);
|
||||
start_item = btrfs_item_nr(l, start);
|
||||
end_item = btrfs_item_nr(l, end);
|
||||
data_len = btrfs_token_item_offset(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 += sizeof(struct btrfs_item) * nr;
|
||||
WARN_ON(data_len < 0);
|
||||
return data_len;
|
||||
@@ -3403,8 +3409,7 @@ static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
|
||||
if (push_items == 0)
|
||||
goto out_unlock;
|
||||
|
||||
if (!empty && push_items == left_nritems)
|
||||
WARN_ON(1);
|
||||
WARN_ON(!empty && push_items == left_nritems);
|
||||
|
||||
/* push left to right */
|
||||
right_nritems = btrfs_header_nritems(right);
|
||||
@@ -3642,11 +3647,9 @@ static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
|
||||
btrfs_set_header_nritems(left, old_left_nritems + push_items);
|
||||
|
||||
/* fixup right node */
|
||||
if (push_items > right_nritems) {
|
||||
printk(KERN_CRIT "push items %d nr %u\n", push_items,
|
||||
if (push_items > right_nritems)
|
||||
WARN(1, KERN_CRIT "push items %d nr %u\n", push_items,
|
||||
right_nritems);
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
if (push_items < right_nritems) {
|
||||
push_space = btrfs_item_offset_nr(right, push_items - 1) -
|
||||
@@ -4602,16 +4605,21 @@ int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
* empty a node.
|
||||
*/
|
||||
static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct btrfs_path *path, int level, int slot,
|
||||
int tree_mod_log)
|
||||
struct btrfs_path *path, int level, int slot)
|
||||
{
|
||||
struct extent_buffer *parent = path->nodes[level];
|
||||
u32 nritems;
|
||||
int ret;
|
||||
|
||||
if (level) {
|
||||
ret = tree_mod_log_insert_key(root->fs_info, parent, slot,
|
||||
MOD_LOG_KEY_REMOVE);
|
||||
BUG_ON(ret < 0);
|
||||
}
|
||||
|
||||
nritems = btrfs_header_nritems(parent);
|
||||
if (slot != nritems - 1) {
|
||||
if (tree_mod_log && level)
|
||||
if (level)
|
||||
tree_mod_log_eb_move(root->fs_info, parent, slot,
|
||||
slot + 1, nritems - slot - 1);
|
||||
memmove_extent_buffer(parent,
|
||||
@@ -4619,10 +4627,6 @@ static void del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
btrfs_node_key_ptr_offset(slot + 1),
|
||||
sizeof(struct btrfs_key_ptr) *
|
||||
(nritems - slot - 1));
|
||||
} else if (tree_mod_log && level) {
|
||||
ret = tree_mod_log_insert_key(root->fs_info, parent, slot,
|
||||
MOD_LOG_KEY_REMOVE);
|
||||
BUG_ON(ret < 0);
|
||||
}
|
||||
|
||||
nritems--;
|
||||
@@ -4656,7 +4660,7 @@ static noinline void btrfs_del_leaf(struct btrfs_trans_handle *trans,
|
||||
struct extent_buffer *leaf)
|
||||
{
|
||||
WARN_ON(btrfs_header_generation(leaf) != trans->transid);
|
||||
del_ptr(trans, root, path, 1, path->slots[1], 1);
|
||||
del_ptr(trans, root, path, 1, path->slots[1]);
|
||||
|
||||
/*
|
||||
* btrfs_free_extent is expensive, we want to make sure we
|
||||
@@ -5123,13 +5127,13 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
|
||||
right_path->search_commit_root = 1;
|
||||
right_path->skip_locking = 1;
|
||||
|
||||
spin_lock(&left_root->root_times_lock);
|
||||
spin_lock(&left_root->root_item_lock);
|
||||
left_start_ctransid = btrfs_root_ctransid(&left_root->root_item);
|
||||
spin_unlock(&left_root->root_times_lock);
|
||||
spin_unlock(&left_root->root_item_lock);
|
||||
|
||||
spin_lock(&right_root->root_times_lock);
|
||||
spin_lock(&right_root->root_item_lock);
|
||||
right_start_ctransid = btrfs_root_ctransid(&right_root->root_item);
|
||||
spin_unlock(&right_root->root_times_lock);
|
||||
spin_unlock(&right_root->root_item_lock);
|
||||
|
||||
trans = btrfs_join_transaction(left_root);
|
||||
if (IS_ERR(trans)) {
|
||||
@@ -5224,15 +5228,15 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock(&left_root->root_times_lock);
|
||||
spin_lock(&left_root->root_item_lock);
|
||||
ctransid = btrfs_root_ctransid(&left_root->root_item);
|
||||
spin_unlock(&left_root->root_times_lock);
|
||||
spin_unlock(&left_root->root_item_lock);
|
||||
if (ctransid != left_start_ctransid)
|
||||
left_start_ctransid = 0;
|
||||
|
||||
spin_lock(&right_root->root_times_lock);
|
||||
spin_lock(&right_root->root_item_lock);
|
||||
ctransid = btrfs_root_ctransid(&right_root->root_item);
|
||||
spin_unlock(&right_root->root_times_lock);
|
||||
spin_unlock(&right_root->root_item_lock);
|
||||
if (ctransid != right_start_ctransid)
|
||||
right_start_ctransid = 0;
|
||||
|
||||
@@ -5496,6 +5500,139 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
|
||||
return btrfs_next_old_leaf(root, path, 0);
|
||||
}
|
||||
|
||||
/* Release the path up to but not including the given level */
|
||||
static void btrfs_release_level(struct btrfs_path *path, int level)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < level; i++) {
|
||||
path->slots[i] = 0;
|
||||
if (!path->nodes[i])
|
||||
continue;
|
||||
if (path->locks[i]) {
|
||||
btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]);
|
||||
path->locks[i] = 0;
|
||||
}
|
||||
free_extent_buffer(path->nodes[i]);
|
||||
path->nodes[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function assumes 2 things
|
||||
*
|
||||
* 1) You are using path->keep_locks
|
||||
* 2) You are not inserting items.
|
||||
*
|
||||
* If either of these are not true do not use this function. If you need a next
|
||||
* leaf with either of these not being true then this function can be easily
|
||||
* adapted to do that, but at the moment these are the limitations.
|
||||
*/
|
||||
int btrfs_next_leaf_write(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_path *path,
|
||||
int del)
|
||||
{
|
||||
struct extent_buffer *b;
|
||||
struct btrfs_key key;
|
||||
u32 nritems;
|
||||
int level = 1;
|
||||
int slot;
|
||||
int ret = 1;
|
||||
int write_lock_level = BTRFS_MAX_LEVEL;
|
||||
int ins_len = del ? -1 : 0;
|
||||
|
||||
WARN_ON(!(path->keep_locks || path->really_keep_locks));
|
||||
|
||||
nritems = btrfs_header_nritems(path->nodes[0]);
|
||||
btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);
|
||||
|
||||
while (path->nodes[level]) {
|
||||
nritems = btrfs_header_nritems(path->nodes[level]);
|
||||
if (!(path->locks[level] & BTRFS_WRITE_LOCK)) {
|
||||
search:
|
||||
btrfs_release_path(path);
|
||||
ret = btrfs_search_slot(trans, root, &key, path,
|
||||
ins_len, 1);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
level = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (path->slots[level] >= nritems - 1) {
|
||||
level++;
|
||||
continue;
|
||||
}
|
||||
|
||||
btrfs_release_level(path, level);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!path->nodes[level]) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
path->slots[level]++;
|
||||
b = path->nodes[level];
|
||||
|
||||
while (b) {
|
||||
level = btrfs_header_level(b);
|
||||
|
||||
if (!should_cow_block(trans, root, b))
|
||||
goto cow_done;
|
||||
|
||||
btrfs_set_path_blocking(path);
|
||||
ret = btrfs_cow_block(trans, root, b,
|
||||
path->nodes[level + 1],
|
||||
path->slots[level + 1], &b);
|
||||
if (ret)
|
||||
goto out;
|
||||
cow_done:
|
||||
path->nodes[level] = b;
|
||||
btrfs_clear_path_blocking(path, NULL, 0);
|
||||
if (level != 0) {
|
||||
ret = setup_nodes_for_search(trans, root, path, b,
|
||||
level, ins_len,
|
||||
&write_lock_level);
|
||||
if (ret == -EAGAIN)
|
||||
goto search;
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
b = path->nodes[level];
|
||||
slot = path->slots[level];
|
||||
|
||||
ret = read_block_for_search(trans, root, path,
|
||||
&b, level, slot, &key, 0);
|
||||
if (ret == -EAGAIN)
|
||||
goto search;
|
||||
if (ret)
|
||||
goto out;
|
||||
level = btrfs_header_level(b);
|
||||
if (!btrfs_try_tree_write_lock(b)) {
|
||||
btrfs_set_path_blocking(path);
|
||||
btrfs_tree_lock(b);
|
||||
btrfs_clear_path_blocking(path, b,
|
||||
BTRFS_WRITE_LOCK);
|
||||
}
|
||||
path->locks[level] = BTRFS_WRITE_LOCK;
|
||||
path->nodes[level] = b;
|
||||
path->slots[level] = 0;
|
||||
} else {
|
||||
path->slots[level] = 0;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
btrfs_release_path(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
|
||||
u64 time_seq)
|
||||
{
|
||||
|
||||
+164
-18
@@ -48,7 +48,7 @@ struct btrfs_ordered_sum;
|
||||
|
||||
#define BTRFS_MAGIC "_BHRfS_M"
|
||||
|
||||
#define BTRFS_MAX_MIRRORS 2
|
||||
#define BTRFS_MAX_MIRRORS 3
|
||||
|
||||
#define BTRFS_MAX_LEVEL 8
|
||||
|
||||
@@ -142,6 +142,8 @@ struct btrfs_ordered_sum;
|
||||
|
||||
#define BTRFS_EMPTY_SUBVOL_DIR_OBJECTID 2
|
||||
|
||||
#define BTRFS_DEV_REPLACE_DEVID 0
|
||||
|
||||
/*
|
||||
* the max metadata block size. This limit is somewhat artificial,
|
||||
* but the memmove costs go through the roof for larger blocks.
|
||||
@@ -172,6 +174,9 @@ static int btrfs_csum_sizes[] = { 4, 0 };
|
||||
/* four bytes for CRC32 */
|
||||
#define BTRFS_EMPTY_DIR_SIZE 0
|
||||
|
||||
/* spefic to btrfs_map_block(), therefore not in include/linux/blk_types.h */
|
||||
#define REQ_GET_READ_MIRRORS (1 << 30)
|
||||
|
||||
#define BTRFS_FT_UNKNOWN 0
|
||||
#define BTRFS_FT_REG_FILE 1
|
||||
#define BTRFS_FT_DIR 2
|
||||
@@ -571,6 +576,7 @@ struct btrfs_path {
|
||||
unsigned int skip_locking:1;
|
||||
unsigned int leave_spinning:1;
|
||||
unsigned int search_commit_root:1;
|
||||
unsigned int really_keep_locks:1;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -885,6 +891,59 @@ struct btrfs_dev_stats_item {
|
||||
__le64 values[BTRFS_DEV_STAT_VALUES_MAX];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
#define BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_ALWAYS 0
|
||||
#define BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_AVOID 1
|
||||
#define BTRFS_DEV_REPLACE_ITEM_STATE_NEVER_STARTED 0
|
||||
#define BTRFS_DEV_REPLACE_ITEM_STATE_STARTED 1
|
||||
#define BTRFS_DEV_REPLACE_ITEM_STATE_SUSPENDED 2
|
||||
#define BTRFS_DEV_REPLACE_ITEM_STATE_FINISHED 3
|
||||
#define BTRFS_DEV_REPLACE_ITEM_STATE_CANCELED 4
|
||||
|
||||
struct btrfs_dev_replace {
|
||||
u64 replace_state; /* see #define above */
|
||||
u64 time_started; /* seconds since 1-Jan-1970 */
|
||||
u64 time_stopped; /* seconds since 1-Jan-1970 */
|
||||
atomic64_t num_write_errors;
|
||||
atomic64_t num_uncorrectable_read_errors;
|
||||
|
||||
u64 cursor_left;
|
||||
u64 committed_cursor_left;
|
||||
u64 cursor_left_last_write_of_item;
|
||||
u64 cursor_right;
|
||||
|
||||
u64 cont_reading_from_srcdev_mode; /* see #define above */
|
||||
|
||||
int is_valid;
|
||||
int item_needs_writeback;
|
||||
struct btrfs_device *srcdev;
|
||||
struct btrfs_device *tgtdev;
|
||||
|
||||
pid_t lock_owner;
|
||||
atomic_t nesting_level;
|
||||
struct mutex lock_finishing_cancel_unmount;
|
||||
struct mutex lock_management_lock;
|
||||
struct mutex lock;
|
||||
|
||||
struct btrfs_scrub_progress scrub_progress;
|
||||
};
|
||||
|
||||
struct btrfs_dev_replace_item {
|
||||
/*
|
||||
* grow this item struct at the end for future enhancements and keep
|
||||
* the existing values unchanged
|
||||
*/
|
||||
__le64 src_devid;
|
||||
__le64 cursor_left;
|
||||
__le64 cursor_right;
|
||||
__le64 cont_reading_from_srcdev_mode;
|
||||
|
||||
__le64 replace_state;
|
||||
__le64 time_started;
|
||||
__le64 time_stopped;
|
||||
__le64 num_write_errors;
|
||||
__le64 num_uncorrectable_read_errors;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/* different types of block groups (and chunks) */
|
||||
#define BTRFS_BLOCK_GROUP_DATA (1ULL << 0)
|
||||
#define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1)
|
||||
@@ -1333,6 +1392,7 @@ struct btrfs_fs_info {
|
||||
struct btrfs_workers generic_worker;
|
||||
struct btrfs_workers workers;
|
||||
struct btrfs_workers delalloc_workers;
|
||||
struct btrfs_workers flush_workers;
|
||||
struct btrfs_workers endio_workers;
|
||||
struct btrfs_workers endio_meta_workers;
|
||||
struct btrfs_workers endio_meta_write_workers;
|
||||
@@ -1429,6 +1489,8 @@ struct btrfs_fs_info {
|
||||
struct rw_semaphore scrub_super_lock;
|
||||
int scrub_workers_refcnt;
|
||||
struct btrfs_workers scrub_workers;
|
||||
struct btrfs_workers scrub_wr_completion_workers;
|
||||
struct btrfs_workers scrub_nocow_workers;
|
||||
|
||||
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
|
||||
u32 check_integrity_print_mask;
|
||||
@@ -1470,6 +1532,11 @@ struct btrfs_fs_info {
|
||||
int backup_root_index;
|
||||
|
||||
int num_tolerated_disk_barrier_failures;
|
||||
|
||||
/* device replace state */
|
||||
struct btrfs_dev_replace dev_replace;
|
||||
|
||||
atomic_t mutually_exclusive_operation_running;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1579,7 +1646,7 @@ struct btrfs_root {
|
||||
|
||||
int force_cow;
|
||||
|
||||
spinlock_t root_times_lock;
|
||||
spinlock_t root_item_lock;
|
||||
};
|
||||
|
||||
struct btrfs_ioctl_defrag_range_args {
|
||||
@@ -1722,6 +1789,12 @@ struct btrfs_ioctl_defrag_range_args {
|
||||
*/
|
||||
#define BTRFS_DEV_STATS_KEY 249
|
||||
|
||||
/*
|
||||
* Persistantly stores the device replace state in the device tree.
|
||||
* The key is built like this: (0, BTRFS_DEV_REPLACE_KEY, 0).
|
||||
*/
|
||||
#define BTRFS_DEV_REPLACE_KEY 250
|
||||
|
||||
/*
|
||||
* string items are for debugging. They just store a short string of
|
||||
* data in the FS
|
||||
@@ -1787,7 +1860,7 @@ struct btrfs_map_token {
|
||||
|
||||
static inline void btrfs_init_map_token (struct btrfs_map_token *token)
|
||||
{
|
||||
memset(token, 0, sizeof(*token));
|
||||
token->kaddr = NULL;
|
||||
}
|
||||
|
||||
/* some macros to generate set/get funcs for the struct fields. This
|
||||
@@ -2755,6 +2828,49 @@ BTRFS_SETGET_FUNCS(qgroup_limit_rsv_rfer, struct btrfs_qgroup_limit_item,
|
||||
BTRFS_SETGET_FUNCS(qgroup_limit_rsv_excl, struct btrfs_qgroup_limit_item,
|
||||
rsv_excl, 64);
|
||||
|
||||
/* btrfs_dev_replace_item */
|
||||
BTRFS_SETGET_FUNCS(dev_replace_src_devid,
|
||||
struct btrfs_dev_replace_item, src_devid, 64);
|
||||
BTRFS_SETGET_FUNCS(dev_replace_cont_reading_from_srcdev_mode,
|
||||
struct btrfs_dev_replace_item, cont_reading_from_srcdev_mode,
|
||||
64);
|
||||
BTRFS_SETGET_FUNCS(dev_replace_replace_state, struct btrfs_dev_replace_item,
|
||||
replace_state, 64);
|
||||
BTRFS_SETGET_FUNCS(dev_replace_time_started, struct btrfs_dev_replace_item,
|
||||
time_started, 64);
|
||||
BTRFS_SETGET_FUNCS(dev_replace_time_stopped, struct btrfs_dev_replace_item,
|
||||
time_stopped, 64);
|
||||
BTRFS_SETGET_FUNCS(dev_replace_num_write_errors, struct btrfs_dev_replace_item,
|
||||
num_write_errors, 64);
|
||||
BTRFS_SETGET_FUNCS(dev_replace_num_uncorrectable_read_errors,
|
||||
struct btrfs_dev_replace_item, num_uncorrectable_read_errors,
|
||||
64);
|
||||
BTRFS_SETGET_FUNCS(dev_replace_cursor_left, struct btrfs_dev_replace_item,
|
||||
cursor_left, 64);
|
||||
BTRFS_SETGET_FUNCS(dev_replace_cursor_right, struct btrfs_dev_replace_item,
|
||||
cursor_right, 64);
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_src_devid,
|
||||
struct btrfs_dev_replace_item, src_devid, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cont_reading_from_srcdev_mode,
|
||||
struct btrfs_dev_replace_item,
|
||||
cont_reading_from_srcdev_mode, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_replace_state,
|
||||
struct btrfs_dev_replace_item, replace_state, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_started,
|
||||
struct btrfs_dev_replace_item, time_started, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_stopped,
|
||||
struct btrfs_dev_replace_item, time_stopped, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_write_errors,
|
||||
struct btrfs_dev_replace_item, num_write_errors, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_uncorrectable_read_errors,
|
||||
struct btrfs_dev_replace_item,
|
||||
num_uncorrectable_read_errors, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_left,
|
||||
struct btrfs_dev_replace_item, cursor_left, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_right,
|
||||
struct btrfs_dev_replace_item, cursor_right, 64);
|
||||
|
||||
static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb)
|
||||
{
|
||||
return sb->s_fs_info;
|
||||
@@ -2900,6 +3016,18 @@ void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
|
||||
u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags);
|
||||
u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data);
|
||||
void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
|
||||
|
||||
enum btrfs_reserve_flush_enum {
|
||||
/* If we are in the transaction, we can't flush anything.*/
|
||||
BTRFS_RESERVE_NO_FLUSH,
|
||||
/*
|
||||
* Flushing delalloc may cause deadlock somewhere, in this
|
||||
* case, use FLUSH LIMIT
|
||||
*/
|
||||
BTRFS_RESERVE_FLUSH_LIMIT,
|
||||
BTRFS_RESERVE_FLUSH_ALL,
|
||||
};
|
||||
|
||||
int btrfs_check_data_free_space(struct inode *inode, u64 bytes);
|
||||
void btrfs_free_reserved_data_space(struct inode *inode, u64 bytes);
|
||||
void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans,
|
||||
@@ -2919,19 +3047,13 @@ struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root,
|
||||
void btrfs_free_block_rsv(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *rsv);
|
||||
int btrfs_block_rsv_add(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv,
|
||||
u64 num_bytes);
|
||||
int btrfs_block_rsv_add_noflush(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv,
|
||||
u64 num_bytes);
|
||||
struct btrfs_block_rsv *block_rsv, u64 num_bytes,
|
||||
enum btrfs_reserve_flush_enum flush);
|
||||
int btrfs_block_rsv_check(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv, int min_factor);
|
||||
int btrfs_block_rsv_refill(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv,
|
||||
u64 min_reserved);
|
||||
int btrfs_block_rsv_refill_noflush(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv,
|
||||
u64 min_reserved);
|
||||
struct btrfs_block_rsv *block_rsv, u64 min_reserved,
|
||||
enum btrfs_reserve_flush_enum flush);
|
||||
int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
|
||||
struct btrfs_block_rsv *dst_rsv,
|
||||
u64 num_bytes);
|
||||
@@ -2955,6 +3077,7 @@ int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range);
|
||||
int btrfs_init_space_info(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info);
|
||||
int __get_raid_index(u64 flags);
|
||||
/* ctree.c */
|
||||
int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key,
|
||||
int level, int *slot);
|
||||
@@ -3065,6 +3188,9 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
|
||||
int btrfs_next_leaf_write(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_path *path,
|
||||
int del);
|
||||
int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
|
||||
u64 time_seq);
|
||||
static inline int btrfs_next_old_item(struct btrfs_root *root,
|
||||
@@ -3157,6 +3283,8 @@ void btrfs_update_root_times(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
|
||||
/* dir-item.c */
|
||||
int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
|
||||
const char *name, int name_len);
|
||||
int btrfs_insert_dir_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, const char *name,
|
||||
int name_len, struct inode *dir,
|
||||
@@ -3256,6 +3384,7 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 objectid,
|
||||
u64 bytenr, int mod);
|
||||
u64 btrfs_file_extent_length(struct btrfs_path *path);
|
||||
int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_ordered_sum *sums);
|
||||
@@ -3271,6 +3400,19 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
|
||||
int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
|
||||
struct list_head *list, int search_commit);
|
||||
/* inode.c */
|
||||
struct btrfs_delalloc_work {
|
||||
struct inode *inode;
|
||||
int wait;
|
||||
int delay_iput;
|
||||
struct completion completion;
|
||||
struct list_head list;
|
||||
struct btrfs_work work;
|
||||
};
|
||||
|
||||
struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode,
|
||||
int wait, int delay_iput);
|
||||
void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work);
|
||||
|
||||
struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
|
||||
size_t pg_offset, u64 start, u64 len,
|
||||
int create);
|
||||
@@ -3370,9 +3512,12 @@ void btrfs_get_block_group_info(struct list_head *groups_list,
|
||||
struct btrfs_ioctl_space_info *space);
|
||||
|
||||
/* file.c */
|
||||
int btrfs_auto_defrag_init(void);
|
||||
void btrfs_auto_defrag_exit(void);
|
||||
int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans,
|
||||
struct inode *inode);
|
||||
int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info);
|
||||
void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync);
|
||||
void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
||||
int skip_pinned);
|
||||
@@ -3519,15 +3664,16 @@ int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_pending_snapshot *pending);
|
||||
|
||||
/* scrub.c */
|
||||
int btrfs_scrub_dev(struct btrfs_root *root, u64 devid, u64 start, u64 end,
|
||||
struct btrfs_scrub_progress *progress, int readonly);
|
||||
int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
|
||||
u64 end, struct btrfs_scrub_progress *progress,
|
||||
int readonly, int is_dev_replace);
|
||||
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_super(struct btrfs_root *root);
|
||||
int __btrfs_scrub_cancel(struct btrfs_fs_info *info);
|
||||
int btrfs_scrub_cancel(struct btrfs_root *root);
|
||||
int btrfs_scrub_cancel_dev(struct btrfs_root *root, struct btrfs_device *dev);
|
||||
int btrfs_scrub_cancel(struct btrfs_fs_info *info);
|
||||
int btrfs_scrub_cancel_dev(struct btrfs_fs_info *info,
|
||||
struct btrfs_device *dev);
|
||||
int btrfs_scrub_cancel_devid(struct btrfs_root *root, u64 devid);
|
||||
int btrfs_scrub_progress(struct btrfs_root *root, u64 devid,
|
||||
struct btrfs_scrub_progress *progress);
|
||||
|
||||
@@ -651,7 +651,8 @@ static int btrfs_delayed_inode_reserve_metadata(
|
||||
*/
|
||||
if (!src_rsv || (!trans->bytes_reserved &&
|
||||
src_rsv->type != BTRFS_BLOCK_RSV_DELALLOC)) {
|
||||
ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes);
|
||||
ret = btrfs_block_rsv_add(root, dst_rsv, num_bytes,
|
||||
BTRFS_RESERVE_NO_FLUSH);
|
||||
/*
|
||||
* Since we're under a transaction reserve_metadata_bytes could
|
||||
* try to commit the transaction which will make it return
|
||||
@@ -686,7 +687,8 @@ static int btrfs_delayed_inode_reserve_metadata(
|
||||
* reserve something strictly for us. If not be a pain and try
|
||||
* to steal from the delalloc block rsv.
|
||||
*/
|
||||
ret = btrfs_block_rsv_add_noflush(root, dst_rsv, num_bytes);
|
||||
ret = btrfs_block_rsv_add(root, dst_rsv, num_bytes,
|
||||
BTRFS_RESERVE_NO_FLUSH);
|
||||
if (!ret)
|
||||
goto out;
|
||||
|
||||
@@ -1255,7 +1257,6 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)
|
||||
struct btrfs_delayed_node *delayed_node = NULL;
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_block_rsv *block_rsv;
|
||||
unsigned long nr = 0;
|
||||
int need_requeue = 0;
|
||||
int ret;
|
||||
|
||||
@@ -1316,11 +1317,9 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)
|
||||
delayed_node);
|
||||
mutex_unlock(&delayed_node->mutex);
|
||||
|
||||
nr = trans->blocks_used;
|
||||
|
||||
trans->block_rsv = block_rsv;
|
||||
btrfs_end_transaction_dmeta(trans, root);
|
||||
__btrfs_btree_balance_dirty(root, nr);
|
||||
btrfs_btree_balance_dirty_nodelay(root);
|
||||
free_path:
|
||||
btrfs_free_path(path);
|
||||
out:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) STRATO AG 2012. 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.
|
||||
*/
|
||||
|
||||
#if !defined(__BTRFS_DEV_REPLACE__)
|
||||
#define __BTRFS_DEV_REPLACE__
|
||||
|
||||
struct btrfs_ioctl_dev_replace_args;
|
||||
|
||||
int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_run_dev_replace(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info);
|
||||
void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_dev_replace_start(struct btrfs_root *root,
|
||||
struct btrfs_ioctl_dev_replace_args *args);
|
||||
void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_ioctl_dev_replace_args *args);
|
||||
int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_ioctl_dev_replace_args *args);
|
||||
void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info);
|
||||
int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace);
|
||||
void btrfs_dev_replace_lock(struct btrfs_dev_replace *dev_replace);
|
||||
void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace);
|
||||
|
||||
static inline void btrfs_dev_replace_stats_inc(atomic64_t *stat_value)
|
||||
{
|
||||
atomic64_inc(stat_value);
|
||||
}
|
||||
#endif
|
||||
@@ -213,6 +213,65 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
|
||||
return btrfs_match_dir_item_name(root, path, name, name_len);
|
||||
}
|
||||
|
||||
int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
|
||||
const char *name, int name_len)
|
||||
{
|
||||
int ret;
|
||||
struct btrfs_key key;
|
||||
struct btrfs_dir_item *di;
|
||||
int data_size;
|
||||
struct extent_buffer *leaf;
|
||||
int slot;
|
||||
struct btrfs_path *path;
|
||||
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
key.objectid = dir;
|
||||
btrfs_set_key_type(&key, BTRFS_DIR_ITEM_KEY);
|
||||
key.offset = btrfs_name_hash(name, name_len);
|
||||
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
|
||||
/* return back any errors */
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
/* nothing found, we're safe */
|
||||
if (ret > 0) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* we found an item, look for our name in the item */
|
||||
di = btrfs_match_dir_item_name(root, path, name, name_len);
|
||||
if (di) {
|
||||
/* our exact name was found */
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* see if there is room in the item to insert this
|
||||
* name
|
||||
*/
|
||||
data_size = sizeof(*di) + name_len + sizeof(struct btrfs_item);
|
||||
leaf = path->nodes[0];
|
||||
slot = path->slots[0];
|
||||
if (data_size + btrfs_item_size_nr(leaf, slot) +
|
||||
sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root)) {
|
||||
ret = -EOVERFLOW;
|
||||
} else {
|
||||
/* plenty of insertion room */
|
||||
ret = 0;
|
||||
}
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* lookup a directory item based on index. 'dir' is the objectid
|
||||
* we're searching in, and 'mod' tells us if you plan on deleting the
|
||||
|
||||
+92
-50
@@ -45,6 +45,7 @@
|
||||
#include "inode-map.h"
|
||||
#include "check-integrity.h"
|
||||
#include "rcu-string.h"
|
||||
#include "dev-replace.h"
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
#include <asm/cpufeature.h>
|
||||
@@ -387,7 +388,7 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
|
||||
if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags))
|
||||
break;
|
||||
|
||||
num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
|
||||
num_copies = btrfs_num_copies(root->fs_info,
|
||||
eb->start, eb->len);
|
||||
if (num_copies == 1)
|
||||
break;
|
||||
@@ -852,11 +853,16 @@ static int __btree_submit_bio_done(struct inode *inode, int rw, struct bio *bio,
|
||||
int mirror_num, unsigned long bio_flags,
|
||||
u64 bio_offset)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* when we're called for a write, we're already in the async
|
||||
* submission context. Just jump into btrfs_map_bio
|
||||
*/
|
||||
return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1);
|
||||
ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio, mirror_num, 1);
|
||||
if (ret)
|
||||
bio_endio(bio, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_async_write(struct inode *inode, unsigned long bio_flags)
|
||||
@@ -878,7 +884,6 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
|
||||
int ret;
|
||||
|
||||
if (!(rw & REQ_WRITE)) {
|
||||
|
||||
/*
|
||||
* called for a read, do the setup so that checksum validation
|
||||
* can happen in the async kernel threads
|
||||
@@ -886,26 +891,32 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
|
||||
ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info,
|
||||
bio, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
|
||||
mirror_num, 0);
|
||||
goto out_w_error;
|
||||
ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
|
||||
mirror_num, 0);
|
||||
} else if (!async) {
|
||||
ret = btree_csum_one_bio(bio);
|
||||
if (ret)
|
||||
return ret;
|
||||
return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
|
||||
mirror_num, 0);
|
||||
goto out_w_error;
|
||||
ret = btrfs_map_bio(BTRFS_I(inode)->root, rw, bio,
|
||||
mirror_num, 0);
|
||||
} else {
|
||||
/*
|
||||
* kthread helpers are used to submit writes so that
|
||||
* checksumming can happen in parallel across all CPUs
|
||||
*/
|
||||
ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
|
||||
inode, rw, bio, mirror_num, 0,
|
||||
bio_offset,
|
||||
__btree_submit_bio_start,
|
||||
__btree_submit_bio_done);
|
||||
}
|
||||
|
||||
/*
|
||||
* kthread helpers are used to submit writes so that checksumming
|
||||
* can happen in parallel across all CPUs
|
||||
*/
|
||||
return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info,
|
||||
inode, rw, bio, mirror_num, 0,
|
||||
bio_offset,
|
||||
__btree_submit_bio_start,
|
||||
__btree_submit_bio_done);
|
||||
if (ret) {
|
||||
out_w_error:
|
||||
bio_endio(bio, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MIGRATION
|
||||
@@ -990,6 +1001,7 @@ static void btree_invalidatepage(struct page *page, unsigned long offset)
|
||||
|
||||
static int btree_set_page_dirty(struct page *page)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
struct extent_buffer *eb;
|
||||
|
||||
BUG_ON(!PagePrivate(page));
|
||||
@@ -998,6 +1010,7 @@ static int btree_set_page_dirty(struct page *page)
|
||||
BUG_ON(!test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
|
||||
BUG_ON(!atomic_read(&eb->refs));
|
||||
btrfs_assert_tree_locked(eb);
|
||||
#endif
|
||||
return __set_page_dirty_nobuffers(page);
|
||||
}
|
||||
|
||||
@@ -1129,11 +1142,11 @@ void clean_tree_block(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
root->fs_info->dirty_metadata_bytes);
|
||||
}
|
||||
spin_unlock(&root->fs_info->delalloc_lock);
|
||||
}
|
||||
|
||||
/* ugh, clear_extent_buffer_dirty needs to lock the page */
|
||||
btrfs_set_lock_blocking(buf);
|
||||
clear_extent_buffer_dirty(buf);
|
||||
/* ugh, clear_extent_buffer_dirty needs to lock the page */
|
||||
btrfs_set_lock_blocking(buf);
|
||||
clear_extent_buffer_dirty(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1193,7 +1206,7 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
|
||||
root->root_key.objectid = objectid;
|
||||
root->anon_dev = 0;
|
||||
|
||||
spin_lock_init(&root->root_times_lock);
|
||||
spin_lock_init(&root->root_item_lock);
|
||||
}
|
||||
|
||||
static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
|
||||
@@ -2131,6 +2144,11 @@ int open_ctree(struct super_block *sb,
|
||||
init_rwsem(&fs_info->extent_commit_sem);
|
||||
init_rwsem(&fs_info->cleanup_work_sem);
|
||||
init_rwsem(&fs_info->subvol_sem);
|
||||
fs_info->dev_replace.lock_owner = 0;
|
||||
atomic_set(&fs_info->dev_replace.nesting_level, 0);
|
||||
mutex_init(&fs_info->dev_replace.lock_finishing_cancel_unmount);
|
||||
mutex_init(&fs_info->dev_replace.lock_management_lock);
|
||||
mutex_init(&fs_info->dev_replace.lock);
|
||||
|
||||
spin_lock_init(&fs_info->qgroup_lock);
|
||||
fs_info->qgroup_tree = RB_ROOT;
|
||||
@@ -2279,6 +2297,10 @@ int open_ctree(struct super_block *sb,
|
||||
fs_info->thread_pool_size,
|
||||
&fs_info->generic_worker);
|
||||
|
||||
btrfs_init_workers(&fs_info->flush_workers, "flush_delalloc",
|
||||
fs_info->thread_pool_size,
|
||||
&fs_info->generic_worker);
|
||||
|
||||
btrfs_init_workers(&fs_info->submit_workers, "submit",
|
||||
min_t(u64, fs_devices->num_devices,
|
||||
fs_info->thread_pool_size),
|
||||
@@ -2350,6 +2372,7 @@ int open_ctree(struct super_block *sb,
|
||||
ret |= btrfs_start_workers(&fs_info->delayed_workers);
|
||||
ret |= btrfs_start_workers(&fs_info->caching_workers);
|
||||
ret |= btrfs_start_workers(&fs_info->readahead_workers);
|
||||
ret |= btrfs_start_workers(&fs_info->flush_workers);
|
||||
if (ret) {
|
||||
err = -ENOMEM;
|
||||
goto fail_sb_buffer;
|
||||
@@ -2418,7 +2441,11 @@ int open_ctree(struct super_block *sb,
|
||||
goto fail_tree_roots;
|
||||
}
|
||||
|
||||
btrfs_close_extra_devices(fs_devices);
|
||||
/*
|
||||
* keep the device that is marked to be the target device for the
|
||||
* dev_replace procedure
|
||||
*/
|
||||
btrfs_close_extra_devices(fs_info, fs_devices, 0);
|
||||
|
||||
if (!fs_devices->latest_bdev) {
|
||||
printk(KERN_CRIT "btrfs: failed to read devices on %s\n",
|
||||
@@ -2490,6 +2517,14 @@ retry_root_backup:
|
||||
goto fail_block_groups;
|
||||
}
|
||||
|
||||
ret = btrfs_init_dev_replace(fs_info);
|
||||
if (ret) {
|
||||
pr_err("btrfs: failed to init dev_replace: %d\n", ret);
|
||||
goto fail_block_groups;
|
||||
}
|
||||
|
||||
btrfs_close_extra_devices(fs_info, fs_devices, 1);
|
||||
|
||||
ret = btrfs_init_space_info(fs_info);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "Failed to initial space info: %d\n", ret);
|
||||
@@ -2503,6 +2538,13 @@ retry_root_backup:
|
||||
}
|
||||
fs_info->num_tolerated_disk_barrier_failures =
|
||||
btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
|
||||
if (fs_info->fs_devices->missing_devices >
|
||||
fs_info->num_tolerated_disk_barrier_failures &&
|
||||
!(sb->s_flags & MS_RDONLY)) {
|
||||
printk(KERN_WARNING
|
||||
"Btrfs: too many missing devices, writeable mount is not allowed\n");
|
||||
goto fail_block_groups;
|
||||
}
|
||||
|
||||
fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root,
|
||||
"btrfs-cleaner");
|
||||
@@ -2631,6 +2673,13 @@ retry_root_backup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = btrfs_resume_dev_replace_async(fs_info);
|
||||
if (ret) {
|
||||
pr_warn("btrfs: failed to resume dev_replace\n");
|
||||
close_ctree(tree_root);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_qgroup:
|
||||
@@ -2667,6 +2716,7 @@ fail_sb_buffer:
|
||||
btrfs_stop_workers(&fs_info->submit_workers);
|
||||
btrfs_stop_workers(&fs_info->delayed_workers);
|
||||
btrfs_stop_workers(&fs_info->caching_workers);
|
||||
btrfs_stop_workers(&fs_info->flush_workers);
|
||||
fail_alloc:
|
||||
fail_iput:
|
||||
btrfs_mapping_tree_free(&fs_info->mapping_tree);
|
||||
@@ -3270,16 +3320,18 @@ int close_ctree(struct btrfs_root *root)
|
||||
smp_mb();
|
||||
|
||||
/* pause restriper - we want to resume on mount */
|
||||
btrfs_pause_balance(root->fs_info);
|
||||
btrfs_pause_balance(fs_info);
|
||||
|
||||
btrfs_scrub_cancel(root);
|
||||
btrfs_dev_replace_suspend_for_unmount(fs_info);
|
||||
|
||||
btrfs_scrub_cancel(fs_info);
|
||||
|
||||
/* wait for any defraggers to finish */
|
||||
wait_event(fs_info->transaction_wait,
|
||||
(atomic_read(&fs_info->defrag_running) == 0));
|
||||
|
||||
/* clear out the rbtree of defraggable inodes */
|
||||
btrfs_run_defrag_inodes(fs_info);
|
||||
btrfs_cleanup_defrag_inodes(fs_info);
|
||||
|
||||
if (!(fs_info->sb->s_flags & MS_RDONLY)) {
|
||||
ret = btrfs_commit_super(root);
|
||||
@@ -3339,6 +3391,7 @@ int close_ctree(struct btrfs_root *root)
|
||||
btrfs_stop_workers(&fs_info->delayed_workers);
|
||||
btrfs_stop_workers(&fs_info->caching_workers);
|
||||
btrfs_stop_workers(&fs_info->readahead_workers);
|
||||
btrfs_stop_workers(&fs_info->flush_workers);
|
||||
|
||||
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
|
||||
if (btrfs_test_opt(root, CHECK_INTEGRITY))
|
||||
@@ -3383,14 +3436,12 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
|
||||
int was_dirty;
|
||||
|
||||
btrfs_assert_tree_locked(buf);
|
||||
if (transid != root->fs_info->generation) {
|
||||
printk(KERN_CRIT "btrfs transid mismatch buffer %llu, "
|
||||
if (transid != root->fs_info->generation)
|
||||
WARN(1, KERN_CRIT "btrfs transid mismatch buffer %llu, "
|
||||
"found %llu running %llu\n",
|
||||
(unsigned long long)buf->start,
|
||||
(unsigned long long)transid,
|
||||
(unsigned long long)root->fs_info->generation);
|
||||
WARN_ON(1);
|
||||
}
|
||||
was_dirty = set_extent_buffer_dirty(buf);
|
||||
if (!was_dirty) {
|
||||
spin_lock(&root->fs_info->delalloc_lock);
|
||||
@@ -3399,7 +3450,8 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
|
||||
}
|
||||
}
|
||||
|
||||
void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
|
||||
static void __btrfs_btree_balance_dirty(struct btrfs_root *root,
|
||||
int flush_delayed)
|
||||
{
|
||||
/*
|
||||
* looks as though older kernels can get into trouble with
|
||||
@@ -3411,7 +3463,8 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
|
||||
if (current->flags & PF_MEMALLOC)
|
||||
return;
|
||||
|
||||
btrfs_balance_delayed_items(root);
|
||||
if (flush_delayed)
|
||||
btrfs_balance_delayed_items(root);
|
||||
|
||||
num_dirty = root->fs_info->dirty_metadata_bytes;
|
||||
|
||||
@@ -3422,25 +3475,14 @@ void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
|
||||
return;
|
||||
}
|
||||
|
||||
void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr)
|
||||
void btrfs_btree_balance_dirty(struct btrfs_root *root)
|
||||
{
|
||||
/*
|
||||
* looks as though older kernels can get into trouble with
|
||||
* this code, they end up stuck in balance_dirty_pages forever
|
||||
*/
|
||||
u64 num_dirty;
|
||||
unsigned long thresh = 32 * 1024 * 1024;
|
||||
__btrfs_btree_balance_dirty(root, 1);
|
||||
}
|
||||
|
||||
if (current->flags & PF_MEMALLOC)
|
||||
return;
|
||||
|
||||
num_dirty = root->fs_info->dirty_metadata_bytes;
|
||||
|
||||
if (num_dirty > thresh) {
|
||||
balance_dirty_pages_ratelimited(
|
||||
root->fs_info->btree_inode->i_mapping);
|
||||
}
|
||||
return;
|
||||
void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root)
|
||||
{
|
||||
__btrfs_btree_balance_dirty(root, 0);
|
||||
}
|
||||
|
||||
int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
|
||||
|
||||
+2
-2
@@ -62,8 +62,8 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
|
||||
struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_key *location);
|
||||
int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info);
|
||||
void btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
|
||||
void __btrfs_btree_balance_dirty(struct btrfs_root *root, unsigned long nr);
|
||||
void btrfs_btree_balance_dirty(struct btrfs_root *root);
|
||||
void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root);
|
||||
void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root);
|
||||
void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
|
||||
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
|
||||
|
||||
+135
-92
@@ -33,6 +33,7 @@
|
||||
#include "volumes.h"
|
||||
#include "locking.h"
|
||||
#include "free-space-cache.h"
|
||||
#include "math.h"
|
||||
|
||||
#undef SCRAMBLE_DELAYED_REFS
|
||||
|
||||
@@ -649,24 +650,6 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info)
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static u64 div_factor(u64 num, int factor)
|
||||
{
|
||||
if (factor == 10)
|
||||
return num;
|
||||
num *= factor;
|
||||
do_div(num, 10);
|
||||
return num;
|
||||
}
|
||||
|
||||
static u64 div_factor_fine(u64 num, int factor)
|
||||
{
|
||||
if (factor == 100)
|
||||
return num;
|
||||
num *= factor;
|
||||
do_div(num, 100);
|
||||
return num;
|
||||
}
|
||||
|
||||
u64 btrfs_find_block_group(struct btrfs_root *root,
|
||||
u64 search_start, u64 search_hint, int owner)
|
||||
{
|
||||
@@ -1835,7 +1818,7 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
|
||||
|
||||
|
||||
/* Tell the block device(s) that the sectors can be discarded */
|
||||
ret = btrfs_map_block(&root->fs_info->mapping_tree, REQ_DISCARD,
|
||||
ret = btrfs_map_block(root->fs_info, REQ_DISCARD,
|
||||
bytenr, &num_bytes, &bbio, 0);
|
||||
/* Error condition is -ENOMEM */
|
||||
if (!ret) {
|
||||
@@ -2314,6 +2297,9 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
|
||||
kfree(extent_op);
|
||||
|
||||
if (ret) {
|
||||
list_del_init(&locked_ref->cluster);
|
||||
mutex_unlock(&locked_ref->mutex);
|
||||
|
||||
printk(KERN_DEBUG "btrfs: run_delayed_extent_op returned %d\n", ret);
|
||||
spin_lock(&delayed_refs->lock);
|
||||
return ret;
|
||||
@@ -2356,6 +2342,10 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
|
||||
count++;
|
||||
|
||||
if (ret) {
|
||||
if (locked_ref) {
|
||||
list_del_init(&locked_ref->cluster);
|
||||
mutex_unlock(&locked_ref->mutex);
|
||||
}
|
||||
printk(KERN_DEBUG "btrfs: run_one_delayed_ref returned %d\n", ret);
|
||||
spin_lock(&delayed_refs->lock);
|
||||
return ret;
|
||||
@@ -3661,7 +3651,7 @@ out:
|
||||
|
||||
static int can_overcommit(struct btrfs_root *root,
|
||||
struct btrfs_space_info *space_info, u64 bytes,
|
||||
int flush)
|
||||
enum btrfs_reserve_flush_enum flush)
|
||||
{
|
||||
u64 profile = btrfs_get_alloc_profile(root, 0);
|
||||
u64 avail;
|
||||
@@ -3685,11 +3675,11 @@ static int can_overcommit(struct btrfs_root *root,
|
||||
avail >>= 1;
|
||||
|
||||
/*
|
||||
* If we aren't flushing don't let us overcommit too much, say
|
||||
* 1/8th of the space. If we can flush, let it overcommit up to
|
||||
* 1/2 of the space.
|
||||
* If we aren't flushing all things, let us overcommit up to
|
||||
* 1/2th of the space. If we can flush, don't let us overcommit
|
||||
* too much, let it overcommit up to 1/8 of the space.
|
||||
*/
|
||||
if (flush)
|
||||
if (flush == BTRFS_RESERVE_FLUSH_ALL)
|
||||
avail >>= 3;
|
||||
else
|
||||
avail >>= 1;
|
||||
@@ -3699,6 +3689,20 @@ static int can_overcommit(struct btrfs_root *root,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int writeback_inodes_sb_nr_if_idle_safe(struct super_block *sb,
|
||||
unsigned long nr_pages,
|
||||
enum wb_reason reason)
|
||||
{
|
||||
if (!writeback_in_progress(sb->s_bdi) &&
|
||||
down_read_trylock(&sb->s_umount)) {
|
||||
writeback_inodes_sb_nr(sb, nr_pages, reason);
|
||||
up_read(&sb->s_umount);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* shrink metadata reservation for delalloc
|
||||
*/
|
||||
@@ -3713,6 +3717,7 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
|
||||
long time_left;
|
||||
unsigned long nr_pages = (2 * 1024 * 1024) >> PAGE_CACHE_SHIFT;
|
||||
int loops = 0;
|
||||
enum btrfs_reserve_flush_enum flush;
|
||||
|
||||
trans = (struct btrfs_trans_handle *)current->journal_info;
|
||||
block_rsv = &root->fs_info->delalloc_block_rsv;
|
||||
@@ -3730,8 +3735,9 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
|
||||
while (delalloc_bytes && loops < 3) {
|
||||
max_reclaim = min(delalloc_bytes, to_reclaim);
|
||||
nr_pages = max_reclaim >> PAGE_CACHE_SHIFT;
|
||||
writeback_inodes_sb_nr_if_idle(root->fs_info->sb, nr_pages,
|
||||
WB_REASON_FS_FREE_SPACE);
|
||||
writeback_inodes_sb_nr_if_idle_safe(root->fs_info->sb,
|
||||
nr_pages,
|
||||
WB_REASON_FS_FREE_SPACE);
|
||||
|
||||
/*
|
||||
* We need to wait for the async pages to actually start before
|
||||
@@ -3740,8 +3746,12 @@ static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig,
|
||||
wait_event(root->fs_info->async_submit_wait,
|
||||
!atomic_read(&root->fs_info->async_delalloc_pages));
|
||||
|
||||
if (!trans)
|
||||
flush = BTRFS_RESERVE_FLUSH_ALL;
|
||||
else
|
||||
flush = BTRFS_RESERVE_NO_FLUSH;
|
||||
spin_lock(&space_info->lock);
|
||||
if (can_overcommit(root, space_info, orig, !trans)) {
|
||||
if (can_overcommit(root, space_info, orig, flush)) {
|
||||
spin_unlock(&space_info->lock);
|
||||
break;
|
||||
}
|
||||
@@ -3899,7 +3909,8 @@ static int flush_space(struct btrfs_root *root,
|
||||
*/
|
||||
static int reserve_metadata_bytes(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv,
|
||||
u64 orig_bytes, int flush)
|
||||
u64 orig_bytes,
|
||||
enum btrfs_reserve_flush_enum flush)
|
||||
{
|
||||
struct btrfs_space_info *space_info = block_rsv->space_info;
|
||||
u64 used;
|
||||
@@ -3912,10 +3923,11 @@ again:
|
||||
ret = 0;
|
||||
spin_lock(&space_info->lock);
|
||||
/*
|
||||
* We only want to wait if somebody other than us is flushing and we are
|
||||
* actually alloed to flush.
|
||||
* We only want to wait if somebody other than us is flushing and we
|
||||
* are actually allowed to flush all things.
|
||||
*/
|
||||
while (flush && !flushing && space_info->flush) {
|
||||
while (flush == BTRFS_RESERVE_FLUSH_ALL && !flushing &&
|
||||
space_info->flush) {
|
||||
spin_unlock(&space_info->lock);
|
||||
/*
|
||||
* If we have a trans handle we can't wait because the flusher
|
||||
@@ -3981,23 +3993,40 @@ again:
|
||||
* Couldn't make our reservation, save our place so while we're trying
|
||||
* to reclaim space we can actually use it instead of somebody else
|
||||
* stealing it from us.
|
||||
*
|
||||
* We make the other tasks wait for the flush only when we can flush
|
||||
* all things.
|
||||
*/
|
||||
if (ret && flush) {
|
||||
if (ret && flush == BTRFS_RESERVE_FLUSH_ALL) {
|
||||
flushing = true;
|
||||
space_info->flush = 1;
|
||||
}
|
||||
|
||||
spin_unlock(&space_info->lock);
|
||||
|
||||
if (!ret || !flush)
|
||||
if (!ret || flush == BTRFS_RESERVE_NO_FLUSH)
|
||||
goto out;
|
||||
|
||||
ret = flush_space(root, space_info, num_bytes, orig_bytes,
|
||||
flush_state);
|
||||
flush_state++;
|
||||
|
||||
/*
|
||||
* If we are FLUSH_LIMIT, we can not flush delalloc, or the deadlock
|
||||
* would happen. So skip delalloc flush.
|
||||
*/
|
||||
if (flush == BTRFS_RESERVE_FLUSH_LIMIT &&
|
||||
(flush_state == FLUSH_DELALLOC ||
|
||||
flush_state == FLUSH_DELALLOC_WAIT))
|
||||
flush_state = ALLOC_CHUNK;
|
||||
|
||||
if (!ret)
|
||||
goto again;
|
||||
else if (flush_state <= COMMIT_TRANS)
|
||||
else if (flush == BTRFS_RESERVE_FLUSH_LIMIT &&
|
||||
flush_state < COMMIT_TRANS)
|
||||
goto again;
|
||||
else if (flush == BTRFS_RESERVE_FLUSH_ALL &&
|
||||
flush_state <= COMMIT_TRANS)
|
||||
goto again;
|
||||
|
||||
out:
|
||||
@@ -4148,9 +4177,9 @@ void btrfs_free_block_rsv(struct btrfs_root *root,
|
||||
kfree(rsv);
|
||||
}
|
||||
|
||||
static inline int __block_rsv_add(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv,
|
||||
u64 num_bytes, int flush)
|
||||
int btrfs_block_rsv_add(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv, u64 num_bytes,
|
||||
enum btrfs_reserve_flush_enum flush)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -4166,20 +4195,6 @@ static inline int __block_rsv_add(struct btrfs_root *root,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_block_rsv_add(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv,
|
||||
u64 num_bytes)
|
||||
{
|
||||
return __block_rsv_add(root, block_rsv, num_bytes, 1);
|
||||
}
|
||||
|
||||
int btrfs_block_rsv_add_noflush(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv,
|
||||
u64 num_bytes)
|
||||
{
|
||||
return __block_rsv_add(root, block_rsv, num_bytes, 0);
|
||||
}
|
||||
|
||||
int btrfs_block_rsv_check(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv, int min_factor)
|
||||
{
|
||||
@@ -4198,9 +4213,9 @@ int btrfs_block_rsv_check(struct btrfs_root *root,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int __btrfs_block_rsv_refill(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv,
|
||||
u64 min_reserved, int flush)
|
||||
int btrfs_block_rsv_refill(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv, u64 min_reserved,
|
||||
enum btrfs_reserve_flush_enum flush)
|
||||
{
|
||||
u64 num_bytes = 0;
|
||||
int ret = -ENOSPC;
|
||||
@@ -4228,20 +4243,6 @@ static inline int __btrfs_block_rsv_refill(struct btrfs_root *root,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_block_rsv_refill(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv,
|
||||
u64 min_reserved)
|
||||
{
|
||||
return __btrfs_block_rsv_refill(root, block_rsv, min_reserved, 1);
|
||||
}
|
||||
|
||||
int btrfs_block_rsv_refill_noflush(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv,
|
||||
u64 min_reserved)
|
||||
{
|
||||
return __btrfs_block_rsv_refill(root, block_rsv, min_reserved, 0);
|
||||
}
|
||||
|
||||
int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
|
||||
struct btrfs_block_rsv *dst_rsv,
|
||||
u64 num_bytes)
|
||||
@@ -4532,17 +4533,27 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
|
||||
u64 csum_bytes;
|
||||
unsigned nr_extents = 0;
|
||||
int extra_reserve = 0;
|
||||
int flush = 1;
|
||||
enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL;
|
||||
int ret;
|
||||
bool delalloc_lock = true;
|
||||
|
||||
/* Need to be holding the i_mutex here if we aren't free space cache */
|
||||
if (btrfs_is_free_space_inode(inode))
|
||||
flush = 0;
|
||||
/* If we are a free space inode we need to not flush since we will be in
|
||||
* the middle of a transaction commit. We also don't need the delalloc
|
||||
* mutex since we won't race with anybody. We need this mostly to make
|
||||
* lockdep shut its filthy mouth.
|
||||
*/
|
||||
if (btrfs_is_free_space_inode(inode)) {
|
||||
flush = BTRFS_RESERVE_NO_FLUSH;
|
||||
delalloc_lock = false;
|
||||
}
|
||||
|
||||
if (flush && btrfs_transaction_in_commit(root->fs_info))
|
||||
if (flush != BTRFS_RESERVE_NO_FLUSH &&
|
||||
btrfs_transaction_in_commit(root->fs_info))
|
||||
schedule_timeout(1);
|
||||
|
||||
mutex_lock(&BTRFS_I(inode)->delalloc_mutex);
|
||||
if (delalloc_lock)
|
||||
mutex_lock(&BTRFS_I(inode)->delalloc_mutex);
|
||||
|
||||
num_bytes = ALIGN(num_bytes, root->sectorsize);
|
||||
|
||||
spin_lock(&BTRFS_I(inode)->lock);
|
||||
@@ -4572,7 +4583,11 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
|
||||
ret = btrfs_qgroup_reserve(root, num_bytes +
|
||||
nr_extents * root->leafsize);
|
||||
if (ret) {
|
||||
mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
|
||||
spin_lock(&BTRFS_I(inode)->lock);
|
||||
calc_csum_metadata_size(inode, num_bytes, 0);
|
||||
spin_unlock(&BTRFS_I(inode)->lock);
|
||||
if (delalloc_lock)
|
||||
mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -4607,7 +4622,12 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
|
||||
btrfs_ino(inode),
|
||||
to_free, 0);
|
||||
}
|
||||
mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
|
||||
if (root->fs_info->quota_enabled) {
|
||||
btrfs_qgroup_free(root, num_bytes +
|
||||
nr_extents * root->leafsize);
|
||||
}
|
||||
if (delalloc_lock)
|
||||
mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -4619,7 +4639,9 @@ int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes)
|
||||
}
|
||||
BTRFS_I(inode)->reserved_extents += nr_extents;
|
||||
spin_unlock(&BTRFS_I(inode)->lock);
|
||||
mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
|
||||
|
||||
if (delalloc_lock)
|
||||
mutex_unlock(&BTRFS_I(inode)->delalloc_mutex);
|
||||
|
||||
if (to_reserve)
|
||||
trace_btrfs_space_reservation(root->fs_info,"delalloc",
|
||||
@@ -4969,9 +4991,13 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
struct btrfs_block_group_cache *cache = NULL;
|
||||
struct btrfs_space_info *space_info;
|
||||
struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
|
||||
u64 len;
|
||||
bool readonly;
|
||||
|
||||
while (start <= end) {
|
||||
readonly = false;
|
||||
if (!cache ||
|
||||
start >= cache->key.objectid + cache->key.offset) {
|
||||
if (cache)
|
||||
@@ -4989,15 +5015,30 @@ static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
|
||||
}
|
||||
|
||||
start += len;
|
||||
space_info = cache->space_info;
|
||||
|
||||
spin_lock(&cache->space_info->lock);
|
||||
spin_lock(&space_info->lock);
|
||||
spin_lock(&cache->lock);
|
||||
cache->pinned -= len;
|
||||
cache->space_info->bytes_pinned -= len;
|
||||
if (cache->ro)
|
||||
cache->space_info->bytes_readonly += len;
|
||||
space_info->bytes_pinned -= len;
|
||||
if (cache->ro) {
|
||||
space_info->bytes_readonly += len;
|
||||
readonly = true;
|
||||
}
|
||||
spin_unlock(&cache->lock);
|
||||
spin_unlock(&cache->space_info->lock);
|
||||
if (!readonly && global_rsv->space_info == space_info) {
|
||||
spin_lock(&global_rsv->lock);
|
||||
if (!global_rsv->full) {
|
||||
len = min(len, global_rsv->size -
|
||||
global_rsv->reserved);
|
||||
global_rsv->reserved += len;
|
||||
space_info->bytes_may_use += len;
|
||||
if (global_rsv->reserved >= global_rsv->size)
|
||||
global_rsv->full = 1;
|
||||
}
|
||||
spin_unlock(&global_rsv->lock);
|
||||
}
|
||||
spin_unlock(&space_info->lock);
|
||||
}
|
||||
|
||||
if (cache)
|
||||
@@ -5466,7 +5507,7 @@ wait_block_group_cache_done(struct btrfs_block_group_cache *cache)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __get_block_group_index(u64 flags)
|
||||
int __get_raid_index(u64 flags)
|
||||
{
|
||||
int index;
|
||||
|
||||
@@ -5486,7 +5527,7 @@ static int __get_block_group_index(u64 flags)
|
||||
|
||||
static int get_block_group_index(struct btrfs_block_group_cache *cache)
|
||||
{
|
||||
return __get_block_group_index(cache->flags);
|
||||
return __get_raid_index(cache->flags);
|
||||
}
|
||||
|
||||
enum btrfs_loop_type {
|
||||
@@ -6269,7 +6310,8 @@ use_block_rsv(struct btrfs_trans_handle *trans,
|
||||
block_rsv = get_block_rsv(trans, root);
|
||||
|
||||
if (block_rsv->size == 0) {
|
||||
ret = reserve_metadata_bytes(root, block_rsv, blocksize, 0);
|
||||
ret = reserve_metadata_bytes(root, block_rsv, blocksize,
|
||||
BTRFS_RESERVE_NO_FLUSH);
|
||||
/*
|
||||
* If we couldn't reserve metadata bytes try and use some from
|
||||
* the global reserve.
|
||||
@@ -6292,11 +6334,11 @@ use_block_rsv(struct btrfs_trans_handle *trans,
|
||||
static DEFINE_RATELIMIT_STATE(_rs,
|
||||
DEFAULT_RATELIMIT_INTERVAL,
|
||||
/*DEFAULT_RATELIMIT_BURST*/ 2);
|
||||
if (__ratelimit(&_rs)) {
|
||||
printk(KERN_DEBUG "btrfs: block rsv returned %d\n", ret);
|
||||
WARN_ON(1);
|
||||
}
|
||||
ret = reserve_metadata_bytes(root, block_rsv, blocksize, 0);
|
||||
if (__ratelimit(&_rs))
|
||||
WARN(1, KERN_DEBUG "btrfs: block rsv returned %d\n",
|
||||
ret);
|
||||
ret = reserve_metadata_bytes(root, block_rsv, blocksize,
|
||||
BTRFS_RESERVE_NO_FLUSH);
|
||||
if (!ret) {
|
||||
return block_rsv;
|
||||
} else if (ret && block_rsv != global_rsv) {
|
||||
@@ -7427,7 +7469,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
|
||||
*/
|
||||
target = get_restripe_target(root->fs_info, block_group->flags);
|
||||
if (target) {
|
||||
index = __get_block_group_index(extended_to_chunk(target));
|
||||
index = __get_raid_index(extended_to_chunk(target));
|
||||
} else {
|
||||
/*
|
||||
* this is just a balance, so if we were marked as full
|
||||
@@ -7461,7 +7503,8 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
|
||||
* check to make sure we can actually find a chunk with enough
|
||||
* space to fit our block group in.
|
||||
*/
|
||||
if (device->total_bytes > device->bytes_used + min_free) {
|
||||
if (device->total_bytes > device->bytes_used + min_free &&
|
||||
!device->is_tgtdev_for_dev_replace) {
|
||||
ret = find_free_dev_extent(device, min_free,
|
||||
&dev_offset, NULL);
|
||||
if (!ret)
|
||||
|
||||
+14
-23
@@ -341,12 +341,10 @@ static int insert_state(struct extent_io_tree *tree,
|
||||
{
|
||||
struct rb_node *node;
|
||||
|
||||
if (end < start) {
|
||||
printk(KERN_ERR "btrfs end < start %llu %llu\n",
|
||||
if (end < start)
|
||||
WARN(1, KERN_ERR "btrfs end < start %llu %llu\n",
|
||||
(unsigned long long)end,
|
||||
(unsigned long long)start);
|
||||
WARN_ON(1);
|
||||
}
|
||||
state->start = start;
|
||||
state->end = end;
|
||||
|
||||
@@ -1919,12 +1917,12 @@ static void repair_io_failure_callback(struct bio *bio, int err)
|
||||
* the standard behavior is to write all copies in a raid setup. here we only
|
||||
* want to write the one bad copy. so we do the mapping for ourselves and issue
|
||||
* submit_bio directly.
|
||||
* to avoid any synchonization issues, wait for the data after writing, which
|
||||
* to avoid any synchronization issues, wait for the data after writing, which
|
||||
* actually prevents the read that triggered the error from finishing.
|
||||
* currently, there can be no more than two copies of every data bit. thus,
|
||||
* exactly one rewrite is required.
|
||||
*/
|
||||
int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
|
||||
int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
|
||||
u64 length, u64 logical, struct page *page,
|
||||
int mirror_num)
|
||||
{
|
||||
@@ -1946,7 +1944,7 @@ int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
|
||||
bio->bi_size = 0;
|
||||
map_length = length;
|
||||
|
||||
ret = btrfs_map_block(map_tree, WRITE, logical,
|
||||
ret = btrfs_map_block(fs_info, WRITE, logical,
|
||||
&map_length, &bbio, mirror_num);
|
||||
if (ret) {
|
||||
bio_put(bio);
|
||||
@@ -1984,14 +1982,13 @@ int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
|
||||
int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb,
|
||||
int mirror_num)
|
||||
{
|
||||
struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
|
||||
u64 start = eb->start;
|
||||
unsigned long i, num_pages = num_extent_pages(eb->start, eb->len);
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < num_pages; i++) {
|
||||
struct page *p = extent_buffer_page(eb, i);
|
||||
ret = repair_io_failure(map_tree, start, PAGE_CACHE_SIZE,
|
||||
ret = repair_io_failure(root->fs_info, start, PAGE_CACHE_SIZE,
|
||||
start, p, mirror_num);
|
||||
if (ret)
|
||||
break;
|
||||
@@ -2010,7 +2007,7 @@ static int clean_io_failure(u64 start, struct page *page)
|
||||
u64 private;
|
||||
u64 private_failure;
|
||||
struct io_failure_record *failrec;
|
||||
struct btrfs_mapping_tree *map_tree;
|
||||
struct btrfs_fs_info *fs_info;
|
||||
struct extent_state *state;
|
||||
int num_copies;
|
||||
int did_repair = 0;
|
||||
@@ -2046,11 +2043,11 @@ static int clean_io_failure(u64 start, struct page *page)
|
||||
spin_unlock(&BTRFS_I(inode)->io_tree.lock);
|
||||
|
||||
if (state && state->start == failrec->start) {
|
||||
map_tree = &BTRFS_I(inode)->root->fs_info->mapping_tree;
|
||||
num_copies = btrfs_num_copies(map_tree, failrec->logical,
|
||||
failrec->len);
|
||||
fs_info = BTRFS_I(inode)->root->fs_info;
|
||||
num_copies = btrfs_num_copies(fs_info, failrec->logical,
|
||||
failrec->len);
|
||||
if (num_copies > 1) {
|
||||
ret = repair_io_failure(map_tree, start, failrec->len,
|
||||
ret = repair_io_failure(fs_info, start, failrec->len,
|
||||
failrec->logical, page,
|
||||
failrec->failed_mirror);
|
||||
did_repair = !ret;
|
||||
@@ -2159,9 +2156,8 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,
|
||||
* clean_io_failure() clean all those errors at once.
|
||||
*/
|
||||
}
|
||||
num_copies = btrfs_num_copies(
|
||||
&BTRFS_I(inode)->root->fs_info->mapping_tree,
|
||||
failrec->logical, failrec->len);
|
||||
num_copies = btrfs_num_copies(BTRFS_I(inode)->root->fs_info,
|
||||
failrec->logical, failrec->len);
|
||||
if (num_copies == 1) {
|
||||
/*
|
||||
* we only have a single copy of the data, so don't bother with
|
||||
@@ -2466,10 +2462,6 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
|
||||
return bio;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since writes are async, they will only return -ENOMEM.
|
||||
* Reads can return the full range of I/O error conditions.
|
||||
*/
|
||||
static int __must_check submit_one_bio(int rw, struct bio *bio,
|
||||
int mirror_num, unsigned long bio_flags)
|
||||
{
|
||||
@@ -4721,10 +4713,9 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
|
||||
}
|
||||
|
||||
if (start + min_len > eb->len) {
|
||||
printk(KERN_ERR "btrfs bad mapping eb start %llu len %lu, "
|
||||
WARN(1, KERN_ERR "btrfs bad mapping eb start %llu len %lu, "
|
||||
"wanted %lu %lu\n", (unsigned long long)eb->start,
|
||||
eb->len, start, min_len);
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -337,9 +337,9 @@ struct bio *
|
||||
btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
|
||||
gfp_t gfp_flags);
|
||||
|
||||
struct btrfs_mapping_tree;
|
||||
struct btrfs_fs_info;
|
||||
|
||||
int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
|
||||
int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
|
||||
u64 length, u64 logical, struct page *page,
|
||||
int mirror_num);
|
||||
int end_extent_writepage(struct page *page, int err, u64 start, u64 end);
|
||||
|
||||
+10
-14
@@ -49,7 +49,7 @@ void extent_map_tree_init(struct extent_map_tree *tree)
|
||||
struct extent_map *alloc_extent_map(void)
|
||||
{
|
||||
struct extent_map *em;
|
||||
em = kmem_cache_alloc(extent_map_cache, GFP_NOFS);
|
||||
em = kmem_cache_zalloc(extent_map_cache, GFP_NOFS);
|
||||
if (!em)
|
||||
return NULL;
|
||||
em->in_tree = 0;
|
||||
@@ -198,16 +198,15 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
|
||||
merge = rb_entry(rb, struct extent_map, rb_node);
|
||||
if (rb && mergable_maps(merge, em)) {
|
||||
em->start = merge->start;
|
||||
em->orig_start = merge->orig_start;
|
||||
em->len += merge->len;
|
||||
em->block_len += merge->block_len;
|
||||
em->block_start = merge->block_start;
|
||||
merge->in_tree = 0;
|
||||
if (merge->generation > em->generation) {
|
||||
em->mod_start = em->start;
|
||||
em->mod_len = em->len;
|
||||
em->generation = merge->generation;
|
||||
list_move(&em->list, &tree->modified_extents);
|
||||
}
|
||||
em->mod_len = (em->mod_len + em->mod_start) - merge->mod_start;
|
||||
em->mod_start = merge->mod_start;
|
||||
em->generation = max(em->generation, merge->generation);
|
||||
list_move(&em->list, &tree->modified_extents);
|
||||
|
||||
list_del_init(&merge->list);
|
||||
rb_erase(&merge->rb_node, &tree->map);
|
||||
@@ -223,11 +222,8 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
|
||||
em->block_len += merge->len;
|
||||
rb_erase(&merge->rb_node, &tree->map);
|
||||
merge->in_tree = 0;
|
||||
if (merge->generation > em->generation) {
|
||||
em->mod_len = em->len;
|
||||
em->generation = merge->generation;
|
||||
list_move(&em->list, &tree->modified_extents);
|
||||
}
|
||||
em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start;
|
||||
em->generation = max(em->generation, merge->generation);
|
||||
list_del_init(&merge->list);
|
||||
free_extent_map(merge);
|
||||
}
|
||||
@@ -265,9 +261,9 @@ int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len,
|
||||
em->mod_start = em->start;
|
||||
em->mod_len = em->len;
|
||||
|
||||
if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) {
|
||||
if (test_bit(EXTENT_FLAG_FILLING, &em->flags)) {
|
||||
prealloc = true;
|
||||
clear_bit(EXTENT_FLAG_PREALLOC, &em->flags);
|
||||
clear_bit(EXTENT_FLAG_FILLING, &em->flags);
|
||||
}
|
||||
|
||||
try_merge_map(tree, em);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#define EXTENT_FLAG_VACANCY 2 /* no file extent item found */
|
||||
#define EXTENT_FLAG_PREALLOC 3 /* pre-allocated extent */
|
||||
#define EXTENT_FLAG_LOGGING 4 /* Logging this extent */
|
||||
#define EXTENT_FLAG_FILLING 5 /* Filling in a preallocated extent */
|
||||
|
||||
struct extent_map {
|
||||
struct rb_node rb_node;
|
||||
@@ -24,6 +25,7 @@ struct extent_map {
|
||||
u64 mod_start;
|
||||
u64 mod_len;
|
||||
u64 orig_start;
|
||||
u64 orig_block_len;
|
||||
u64 block_start;
|
||||
u64 block_len;
|
||||
u64 generation;
|
||||
|
||||
+20
-1
@@ -133,7 +133,6 @@ fail:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
||||
int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_path *path, u64 objectid,
|
||||
@@ -151,6 +150,26 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
||||
return ret;
|
||||
}
|
||||
|
||||
u64 btrfs_file_extent_length(struct btrfs_path *path)
|
||||
{
|
||||
int extent_type;
|
||||
struct btrfs_file_extent_item *fi;
|
||||
u64 len;
|
||||
|
||||
fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
|
||||
struct btrfs_file_extent_item);
|
||||
extent_type = btrfs_file_extent_type(path->nodes[0], fi);
|
||||
|
||||
if (extent_type == BTRFS_FILE_EXTENT_REG ||
|
||||
extent_type == BTRFS_FILE_EXTENT_PREALLOC)
|
||||
len = btrfs_file_extent_num_bytes(path->nodes[0], fi);
|
||||
else if (extent_type == BTRFS_FILE_EXTENT_INLINE)
|
||||
len = btrfs_file_extent_inline_len(path->nodes[0], fi);
|
||||
else
|
||||
BUG();
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
|
||||
struct inode *inode, struct bio *bio,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user