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 git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: Btrfs: BUG to BUG_ON changes Btrfs: remove dead code Btrfs: remove dead code Btrfs: fix typos in comments Btrfs: remove unused ftrace include Btrfs: fix __ucmpdi2 compile bug on 32 bit builds Btrfs: free inode struct when btrfs_new_inode fails Btrfs: fix race in worker_loop Btrfs: add flushoncommit mount option Btrfs: notreelog mount option Btrfs: introduce btrfs_show_options Btrfs: rework allocation clustering Btrfs: Optimize locking in btrfs_next_leaf() Btrfs: break up btrfs_search_slot into smaller pieces Btrfs: kill the pinned_mutex Btrfs: kill the block group alloc mutex Btrfs: clean up find_free_extent Btrfs: free space cache cleanups Btrfs: unplug in the async bio submission threads Btrfs: keep processing bios for a given bdev if our proc is batching
This commit is contained in:
@@ -20,7 +20,6 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include "async-thread.h"
|
||||
|
||||
#define WORK_QUEUED_BIT 0
|
||||
@@ -195,6 +194,9 @@ again_locked:
|
||||
if (!list_empty(&worker->pending))
|
||||
continue;
|
||||
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
|
||||
/* still no more work?, sleep for real */
|
||||
spin_lock_irq(&worker->lock);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
@@ -208,7 +210,8 @@ again_locked:
|
||||
worker->working = 0;
|
||||
spin_unlock_irq(&worker->lock);
|
||||
|
||||
schedule();
|
||||
if (!kthread_should_stop())
|
||||
schedule();
|
||||
}
|
||||
__set_current_state(TASK_RUNNING);
|
||||
}
|
||||
|
||||
+197
-115
@@ -1244,9 +1244,9 @@ static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans,
|
||||
* readahead one full node of leaves, finding things that are close
|
||||
* to the block in 'slot', and triggering ra on them.
|
||||
*/
|
||||
static noinline void reada_for_search(struct btrfs_root *root,
|
||||
struct btrfs_path *path,
|
||||
int level, int slot, u64 objectid)
|
||||
static void reada_for_search(struct btrfs_root *root,
|
||||
struct btrfs_path *path,
|
||||
int level, int slot, u64 objectid)
|
||||
{
|
||||
struct extent_buffer *node;
|
||||
struct btrfs_disk_key disk_key;
|
||||
@@ -1446,6 +1446,117 @@ noinline void btrfs_unlock_up_safe(struct btrfs_path *path, int level)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* helper function for btrfs_search_slot. The goal is to find a block
|
||||
* in cache without setting the path to blocking. If we find the block
|
||||
* we return zero and the path is unchanged.
|
||||
*
|
||||
* If we can't find the block, we set the path blocking and do some
|
||||
* reada. -EAGAIN is returned and the search must be repeated.
|
||||
*/
|
||||
static int
|
||||
read_block_for_search(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_path *p,
|
||||
struct extent_buffer **eb_ret, int level, int slot,
|
||||
struct btrfs_key *key)
|
||||
{
|
||||
u64 blocknr;
|
||||
u64 gen;
|
||||
u32 blocksize;
|
||||
struct extent_buffer *b = *eb_ret;
|
||||
struct extent_buffer *tmp;
|
||||
|
||||
blocknr = btrfs_node_blockptr(b, slot);
|
||||
gen = btrfs_node_ptr_generation(b, slot);
|
||||
blocksize = btrfs_level_size(root, level - 1);
|
||||
|
||||
tmp = btrfs_find_tree_block(root, blocknr, blocksize);
|
||||
if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
|
||||
*eb_ret = tmp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* reduce lock contention at high levels
|
||||
* of the btree by dropping locks before
|
||||
* we read.
|
||||
*/
|
||||
btrfs_release_path(NULL, p);
|
||||
if (tmp)
|
||||
free_extent_buffer(tmp);
|
||||
if (p->reada)
|
||||
reada_for_search(root, p, level, slot, key->objectid);
|
||||
|
||||
tmp = read_tree_block(root, blocknr, blocksize, gen);
|
||||
if (tmp)
|
||||
free_extent_buffer(tmp);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/*
|
||||
* helper function for btrfs_search_slot. This does all of the checks
|
||||
* for node-level blocks and does any balancing required based on
|
||||
* the ins_len.
|
||||
*
|
||||
* If no extra work was required, zero is returned. If we had to
|
||||
* drop the path, -EAGAIN is returned and btrfs_search_slot must
|
||||
* start over
|
||||
*/
|
||||
static int
|
||||
setup_nodes_for_search(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct btrfs_path *p,
|
||||
struct extent_buffer *b, int level, int ins_len)
|
||||
{
|
||||
int ret;
|
||||
if ((p->search_for_split || ins_len > 0) && btrfs_header_nritems(b) >=
|
||||
BTRFS_NODEPTRS_PER_BLOCK(root) - 3) {
|
||||
int sret;
|
||||
|
||||
sret = reada_for_balance(root, p, level);
|
||||
if (sret)
|
||||
goto again;
|
||||
|
||||
btrfs_set_path_blocking(p);
|
||||
sret = split_node(trans, root, p, level);
|
||||
btrfs_clear_path_blocking(p, NULL);
|
||||
|
||||
BUG_ON(sret > 0);
|
||||
if (sret) {
|
||||
ret = sret;
|
||||
goto done;
|
||||
}
|
||||
b = p->nodes[level];
|
||||
} else if (ins_len < 0 && btrfs_header_nritems(b) <
|
||||
BTRFS_NODEPTRS_PER_BLOCK(root) / 4) {
|
||||
int sret;
|
||||
|
||||
sret = reada_for_balance(root, p, level);
|
||||
if (sret)
|
||||
goto again;
|
||||
|
||||
btrfs_set_path_blocking(p);
|
||||
sret = balance_level(trans, root, p, level);
|
||||
btrfs_clear_path_blocking(p, NULL);
|
||||
|
||||
if (sret) {
|
||||
ret = sret;
|
||||
goto done;
|
||||
}
|
||||
b = p->nodes[level];
|
||||
if (!b) {
|
||||
btrfs_release_path(NULL, p);
|
||||
goto again;
|
||||
}
|
||||
BUG_ON(btrfs_header_nritems(b) == 1);
|
||||
}
|
||||
return 0;
|
||||
|
||||
again:
|
||||
ret = -EAGAIN;
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* look for key in the tree. path is filled in with nodes along the way
|
||||
* if key is found, we return zero and you can find the item in the leaf
|
||||
@@ -1464,16 +1575,11 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
ins_len, int cow)
|
||||
{
|
||||
struct extent_buffer *b;
|
||||
struct extent_buffer *tmp;
|
||||
int slot;
|
||||
int ret;
|
||||
int level;
|
||||
int should_reada = p->reada;
|
||||
int lowest_unlock = 1;
|
||||
int blocksize;
|
||||
u8 lowest_level = 0;
|
||||
u64 blocknr;
|
||||
u64 gen;
|
||||
|
||||
lowest_level = p->lowest_level;
|
||||
WARN_ON(lowest_level && ins_len > 0);
|
||||
@@ -1502,7 +1608,11 @@ again:
|
||||
if (cow) {
|
||||
int wret;
|
||||
|
||||
/* is a cow on this block not required */
|
||||
/*
|
||||
* if we don't really need to cow this block
|
||||
* then we don't want to set the path blocking,
|
||||
* so we test it here
|
||||
*/
|
||||
if (btrfs_header_generation(b) == trans->transid &&
|
||||
btrfs_header_owner(b) == root->root_key.objectid &&
|
||||
!btrfs_header_flag(b, BTRFS_HEADER_FLAG_WRITTEN)) {
|
||||
@@ -1557,51 +1667,15 @@ cow_done:
|
||||
if (ret && slot > 0)
|
||||
slot -= 1;
|
||||
p->slots[level] = slot;
|
||||
if ((p->search_for_split || ins_len > 0) &&
|
||||
btrfs_header_nritems(b) >=
|
||||
BTRFS_NODEPTRS_PER_BLOCK(root) - 3) {
|
||||
int sret;
|
||||
ret = setup_nodes_for_search(trans, root, p, b, level,
|
||||
ins_len);
|
||||
if (ret == -EAGAIN)
|
||||
goto again;
|
||||
else if (ret)
|
||||
goto done;
|
||||
b = p->nodes[level];
|
||||
slot = p->slots[level];
|
||||
|
||||
sret = reada_for_balance(root, p, level);
|
||||
if (sret)
|
||||
goto again;
|
||||
|
||||
btrfs_set_path_blocking(p);
|
||||
sret = split_node(trans, root, p, level);
|
||||
btrfs_clear_path_blocking(p, NULL);
|
||||
|
||||
BUG_ON(sret > 0);
|
||||
if (sret) {
|
||||
ret = sret;
|
||||
goto done;
|
||||
}
|
||||
b = p->nodes[level];
|
||||
slot = p->slots[level];
|
||||
} else if (ins_len < 0 &&
|
||||
btrfs_header_nritems(b) <
|
||||
BTRFS_NODEPTRS_PER_BLOCK(root) / 4) {
|
||||
int sret;
|
||||
|
||||
sret = reada_for_balance(root, p, level);
|
||||
if (sret)
|
||||
goto again;
|
||||
|
||||
btrfs_set_path_blocking(p);
|
||||
sret = balance_level(trans, root, p, level);
|
||||
btrfs_clear_path_blocking(p, NULL);
|
||||
|
||||
if (sret) {
|
||||
ret = sret;
|
||||
goto done;
|
||||
}
|
||||
b = p->nodes[level];
|
||||
if (!b) {
|
||||
btrfs_release_path(NULL, p);
|
||||
goto again;
|
||||
}
|
||||
slot = p->slots[level];
|
||||
BUG_ON(btrfs_header_nritems(b) == 1);
|
||||
}
|
||||
unlock_up(p, level, lowest_unlock);
|
||||
|
||||
/* this is only true while dropping a snapshot */
|
||||
@@ -1610,44 +1684,11 @@ cow_done:
|
||||
goto done;
|
||||
}
|
||||
|
||||
blocknr = btrfs_node_blockptr(b, slot);
|
||||
gen = btrfs_node_ptr_generation(b, slot);
|
||||
blocksize = btrfs_level_size(root, level - 1);
|
||||
ret = read_block_for_search(trans, root, p,
|
||||
&b, level, slot, key);
|
||||
if (ret == -EAGAIN)
|
||||
goto again;
|
||||
|
||||
tmp = btrfs_find_tree_block(root, blocknr, blocksize);
|
||||
if (tmp && btrfs_buffer_uptodate(tmp, gen)) {
|
||||
b = tmp;
|
||||
} else {
|
||||
/*
|
||||
* reduce lock contention at high levels
|
||||
* of the btree by dropping locks before
|
||||
* we read.
|
||||
*/
|
||||
if (level > 0) {
|
||||
btrfs_release_path(NULL, p);
|
||||
if (tmp)
|
||||
free_extent_buffer(tmp);
|
||||
if (should_reada)
|
||||
reada_for_search(root, p,
|
||||
level, slot,
|
||||
key->objectid);
|
||||
|
||||
tmp = read_tree_block(root, blocknr,
|
||||
blocksize, gen);
|
||||
if (tmp)
|
||||
free_extent_buffer(tmp);
|
||||
goto again;
|
||||
} else {
|
||||
btrfs_set_path_blocking(p);
|
||||
if (tmp)
|
||||
free_extent_buffer(tmp);
|
||||
if (should_reada)
|
||||
reada_for_search(root, p,
|
||||
level, slot,
|
||||
key->objectid);
|
||||
b = read_node_slot(root, b, slot);
|
||||
}
|
||||
}
|
||||
if (!p->skip_locking) {
|
||||
int lret;
|
||||
|
||||
@@ -2116,8 +2157,7 @@ static int insert_ptr(struct btrfs_trans_handle *trans, struct btrfs_root
|
||||
BUG_ON(!path->nodes[level]);
|
||||
lower = path->nodes[level];
|
||||
nritems = btrfs_header_nritems(lower);
|
||||
if (slot > nritems)
|
||||
BUG();
|
||||
BUG_ON(slot > nritems);
|
||||
if (nritems == BTRFS_NODEPTRS_PER_BLOCK(root))
|
||||
BUG();
|
||||
if (slot != nritems) {
|
||||
@@ -4086,28 +4126,44 @@ next:
|
||||
int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
|
||||
{
|
||||
int slot;
|
||||
int level = 1;
|
||||
int level;
|
||||
struct extent_buffer *c;
|
||||
struct extent_buffer *next = NULL;
|
||||
struct extent_buffer *next;
|
||||
struct btrfs_key key;
|
||||
u32 nritems;
|
||||
int ret;
|
||||
int old_spinning = path->leave_spinning;
|
||||
int force_blocking = 0;
|
||||
|
||||
nritems = btrfs_header_nritems(path->nodes[0]);
|
||||
if (nritems == 0)
|
||||
return 1;
|
||||
|
||||
btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);
|
||||
/*
|
||||
* we take the blocks in an order that upsets lockdep. Using
|
||||
* blocking mode is the only way around it.
|
||||
*/
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
force_blocking = 1;
|
||||
#endif
|
||||
|
||||
btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1);
|
||||
again:
|
||||
level = 1;
|
||||
next = NULL;
|
||||
btrfs_release_path(root, path);
|
||||
|
||||
path->keep_locks = 1;
|
||||
|
||||
if (!force_blocking)
|
||||
path->leave_spinning = 1;
|
||||
|
||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||
path->keep_locks = 0;
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
btrfs_set_path_blocking(path);
|
||||
nritems = btrfs_header_nritems(path->nodes[0]);
|
||||
/*
|
||||
* by releasing the path above we dropped all our locks. A balance
|
||||
@@ -4117,19 +4173,24 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
|
||||
*/
|
||||
if (nritems > 0 && path->slots[0] < nritems - 1) {
|
||||
path->slots[0]++;
|
||||
ret = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
while (level < BTRFS_MAX_LEVEL) {
|
||||
if (!path->nodes[level])
|
||||
return 1;
|
||||
if (!path->nodes[level]) {
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
slot = path->slots[level] + 1;
|
||||
c = path->nodes[level];
|
||||
if (slot >= btrfs_header_nritems(c)) {
|
||||
level++;
|
||||
if (level == BTRFS_MAX_LEVEL)
|
||||
return 1;
|
||||
if (level == BTRFS_MAX_LEVEL) {
|
||||
ret = 1;
|
||||
goto done;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -4138,16 +4199,22 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
|
||||
free_extent_buffer(next);
|
||||
}
|
||||
|
||||
/* the path was set to blocking above */
|
||||
if (level == 1 && (path->locks[1] || path->skip_locking) &&
|
||||
path->reada)
|
||||
reada_for_search(root, path, level, slot, 0);
|
||||
next = c;
|
||||
ret = read_block_for_search(NULL, root, path, &next, level,
|
||||
slot, &key);
|
||||
if (ret == -EAGAIN)
|
||||
goto again;
|
||||
|
||||
next = read_node_slot(root, c, slot);
|
||||
if (!path->skip_locking) {
|
||||
btrfs_assert_tree_locked(c);
|
||||
btrfs_tree_lock(next);
|
||||
btrfs_set_lock_blocking(next);
|
||||
ret = btrfs_try_spin_lock(next);
|
||||
if (!ret) {
|
||||
btrfs_set_path_blocking(path);
|
||||
btrfs_tree_lock(next);
|
||||
if (!force_blocking)
|
||||
btrfs_clear_path_blocking(path, next);
|
||||
}
|
||||
if (force_blocking)
|
||||
btrfs_set_lock_blocking(next);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -4157,27 +4224,42 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
|
||||
c = path->nodes[level];
|
||||
if (path->locks[level])
|
||||
btrfs_tree_unlock(c);
|
||||
|
||||
free_extent_buffer(c);
|
||||
path->nodes[level] = next;
|
||||
path->slots[level] = 0;
|
||||
if (!path->skip_locking)
|
||||
path->locks[level] = 1;
|
||||
|
||||
if (!level)
|
||||
break;
|
||||
|
||||
btrfs_set_path_blocking(path);
|
||||
if (level == 1 && path->locks[1] && path->reada)
|
||||
reada_for_search(root, path, level, slot, 0);
|
||||
next = read_node_slot(root, next, 0);
|
||||
ret = read_block_for_search(NULL, root, path, &next, level,
|
||||
0, &key);
|
||||
if (ret == -EAGAIN)
|
||||
goto again;
|
||||
|
||||
if (!path->skip_locking) {
|
||||
btrfs_assert_tree_locked(path->nodes[level]);
|
||||
btrfs_tree_lock(next);
|
||||
btrfs_set_lock_blocking(next);
|
||||
ret = btrfs_try_spin_lock(next);
|
||||
if (!ret) {
|
||||
btrfs_set_path_blocking(path);
|
||||
btrfs_tree_lock(next);
|
||||
if (!force_blocking)
|
||||
btrfs_clear_path_blocking(path, next);
|
||||
}
|
||||
if (force_blocking)
|
||||
btrfs_set_lock_blocking(next);
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
done:
|
||||
unlock_up(path, 0, 1);
|
||||
return 0;
|
||||
path->leave_spinning = old_spinning;
|
||||
if (!old_spinning)
|
||||
btrfs_set_path_blocking(path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+49
-35
@@ -143,12 +143,15 @@ static int btrfs_csum_sizes[] = { 4, 0 };
|
||||
#define BTRFS_FT_MAX 9
|
||||
|
||||
/*
|
||||
* the key defines the order in the tree, and so it also defines (optimal)
|
||||
* block layout. objectid corresonds to the inode number. The flags
|
||||
* tells us things about the object, and is a kind of stream selector.
|
||||
* so for a given inode, keys with flags of 1 might refer to the inode
|
||||
* data, flags of 2 may point to file data in the btree and flags == 3
|
||||
* may point to extents.
|
||||
* The key defines the order in the tree, and so it also defines (optimal)
|
||||
* block layout.
|
||||
*
|
||||
* objectid corresponds to the inode number.
|
||||
*
|
||||
* type tells us things about the object, and is a kind of stream selector.
|
||||
* so for a given inode, keys with type of 1 might refer to the inode data,
|
||||
* type of 2 may point to file data in the btree and type == 3 may point to
|
||||
* extents.
|
||||
*
|
||||
* offset is the starting byte offset for this key in the stream.
|
||||
*
|
||||
@@ -200,7 +203,7 @@ struct btrfs_dev_item {
|
||||
|
||||
/*
|
||||
* starting byte of this partition on the device,
|
||||
* to allowr for stripe alignment in the future
|
||||
* to allow for stripe alignment in the future
|
||||
*/
|
||||
__le64 start_offset;
|
||||
|
||||
@@ -633,18 +636,35 @@ struct btrfs_space_info {
|
||||
struct rw_semaphore groups_sem;
|
||||
};
|
||||
|
||||
struct btrfs_free_space {
|
||||
struct rb_node bytes_index;
|
||||
struct rb_node offset_index;
|
||||
u64 offset;
|
||||
u64 bytes;
|
||||
/*
|
||||
* free clusters are used to claim free space in relatively large chunks,
|
||||
* allowing us to do less seeky writes. They are used for all metadata
|
||||
* allocations and data allocations in ssd mode.
|
||||
*/
|
||||
struct btrfs_free_cluster {
|
||||
spinlock_t lock;
|
||||
spinlock_t refill_lock;
|
||||
struct rb_root root;
|
||||
|
||||
/* largest extent in this cluster */
|
||||
u64 max_size;
|
||||
|
||||
/* first extent starting offset */
|
||||
u64 window_start;
|
||||
|
||||
struct btrfs_block_group_cache *block_group;
|
||||
/*
|
||||
* when a cluster is allocated from a block group, we put the
|
||||
* cluster onto a list in the block group so that it can
|
||||
* be freed before the block group is freed.
|
||||
*/
|
||||
struct list_head block_group_list;
|
||||
};
|
||||
|
||||
struct btrfs_block_group_cache {
|
||||
struct btrfs_key key;
|
||||
struct btrfs_block_group_item item;
|
||||
spinlock_t lock;
|
||||
struct mutex alloc_mutex;
|
||||
struct mutex cache_mutex;
|
||||
u64 pinned;
|
||||
u64 reserved;
|
||||
@@ -656,6 +676,7 @@ struct btrfs_block_group_cache {
|
||||
struct btrfs_space_info *space_info;
|
||||
|
||||
/* free space cache stuff */
|
||||
spinlock_t tree_lock;
|
||||
struct rb_root free_space_bytes;
|
||||
struct rb_root free_space_offset;
|
||||
|
||||
@@ -667,6 +688,11 @@ struct btrfs_block_group_cache {
|
||||
|
||||
/* usage count */
|
||||
atomic_t count;
|
||||
|
||||
/* List of struct btrfs_free_clusters for this block group.
|
||||
* Today it will only have one thing on it, but that may change
|
||||
*/
|
||||
struct list_head cluster_list;
|
||||
};
|
||||
|
||||
struct btrfs_leaf_ref_tree {
|
||||
@@ -728,7 +754,6 @@ struct btrfs_fs_info {
|
||||
struct mutex tree_log_mutex;
|
||||
struct mutex transaction_kthread_mutex;
|
||||
struct mutex cleaner_mutex;
|
||||
struct mutex pinned_mutex;
|
||||
struct mutex chunk_mutex;
|
||||
struct mutex drop_mutex;
|
||||
struct mutex volume_mutex;
|
||||
@@ -839,8 +864,12 @@ struct btrfs_fs_info {
|
||||
spinlock_t delalloc_lock;
|
||||
spinlock_t new_trans_lock;
|
||||
u64 delalloc_bytes;
|
||||
u64 last_alloc;
|
||||
u64 last_data_alloc;
|
||||
|
||||
/* data_alloc_cluster is only used in ssd mode */
|
||||
struct btrfs_free_cluster data_alloc_cluster;
|
||||
|
||||
/* all metadata allocations go through this cluster */
|
||||
struct btrfs_free_cluster meta_alloc_cluster;
|
||||
|
||||
spinlock_t ref_cache_lock;
|
||||
u64 total_ref_cache_size;
|
||||
@@ -932,7 +961,6 @@ struct btrfs_root {
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
* inode items have the data typically returned from stat and store other
|
||||
* info about object characteristics. There is one for every file and dir in
|
||||
* the FS
|
||||
@@ -963,7 +991,7 @@ struct btrfs_root {
|
||||
#define BTRFS_EXTENT_CSUM_KEY 128
|
||||
|
||||
/*
|
||||
* root items point to tree roots. There are typically in the root
|
||||
* root items point to tree roots. They are typically in the root
|
||||
* tree used by the super block to find all the other trees
|
||||
*/
|
||||
#define BTRFS_ROOT_ITEM_KEY 132
|
||||
@@ -1010,6 +1038,8 @@ struct btrfs_root {
|
||||
#define BTRFS_MOUNT_SSD (1 << 3)
|
||||
#define BTRFS_MOUNT_DEGRADED (1 << 4)
|
||||
#define BTRFS_MOUNT_COMPRESS (1 << 5)
|
||||
#define BTRFS_MOUNT_NOTREELOG (1 << 6)
|
||||
#define BTRFS_MOUNT_FLUSHONCOMMIT (1 << 7)
|
||||
|
||||
#define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt)
|
||||
#define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt)
|
||||
@@ -1748,6 +1778,7 @@ static inline struct dentry *fdentry(struct file *file)
|
||||
}
|
||||
|
||||
/* extent-tree.c */
|
||||
void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
|
||||
int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, unsigned long count);
|
||||
int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len);
|
||||
@@ -2174,21 +2205,4 @@ int btrfs_check_acl(struct inode *inode, int mask);
|
||||
int btrfs_init_acl(struct inode *inode, struct inode *dir);
|
||||
int btrfs_acl_chmod(struct inode *inode);
|
||||
|
||||
/* free-space-cache.c */
|
||||
int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
|
||||
u64 bytenr, u64 size);
|
||||
int btrfs_add_free_space_lock(struct btrfs_block_group_cache *block_group,
|
||||
u64 offset, u64 bytes);
|
||||
int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
|
||||
u64 bytenr, u64 size);
|
||||
int btrfs_remove_free_space_lock(struct btrfs_block_group_cache *block_group,
|
||||
u64 offset, u64 bytes);
|
||||
void btrfs_remove_free_space_cache(struct btrfs_block_group_cache
|
||||
*block_group);
|
||||
struct btrfs_free_space *btrfs_find_free_space(struct btrfs_block_group_cache
|
||||
*block_group, u64 offset,
|
||||
u64 bytes);
|
||||
void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
|
||||
u64 bytes);
|
||||
u64 btrfs_block_group_free_space(struct btrfs_block_group_cache *block_group);
|
||||
#endif
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/sort.h>
|
||||
#include <linux/ftrace.h>
|
||||
#include "ctree.h"
|
||||
#include "delayed-ref.h"
|
||||
#include "transaction.h"
|
||||
|
||||
+5
-3
@@ -38,6 +38,7 @@
|
||||
#include "locking.h"
|
||||
#include "ref-cache.h"
|
||||
#include "tree-log.h"
|
||||
#include "free-space-cache.h"
|
||||
|
||||
static struct extent_io_ops btree_extent_io_ops;
|
||||
static void end_workqueue_fn(struct btrfs_work *work);
|
||||
@@ -1412,8 +1413,6 @@ static int bio_ready_for_csum(struct bio *bio)
|
||||
|
||||
ret = extent_range_uptodate(io_tree, start + length,
|
||||
start + buf_len - 1);
|
||||
if (ret == 1)
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1647,12 +1646,15 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||
mutex_init(&fs_info->ordered_operations_mutex);
|
||||
mutex_init(&fs_info->tree_log_mutex);
|
||||
mutex_init(&fs_info->drop_mutex);
|
||||
mutex_init(&fs_info->pinned_mutex);
|
||||
mutex_init(&fs_info->chunk_mutex);
|
||||
mutex_init(&fs_info->transaction_kthread_mutex);
|
||||
mutex_init(&fs_info->cleaner_mutex);
|
||||
mutex_init(&fs_info->volume_mutex);
|
||||
mutex_init(&fs_info->tree_reloc_mutex);
|
||||
|
||||
btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
|
||||
btrfs_init_free_cluster(&fs_info->data_alloc_cluster);
|
||||
|
||||
init_waitqueue_head(&fs_info->transaction_throttle);
|
||||
init_waitqueue_head(&fs_info->transaction_wait);
|
||||
init_waitqueue_head(&fs_info->async_submit_wait);
|
||||
|
||||
+203
-213
File diff suppressed because it is too large
Load Diff
+5
-11
@@ -2884,25 +2884,19 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
disko = 0;
|
||||
flags = 0;
|
||||
|
||||
switch (em->block_start) {
|
||||
case EXTENT_MAP_LAST_BYTE:
|
||||
if (em->block_start == EXTENT_MAP_LAST_BYTE) {
|
||||
end = 1;
|
||||
flags |= FIEMAP_EXTENT_LAST;
|
||||
break;
|
||||
case EXTENT_MAP_HOLE:
|
||||
} else if (em->block_start == EXTENT_MAP_HOLE) {
|
||||
flags |= FIEMAP_EXTENT_UNWRITTEN;
|
||||
break;
|
||||
case EXTENT_MAP_INLINE:
|
||||
} else if (em->block_start == EXTENT_MAP_INLINE) {
|
||||
flags |= (FIEMAP_EXTENT_DATA_INLINE |
|
||||
FIEMAP_EXTENT_NOT_ALIGNED);
|
||||
break;
|
||||
case EXTENT_MAP_DELALLOC:
|
||||
} else if (em->block_start == EXTENT_MAP_DELALLOC) {
|
||||
flags |= (FIEMAP_EXTENT_DELALLOC |
|
||||
FIEMAP_EXTENT_UNKNOWN);
|
||||
break;
|
||||
default:
|
||||
} else {
|
||||
disko = em->block_start;
|
||||
break;
|
||||
}
|
||||
if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
|
||||
flags |= FIEMAP_EXTENT_ENCODED;
|
||||
|
||||
@@ -234,7 +234,6 @@ int add_extent_mapping(struct extent_map_tree *tree,
|
||||
rb = tree_insert(&tree->map, em->start, &em->rb_node);
|
||||
if (rb) {
|
||||
ret = -EEXIST;
|
||||
free_extent_map(merge);
|
||||
goto out;
|
||||
}
|
||||
atomic_inc(&em->refs);
|
||||
|
||||
+378
-158
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Oracle. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License v2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 021110-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __BTRFS_FREE_SPACE_CACHE
|
||||
#define __BTRFS_FREE_SPACE_CACHE
|
||||
|
||||
int btrfs_add_free_space(struct btrfs_block_group_cache *block_group,
|
||||
u64 bytenr, u64 size);
|
||||
int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
|
||||
u64 bytenr, u64 size);
|
||||
void btrfs_remove_free_space_cache(struct btrfs_block_group_cache
|
||||
*block_group);
|
||||
u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
|
||||
u64 offset, u64 bytes, u64 empty_size);
|
||||
void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
|
||||
u64 bytes);
|
||||
u64 btrfs_block_group_free_space(struct btrfs_block_group_cache *block_group);
|
||||
int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_block_group_cache *block_group,
|
||||
struct btrfs_free_cluster *cluster,
|
||||
u64 offset, u64 bytes, u64 empty_size);
|
||||
void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster);
|
||||
u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group,
|
||||
struct btrfs_free_cluster *cluster, u64 bytes,
|
||||
u64 min_start);
|
||||
int btrfs_return_cluster_to_free_space(
|
||||
struct btrfs_block_group_cache *block_group,
|
||||
struct btrfs_free_cluster *cluster);
|
||||
#endif
|
||||
+4
-1
@@ -3481,8 +3481,10 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
||||
|
||||
if (dir) {
|
||||
ret = btrfs_set_inode_index(dir, index);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
iput(inode);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* index_cnt is ignored for everything but a dir,
|
||||
@@ -3565,6 +3567,7 @@ fail:
|
||||
if (dir)
|
||||
BTRFS_I(dir)->index_cnt--;
|
||||
btrfs_free_path(path);
|
||||
iput(inode);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -60,8 +60,8 @@ void btrfs_clear_lock_blocking(struct extent_buffer *eb)
|
||||
|
||||
/*
|
||||
* unfortunately, many of the places that currently set a lock to blocking
|
||||
* don't end up blocking for every long, and often they don't block
|
||||
* at all. For a dbench 50 run, if we don't spin one the blocking bit
|
||||
* don't end up blocking for very long, and often they don't block
|
||||
* at all. For a dbench 50 run, if we don't spin on the blocking bit
|
||||
* at all, the context switch rate can jump up to 400,000/sec or more.
|
||||
*
|
||||
* So, we're still stuck with this crummy spin on the blocking bit,
|
||||
|
||||
+50
-4
@@ -24,6 +24,7 @@
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/backing-dev.h>
|
||||
@@ -66,7 +67,8 @@ static void btrfs_put_super(struct super_block *sb)
|
||||
enum {
|
||||
Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow,
|
||||
Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
|
||||
Opt_ssd, Opt_thread_pool, Opt_noacl, Opt_compress, Opt_err,
|
||||
Opt_ssd, Opt_thread_pool, Opt_noacl, Opt_compress, Opt_notreelog,
|
||||
Opt_flushoncommit, Opt_err,
|
||||
};
|
||||
|
||||
static match_table_t tokens = {
|
||||
@@ -83,6 +85,8 @@ static match_table_t tokens = {
|
||||
{Opt_compress, "compress"},
|
||||
{Opt_ssd, "ssd"},
|
||||
{Opt_noacl, "noacl"},
|
||||
{Opt_notreelog, "notreelog"},
|
||||
{Opt_flushoncommit, "flushoncommit"},
|
||||
{Opt_err, NULL},
|
||||
};
|
||||
|
||||
@@ -222,6 +226,14 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
|
||||
case Opt_noacl:
|
||||
root->fs_info->sb->s_flags &= ~MS_POSIXACL;
|
||||
break;
|
||||
case Opt_notreelog:
|
||||
printk(KERN_INFO "btrfs: disabling tree log\n");
|
||||
btrfs_set_opt(info->mount_opt, NOTREELOG);
|
||||
break;
|
||||
case Opt_flushoncommit:
|
||||
printk(KERN_INFO "btrfs: turning on flush-on-commit\n");
|
||||
btrfs_set_opt(info->mount_opt, FLUSHONCOMMIT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -363,9 +375,8 @@ fail_close:
|
||||
int btrfs_sync_fs(struct super_block *sb, int wait)
|
||||
{
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_root *root = btrfs_sb(sb);
|
||||
int ret;
|
||||
root = btrfs_sb(sb);
|
||||
|
||||
if (sb->s_flags & MS_RDONLY)
|
||||
return 0;
|
||||
@@ -385,6 +396,41 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
||||
{
|
||||
struct btrfs_root *root = btrfs_sb(vfs->mnt_sb);
|
||||
struct btrfs_fs_info *info = root->fs_info;
|
||||
|
||||
if (btrfs_test_opt(root, DEGRADED))
|
||||
seq_puts(seq, ",degraded");
|
||||
if (btrfs_test_opt(root, NODATASUM))
|
||||
seq_puts(seq, ",nodatasum");
|
||||
if (btrfs_test_opt(root, NODATACOW))
|
||||
seq_puts(seq, ",nodatacow");
|
||||
if (btrfs_test_opt(root, NOBARRIER))
|
||||
seq_puts(seq, ",nobarrier");
|
||||
if (info->max_extent != (u64)-1)
|
||||
seq_printf(seq, ",max_extent=%llu", info->max_extent);
|
||||
if (info->max_inline != 8192 * 1024)
|
||||
seq_printf(seq, ",max_inline=%llu", info->max_inline);
|
||||
if (info->alloc_start != 0)
|
||||
seq_printf(seq, ",alloc_start=%llu", info->alloc_start);
|
||||
if (info->thread_pool_size != min_t(unsigned long,
|
||||
num_online_cpus() + 2, 8))
|
||||
seq_printf(seq, ",thread_pool=%d", info->thread_pool_size);
|
||||
if (btrfs_test_opt(root, COMPRESS))
|
||||
seq_puts(seq, ",compress");
|
||||
if (btrfs_test_opt(root, SSD))
|
||||
seq_puts(seq, ",ssd");
|
||||
if (btrfs_test_opt(root, NOTREELOG))
|
||||
seq_puts(seq, ",no-treelog");
|
||||
if (btrfs_test_opt(root, FLUSHONCOMMIT))
|
||||
seq_puts(seq, ",flush-on-commit");
|
||||
if (!(root->fs_info->sb->s_flags & MS_POSIXACL))
|
||||
seq_puts(seq, ",noacl");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void btrfs_write_super(struct super_block *sb)
|
||||
{
|
||||
sb->s_dirt = 0;
|
||||
@@ -630,7 +676,7 @@ static struct super_operations btrfs_super_ops = {
|
||||
.put_super = btrfs_put_super,
|
||||
.write_super = btrfs_write_super,
|
||||
.sync_fs = btrfs_sync_fs,
|
||||
.show_options = generic_show_options,
|
||||
.show_options = btrfs_show_options,
|
||||
.write_inode = btrfs_write_inode,
|
||||
.dirty_inode = btrfs_dirty_inode,
|
||||
.alloc_inode = btrfs_alloc_inode,
|
||||
|
||||
@@ -53,8 +53,6 @@ static noinline int join_transaction(struct btrfs_root *root)
|
||||
GFP_NOFS);
|
||||
BUG_ON(!cur_trans);
|
||||
root->fs_info->generation++;
|
||||
root->fs_info->last_alloc = 0;
|
||||
root->fs_info->last_data_alloc = 0;
|
||||
cur_trans->num_writers = 1;
|
||||
cur_trans->num_joined = 0;
|
||||
cur_trans->transid = root->fs_info->generation;
|
||||
@@ -974,6 +972,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||
int ret;
|
||||
int should_grow = 0;
|
||||
unsigned long now = get_seconds();
|
||||
int flush_on_commit = btrfs_test_opt(root, FLUSHONCOMMIT);
|
||||
|
||||
btrfs_run_ordered_operations(root, 0);
|
||||
|
||||
@@ -1053,7 +1052,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||
|
||||
mutex_unlock(&root->fs_info->trans_mutex);
|
||||
|
||||
if (snap_pending) {
|
||||
if (flush_on_commit || snap_pending) {
|
||||
if (flush_on_commit)
|
||||
btrfs_start_delalloc_inodes(root);
|
||||
ret = btrfs_wait_ordered_extents(root, 1);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
+7
-5
@@ -262,11 +262,9 @@ static int process_one_buffer(struct btrfs_root *log,
|
||||
struct extent_buffer *eb,
|
||||
struct walk_control *wc, u64 gen)
|
||||
{
|
||||
if (wc->pin) {
|
||||
mutex_lock(&log->fs_info->pinned_mutex);
|
||||
if (wc->pin)
|
||||
btrfs_update_pinned_extents(log->fs_info->extent_root,
|
||||
eb->start, eb->len, 1);
|
||||
}
|
||||
|
||||
if (btrfs_buffer_uptodate(eb, gen)) {
|
||||
if (wc->write)
|
||||
@@ -1224,8 +1222,7 @@ insert:
|
||||
ret = insert_one_name(trans, root, path, key->objectid, key->offset,
|
||||
name, name_len, log_type, &log_key);
|
||||
|
||||
if (ret && ret != -ENOENT)
|
||||
BUG();
|
||||
BUG_ON(ret && ret != -ENOENT);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2900,6 +2897,11 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
|
||||
|
||||
sb = inode->i_sb;
|
||||
|
||||
if (btrfs_test_opt(root, NOTREELOG)) {
|
||||
ret = 1;
|
||||
goto end_no_trans;
|
||||
}
|
||||
|
||||
if (root->fs_info->last_trans_log_full_commit >
|
||||
root->fs_info->last_trans_committed) {
|
||||
ret = 1;
|
||||
|
||||
+40
-1
@@ -20,6 +20,7 @@
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/iocontext.h>
|
||||
#include <asm/div64.h>
|
||||
#include "compat.h"
|
||||
#include "ctree.h"
|
||||
@@ -145,8 +146,9 @@ static noinline int run_scheduled_bios(struct btrfs_device *device)
|
||||
int again = 0;
|
||||
unsigned long num_run = 0;
|
||||
unsigned long limit;
|
||||
unsigned long last_waited = 0;
|
||||
|
||||
bdi = device->bdev->bd_inode->i_mapping->backing_dev_info;
|
||||
bdi = blk_get_backing_dev_info(device->bdev);
|
||||
fs_info = device->dev_root->fs_info;
|
||||
limit = btrfs_async_submit_limit(fs_info);
|
||||
limit = limit * 2 / 3;
|
||||
@@ -207,7 +209,32 @@ loop_lock:
|
||||
if (pending && bdi_write_congested(bdi) && num_run > 16 &&
|
||||
fs_info->fs_devices->open_devices > 1) {
|
||||
struct bio *old_head;
|
||||
struct io_context *ioc;
|
||||
|
||||
ioc = current->io_context;
|
||||
|
||||
/*
|
||||
* the main goal here is that we don't want to
|
||||
* block if we're going to be able to submit
|
||||
* more requests without blocking.
|
||||
*
|
||||
* This code does two great things, it pokes into
|
||||
* the elevator code from a filesystem _and_
|
||||
* it makes assumptions about how batching works.
|
||||
*/
|
||||
if (ioc && ioc->nr_batch_requests > 0 &&
|
||||
time_before(jiffies, ioc->last_waited + HZ/50UL) &&
|
||||
(last_waited == 0 ||
|
||||
ioc->last_waited == last_waited)) {
|
||||
/*
|
||||
* we want to go through our batch of
|
||||
* requests and stop. So, we copy out
|
||||
* the ioc->last_waited time and test
|
||||
* against it before looping
|
||||
*/
|
||||
last_waited = ioc->last_waited;
|
||||
continue;
|
||||
}
|
||||
spin_lock(&device->io_lock);
|
||||
|
||||
old_head = device->pending_bios;
|
||||
@@ -231,6 +258,18 @@ loop_lock:
|
||||
if (device->pending_bios)
|
||||
goto loop_lock;
|
||||
spin_unlock(&device->io_lock);
|
||||
|
||||
/*
|
||||
* IO has already been through a long path to get here. Checksumming,
|
||||
* async helper threads, perhaps compression. We've done a pretty
|
||||
* good job of collecting a batch of IO and should just unplug
|
||||
* the device right away.
|
||||
*
|
||||
* This will help anyone who is waiting on the IO, they might have
|
||||
* already unplugged, but managed to do so before the bio they
|
||||
* cared about found its way down here.
|
||||
*/
|
||||
blk_run_backing_dev(bdi, NULL);
|
||||
done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
+1
-1
@@ -76,7 +76,7 @@ struct btrfs_device {
|
||||
struct btrfs_fs_devices {
|
||||
u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
|
||||
|
||||
/* the device with this id has the most recent coyp of the super */
|
||||
/* the device with this id has the most recent copy of the super */
|
||||
u64 latest_devid;
|
||||
u64 latest_trans;
|
||||
u64 num_devices;
|
||||
|
||||
Reference in New Issue
Block a user