mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull large btrfs update from Chris Mason:
"This pull request is very large, and the two main features in here
have been under testing/devel for quite a while.
We have subvolume quotas from the strato developers. This enables
full tracking of how many blocks are allocated to each subvolume (and
all snapshots) and you can set limits on a per-subvolume basis. You
can also create quota groups and toss multiple subvolumes into a big
group. It's everything you need to be a web hosting company and give
each user their own subvolume.
The userland side of the quotas is being refreshed, they'll send out
details on where to grab it soon.
Next is the kernel side of btrfs send/receive from Alexander Block.
This leverages the same infrastructure as the quota code to figure out
relationships between blocks and their owners. It can then compute
the difference between two snapshots and sends the diffs in a neutral
format into userland.
The basic model:
create a snapshot
send that snapshot as the initial backup
make changes
create a second snapshot
send the incremental as a backup
delete the first snapshot
(use the second snapshot for the next incremental)
The receive portion is all in userland, and in the 'next' branch of my
btrfs-progs repo.
There's still some work to do in terms of optimizing the send side
from kernel to userland. The really important part is figuring out
how two snapshots are different, and this is where we are
concentrating right now. The initial send of a dataset is a little
slower than tar, but the incremental sends are dramatically faster
than what rsync can do.
On top of all of that, we have a nice queue of fixes, cleanups and
optimizations."
Fix up trivial modify/del conflict in fs/btrfs/ioctl.c
Also fix up semantic conflict in fs/btrfs/send.c: the interface to
dentry_open() changed in commit 765927b2d5 ("switch dentry_open() to
struct path, make it grab references itself"), and since it now grabs
whatever references it needs, we should no longer do the mntget() on the
mnt (and we need to dput() the dentry reference we took).
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (65 commits)
Btrfs: uninit variable fixes in send/receive
Btrfs: introduce BTRFS_IOC_SEND for btrfs send/receive
Btrfs: add btrfs_compare_trees function
Btrfs: introduce subvol uuids and times
Btrfs: make iref_to_path non static
Btrfs: add a barrier before a waitqueue_active check
Btrfs: call the ordered free operation without any locks held
Btrfs: Check INCOMPAT flags on remount and add helper function
Btrfs: add helper for tree enumeration
btrfs: allow cross-subvolume file clone
Btrfs: improve multi-thread buffer read
Btrfs: make btrfs's allocation smoothly with preallocation
Btrfs: lock the transition from dirty to writeback for an eb
Btrfs: fix potential race in extent buffer freeing
Btrfs: don't return true in releasepage unless we actually freed the eb
Btrfs: suppress printk() if all device I/O stats are zero
Btrfs: remove unwanted printk() for btrfs device I/O stats
Btrfs: rewrite BTRFS_SETGET_FUNCS
Btrfs: zero unused bytes in inode item
Btrfs: kill free_space pointer from inode structure
...
Conflicts:
fs/btrfs/ioctl.c
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
|
||||
reada.o backref.o ulist.o qgroup.o send.o
|
||||
|
||||
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
|
||||
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
|
||||
|
||||
@@ -206,10 +206,17 @@ static noinline void run_ordered_completions(struct btrfs_workers *workers,
|
||||
|
||||
work->ordered_func(work);
|
||||
|
||||
/* now take the lock again and call the freeing code */
|
||||
/* now take the lock again and drop our item from the list */
|
||||
spin_lock(&workers->order_lock);
|
||||
list_del(&work->order_list);
|
||||
spin_unlock(&workers->order_lock);
|
||||
|
||||
/*
|
||||
* we don't want to call the ordered free functions
|
||||
* with the lock held though
|
||||
*/
|
||||
work->ordered_free(work);
|
||||
spin_lock(&workers->order_lock);
|
||||
}
|
||||
|
||||
spin_unlock(&workers->order_lock);
|
||||
|
||||
+14
-26
@@ -773,9 +773,8 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
|
||||
*/
|
||||
static int find_parent_nodes(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info, u64 bytenr,
|
||||
u64 delayed_ref_seq, u64 time_seq,
|
||||
struct ulist *refs, struct ulist *roots,
|
||||
const u64 *extent_item_pos)
|
||||
u64 time_seq, struct ulist *refs,
|
||||
struct ulist *roots, const u64 *extent_item_pos)
|
||||
{
|
||||
struct btrfs_key key;
|
||||
struct btrfs_path *path;
|
||||
@@ -837,7 +836,7 @@ again:
|
||||
btrfs_put_delayed_ref(&head->node);
|
||||
goto again;
|
||||
}
|
||||
ret = __add_delayed_refs(head, delayed_ref_seq,
|
||||
ret = __add_delayed_refs(head, time_seq,
|
||||
&prefs_delayed);
|
||||
mutex_unlock(&head->mutex);
|
||||
if (ret) {
|
||||
@@ -981,8 +980,7 @@ static void free_leaf_list(struct ulist *blocks)
|
||||
*/
|
||||
static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info, u64 bytenr,
|
||||
u64 delayed_ref_seq, u64 time_seq,
|
||||
struct ulist **leafs,
|
||||
u64 time_seq, struct ulist **leafs,
|
||||
const u64 *extent_item_pos)
|
||||
{
|
||||
struct ulist *tmp;
|
||||
@@ -997,7 +995,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = find_parent_nodes(trans, fs_info, bytenr, delayed_ref_seq,
|
||||
ret = find_parent_nodes(trans, fs_info, bytenr,
|
||||
time_seq, *leafs, tmp, extent_item_pos);
|
||||
ulist_free(tmp);
|
||||
|
||||
@@ -1024,8 +1022,7 @@ static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans,
|
||||
*/
|
||||
int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info, u64 bytenr,
|
||||
u64 delayed_ref_seq, u64 time_seq,
|
||||
struct ulist **roots)
|
||||
u64 time_seq, struct ulist **roots)
|
||||
{
|
||||
struct ulist *tmp;
|
||||
struct ulist_node *node = NULL;
|
||||
@@ -1043,7 +1040,7 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
|
||||
|
||||
ULIST_ITER_INIT(&uiter);
|
||||
while (1) {
|
||||
ret = find_parent_nodes(trans, fs_info, bytenr, delayed_ref_seq,
|
||||
ret = find_parent_nodes(trans, fs_info, bytenr,
|
||||
time_seq, tmp, *roots, NULL);
|
||||
if (ret < 0 && ret != -ENOENT) {
|
||||
ulist_free(tmp);
|
||||
@@ -1125,10 +1122,10 @@ static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
|
||||
* required for the path to fit into the buffer. in that case, the returned
|
||||
* value will be smaller than dest. callers must check this!
|
||||
*/
|
||||
static char *iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
|
||||
struct btrfs_inode_ref *iref,
|
||||
struct extent_buffer *eb_in, u64 parent,
|
||||
char *dest, u32 size)
|
||||
char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
|
||||
struct btrfs_inode_ref *iref,
|
||||
struct extent_buffer *eb_in, u64 parent,
|
||||
char *dest, u32 size)
|
||||
{
|
||||
u32 len;
|
||||
int slot;
|
||||
@@ -1376,11 +1373,9 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
|
||||
struct ulist *roots = NULL;
|
||||
struct ulist_node *ref_node = NULL;
|
||||
struct ulist_node *root_node = NULL;
|
||||
struct seq_list seq_elem = {};
|
||||
struct seq_list tree_mod_seq_elem = {};
|
||||
struct ulist_iterator ref_uiter;
|
||||
struct ulist_iterator root_uiter;
|
||||
struct btrfs_delayed_ref_root *delayed_refs = NULL;
|
||||
|
||||
pr_debug("resolving all inodes for extent %llu\n",
|
||||
extent_item_objectid);
|
||||
@@ -1391,16 +1386,11 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
|
||||
trans = btrfs_join_transaction(fs_info->extent_root);
|
||||
if (IS_ERR(trans))
|
||||
return PTR_ERR(trans);
|
||||
|
||||
delayed_refs = &trans->transaction->delayed_refs;
|
||||
spin_lock(&delayed_refs->lock);
|
||||
btrfs_get_delayed_seq(delayed_refs, &seq_elem);
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem);
|
||||
}
|
||||
|
||||
ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
|
||||
seq_elem.seq, tree_mod_seq_elem.seq, &refs,
|
||||
tree_mod_seq_elem.seq, &refs,
|
||||
&extent_item_pos);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -1408,8 +1398,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
|
||||
ULIST_ITER_INIT(&ref_uiter);
|
||||
while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) {
|
||||
ret = btrfs_find_all_roots(trans, fs_info, ref_node->val,
|
||||
seq_elem.seq,
|
||||
tree_mod_seq_elem.seq, &roots);
|
||||
tree_mod_seq_elem.seq, &roots);
|
||||
if (ret)
|
||||
break;
|
||||
ULIST_ITER_INIT(&root_uiter);
|
||||
@@ -1431,7 +1420,6 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
|
||||
out:
|
||||
if (!search_commit_root) {
|
||||
btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem);
|
||||
btrfs_put_delayed_seq(delayed_refs, &seq_elem);
|
||||
btrfs_end_transaction(trans, fs_info->extent_root);
|
||||
}
|
||||
|
||||
@@ -1543,7 +1531,7 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref,
|
||||
ipath->fspath->bytes_left - s_ptr : 0;
|
||||
|
||||
fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr;
|
||||
fspath = iref_to_path(ipath->fs_root, ipath->btrfs_path, iref, eb,
|
||||
fspath = btrfs_iref_to_path(ipath->fs_root, ipath->btrfs_path, iref, eb,
|
||||
inum, fspath_min, bytes_left);
|
||||
if (IS_ERR(fspath))
|
||||
return PTR_ERR(fspath);
|
||||
|
||||
+5
-2
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "ioctl.h"
|
||||
#include "ulist.h"
|
||||
#include "extent_io.h"
|
||||
|
||||
#define BTRFS_BACKREF_SEARCH_COMMIT_ROOT ((struct btrfs_trans_handle *)0)
|
||||
|
||||
@@ -58,8 +59,10 @@ int paths_from_inode(u64 inum, struct inode_fs_paths *ipath);
|
||||
|
||||
int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info, u64 bytenr,
|
||||
u64 delayed_ref_seq, u64 time_seq,
|
||||
struct ulist **roots);
|
||||
u64 time_seq, struct ulist **roots);
|
||||
char *btrfs_iref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path,
|
||||
struct btrfs_inode_ref *iref, struct extent_buffer *eb,
|
||||
u64 parent, char *dest, u32 size);
|
||||
|
||||
struct btrfs_data_container *init_data_container(u32 total_bytes);
|
||||
struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
|
||||
|
||||
@@ -87,9 +87,6 @@ struct btrfs_inode {
|
||||
/* node for the red-black tree that links inodes in subvolume root */
|
||||
struct rb_node rb_node;
|
||||
|
||||
/* the space_info for where this inode's data allocations are done */
|
||||
struct btrfs_space_info *space_info;
|
||||
|
||||
unsigned long runtime_flags;
|
||||
|
||||
/* full 64 bit generation number, struct vfs_inode doesn't have a big
|
||||
@@ -191,11 +188,14 @@ static inline void btrfs_i_size_write(struct inode *inode, u64 size)
|
||||
BTRFS_I(inode)->disk_i_size = size;
|
||||
}
|
||||
|
||||
static inline bool btrfs_is_free_space_inode(struct btrfs_root *root,
|
||||
struct inode *inode)
|
||||
static inline bool btrfs_is_free_space_inode(struct inode *inode)
|
||||
{
|
||||
if (root == root->fs_info->tree_root ||
|
||||
BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID)
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
|
||||
if (root == root->fs_info->tree_root &&
|
||||
btrfs_ino(inode) != BTRFS_BTREE_INODE_OBJECTID)
|
||||
return true;
|
||||
if (BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1032,6 +1032,7 @@ continue_with_current_leaf_stack_frame:
|
||||
struct btrfs_disk_key *disk_key;
|
||||
u8 type;
|
||||
u32 item_offset;
|
||||
u32 item_size;
|
||||
|
||||
if (disk_item_offset + sizeof(struct btrfs_item) >
|
||||
sf->block_ctx->len) {
|
||||
@@ -1047,6 +1048,7 @@ leaf_item_out_of_bounce_error:
|
||||
disk_item_offset,
|
||||
sizeof(struct btrfs_item));
|
||||
item_offset = le32_to_cpu(disk_item.offset);
|
||||
item_size = le32_to_cpu(disk_item.size);
|
||||
disk_key = &disk_item.key;
|
||||
type = disk_key->type;
|
||||
|
||||
@@ -1057,14 +1059,13 @@ leaf_item_out_of_bounce_error:
|
||||
|
||||
root_item_offset = item_offset +
|
||||
offsetof(struct btrfs_leaf, items);
|
||||
if (root_item_offset +
|
||||
sizeof(struct btrfs_root_item) >
|
||||
if (root_item_offset + item_size >
|
||||
sf->block_ctx->len)
|
||||
goto leaf_item_out_of_bounce_error;
|
||||
btrfsic_read_from_block_data(
|
||||
sf->block_ctx, &root_item,
|
||||
root_item_offset,
|
||||
sizeof(struct btrfs_root_item));
|
||||
item_size);
|
||||
next_bytenr = le64_to_cpu(root_item.bytenr);
|
||||
|
||||
sf->error =
|
||||
|
||||
+671
-104
File diff suppressed because it is too large
Load Diff
+353
-15
File diff suppressed because it is too large
Load Diff
@@ -62,6 +62,7 @@ static inline void btrfs_init_delayed_node(
|
||||
INIT_LIST_HEAD(&delayed_node->n_list);
|
||||
INIT_LIST_HEAD(&delayed_node->p_list);
|
||||
delayed_node->bytes_reserved = 0;
|
||||
memset(&delayed_node->inode_item, 0, sizeof(delayed_node->inode_item));
|
||||
}
|
||||
|
||||
static inline int btrfs_is_continuous_delayed_item(
|
||||
@@ -1113,8 +1114,8 @@ static int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
|
||||
* Returns < 0 on error and returns with an aborted transaction with any
|
||||
* outstanding delayed items cleaned up.
|
||||
*/
|
||||
int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, int nr)
|
||||
{
|
||||
struct btrfs_root *curr_root = root;
|
||||
struct btrfs_delayed_root *delayed_root;
|
||||
@@ -1122,6 +1123,7 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_block_rsv *block_rsv;
|
||||
int ret = 0;
|
||||
bool count = (nr > 0);
|
||||
|
||||
if (trans->aborted)
|
||||
return -EIO;
|
||||
@@ -1137,7 +1139,7 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
||||
delayed_root = btrfs_get_delayed_root(root);
|
||||
|
||||
curr_node = btrfs_first_delayed_node(delayed_root);
|
||||
while (curr_node) {
|
||||
while (curr_node && (!count || (count && nr--))) {
|
||||
curr_root = curr_node->root;
|
||||
ret = btrfs_insert_delayed_items(trans, path, curr_root,
|
||||
curr_node);
|
||||
@@ -1149,6 +1151,7 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
||||
path, curr_node);
|
||||
if (ret) {
|
||||
btrfs_release_delayed_node(curr_node);
|
||||
curr_node = NULL;
|
||||
btrfs_abort_transaction(trans, root, ret);
|
||||
break;
|
||||
}
|
||||
@@ -1158,12 +1161,26 @@ int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
||||
btrfs_release_delayed_node(prev_node);
|
||||
}
|
||||
|
||||
if (curr_node)
|
||||
btrfs_release_delayed_node(curr_node);
|
||||
btrfs_free_path(path);
|
||||
trans->block_rsv = block_rsv;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
return __btrfs_run_delayed_items(trans, root, -1);
|
||||
}
|
||||
|
||||
int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, int nr)
|
||||
{
|
||||
return __btrfs_run_delayed_items(trans, root, nr);
|
||||
}
|
||||
|
||||
static int __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_delayed_node *node)
|
||||
{
|
||||
|
||||
@@ -107,6 +107,8 @@ int btrfs_inode_delayed_dir_index_count(struct inode *inode);
|
||||
|
||||
int btrfs_run_delayed_items(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, int nr);
|
||||
|
||||
void btrfs_balance_delayed_items(struct btrfs_root *root);
|
||||
|
||||
|
||||
+31
-23
@@ -233,22 +233,26 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_check_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs,
|
||||
int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_delayed_ref_root *delayed_refs,
|
||||
u64 seq)
|
||||
{
|
||||
struct seq_list *elem;
|
||||
int ret = 0;
|
||||
|
||||
assert_spin_locked(&delayed_refs->lock);
|
||||
if (list_empty(&delayed_refs->seq_head))
|
||||
return 0;
|
||||
|
||||
elem = list_first_entry(&delayed_refs->seq_head, struct seq_list, list);
|
||||
if (seq >= elem->seq) {
|
||||
pr_debug("holding back delayed_ref %llu, lowest is %llu (%p)\n",
|
||||
seq, elem->seq, delayed_refs);
|
||||
return 1;
|
||||
spin_lock(&fs_info->tree_mod_seq_lock);
|
||||
if (!list_empty(&fs_info->tree_mod_seq_list)) {
|
||||
elem = list_first_entry(&fs_info->tree_mod_seq_list,
|
||||
struct seq_list, list);
|
||||
if (seq >= elem->seq) {
|
||||
pr_debug("holding back delayed_ref %llu, lowest is "
|
||||
"%llu (%p)\n", seq, elem->seq, delayed_refs);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
spin_unlock(&fs_info->tree_mod_seq_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
|
||||
@@ -525,8 +529,8 @@ static noinline void add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
|
||||
ref->is_head = 0;
|
||||
ref->in_tree = 1;
|
||||
|
||||
if (is_fstree(ref_root))
|
||||
seq = inc_delayed_seq(delayed_refs);
|
||||
if (need_ref_seq(for_cow, ref_root))
|
||||
seq = btrfs_get_tree_mod_seq(fs_info, &trans->delayed_ref_elem);
|
||||
ref->seq = seq;
|
||||
|
||||
full_ref = btrfs_delayed_node_to_tree_ref(ref);
|
||||
@@ -584,8 +588,8 @@ static noinline void add_delayed_data_ref(struct btrfs_fs_info *fs_info,
|
||||
ref->is_head = 0;
|
||||
ref->in_tree = 1;
|
||||
|
||||
if (is_fstree(ref_root))
|
||||
seq = inc_delayed_seq(delayed_refs);
|
||||
if (need_ref_seq(for_cow, ref_root))
|
||||
seq = btrfs_get_tree_mod_seq(fs_info, &trans->delayed_ref_elem);
|
||||
ref->seq = seq;
|
||||
|
||||
full_ref = btrfs_delayed_node_to_data_ref(ref);
|
||||
@@ -658,10 +662,12 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
|
||||
add_delayed_tree_ref(fs_info, trans, &ref->node, bytenr,
|
||||
num_bytes, parent, ref_root, level, action,
|
||||
for_cow);
|
||||
if (!is_fstree(ref_root) &&
|
||||
waitqueue_active(&delayed_refs->seq_wait))
|
||||
wake_up(&delayed_refs->seq_wait);
|
||||
if (!need_ref_seq(for_cow, ref_root) &&
|
||||
waitqueue_active(&fs_info->tree_mod_seq_wait))
|
||||
wake_up(&fs_info->tree_mod_seq_wait);
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
if (need_ref_seq(for_cow, ref_root))
|
||||
btrfs_qgroup_record_ref(trans, &ref->node, extent_op);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -707,10 +713,12 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
|
||||
add_delayed_data_ref(fs_info, trans, &ref->node, bytenr,
|
||||
num_bytes, parent, ref_root, owner, offset,
|
||||
action, for_cow);
|
||||
if (!is_fstree(ref_root) &&
|
||||
waitqueue_active(&delayed_refs->seq_wait))
|
||||
wake_up(&delayed_refs->seq_wait);
|
||||
if (!need_ref_seq(for_cow, ref_root) &&
|
||||
waitqueue_active(&fs_info->tree_mod_seq_wait))
|
||||
wake_up(&fs_info->tree_mod_seq_wait);
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
if (need_ref_seq(for_cow, ref_root))
|
||||
btrfs_qgroup_record_ref(trans, &ref->node, extent_op);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -736,8 +744,8 @@ int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
|
||||
num_bytes, BTRFS_UPDATE_DELAYED_HEAD,
|
||||
extent_op->is_data);
|
||||
|
||||
if (waitqueue_active(&delayed_refs->seq_wait))
|
||||
wake_up(&delayed_refs->seq_wait);
|
||||
if (waitqueue_active(&fs_info->tree_mod_seq_wait))
|
||||
wake_up(&fs_info->tree_mod_seq_wait);
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+21
-47
@@ -139,26 +139,6 @@ struct btrfs_delayed_ref_root {
|
||||
int flushing;
|
||||
|
||||
u64 run_delayed_start;
|
||||
|
||||
/*
|
||||
* seq number of delayed refs. We need to know if a backref was being
|
||||
* added before the currently processed ref or afterwards.
|
||||
*/
|
||||
u64 seq;
|
||||
|
||||
/*
|
||||
* seq_list holds a list of all seq numbers that are currently being
|
||||
* added to the list. While walking backrefs (btrfs_find_all_roots,
|
||||
* qgroups), which might take some time, no newer ref must be processed,
|
||||
* as it might influence the outcome of the walk.
|
||||
*/
|
||||
struct list_head seq_head;
|
||||
|
||||
/*
|
||||
* when the only refs we have in the list must not be processed, we want
|
||||
* to wait for more refs to show up or for the end of backref walking.
|
||||
*/
|
||||
wait_queue_head_t seq_wait;
|
||||
};
|
||||
|
||||
static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref)
|
||||
@@ -195,35 +175,29 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
|
||||
int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
|
||||
struct list_head *cluster, u64 search_start);
|
||||
|
||||
static inline u64 inc_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs)
|
||||
{
|
||||
assert_spin_locked(&delayed_refs->lock);
|
||||
++delayed_refs->seq;
|
||||
return delayed_refs->seq;
|
||||
}
|
||||
|
||||
static inline void
|
||||
btrfs_get_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs,
|
||||
struct seq_list *elem)
|
||||
{
|
||||
assert_spin_locked(&delayed_refs->lock);
|
||||
elem->seq = delayed_refs->seq;
|
||||
list_add_tail(&elem->list, &delayed_refs->seq_head);
|
||||
}
|
||||
|
||||
static inline void
|
||||
btrfs_put_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs,
|
||||
struct seq_list *elem)
|
||||
{
|
||||
spin_lock(&delayed_refs->lock);
|
||||
list_del(&elem->list);
|
||||
wake_up(&delayed_refs->seq_wait);
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
}
|
||||
|
||||
int btrfs_check_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs,
|
||||
int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_delayed_ref_root *delayed_refs,
|
||||
u64 seq);
|
||||
|
||||
/*
|
||||
* delayed refs with a ref_seq > 0 must be held back during backref walking.
|
||||
* this only applies to items in one of the fs-trees. for_cow items never need
|
||||
* to be held back, so they won't get a ref_seq number.
|
||||
*/
|
||||
static inline int need_ref_seq(int for_cow, u64 rootid)
|
||||
{
|
||||
if (for_cow)
|
||||
return 0;
|
||||
|
||||
if (rootid == BTRFS_FS_TREE_OBJECTID)
|
||||
return 1;
|
||||
|
||||
if ((s64)rootid >= (s64)BTRFS_FIRST_FREE_OBJECTID)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* a node might live in a head or a regular ref, this lets you
|
||||
* test for the proper type to use.
|
||||
|
||||
+136
-14
@@ -407,7 +407,7 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
|
||||
break;
|
||||
}
|
||||
|
||||
if (failed && !ret)
|
||||
if (failed && !ret && failed_mirror)
|
||||
repair_eb_io_failure(root, eb, failed_mirror);
|
||||
|
||||
return ret;
|
||||
@@ -1182,6 +1182,8 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
|
||||
root->defrag_running = 0;
|
||||
root->root_key.objectid = objectid;
|
||||
root->anon_dev = 0;
|
||||
|
||||
spin_lock_init(&root->root_times_lock);
|
||||
}
|
||||
|
||||
static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
|
||||
@@ -1225,6 +1227,82 @@ static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info)
|
||||
return root;
|
||||
}
|
||||
|
||||
struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info,
|
||||
u64 objectid)
|
||||
{
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_root *tree_root = fs_info->tree_root;
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_key key;
|
||||
int ret = 0;
|
||||
u64 bytenr;
|
||||
|
||||
root = btrfs_alloc_root(fs_info);
|
||||
if (!root)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
__setup_root(tree_root->nodesize, tree_root->leafsize,
|
||||
tree_root->sectorsize, tree_root->stripesize,
|
||||
root, fs_info, objectid);
|
||||
root->root_key.objectid = objectid;
|
||||
root->root_key.type = BTRFS_ROOT_ITEM_KEY;
|
||||
root->root_key.offset = 0;
|
||||
|
||||
leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
|
||||
0, objectid, NULL, 0, 0, 0);
|
||||
if (IS_ERR(leaf)) {
|
||||
ret = PTR_ERR(leaf);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bytenr = leaf->start;
|
||||
memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header));
|
||||
btrfs_set_header_bytenr(leaf, leaf->start);
|
||||
btrfs_set_header_generation(leaf, trans->transid);
|
||||
btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV);
|
||||
btrfs_set_header_owner(leaf, objectid);
|
||||
root->node = leaf;
|
||||
|
||||
write_extent_buffer(leaf, fs_info->fsid,
|
||||
(unsigned long)btrfs_header_fsid(leaf),
|
||||
BTRFS_FSID_SIZE);
|
||||
write_extent_buffer(leaf, fs_info->chunk_tree_uuid,
|
||||
(unsigned long)btrfs_header_chunk_tree_uuid(leaf),
|
||||
BTRFS_UUID_SIZE);
|
||||
btrfs_mark_buffer_dirty(leaf);
|
||||
|
||||
root->commit_root = btrfs_root_node(root);
|
||||
root->track_dirty = 1;
|
||||
|
||||
|
||||
root->root_item.flags = 0;
|
||||
root->root_item.byte_limit = 0;
|
||||
btrfs_set_root_bytenr(&root->root_item, leaf->start);
|
||||
btrfs_set_root_generation(&root->root_item, trans->transid);
|
||||
btrfs_set_root_level(&root->root_item, 0);
|
||||
btrfs_set_root_refs(&root->root_item, 1);
|
||||
btrfs_set_root_used(&root->root_item, leaf->len);
|
||||
btrfs_set_root_last_snapshot(&root->root_item, 0);
|
||||
btrfs_set_root_dirid(&root->root_item, 0);
|
||||
root->root_item.drop_level = 0;
|
||||
|
||||
key.objectid = objectid;
|
||||
key.type = BTRFS_ROOT_ITEM_KEY;
|
||||
key.offset = 0;
|
||||
ret = btrfs_insert_root(trans, tree_root, &key, &root->root_item);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
btrfs_tree_unlock(leaf);
|
||||
|
||||
fail:
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
@@ -1326,6 +1404,7 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
|
||||
u64 generation;
|
||||
u32 blocksize;
|
||||
int ret = 0;
|
||||
int slot;
|
||||
|
||||
root = btrfs_alloc_root(fs_info);
|
||||
if (!root)
|
||||
@@ -1352,9 +1431,8 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
|
||||
ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0);
|
||||
if (ret == 0) {
|
||||
l = path->nodes[0];
|
||||
read_extent_buffer(l, &root->root_item,
|
||||
btrfs_item_ptr_offset(l, path->slots[0]),
|
||||
sizeof(root->root_item));
|
||||
slot = path->slots[0];
|
||||
btrfs_read_root_item(tree_root, l, slot, &root->root_item);
|
||||
memcpy(&root->root_key, location, sizeof(*location));
|
||||
}
|
||||
btrfs_free_path(path);
|
||||
@@ -1396,6 +1474,9 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
|
||||
return fs_info->dev_root;
|
||||
if (location->objectid == BTRFS_CSUM_TREE_OBJECTID)
|
||||
return fs_info->csum_root;
|
||||
if (location->objectid == BTRFS_QUOTA_TREE_OBJECTID)
|
||||
return fs_info->quota_root ? fs_info->quota_root :
|
||||
ERR_PTR(-ENOENT);
|
||||
again:
|
||||
spin_lock(&fs_info->fs_roots_radix_lock);
|
||||
root = radix_tree_lookup(&fs_info->fs_roots_radix,
|
||||
@@ -1823,6 +1904,10 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
|
||||
free_extent_buffer(info->extent_root->commit_root);
|
||||
free_extent_buffer(info->csum_root->node);
|
||||
free_extent_buffer(info->csum_root->commit_root);
|
||||
if (info->quota_root) {
|
||||
free_extent_buffer(info->quota_root->node);
|
||||
free_extent_buffer(info->quota_root->commit_root);
|
||||
}
|
||||
|
||||
info->tree_root->node = NULL;
|
||||
info->tree_root->commit_root = NULL;
|
||||
@@ -1832,6 +1917,10 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
|
||||
info->extent_root->commit_root = NULL;
|
||||
info->csum_root->node = NULL;
|
||||
info->csum_root->commit_root = NULL;
|
||||
if (info->quota_root) {
|
||||
info->quota_root->node = NULL;
|
||||
info->quota_root->commit_root = NULL;
|
||||
}
|
||||
|
||||
if (chunk_root) {
|
||||
free_extent_buffer(info->chunk_root->node);
|
||||
@@ -1862,6 +1951,7 @@ int open_ctree(struct super_block *sb,
|
||||
struct btrfs_root *csum_root;
|
||||
struct btrfs_root *chunk_root;
|
||||
struct btrfs_root *dev_root;
|
||||
struct btrfs_root *quota_root;
|
||||
struct btrfs_root *log_tree_root;
|
||||
int ret;
|
||||
int err = -EINVAL;
|
||||
@@ -1873,9 +1963,10 @@ int open_ctree(struct super_block *sb,
|
||||
csum_root = fs_info->csum_root = btrfs_alloc_root(fs_info);
|
||||
chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info);
|
||||
dev_root = fs_info->dev_root = btrfs_alloc_root(fs_info);
|
||||
quota_root = fs_info->quota_root = btrfs_alloc_root(fs_info);
|
||||
|
||||
if (!tree_root || !extent_root || !csum_root ||
|
||||
!chunk_root || !dev_root) {
|
||||
!chunk_root || !dev_root || !quota_root) {
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
@@ -1944,6 +2035,8 @@ int open_ctree(struct super_block *sb,
|
||||
fs_info->free_chunk_space = 0;
|
||||
fs_info->tree_mod_log = RB_ROOT;
|
||||
|
||||
init_waitqueue_head(&fs_info->tree_mod_seq_wait);
|
||||
|
||||
/* readahead state */
|
||||
INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_WAIT);
|
||||
spin_lock_init(&fs_info->reada_lock);
|
||||
@@ -2032,6 +2125,13 @@ int open_ctree(struct super_block *sb,
|
||||
init_rwsem(&fs_info->cleanup_work_sem);
|
||||
init_rwsem(&fs_info->subvol_sem);
|
||||
|
||||
spin_lock_init(&fs_info->qgroup_lock);
|
||||
fs_info->qgroup_tree = RB_ROOT;
|
||||
INIT_LIST_HEAD(&fs_info->dirty_qgroups);
|
||||
fs_info->qgroup_seq = 1;
|
||||
fs_info->quota_enabled = 0;
|
||||
fs_info->pending_quota_state = 0;
|
||||
|
||||
btrfs_init_free_cluster(&fs_info->meta_alloc_cluster);
|
||||
btrfs_init_free_cluster(&fs_info->data_alloc_cluster);
|
||||
|
||||
@@ -2244,7 +2344,7 @@ int open_ctree(struct super_block *sb,
|
||||
ret |= btrfs_start_workers(&fs_info->caching_workers);
|
||||
ret |= btrfs_start_workers(&fs_info->readahead_workers);
|
||||
if (ret) {
|
||||
ret = -ENOMEM;
|
||||
err = -ENOMEM;
|
||||
goto fail_sb_buffer;
|
||||
}
|
||||
|
||||
@@ -2356,6 +2456,17 @@ retry_root_backup:
|
||||
goto recovery_tree_root;
|
||||
csum_root->track_dirty = 1;
|
||||
|
||||
ret = find_and_setup_root(tree_root, fs_info,
|
||||
BTRFS_QUOTA_TREE_OBJECTID, quota_root);
|
||||
if (ret) {
|
||||
kfree(quota_root);
|
||||
quota_root = fs_info->quota_root = NULL;
|
||||
} else {
|
||||
quota_root->track_dirty = 1;
|
||||
fs_info->quota_enabled = 1;
|
||||
fs_info->pending_quota_state = 1;
|
||||
}
|
||||
|
||||
fs_info->generation = generation;
|
||||
fs_info->last_trans_committed = generation;
|
||||
|
||||
@@ -2415,6 +2526,9 @@ retry_root_backup:
|
||||
" integrity check module %s\n", sb->s_id);
|
||||
}
|
||||
#endif
|
||||
ret = btrfs_read_qgroup_config(fs_info);
|
||||
if (ret)
|
||||
goto fail_trans_kthread;
|
||||
|
||||
/* do not make disk changes in broken FS */
|
||||
if (btrfs_super_log_root(disk_super) != 0 &&
|
||||
@@ -2425,7 +2539,7 @@ retry_root_backup:
|
||||
printk(KERN_WARNING "Btrfs log replay required "
|
||||
"on RO media\n");
|
||||
err = -EIO;
|
||||
goto fail_trans_kthread;
|
||||
goto fail_qgroup;
|
||||
}
|
||||
blocksize =
|
||||
btrfs_level_size(tree_root,
|
||||
@@ -2434,7 +2548,7 @@ retry_root_backup:
|
||||
log_tree_root = btrfs_alloc_root(fs_info);
|
||||
if (!log_tree_root) {
|
||||
err = -ENOMEM;
|
||||
goto fail_trans_kthread;
|
||||
goto fail_qgroup;
|
||||
}
|
||||
|
||||
__setup_root(nodesize, leafsize, sectorsize, stripesize,
|
||||
@@ -2466,15 +2580,15 @@ retry_root_backup:
|
||||
|
||||
if (!(sb->s_flags & MS_RDONLY)) {
|
||||
ret = btrfs_cleanup_fs_roots(fs_info);
|
||||
if (ret) {
|
||||
}
|
||||
if (ret)
|
||||
goto fail_trans_kthread;
|
||||
|
||||
ret = btrfs_recover_relocation(tree_root);
|
||||
if (ret < 0) {
|
||||
printk(KERN_WARNING
|
||||
"btrfs: failed to recover relocation\n");
|
||||
err = -EINVAL;
|
||||
goto fail_trans_kthread;
|
||||
goto fail_qgroup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2484,10 +2598,10 @@ retry_root_backup:
|
||||
|
||||
fs_info->fs_root = btrfs_read_fs_root_no_name(fs_info, &location);
|
||||
if (!fs_info->fs_root)
|
||||
goto fail_trans_kthread;
|
||||
goto fail_qgroup;
|
||||
if (IS_ERR(fs_info->fs_root)) {
|
||||
err = PTR_ERR(fs_info->fs_root);
|
||||
goto fail_trans_kthread;
|
||||
goto fail_qgroup;
|
||||
}
|
||||
|
||||
if (sb->s_flags & MS_RDONLY)
|
||||
@@ -2511,6 +2625,8 @@ retry_root_backup:
|
||||
|
||||
return 0;
|
||||
|
||||
fail_qgroup:
|
||||
btrfs_free_qgroup_config(fs_info);
|
||||
fail_trans_kthread:
|
||||
kthread_stop(fs_info->transaction_kthread);
|
||||
fail_cleaner:
|
||||
@@ -3109,6 +3225,8 @@ int close_ctree(struct btrfs_root *root)
|
||||
fs_info->closing = 2;
|
||||
smp_mb();
|
||||
|
||||
btrfs_free_qgroup_config(root->fs_info);
|
||||
|
||||
if (fs_info->delalloc_bytes) {
|
||||
printk(KERN_INFO "btrfs: at unmount delalloc count %llu\n",
|
||||
(unsigned long long)fs_info->delalloc_bytes);
|
||||
@@ -3128,6 +3246,10 @@ int close_ctree(struct btrfs_root *root)
|
||||
free_extent_buffer(fs_info->dev_root->commit_root);
|
||||
free_extent_buffer(fs_info->csum_root->node);
|
||||
free_extent_buffer(fs_info->csum_root->commit_root);
|
||||
if (fs_info->quota_root) {
|
||||
free_extent_buffer(fs_info->quota_root->node);
|
||||
free_extent_buffer(fs_info->quota_root->commit_root);
|
||||
}
|
||||
|
||||
btrfs_free_block_groups(fs_info);
|
||||
|
||||
@@ -3258,7 +3380,7 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
|
||||
return btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
|
||||
}
|
||||
|
||||
static int btree_lock_page_hook(struct page *page, void *data,
|
||||
int btree_lock_page_hook(struct page *page, void *data,
|
||||
void (*flush_fn)(void *))
|
||||
{
|
||||
struct inode *inode = page->mapping->host;
|
||||
|
||||
@@ -89,6 +89,12 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
|
||||
int btrfs_cleanup_transaction(struct btrfs_root *root);
|
||||
void btrfs_cleanup_one_transaction(struct btrfs_transaction *trans,
|
||||
struct btrfs_root *root);
|
||||
void btrfs_abort_devices(struct btrfs_root *root);
|
||||
struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_fs_info *fs_info,
|
||||
u64 objectid);
|
||||
int btree_lock_page_hook(struct page *page, void *data,
|
||||
void (*flush_fn)(void *));
|
||||
|
||||
#ifdef CONFIG_DEBUG_LOCK_ALLOC
|
||||
void btrfs_init_lockdep(void);
|
||||
|
||||
+240
-118
File diff suppressed because it is too large
Load Diff
+42
-16
@@ -1919,7 +1919,7 @@ int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
printk_in_rcu(KERN_INFO "btrfs read error corrected: ino %lu off %llu "
|
||||
printk_ratelimited_in_rcu(KERN_INFO "btrfs read error corrected: ino %lu off %llu "
|
||||
"(dev %s sector %llu)\n", page->mapping->host->i_ino,
|
||||
start, rcu_str_deref(dev->name), sector);
|
||||
|
||||
@@ -3078,8 +3078,15 @@ static int lock_extent_buffer_for_io(struct extent_buffer *eb,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to do this to prevent races in people who check if the eb is
|
||||
* under IO since we can end up having no IO bits set for a short period
|
||||
* of time.
|
||||
*/
|
||||
spin_lock(&eb->refs_lock);
|
||||
if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) {
|
||||
set_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags);
|
||||
spin_unlock(&eb->refs_lock);
|
||||
btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
|
||||
spin_lock(&fs_info->delalloc_lock);
|
||||
if (fs_info->dirty_metadata_bytes >= eb->len)
|
||||
@@ -3088,6 +3095,8 @@ static int lock_extent_buffer_for_io(struct extent_buffer *eb,
|
||||
WARN_ON(1);
|
||||
spin_unlock(&fs_info->delalloc_lock);
|
||||
ret = 1;
|
||||
} else {
|
||||
spin_unlock(&eb->refs_lock);
|
||||
}
|
||||
|
||||
btrfs_tree_unlock(eb);
|
||||
@@ -3558,19 +3567,38 @@ int extent_readpages(struct extent_io_tree *tree,
|
||||
struct bio *bio = NULL;
|
||||
unsigned page_idx;
|
||||
unsigned long bio_flags = 0;
|
||||
struct page *pagepool[16];
|
||||
struct page *page;
|
||||
int i = 0;
|
||||
int nr = 0;
|
||||
|
||||
for (page_idx = 0; page_idx < nr_pages; page_idx++) {
|
||||
struct page *page = list_entry(pages->prev, struct page, lru);
|
||||
page = list_entry(pages->prev, struct page, lru);
|
||||
|
||||
prefetchw(&page->flags);
|
||||
list_del(&page->lru);
|
||||
if (!add_to_page_cache_lru(page, mapping,
|
||||
if (add_to_page_cache_lru(page, mapping,
|
||||
page->index, GFP_NOFS)) {
|
||||
__extent_read_full_page(tree, page, get_extent,
|
||||
&bio, 0, &bio_flags);
|
||||
page_cache_release(page);
|
||||
continue;
|
||||
}
|
||||
page_cache_release(page);
|
||||
|
||||
pagepool[nr++] = page;
|
||||
if (nr < ARRAY_SIZE(pagepool))
|
||||
continue;
|
||||
for (i = 0; i < nr; i++) {
|
||||
__extent_read_full_page(tree, pagepool[i], get_extent,
|
||||
&bio, 0, &bio_flags);
|
||||
page_cache_release(pagepool[i]);
|
||||
}
|
||||
nr = 0;
|
||||
}
|
||||
for (i = 0; i < nr; i++) {
|
||||
__extent_read_full_page(tree, pagepool[i], get_extent,
|
||||
&bio, 0, &bio_flags);
|
||||
page_cache_release(pagepool[i]);
|
||||
}
|
||||
|
||||
BUG_ON(!list_empty(pages));
|
||||
if (bio)
|
||||
return submit_one_bio(READ, bio, 0, bio_flags);
|
||||
@@ -4124,11 +4152,10 @@ static void check_buffer_tree_ref(struct extent_buffer *eb)
|
||||
* So bump the ref count first, then set the bit. If someone
|
||||
* beat us to it, drop the ref we added.
|
||||
*/
|
||||
if (!test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) {
|
||||
spin_lock(&eb->refs_lock);
|
||||
if (!test_and_set_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
|
||||
atomic_inc(&eb->refs);
|
||||
if (test_and_set_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
|
||||
atomic_dec(&eb->refs);
|
||||
}
|
||||
spin_unlock(&eb->refs_lock);
|
||||
}
|
||||
|
||||
static void mark_extent_buffer_accessed(struct extent_buffer *eb)
|
||||
@@ -4240,9 +4267,7 @@ again:
|
||||
goto free_eb;
|
||||
}
|
||||
/* add one reference for the tree */
|
||||
spin_lock(&eb->refs_lock);
|
||||
check_buffer_tree_ref(eb);
|
||||
spin_unlock(&eb->refs_lock);
|
||||
spin_unlock(&tree->buffer_lock);
|
||||
radix_tree_preload_end();
|
||||
|
||||
@@ -4301,7 +4326,7 @@ static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head)
|
||||
}
|
||||
|
||||
/* Expects to have eb->eb_lock already held */
|
||||
static void release_extent_buffer(struct extent_buffer *eb, gfp_t mask)
|
||||
static int release_extent_buffer(struct extent_buffer *eb, gfp_t mask)
|
||||
{
|
||||
WARN_ON(atomic_read(&eb->refs) == 0);
|
||||
if (atomic_dec_and_test(&eb->refs)) {
|
||||
@@ -4322,9 +4347,11 @@ static void release_extent_buffer(struct extent_buffer *eb, gfp_t mask)
|
||||
btrfs_release_extent_buffer_page(eb, 0);
|
||||
|
||||
call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu);
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
spin_unlock(&eb->refs_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void free_extent_buffer(struct extent_buffer *eb)
|
||||
@@ -4963,7 +4990,6 @@ int try_release_extent_buffer(struct page *page, gfp_t mask)
|
||||
spin_unlock(&eb->refs_lock);
|
||||
return 0;
|
||||
}
|
||||
release_extent_buffer(eb, mask);
|
||||
|
||||
return 1;
|
||||
return release_extent_buffer(eb, mask);
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
|
||||
* read from the commit root and sidestep a nasty deadlock
|
||||
* between reading the free space cache and updating the csum tree.
|
||||
*/
|
||||
if (btrfs_is_free_space_inode(root, inode)) {
|
||||
if (btrfs_is_free_space_inode(inode)) {
|
||||
path->search_commit_root = 1;
|
||||
path->skip_locking = 1;
|
||||
}
|
||||
@@ -690,6 +690,7 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
|
||||
return -ENOMEM;
|
||||
|
||||
sector_sum = sums->sums;
|
||||
trans->adding_csums = 1;
|
||||
again:
|
||||
next_offset = (u64)-1;
|
||||
found_next = 0;
|
||||
@@ -853,6 +854,7 @@ next_sector:
|
||||
goto again;
|
||||
}
|
||||
out:
|
||||
trans->adding_csums = 0;
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
|
||||
|
||||
@@ -1968,7 +1968,7 @@ void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
|
||||
|
||||
for (n = rb_first(&ctl->free_space_offset); n; n = rb_next(n)) {
|
||||
info = rb_entry(n, struct btrfs_free_space, offset_index);
|
||||
if (info->bytes >= bytes)
|
||||
if (info->bytes >= bytes && !block_group->ro)
|
||||
count++;
|
||||
printk(KERN_CRIT "entry offset %llu, bytes %llu, bitmap %s\n",
|
||||
(unsigned long long)info->offset,
|
||||
|
||||
+25
-17
@@ -825,7 +825,7 @@ static noinline int cow_file_range(struct inode *inode,
|
||||
struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(btrfs_is_free_space_inode(root, inode));
|
||||
BUG_ON(btrfs_is_free_space_inode(inode));
|
||||
trans = btrfs_join_transaction(root);
|
||||
if (IS_ERR(trans)) {
|
||||
extent_clear_unlock_delalloc(inode,
|
||||
@@ -1010,7 +1010,7 @@ static noinline void async_cow_submit(struct btrfs_work *work)
|
||||
atomic_sub(nr_pages, &root->fs_info->async_delalloc_pages);
|
||||
|
||||
if (atomic_read(&root->fs_info->async_delalloc_pages) <
|
||||
5 * 1042 * 1024 &&
|
||||
5 * 1024 * 1024 &&
|
||||
waitqueue_active(&root->fs_info->async_submit_wait))
|
||||
wake_up(&root->fs_info->async_submit_wait);
|
||||
|
||||
@@ -1035,7 +1035,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
unsigned long nr_pages;
|
||||
u64 cur_end;
|
||||
int limit = 10 * 1024 * 1042;
|
||||
int limit = 10 * 1024 * 1024;
|
||||
|
||||
clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, EXTENT_LOCKED,
|
||||
1, 0, NULL, GFP_NOFS);
|
||||
@@ -1153,7 +1153,7 @@ static noinline int run_delalloc_nocow(struct inode *inode,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nolock = btrfs_is_free_space_inode(root, inode);
|
||||
nolock = btrfs_is_free_space_inode(inode);
|
||||
|
||||
if (nolock)
|
||||
trans = btrfs_join_transaction_nolock(root);
|
||||
@@ -1466,7 +1466,7 @@ static void btrfs_set_bit_hook(struct inode *inode,
|
||||
if (!(state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
u64 len = state->end + 1 - state->start;
|
||||
bool do_list = !btrfs_is_free_space_inode(root, inode);
|
||||
bool do_list = !btrfs_is_free_space_inode(inode);
|
||||
|
||||
if (*bits & EXTENT_FIRST_DELALLOC) {
|
||||
*bits &= ~EXTENT_FIRST_DELALLOC;
|
||||
@@ -1501,7 +1501,7 @@ static void btrfs_clear_bit_hook(struct inode *inode,
|
||||
if ((state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) {
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
u64 len = state->end + 1 - state->start;
|
||||
bool do_list = !btrfs_is_free_space_inode(root, inode);
|
||||
bool do_list = !btrfs_is_free_space_inode(inode);
|
||||
|
||||
if (*bits & EXTENT_FIRST_DELALLOC) {
|
||||
*bits &= ~EXTENT_FIRST_DELALLOC;
|
||||
@@ -1612,7 +1612,7 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
|
||||
|
||||
skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
|
||||
|
||||
if (btrfs_is_free_space_inode(root, inode))
|
||||
if (btrfs_is_free_space_inode(inode))
|
||||
metadata = 2;
|
||||
|
||||
if (!(rw & REQ_WRITE)) {
|
||||
@@ -1869,7 +1869,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
|
||||
int ret;
|
||||
bool nolock;
|
||||
|
||||
nolock = btrfs_is_free_space_inode(root, inode);
|
||||
nolock = btrfs_is_free_space_inode(inode);
|
||||
|
||||
if (test_bit(BTRFS_ORDERED_IOERR, &ordered_extent->flags)) {
|
||||
ret = -EIO;
|
||||
@@ -2007,7 +2007,7 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
|
||||
ordered_extent->work.func = finish_ordered_fn;
|
||||
ordered_extent->work.flags = 0;
|
||||
|
||||
if (btrfs_is_free_space_inode(root, inode))
|
||||
if (btrfs_is_free_space_inode(inode))
|
||||
workers = &root->fs_info->endio_freespace_worker;
|
||||
else
|
||||
workers = &root->fs_info->endio_write_workers;
|
||||
@@ -2732,8 +2732,10 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,
|
||||
* The data relocation inode should also be directly updated
|
||||
* without delay
|
||||
*/
|
||||
if (!btrfs_is_free_space_inode(root, inode)
|
||||
if (!btrfs_is_free_space_inode(inode)
|
||||
&& root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) {
|
||||
btrfs_update_root_times(trans, root);
|
||||
|
||||
ret = btrfs_delayed_update_inode(trans, root, inode);
|
||||
if (!ret)
|
||||
btrfs_set_inode_last_trans(trans, inode);
|
||||
@@ -2833,7 +2835,7 @@ err:
|
||||
inode_inc_iversion(inode);
|
||||
inode_inc_iversion(dir);
|
||||
inode->i_ctime = dir->i_mtime = dir->i_ctime = CURRENT_TIME;
|
||||
btrfs_update_inode(trans, root, dir);
|
||||
ret = btrfs_update_inode(trans, root, dir);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -3743,7 +3745,7 @@ void btrfs_evict_inode(struct inode *inode)
|
||||
|
||||
truncate_inode_pages(&inode->i_data, 0);
|
||||
if (inode->i_nlink && (btrfs_root_refs(&root->root_item) != 0 ||
|
||||
btrfs_is_free_space_inode(root, inode)))
|
||||
btrfs_is_free_space_inode(inode)))
|
||||
goto no_delete;
|
||||
|
||||
if (is_bad_inode(inode)) {
|
||||
@@ -4082,7 +4084,6 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
|
||||
struct btrfs_iget_args *args = p;
|
||||
inode->i_ino = args->ino;
|
||||
BTRFS_I(inode)->root = args->root;
|
||||
btrfs_set_inode_space_info(args->root, inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4457,7 +4458,7 @@ int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc)
|
||||
if (test_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags))
|
||||
return 0;
|
||||
|
||||
if (btrfs_fs_closing(root->fs_info) && btrfs_is_free_space_inode(root, inode))
|
||||
if (btrfs_fs_closing(root->fs_info) && btrfs_is_free_space_inode(inode))
|
||||
nolock = true;
|
||||
|
||||
if (wbc->sync_mode == WB_SYNC_ALL) {
|
||||
@@ -4518,6 +4519,11 @@ int btrfs_dirty_inode(struct inode *inode)
|
||||
static int btrfs_update_time(struct inode *inode, struct timespec *now,
|
||||
int flags)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
|
||||
if (btrfs_root_readonly(root))
|
||||
return -EROFS;
|
||||
|
||||
if (flags & S_VERSION)
|
||||
inode_inc_iversion(inode);
|
||||
if (flags & S_CTIME)
|
||||
@@ -4662,7 +4668,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
||||
BTRFS_I(inode)->root = root;
|
||||
BTRFS_I(inode)->generation = trans->transid;
|
||||
inode->i_generation = BTRFS_I(inode)->generation;
|
||||
btrfs_set_inode_space_info(root, inode);
|
||||
|
||||
if (S_ISDIR(mode))
|
||||
owner = 0;
|
||||
@@ -4690,6 +4695,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
||||
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
|
||||
inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
|
||||
struct btrfs_inode_item);
|
||||
memset_extent_buffer(path->nodes[0], 0, (unsigned long)inode_item,
|
||||
sizeof(*inode_item));
|
||||
fill_inode_item(trans, path->nodes[0], inode_item, inode);
|
||||
|
||||
ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1,
|
||||
@@ -4723,6 +4730,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
||||
trace_btrfs_inode_new(inode);
|
||||
btrfs_set_inode_last_trans(trans, inode);
|
||||
|
||||
btrfs_update_root_times(trans, root);
|
||||
|
||||
return inode;
|
||||
fail:
|
||||
if (dir)
|
||||
@@ -6939,7 +6948,6 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
|
||||
return NULL;
|
||||
|
||||
ei->root = NULL;
|
||||
ei->space_info = NULL;
|
||||
ei->generation = 0;
|
||||
ei->last_trans = 0;
|
||||
ei->last_sub_trans = 0;
|
||||
@@ -7046,7 +7054,7 @@ int btrfs_drop_inode(struct inode *inode)
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
|
||||
if (btrfs_root_refs(&root->root_item) == 0 &&
|
||||
!btrfs_is_free_space_inode(root, inode))
|
||||
!btrfs_is_free_space_inode(inode))
|
||||
return 1;
|
||||
else
|
||||
return generic_drop_inode(inode);
|
||||
|
||||
+388
-79
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user