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
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (62 commits) Btrfs: use larger system chunks Btrfs: add a delalloc mutex to inodes for delalloc reservations Btrfs: space leak tracepoints Btrfs: protect orphan block rsv with spin_lock Btrfs: add allocator tracepoints Btrfs: don't call btrfs_throttle in file write Btrfs: release space on error in page_mkwrite Btrfs: fix btrfsck error 400 when truncating a compressed Btrfs: do not use btrfs_end_transaction_throttle everywhere Btrfs: add balance progress reporting Btrfs: allow for resuming restriper after it was paused Btrfs: allow for canceling restriper Btrfs: allow for pausing restriper Btrfs: add skip_balance mount option Btrfs: recover balance on mount Btrfs: save balance parameters to disk Btrfs: soft profile changing mode (aka soft convert) Btrfs: implement online profile changing Btrfs: do not reduce profile in do_chunk_alloc() Btrfs: virtual address space subset filter ... Fix up trivial conflict in fs/btrfs/ioctl.c due to the use of the new mnt_drop_write_file() helper.
This commit is contained in:
@@ -31,3 +31,22 @@ config BTRFS_FS_POSIX_ACL
|
||||
Linux website <http://acl.bestbits.at/>.
|
||||
|
||||
If you don't know what Access Control Lists are, say N
|
||||
|
||||
config BTRFS_FS_CHECK_INTEGRITY
|
||||
bool "Btrfs with integrity check tool compiled in (DANGEROUS)"
|
||||
depends on BTRFS_FS
|
||||
help
|
||||
Adds code that examines all block write requests (including
|
||||
writes of the super block). The goal is to verify that the
|
||||
state of the filesystem on disk is always consistent, i.e.,
|
||||
after a power-loss or kernel panic event the filesystem is
|
||||
in a consistent state.
|
||||
|
||||
If the integrity check tool is included and activated in
|
||||
the mount options, plenty of kernel memory is used, and
|
||||
plenty of additional CPU cycles are spent. Enabling this
|
||||
functionality is not intended for normal use.
|
||||
|
||||
In most cases, unless you are a btrfs developer who needs
|
||||
to verify the integrity of (super)-block write requests
|
||||
during the run of a regression test, say N
|
||||
|
||||
+2
-1
@@ -8,6 +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
|
||||
reada.o backref.o ulist.o
|
||||
|
||||
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
|
||||
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
|
||||
|
||||
+878
-253
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@
|
||||
#define __BTRFS_BACKREF__
|
||||
|
||||
#include "ioctl.h"
|
||||
#include "ulist.h"
|
||||
|
||||
struct inode_fs_paths {
|
||||
struct btrfs_path *btrfs_path;
|
||||
@@ -54,6 +55,10 @@ int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info,
|
||||
|
||||
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 num_bytes, u64 seq, struct ulist **roots);
|
||||
|
||||
struct btrfs_data_container *init_data_container(u32 total_bytes);
|
||||
struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root,
|
||||
struct btrfs_path *path);
|
||||
|
||||
@@ -51,6 +51,9 @@ struct btrfs_inode {
|
||||
/* held while logging the inode in tree-log.c */
|
||||
struct mutex log_mutex;
|
||||
|
||||
/* held while doing delalloc reservations */
|
||||
struct mutex delalloc_mutex;
|
||||
|
||||
/* used to order data wrt metadata */
|
||||
struct btrfs_ordered_inode_tree ordered_tree;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) STRATO AG 2011. 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_CHECK_INTEGRITY__)
|
||||
#define __BTRFS_CHECK_INTEGRITY__
|
||||
|
||||
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
|
||||
int btrfsic_submit_bh(int rw, struct buffer_head *bh);
|
||||
void btrfsic_submit_bio(int rw, struct bio *bio);
|
||||
#else
|
||||
#define btrfsic_submit_bh submit_bh
|
||||
#define btrfsic_submit_bio submit_bio
|
||||
#endif
|
||||
|
||||
int btrfsic_mount(struct btrfs_root *root,
|
||||
struct btrfs_fs_devices *fs_devices,
|
||||
int including_extent_data, u32 print_mask);
|
||||
void btrfsic_unmount(struct btrfs_root *root,
|
||||
struct btrfs_fs_devices *fs_devices);
|
||||
|
||||
#endif
|
||||
+21
-21
@@ -240,7 +240,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
|
||||
|
||||
cow = btrfs_alloc_free_block(trans, root, buf->len, 0,
|
||||
new_root_objectid, &disk_key, level,
|
||||
buf->start, 0);
|
||||
buf->start, 0, 1);
|
||||
if (IS_ERR(cow))
|
||||
return PTR_ERR(cow);
|
||||
|
||||
@@ -261,9 +261,9 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
|
||||
|
||||
WARN_ON(btrfs_header_generation(buf) > trans->transid);
|
||||
if (new_root_objectid == BTRFS_TREE_RELOC_OBJECTID)
|
||||
ret = btrfs_inc_ref(trans, root, cow, 1);
|
||||
ret = btrfs_inc_ref(trans, root, cow, 1, 1);
|
||||
else
|
||||
ret = btrfs_inc_ref(trans, root, cow, 0);
|
||||
ret = btrfs_inc_ref(trans, root, cow, 0, 1);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -350,14 +350,14 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
|
||||
if ((owner == root->root_key.objectid ||
|
||||
root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) &&
|
||||
!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) {
|
||||
ret = btrfs_inc_ref(trans, root, buf, 1);
|
||||
ret = btrfs_inc_ref(trans, root, buf, 1, 1);
|
||||
BUG_ON(ret);
|
||||
|
||||
if (root->root_key.objectid ==
|
||||
BTRFS_TREE_RELOC_OBJECTID) {
|
||||
ret = btrfs_dec_ref(trans, root, buf, 0);
|
||||
ret = btrfs_dec_ref(trans, root, buf, 0, 1);
|
||||
BUG_ON(ret);
|
||||
ret = btrfs_inc_ref(trans, root, cow, 1);
|
||||
ret = btrfs_inc_ref(trans, root, cow, 1, 1);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF;
|
||||
@@ -365,9 +365,9 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
|
||||
|
||||
if (root->root_key.objectid ==
|
||||
BTRFS_TREE_RELOC_OBJECTID)
|
||||
ret = btrfs_inc_ref(trans, root, cow, 1);
|
||||
ret = btrfs_inc_ref(trans, root, cow, 1, 1);
|
||||
else
|
||||
ret = btrfs_inc_ref(trans, root, cow, 0);
|
||||
ret = btrfs_inc_ref(trans, root, cow, 0, 1);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
if (new_flags != 0) {
|
||||
@@ -381,11 +381,11 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
|
||||
if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
|
||||
if (root->root_key.objectid ==
|
||||
BTRFS_TREE_RELOC_OBJECTID)
|
||||
ret = btrfs_inc_ref(trans, root, cow, 1);
|
||||
ret = btrfs_inc_ref(trans, root, cow, 1, 1);
|
||||
else
|
||||
ret = btrfs_inc_ref(trans, root, cow, 0);
|
||||
ret = btrfs_inc_ref(trans, root, cow, 0, 1);
|
||||
BUG_ON(ret);
|
||||
ret = btrfs_dec_ref(trans, root, buf, 1);
|
||||
ret = btrfs_dec_ref(trans, root, buf, 1, 1);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
clean_tree_block(trans, root, buf);
|
||||
@@ -446,7 +446,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
||||
|
||||
cow = btrfs_alloc_free_block(trans, root, buf->len, parent_start,
|
||||
root->root_key.objectid, &disk_key,
|
||||
level, search_start, empty_size);
|
||||
level, search_start, empty_size, 1);
|
||||
if (IS_ERR(cow))
|
||||
return PTR_ERR(cow);
|
||||
|
||||
@@ -484,7 +484,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
||||
rcu_assign_pointer(root->node, cow);
|
||||
|
||||
btrfs_free_tree_block(trans, root, buf, parent_start,
|
||||
last_ref);
|
||||
last_ref, 1);
|
||||
free_extent_buffer(buf);
|
||||
add_root_to_dirty_list(root);
|
||||
} else {
|
||||
@@ -500,7 +500,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
||||
trans->transid);
|
||||
btrfs_mark_buffer_dirty(parent);
|
||||
btrfs_free_tree_block(trans, root, buf, parent_start,
|
||||
last_ref);
|
||||
last_ref, 1);
|
||||
}
|
||||
if (unlock_orig)
|
||||
btrfs_tree_unlock(buf);
|
||||
@@ -957,7 +957,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
||||
free_extent_buffer(mid);
|
||||
|
||||
root_sub_used(root, mid->len);
|
||||
btrfs_free_tree_block(trans, root, mid, 0, 1);
|
||||
btrfs_free_tree_block(trans, root, mid, 0, 1, 0);
|
||||
/* once for the root ptr */
|
||||
free_extent_buffer(mid);
|
||||
return 0;
|
||||
@@ -1015,7 +1015,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
||||
if (wret)
|
||||
ret = wret;
|
||||
root_sub_used(root, right->len);
|
||||
btrfs_free_tree_block(trans, root, right, 0, 1);
|
||||
btrfs_free_tree_block(trans, root, right, 0, 1, 0);
|
||||
free_extent_buffer(right);
|
||||
right = NULL;
|
||||
} else {
|
||||
@@ -1055,7 +1055,7 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
|
||||
if (wret)
|
||||
ret = wret;
|
||||
root_sub_used(root, mid->len);
|
||||
btrfs_free_tree_block(trans, root, mid, 0, 1);
|
||||
btrfs_free_tree_block(trans, root, mid, 0, 1, 0);
|
||||
free_extent_buffer(mid);
|
||||
mid = NULL;
|
||||
} else {
|
||||
@@ -2089,7 +2089,7 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
|
||||
|
||||
c = btrfs_alloc_free_block(trans, root, root->nodesize, 0,
|
||||
root->root_key.objectid, &lower_key,
|
||||
level, root->node->start, 0);
|
||||
level, root->node->start, 0, 0);
|
||||
if (IS_ERR(c))
|
||||
return PTR_ERR(c);
|
||||
|
||||
@@ -2216,7 +2216,7 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
|
||||
|
||||
split = btrfs_alloc_free_block(trans, root, root->nodesize, 0,
|
||||
root->root_key.objectid,
|
||||
&disk_key, level, c->start, 0);
|
||||
&disk_key, level, c->start, 0, 0);
|
||||
if (IS_ERR(split))
|
||||
return PTR_ERR(split);
|
||||
|
||||
@@ -2970,7 +2970,7 @@ again:
|
||||
|
||||
right = btrfs_alloc_free_block(trans, root, root->leafsize, 0,
|
||||
root->root_key.objectid,
|
||||
&disk_key, 0, l->start, 0);
|
||||
&disk_key, 0, l->start, 0, 0);
|
||||
if (IS_ERR(right))
|
||||
return PTR_ERR(right);
|
||||
|
||||
@@ -3781,7 +3781,7 @@ static noinline int btrfs_del_leaf(struct btrfs_trans_handle *trans,
|
||||
|
||||
root_sub_used(root, leaf->len);
|
||||
|
||||
btrfs_free_tree_block(trans, root, leaf, 0, 1);
|
||||
btrfs_free_tree_block(trans, root, leaf, 0, 1, 0);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
|
||||
+216
-21
@@ -86,6 +86,9 @@ struct btrfs_ordered_sum;
|
||||
/* holds checksums of all the data extents */
|
||||
#define BTRFS_CSUM_TREE_OBJECTID 7ULL
|
||||
|
||||
/* for storing balance parameters in the root tree */
|
||||
#define BTRFS_BALANCE_OBJECTID -4ULL
|
||||
|
||||
/* orhpan objectid for tracking unlinked/truncated files */
|
||||
#define BTRFS_ORPHAN_OBJECTID -5ULL
|
||||
|
||||
@@ -692,6 +695,54 @@ struct btrfs_root_ref {
|
||||
__le16 name_len;
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
struct btrfs_disk_balance_args {
|
||||
/*
|
||||
* profiles to operate on, single is denoted by
|
||||
* BTRFS_AVAIL_ALLOC_BIT_SINGLE
|
||||
*/
|
||||
__le64 profiles;
|
||||
|
||||
/* usage filter */
|
||||
__le64 usage;
|
||||
|
||||
/* devid filter */
|
||||
__le64 devid;
|
||||
|
||||
/* devid subset filter [pstart..pend) */
|
||||
__le64 pstart;
|
||||
__le64 pend;
|
||||
|
||||
/* btrfs virtual address space subset filter [vstart..vend) */
|
||||
__le64 vstart;
|
||||
__le64 vend;
|
||||
|
||||
/*
|
||||
* profile to convert to, single is denoted by
|
||||
* BTRFS_AVAIL_ALLOC_BIT_SINGLE
|
||||
*/
|
||||
__le64 target;
|
||||
|
||||
/* BTRFS_BALANCE_ARGS_* */
|
||||
__le64 flags;
|
||||
|
||||
__le64 unused[8];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/*
|
||||
* store balance parameters to disk so that balance can be properly
|
||||
* resumed after crash or unmount
|
||||
*/
|
||||
struct btrfs_balance_item {
|
||||
/* BTRFS_BALANCE_* */
|
||||
__le64 flags;
|
||||
|
||||
struct btrfs_disk_balance_args data;
|
||||
struct btrfs_disk_balance_args meta;
|
||||
struct btrfs_disk_balance_args sys;
|
||||
|
||||
__le64 unused[4];
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
#define BTRFS_FILE_EXTENT_INLINE 0
|
||||
#define BTRFS_FILE_EXTENT_REG 1
|
||||
#define BTRFS_FILE_EXTENT_PREALLOC 2
|
||||
@@ -751,14 +802,32 @@ struct btrfs_csum_item {
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/* different types of block groups (and chunks) */
|
||||
#define BTRFS_BLOCK_GROUP_DATA (1 << 0)
|
||||
#define BTRFS_BLOCK_GROUP_SYSTEM (1 << 1)
|
||||
#define BTRFS_BLOCK_GROUP_METADATA (1 << 2)
|
||||
#define BTRFS_BLOCK_GROUP_RAID0 (1 << 3)
|
||||
#define BTRFS_BLOCK_GROUP_RAID1 (1 << 4)
|
||||
#define BTRFS_BLOCK_GROUP_DUP (1 << 5)
|
||||
#define BTRFS_BLOCK_GROUP_RAID10 (1 << 6)
|
||||
#define BTRFS_NR_RAID_TYPES 5
|
||||
#define BTRFS_BLOCK_GROUP_DATA (1ULL << 0)
|
||||
#define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1)
|
||||
#define BTRFS_BLOCK_GROUP_METADATA (1ULL << 2)
|
||||
#define BTRFS_BLOCK_GROUP_RAID0 (1ULL << 3)
|
||||
#define BTRFS_BLOCK_GROUP_RAID1 (1ULL << 4)
|
||||
#define BTRFS_BLOCK_GROUP_DUP (1ULL << 5)
|
||||
#define BTRFS_BLOCK_GROUP_RAID10 (1ULL << 6)
|
||||
#define BTRFS_BLOCK_GROUP_RESERVED BTRFS_AVAIL_ALLOC_BIT_SINGLE
|
||||
#define BTRFS_NR_RAID_TYPES 5
|
||||
|
||||
#define BTRFS_BLOCK_GROUP_TYPE_MASK (BTRFS_BLOCK_GROUP_DATA | \
|
||||
BTRFS_BLOCK_GROUP_SYSTEM | \
|
||||
BTRFS_BLOCK_GROUP_METADATA)
|
||||
|
||||
#define BTRFS_BLOCK_GROUP_PROFILE_MASK (BTRFS_BLOCK_GROUP_RAID0 | \
|
||||
BTRFS_BLOCK_GROUP_RAID1 | \
|
||||
BTRFS_BLOCK_GROUP_DUP | \
|
||||
BTRFS_BLOCK_GROUP_RAID10)
|
||||
/*
|
||||
* We need a bit for restriper to be able to tell when chunks of type
|
||||
* SINGLE are available. This "extended" profile format is used in
|
||||
* fs_info->avail_*_alloc_bits (in-memory) and balance item fields
|
||||
* (on-disk). The corresponding on-disk bit in chunk.type is reserved
|
||||
* to avoid remappings between two formats in future.
|
||||
*/
|
||||
#define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48)
|
||||
|
||||
struct btrfs_block_group_item {
|
||||
__le64 used;
|
||||
@@ -916,6 +985,7 @@ struct btrfs_block_group_cache {
|
||||
struct reloc_control;
|
||||
struct btrfs_device;
|
||||
struct btrfs_fs_devices;
|
||||
struct btrfs_balance_control;
|
||||
struct btrfs_delayed_root;
|
||||
struct btrfs_fs_info {
|
||||
u8 fsid[BTRFS_FSID_SIZE];
|
||||
@@ -971,7 +1041,7 @@ struct btrfs_fs_info {
|
||||
* is required instead of the faster short fsync log commits
|
||||
*/
|
||||
u64 last_trans_log_full_commit;
|
||||
unsigned long mount_opt:20;
|
||||
unsigned long mount_opt:21;
|
||||
unsigned long compress_type:4;
|
||||
u64 max_inline;
|
||||
u64 alloc_start;
|
||||
@@ -1132,12 +1202,23 @@ struct btrfs_fs_info {
|
||||
spinlock_t ref_cache_lock;
|
||||
u64 total_ref_cache_size;
|
||||
|
||||
/*
|
||||
* these three are in extended format (availability of single
|
||||
* chunks is denoted by BTRFS_AVAIL_ALLOC_BIT_SINGLE bit, other
|
||||
* types are denoted by corresponding BTRFS_BLOCK_GROUP_* bits)
|
||||
*/
|
||||
u64 avail_data_alloc_bits;
|
||||
u64 avail_metadata_alloc_bits;
|
||||
u64 avail_system_alloc_bits;
|
||||
u64 data_alloc_profile;
|
||||
u64 metadata_alloc_profile;
|
||||
u64 system_alloc_profile;
|
||||
|
||||
/* restriper state */
|
||||
spinlock_t balance_lock;
|
||||
struct mutex balance_mutex;
|
||||
atomic_t balance_running;
|
||||
atomic_t balance_pause_req;
|
||||
atomic_t balance_cancel_req;
|
||||
struct btrfs_balance_control *balance_ctl;
|
||||
wait_queue_head_t balance_wait_q;
|
||||
|
||||
unsigned data_chunk_allocations;
|
||||
unsigned metadata_ratio;
|
||||
@@ -1155,6 +1236,10 @@ struct btrfs_fs_info {
|
||||
int scrub_workers_refcnt;
|
||||
struct btrfs_workers scrub_workers;
|
||||
|
||||
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
|
||||
u32 check_integrity_print_mask;
|
||||
#endif
|
||||
|
||||
/* filesystem state */
|
||||
u64 fs_state;
|
||||
|
||||
@@ -1383,6 +1468,8 @@ struct btrfs_ioctl_defrag_range_args {
|
||||
#define BTRFS_DEV_ITEM_KEY 216
|
||||
#define BTRFS_CHUNK_ITEM_KEY 228
|
||||
|
||||
#define BTRFS_BALANCE_ITEM_KEY 248
|
||||
|
||||
/*
|
||||
* string items are for debugging. They just store a short string of
|
||||
* data in the FS
|
||||
@@ -1413,6 +1500,9 @@ struct btrfs_ioctl_defrag_range_args {
|
||||
#define BTRFS_MOUNT_AUTO_DEFRAG (1 << 16)
|
||||
#define BTRFS_MOUNT_INODE_MAP_CACHE (1 << 17)
|
||||
#define BTRFS_MOUNT_RECOVERY (1 << 18)
|
||||
#define BTRFS_MOUNT_SKIP_BALANCE (1 << 19)
|
||||
#define BTRFS_MOUNT_CHECK_INTEGRITY (1 << 20)
|
||||
#define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21)
|
||||
|
||||
#define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt)
|
||||
#define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt)
|
||||
@@ -2077,8 +2167,86 @@ BTRFS_SETGET_STACK_FUNCS(backup_bytes_used, struct btrfs_root_backup,
|
||||
BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup,
|
||||
num_devices, 64);
|
||||
|
||||
/* struct btrfs_super_block */
|
||||
/* struct btrfs_balance_item */
|
||||
BTRFS_SETGET_FUNCS(balance_flags, struct btrfs_balance_item, flags, 64);
|
||||
|
||||
static inline void btrfs_balance_data(struct extent_buffer *eb,
|
||||
struct btrfs_balance_item *bi,
|
||||
struct btrfs_disk_balance_args *ba)
|
||||
{
|
||||
read_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_balance_data(struct extent_buffer *eb,
|
||||
struct btrfs_balance_item *bi,
|
||||
struct btrfs_disk_balance_args *ba)
|
||||
{
|
||||
write_eb_member(eb, bi, struct btrfs_balance_item, data, ba);
|
||||
}
|
||||
|
||||
static inline void btrfs_balance_meta(struct extent_buffer *eb,
|
||||
struct btrfs_balance_item *bi,
|
||||
struct btrfs_disk_balance_args *ba)
|
||||
{
|
||||
read_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_balance_meta(struct extent_buffer *eb,
|
||||
struct btrfs_balance_item *bi,
|
||||
struct btrfs_disk_balance_args *ba)
|
||||
{
|
||||
write_eb_member(eb, bi, struct btrfs_balance_item, meta, ba);
|
||||
}
|
||||
|
||||
static inline void btrfs_balance_sys(struct extent_buffer *eb,
|
||||
struct btrfs_balance_item *bi,
|
||||
struct btrfs_disk_balance_args *ba)
|
||||
{
|
||||
read_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
|
||||
}
|
||||
|
||||
static inline void btrfs_set_balance_sys(struct extent_buffer *eb,
|
||||
struct btrfs_balance_item *bi,
|
||||
struct btrfs_disk_balance_args *ba)
|
||||
{
|
||||
write_eb_member(eb, bi, struct btrfs_balance_item, sys, ba);
|
||||
}
|
||||
|
||||
static inline void
|
||||
btrfs_disk_balance_args_to_cpu(struct btrfs_balance_args *cpu,
|
||||
struct btrfs_disk_balance_args *disk)
|
||||
{
|
||||
memset(cpu, 0, sizeof(*cpu));
|
||||
|
||||
cpu->profiles = le64_to_cpu(disk->profiles);
|
||||
cpu->usage = le64_to_cpu(disk->usage);
|
||||
cpu->devid = le64_to_cpu(disk->devid);
|
||||
cpu->pstart = le64_to_cpu(disk->pstart);
|
||||
cpu->pend = le64_to_cpu(disk->pend);
|
||||
cpu->vstart = le64_to_cpu(disk->vstart);
|
||||
cpu->vend = le64_to_cpu(disk->vend);
|
||||
cpu->target = le64_to_cpu(disk->target);
|
||||
cpu->flags = le64_to_cpu(disk->flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
btrfs_cpu_balance_args_to_disk(struct btrfs_disk_balance_args *disk,
|
||||
struct btrfs_balance_args *cpu)
|
||||
{
|
||||
memset(disk, 0, sizeof(*disk));
|
||||
|
||||
disk->profiles = cpu_to_le64(cpu->profiles);
|
||||
disk->usage = cpu_to_le64(cpu->usage);
|
||||
disk->devid = cpu_to_le64(cpu->devid);
|
||||
disk->pstart = cpu_to_le64(cpu->pstart);
|
||||
disk->pend = cpu_to_le64(cpu->pend);
|
||||
disk->vstart = cpu_to_le64(cpu->vstart);
|
||||
disk->vend = cpu_to_le64(cpu->vend);
|
||||
disk->target = cpu_to_le64(cpu->target);
|
||||
disk->flags = cpu_to_le64(cpu->flags);
|
||||
}
|
||||
|
||||
/* struct btrfs_super_block */
|
||||
BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block,
|
||||
@@ -2277,11 +2445,11 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u32 blocksize,
|
||||
u64 parent, u64 root_objectid,
|
||||
struct btrfs_disk_key *key, int level,
|
||||
u64 hint, u64 empty_size);
|
||||
u64 hint, u64 empty_size, int for_cow);
|
||||
void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct extent_buffer *buf,
|
||||
u64 parent, int last_ref);
|
||||
u64 parent, int last_ref, int for_cow);
|
||||
struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 bytenr, u32 blocksize,
|
||||
@@ -2301,17 +2469,17 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
|
||||
u64 search_end, struct btrfs_key *ins,
|
||||
u64 data);
|
||||
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct extent_buffer *buf, int full_backref);
|
||||
struct extent_buffer *buf, int full_backref, int for_cow);
|
||||
int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct extent_buffer *buf, int full_backref);
|
||||
struct extent_buffer *buf, int full_backref, int for_cow);
|
||||
int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 bytenr, u64 num_bytes, u64 flags,
|
||||
int is_data);
|
||||
int btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 bytenr, u64 num_bytes, u64 parent,
|
||||
u64 root_objectid, u64 owner, u64 offset);
|
||||
u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid,
|
||||
u64 owner, u64 offset, int for_cow);
|
||||
|
||||
int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len);
|
||||
int btrfs_free_and_pin_reserved_extent(struct btrfs_root *root,
|
||||
@@ -2323,7 +2491,7 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
|
||||
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 bytenr, u64 num_bytes, u64 parent,
|
||||
u64 root_objectid, u64 owner, u64 offset);
|
||||
u64 root_objectid, u64 owner, u64 offset, int for_cow);
|
||||
|
||||
int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
@@ -2482,10 +2650,18 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
|
||||
int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
|
||||
static inline int btrfs_next_item(struct btrfs_root *root, struct btrfs_path *p)
|
||||
{
|
||||
++p->slots[0];
|
||||
if (p->slots[0] >= btrfs_header_nritems(p->nodes[0]))
|
||||
return btrfs_next_leaf(root, p);
|
||||
return 0;
|
||||
}
|
||||
int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
|
||||
int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf);
|
||||
void btrfs_drop_snapshot(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv, int update_ref);
|
||||
struct btrfs_block_rsv *block_rsv, int update_ref,
|
||||
int for_reloc);
|
||||
int btrfs_drop_subtree(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct extent_buffer *node,
|
||||
@@ -2500,6 +2676,7 @@ static inline int btrfs_fs_closing(struct btrfs_fs_info *fs_info)
|
||||
}
|
||||
static inline void free_fs_info(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
kfree(fs_info->balance_ctl);
|
||||
kfree(fs_info->delayed_root);
|
||||
kfree(fs_info->extent_root);
|
||||
kfree(fs_info->tree_root);
|
||||
@@ -2510,6 +2687,24 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info)
|
||||
kfree(fs_info->super_for_commit);
|
||||
kfree(fs_info);
|
||||
}
|
||||
/**
|
||||
* profile_is_valid - tests whether a given profile is valid and reduced
|
||||
* @flags: profile to validate
|
||||
* @extended: if true @flags is treated as an extended profile
|
||||
*/
|
||||
static inline int profile_is_valid(u64 flags, int extended)
|
||||
{
|
||||
u64 mask = ~BTRFS_BLOCK_GROUP_PROFILE_MASK;
|
||||
|
||||
flags &= ~BTRFS_BLOCK_GROUP_TYPE_MASK;
|
||||
if (extended)
|
||||
mask &= ~BTRFS_AVAIL_ALLOC_BIT_SINGLE;
|
||||
|
||||
if (flags & mask)
|
||||
return 0;
|
||||
/* true if zero or exactly one bit set */
|
||||
return (flags & (~flags + 1)) == flags;
|
||||
}
|
||||
|
||||
/* root-item.c */
|
||||
int btrfs_find_root_ref(struct btrfs_root *tree_root,
|
||||
|
||||
+33
-12
@@ -595,8 +595,12 @@ static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans,
|
||||
|
||||
num_bytes = btrfs_calc_trans_metadata_size(root, 1);
|
||||
ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes);
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
trace_btrfs_space_reservation(root->fs_info, "delayed_item",
|
||||
item->key.objectid,
|
||||
num_bytes, 1);
|
||||
item->bytes_reserved = num_bytes;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -610,6 +614,9 @@ static void btrfs_delayed_item_release_metadata(struct btrfs_root *root,
|
||||
return;
|
||||
|
||||
rsv = &root->fs_info->delayed_block_rsv;
|
||||
trace_btrfs_space_reservation(root->fs_info, "delayed_item",
|
||||
item->key.objectid, item->bytes_reserved,
|
||||
0);
|
||||
btrfs_block_rsv_release(root, rsv,
|
||||
item->bytes_reserved);
|
||||
}
|
||||
@@ -624,7 +631,7 @@ static int btrfs_delayed_inode_reserve_metadata(
|
||||
struct btrfs_block_rsv *dst_rsv;
|
||||
u64 num_bytes;
|
||||
int ret;
|
||||
int release = false;
|
||||
bool release = false;
|
||||
|
||||
src_rsv = trans->block_rsv;
|
||||
dst_rsv = &root->fs_info->delayed_block_rsv;
|
||||
@@ -651,8 +658,13 @@ static int btrfs_delayed_inode_reserve_metadata(
|
||||
*/
|
||||
if (ret == -EAGAIN)
|
||||
ret = -ENOSPC;
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
node->bytes_reserved = num_bytes;
|
||||
trace_btrfs_space_reservation(root->fs_info,
|
||||
"delayed_inode",
|
||||
btrfs_ino(inode),
|
||||
num_bytes, 1);
|
||||
}
|
||||
return ret;
|
||||
} else if (src_rsv == &root->fs_info->delalloc_block_rsv) {
|
||||
spin_lock(&BTRFS_I(inode)->lock);
|
||||
@@ -707,11 +719,17 @@ out:
|
||||
* reservation here. I think it may be time for a documentation page on
|
||||
* how block rsvs. work.
|
||||
*/
|
||||
if (!ret)
|
||||
if (!ret) {
|
||||
trace_btrfs_space_reservation(root->fs_info, "delayed_inode",
|
||||
btrfs_ino(inode), num_bytes, 1);
|
||||
node->bytes_reserved = num_bytes;
|
||||
}
|
||||
|
||||
if (release)
|
||||
if (release) {
|
||||
trace_btrfs_space_reservation(root->fs_info, "delalloc",
|
||||
btrfs_ino(inode), num_bytes, 0);
|
||||
btrfs_block_rsv_release(root, src_rsv, num_bytes);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -725,6 +743,8 @@ static void btrfs_delayed_inode_release_metadata(struct btrfs_root *root,
|
||||
return;
|
||||
|
||||
rsv = &root->fs_info->delayed_block_rsv;
|
||||
trace_btrfs_space_reservation(root->fs_info, "delayed_inode",
|
||||
node->inode_id, node->bytes_reserved, 0);
|
||||
btrfs_block_rsv_release(root, rsv,
|
||||
node->bytes_reserved);
|
||||
node->bytes_reserved = 0;
|
||||
@@ -1372,13 +1392,6 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
|
||||
goto release_node;
|
||||
}
|
||||
|
||||
ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item);
|
||||
/*
|
||||
* we have reserved enough space when we start a new transaction,
|
||||
* so reserving metadata failure is impossible
|
||||
*/
|
||||
BUG_ON(ret);
|
||||
|
||||
delayed_item->key.objectid = btrfs_ino(dir);
|
||||
btrfs_set_key_type(&delayed_item->key, BTRFS_DIR_INDEX_KEY);
|
||||
delayed_item->key.offset = index;
|
||||
@@ -1391,6 +1404,14 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
|
||||
dir_item->type = type;
|
||||
memcpy((char *)(dir_item + 1), name, name_len);
|
||||
|
||||
ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item);
|
||||
/*
|
||||
* we have reserved enough space when we start a new transaction,
|
||||
* so reserving metadata failure is impossible
|
||||
*/
|
||||
BUG_ON(ret);
|
||||
|
||||
|
||||
mutex_lock(&delayed_node->mutex);
|
||||
ret = __btrfs_add_delayed_insertion_item(delayed_node, delayed_item);
|
||||
if (unlikely(ret)) {
|
||||
|
||||
+106
-47
@@ -101,6 +101,11 @@ static int comp_entry(struct btrfs_delayed_ref_node *ref2,
|
||||
return -1;
|
||||
if (ref1->type > ref2->type)
|
||||
return 1;
|
||||
/* merging of sequenced refs is not allowed */
|
||||
if (ref1->seq < ref2->seq)
|
||||
return -1;
|
||||
if (ref1->seq > ref2->seq)
|
||||
return 1;
|
||||
if (ref1->type == BTRFS_TREE_BLOCK_REF_KEY ||
|
||||
ref1->type == BTRFS_SHARED_BLOCK_REF_KEY) {
|
||||
return comp_tree_refs(btrfs_delayed_node_to_tree_ref(ref2),
|
||||
@@ -150,16 +155,22 @@ static struct btrfs_delayed_ref_node *tree_insert(struct rb_root *root,
|
||||
|
||||
/*
|
||||
* find an head entry based on bytenr. This returns the delayed ref
|
||||
* head if it was able to find one, or NULL if nothing was in that spot
|
||||
* head if it was able to find one, or NULL if nothing was in that spot.
|
||||
* If return_bigger is given, the next bigger entry is returned if no exact
|
||||
* match is found.
|
||||
*/
|
||||
static struct btrfs_delayed_ref_node *find_ref_head(struct rb_root *root,
|
||||
u64 bytenr,
|
||||
struct btrfs_delayed_ref_node **last)
|
||||
struct btrfs_delayed_ref_node **last,
|
||||
int return_bigger)
|
||||
{
|
||||
struct rb_node *n = root->rb_node;
|
||||
struct rb_node *n;
|
||||
struct btrfs_delayed_ref_node *entry;
|
||||
int cmp;
|
||||
int cmp = 0;
|
||||
|
||||
again:
|
||||
n = root->rb_node;
|
||||
entry = NULL;
|
||||
while (n) {
|
||||
entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node);
|
||||
WARN_ON(!entry->in_tree);
|
||||
@@ -182,6 +193,19 @@ static struct btrfs_delayed_ref_node *find_ref_head(struct rb_root *root,
|
||||
else
|
||||
return entry;
|
||||
}
|
||||
if (entry && return_bigger) {
|
||||
if (cmp > 0) {
|
||||
n = rb_next(&entry->rb_node);
|
||||
if (!n)
|
||||
n = rb_first(root);
|
||||
entry = rb_entry(n, struct btrfs_delayed_ref_node,
|
||||
rb_node);
|
||||
bytenr = entry->bytenr;
|
||||
return_bigger = 0;
|
||||
goto again;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -209,6 +233,24 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_check_delayed_seq(struct btrfs_delayed_ref_root *delayed_refs,
|
||||
u64 seq)
|
||||
{
|
||||
struct seq_list *elem;
|
||||
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
|
||||
struct list_head *cluster, u64 start)
|
||||
{
|
||||
@@ -223,20 +265,8 @@ int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
|
||||
node = rb_first(&delayed_refs->root);
|
||||
} else {
|
||||
ref = NULL;
|
||||
find_ref_head(&delayed_refs->root, start, &ref);
|
||||
find_ref_head(&delayed_refs->root, start + 1, &ref, 1);
|
||||
if (ref) {
|
||||
struct btrfs_delayed_ref_node *tmp;
|
||||
|
||||
node = rb_prev(&ref->rb_node);
|
||||
while (node) {
|
||||
tmp = rb_entry(node,
|
||||
struct btrfs_delayed_ref_node,
|
||||
rb_node);
|
||||
if (tmp->bytenr < start)
|
||||
break;
|
||||
ref = tmp;
|
||||
node = rb_prev(&ref->rb_node);
|
||||
}
|
||||
node = &ref->rb_node;
|
||||
} else
|
||||
node = rb_first(&delayed_refs->root);
|
||||
@@ -390,7 +420,8 @@ update_existing_head_ref(struct btrfs_delayed_ref_node *existing,
|
||||
* this does all the dirty work in terms of maintaining the correct
|
||||
* overall modification count.
|
||||
*/
|
||||
static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans,
|
||||
static noinline int add_delayed_ref_head(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_trans_handle *trans,
|
||||
struct btrfs_delayed_ref_node *ref,
|
||||
u64 bytenr, u64 num_bytes,
|
||||
int action, int is_data)
|
||||
@@ -437,6 +468,7 @@ static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans,
|
||||
ref->action = 0;
|
||||
ref->is_head = 1;
|
||||
ref->in_tree = 1;
|
||||
ref->seq = 0;
|
||||
|
||||
head_ref = btrfs_delayed_node_to_head(ref);
|
||||
head_ref->must_insert_reserved = must_insert_reserved;
|
||||
@@ -468,14 +500,17 @@ static noinline int add_delayed_ref_head(struct btrfs_trans_handle *trans,
|
||||
/*
|
||||
* helper to insert a delayed tree ref into the rbtree.
|
||||
*/
|
||||
static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans,
|
||||
static noinline int add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_trans_handle *trans,
|
||||
struct btrfs_delayed_ref_node *ref,
|
||||
u64 bytenr, u64 num_bytes, u64 parent,
|
||||
u64 ref_root, int level, int action)
|
||||
u64 ref_root, int level, int action,
|
||||
int for_cow)
|
||||
{
|
||||
struct btrfs_delayed_ref_node *existing;
|
||||
struct btrfs_delayed_tree_ref *full_ref;
|
||||
struct btrfs_delayed_ref_root *delayed_refs;
|
||||
u64 seq = 0;
|
||||
|
||||
if (action == BTRFS_ADD_DELAYED_EXTENT)
|
||||
action = BTRFS_ADD_DELAYED_REF;
|
||||
@@ -491,14 +526,17 @@ static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans,
|
||||
ref->is_head = 0;
|
||||
ref->in_tree = 1;
|
||||
|
||||
if (need_ref_seq(for_cow, ref_root))
|
||||
seq = inc_delayed_seq(delayed_refs);
|
||||
ref->seq = seq;
|
||||
|
||||
full_ref = btrfs_delayed_node_to_tree_ref(ref);
|
||||
if (parent) {
|
||||
full_ref->parent = parent;
|
||||
full_ref->parent = parent;
|
||||
full_ref->root = ref_root;
|
||||
if (parent)
|
||||
ref->type = BTRFS_SHARED_BLOCK_REF_KEY;
|
||||
} else {
|
||||
full_ref->root = ref_root;
|
||||
else
|
||||
ref->type = BTRFS_TREE_BLOCK_REF_KEY;
|
||||
}
|
||||
full_ref->level = level;
|
||||
|
||||
trace_btrfs_delayed_tree_ref(ref, full_ref, action);
|
||||
@@ -522,15 +560,17 @@ static noinline int add_delayed_tree_ref(struct btrfs_trans_handle *trans,
|
||||
/*
|
||||
* helper to insert a delayed data ref into the rbtree.
|
||||
*/
|
||||
static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans,
|
||||
static noinline int add_delayed_data_ref(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_trans_handle *trans,
|
||||
struct btrfs_delayed_ref_node *ref,
|
||||
u64 bytenr, u64 num_bytes, u64 parent,
|
||||
u64 ref_root, u64 owner, u64 offset,
|
||||
int action)
|
||||
int action, int for_cow)
|
||||
{
|
||||
struct btrfs_delayed_ref_node *existing;
|
||||
struct btrfs_delayed_data_ref *full_ref;
|
||||
struct btrfs_delayed_ref_root *delayed_refs;
|
||||
u64 seq = 0;
|
||||
|
||||
if (action == BTRFS_ADD_DELAYED_EXTENT)
|
||||
action = BTRFS_ADD_DELAYED_REF;
|
||||
@@ -546,14 +586,18 @@ static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans,
|
||||
ref->is_head = 0;
|
||||
ref->in_tree = 1;
|
||||
|
||||
if (need_ref_seq(for_cow, ref_root))
|
||||
seq = inc_delayed_seq(delayed_refs);
|
||||
ref->seq = seq;
|
||||
|
||||
full_ref = btrfs_delayed_node_to_data_ref(ref);
|
||||
if (parent) {
|
||||
full_ref->parent = parent;
|
||||
full_ref->parent = parent;
|
||||
full_ref->root = ref_root;
|
||||
if (parent)
|
||||
ref->type = BTRFS_SHARED_DATA_REF_KEY;
|
||||
} else {
|
||||
full_ref->root = ref_root;
|
||||
else
|
||||
ref->type = BTRFS_EXTENT_DATA_REF_KEY;
|
||||
}
|
||||
|
||||
full_ref->objectid = owner;
|
||||
full_ref->offset = offset;
|
||||
|
||||
@@ -580,10 +624,12 @@ static noinline int add_delayed_data_ref(struct btrfs_trans_handle *trans,
|
||||
* to make sure the delayed ref is eventually processed before this
|
||||
* transaction commits.
|
||||
*/
|
||||
int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
|
||||
int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_trans_handle *trans,
|
||||
u64 bytenr, u64 num_bytes, u64 parent,
|
||||
u64 ref_root, int level, int action,
|
||||
struct btrfs_delayed_extent_op *extent_op)
|
||||
struct btrfs_delayed_extent_op *extent_op,
|
||||
int for_cow)
|
||||
{
|
||||
struct btrfs_delayed_tree_ref *ref;
|
||||
struct btrfs_delayed_ref_head *head_ref;
|
||||
@@ -610,13 +656,17 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
|
||||
* insert both the head node and the new ref without dropping
|
||||
* the spin lock
|
||||
*/
|
||||
ret = add_delayed_ref_head(trans, &head_ref->node, bytenr, num_bytes,
|
||||
action, 0);
|
||||
ret = add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
|
||||
num_bytes, action, 0);
|
||||
BUG_ON(ret);
|
||||
|
||||
ret = add_delayed_tree_ref(trans, &ref->node, bytenr, num_bytes,
|
||||
parent, ref_root, level, action);
|
||||
ret = add_delayed_tree_ref(fs_info, trans, &ref->node, bytenr,
|
||||
num_bytes, parent, ref_root, level, action,
|
||||
for_cow);
|
||||
BUG_ON(ret);
|
||||
if (!need_ref_seq(for_cow, ref_root) &&
|
||||
waitqueue_active(&delayed_refs->seq_wait))
|
||||
wake_up(&delayed_refs->seq_wait);
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -624,11 +674,13 @@ int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
|
||||
/*
|
||||
* add a delayed data ref. it's similar to btrfs_add_delayed_tree_ref.
|
||||
*/
|
||||
int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans,
|
||||
int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_trans_handle *trans,
|
||||
u64 bytenr, u64 num_bytes,
|
||||
u64 parent, u64 ref_root,
|
||||
u64 owner, u64 offset, int action,
|
||||
struct btrfs_delayed_extent_op *extent_op)
|
||||
struct btrfs_delayed_extent_op *extent_op,
|
||||
int for_cow)
|
||||
{
|
||||
struct btrfs_delayed_data_ref *ref;
|
||||
struct btrfs_delayed_ref_head *head_ref;
|
||||
@@ -655,18 +707,23 @@ int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans,
|
||||
* insert both the head node and the new ref without dropping
|
||||
* the spin lock
|
||||
*/
|
||||
ret = add_delayed_ref_head(trans, &head_ref->node, bytenr, num_bytes,
|
||||
action, 1);
|
||||
ret = add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
|
||||
num_bytes, action, 1);
|
||||
BUG_ON(ret);
|
||||
|
||||
ret = add_delayed_data_ref(trans, &ref->node, bytenr, num_bytes,
|
||||
parent, ref_root, owner, offset, action);
|
||||
ret = add_delayed_data_ref(fs_info, trans, &ref->node, bytenr,
|
||||
num_bytes, parent, ref_root, owner, offset,
|
||||
action, for_cow);
|
||||
BUG_ON(ret);
|
||||
if (!need_ref_seq(for_cow, ref_root) &&
|
||||
waitqueue_active(&delayed_refs->seq_wait))
|
||||
wake_up(&delayed_refs->seq_wait);
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans,
|
||||
int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_trans_handle *trans,
|
||||
u64 bytenr, u64 num_bytes,
|
||||
struct btrfs_delayed_extent_op *extent_op)
|
||||
{
|
||||
@@ -683,11 +740,13 @@ int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans,
|
||||
delayed_refs = &trans->transaction->delayed_refs;
|
||||
spin_lock(&delayed_refs->lock);
|
||||
|
||||
ret = add_delayed_ref_head(trans, &head_ref->node, bytenr,
|
||||
ret = add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
|
||||
num_bytes, BTRFS_UPDATE_DELAYED_HEAD,
|
||||
extent_op->is_data);
|
||||
BUG_ON(ret);
|
||||
|
||||
if (waitqueue_active(&delayed_refs->seq_wait))
|
||||
wake_up(&delayed_refs->seq_wait);
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -704,7 +763,7 @@ btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr)
|
||||
struct btrfs_delayed_ref_root *delayed_refs;
|
||||
|
||||
delayed_refs = &trans->transaction->delayed_refs;
|
||||
ref = find_ref_head(&delayed_refs->root, bytenr, NULL);
|
||||
ref = find_ref_head(&delayed_refs->root, bytenr, NULL, 0);
|
||||
if (ref)
|
||||
return btrfs_delayed_node_to_head(ref);
|
||||
return NULL;
|
||||
|
||||
+91
-13
@@ -33,6 +33,9 @@ struct btrfs_delayed_ref_node {
|
||||
/* the size of the extent */
|
||||
u64 num_bytes;
|
||||
|
||||
/* seq number to keep track of insertion order */
|
||||
u64 seq;
|
||||
|
||||
/* ref count on this data structure */
|
||||
atomic_t refs;
|
||||
|
||||
@@ -98,19 +101,15 @@ struct btrfs_delayed_ref_head {
|
||||
|
||||
struct btrfs_delayed_tree_ref {
|
||||
struct btrfs_delayed_ref_node node;
|
||||
union {
|
||||
u64 root;
|
||||
u64 parent;
|
||||
};
|
||||
u64 root;
|
||||
u64 parent;
|
||||
int level;
|
||||
};
|
||||
|
||||
struct btrfs_delayed_data_ref {
|
||||
struct btrfs_delayed_ref_node node;
|
||||
union {
|
||||
u64 root;
|
||||
u64 parent;
|
||||
};
|
||||
u64 root;
|
||||
u64 parent;
|
||||
u64 objectid;
|
||||
u64 offset;
|
||||
};
|
||||
@@ -140,6 +139,26 @@ 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)
|
||||
@@ -151,16 +170,21 @@ static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref)
|
||||
}
|
||||
}
|
||||
|
||||
int btrfs_add_delayed_tree_ref(struct btrfs_trans_handle *trans,
|
||||
int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_trans_handle *trans,
|
||||
u64 bytenr, u64 num_bytes, u64 parent,
|
||||
u64 ref_root, int level, int action,
|
||||
struct btrfs_delayed_extent_op *extent_op);
|
||||
int btrfs_add_delayed_data_ref(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_delayed_extent_op *extent_op,
|
||||
int for_cow);
|
||||
int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_trans_handle *trans,
|
||||
u64 bytenr, u64 num_bytes,
|
||||
u64 parent, u64 ref_root,
|
||||
u64 owner, u64 offset, int action,
|
||||
struct btrfs_delayed_extent_op *extent_op);
|
||||
int btrfs_add_delayed_extent_op(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_delayed_extent_op *extent_op,
|
||||
int for_cow);
|
||||
int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_trans_handle *trans,
|
||||
u64 bytenr, u64 num_bytes,
|
||||
struct btrfs_delayed_extent_op *extent_op);
|
||||
|
||||
@@ -170,6 +194,60 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_delayed_ref_head *head);
|
||||
int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
|
||||
struct list_head *cluster, u64 search_start);
|
||||
|
||||
struct seq_list {
|
||||
struct list_head list;
|
||||
u64 seq;
|
||||
};
|
||||
|
||||
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,
|
||||
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.
|
||||
|
||||
+41
-8
@@ -43,6 +43,7 @@
|
||||
#include "tree-log.h"
|
||||
#include "free-space-cache.h"
|
||||
#include "inode-map.h"
|
||||
#include "check-integrity.h"
|
||||
|
||||
static struct extent_io_ops btree_extent_io_ops;
|
||||
static void end_workqueue_fn(struct btrfs_work *work);
|
||||
@@ -1244,7 +1245,8 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
|
||||
root->ref_cows = 0;
|
||||
|
||||
leaf = btrfs_alloc_free_block(trans, root, root->leafsize, 0,
|
||||
BTRFS_TREE_LOG_OBJECTID, NULL, 0, 0, 0);
|
||||
BTRFS_TREE_LOG_OBJECTID, NULL,
|
||||
0, 0, 0, 0);
|
||||
if (IS_ERR(leaf)) {
|
||||
kfree(root);
|
||||
return ERR_CAST(leaf);
|
||||
@@ -1998,6 +2000,17 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||
init_waitqueue_head(&fs_info->scrub_pause_wait);
|
||||
init_rwsem(&fs_info->scrub_super_lock);
|
||||
fs_info->scrub_workers_refcnt = 0;
|
||||
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
|
||||
fs_info->check_integrity_print_mask = 0;
|
||||
#endif
|
||||
|
||||
spin_lock_init(&fs_info->balance_lock);
|
||||
mutex_init(&fs_info->balance_mutex);
|
||||
atomic_set(&fs_info->balance_running, 0);
|
||||
atomic_set(&fs_info->balance_pause_req, 0);
|
||||
atomic_set(&fs_info->balance_cancel_req, 0);
|
||||
fs_info->balance_ctl = NULL;
|
||||
init_waitqueue_head(&fs_info->balance_wait_q);
|
||||
|
||||
sb->s_blocksize = 4096;
|
||||
sb->s_blocksize_bits = blksize_bits(4096);
|
||||
@@ -2267,9 +2280,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
|
||||
(unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node),
|
||||
BTRFS_UUID_SIZE);
|
||||
|
||||
mutex_lock(&fs_info->chunk_mutex);
|
||||
ret = btrfs_read_chunk_tree(chunk_root);
|
||||
mutex_unlock(&fs_info->chunk_mutex);
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n",
|
||||
sb->s_id);
|
||||
@@ -2318,9 +2329,6 @@ retry_root_backup:
|
||||
|
||||
fs_info->generation = generation;
|
||||
fs_info->last_trans_committed = generation;
|
||||
fs_info->data_alloc_profile = (u64)-1;
|
||||
fs_info->metadata_alloc_profile = (u64)-1;
|
||||
fs_info->system_alloc_profile = fs_info->metadata_alloc_profile;
|
||||
|
||||
ret = btrfs_init_space_info(fs_info);
|
||||
if (ret) {
|
||||
@@ -2353,6 +2361,19 @@ retry_root_backup:
|
||||
btrfs_set_opt(fs_info->mount_opt, SSD);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
|
||||
if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) {
|
||||
ret = btrfsic_mount(tree_root, fs_devices,
|
||||
btrfs_test_opt(tree_root,
|
||||
CHECK_INTEGRITY_INCLUDING_EXTENT_DATA) ?
|
||||
1 : 0,
|
||||
fs_info->check_integrity_print_mask);
|
||||
if (ret)
|
||||
printk(KERN_WARNING "btrfs: failed to initialize"
|
||||
" integrity check module %s\n", sb->s_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* do not make disk changes in broken FS */
|
||||
if (btrfs_super_log_root(disk_super) != 0 &&
|
||||
!(fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR)) {
|
||||
@@ -2423,6 +2444,10 @@ retry_root_backup:
|
||||
if (!err)
|
||||
err = btrfs_orphan_cleanup(fs_info->tree_root);
|
||||
up_read(&fs_info->cleanup_work_sem);
|
||||
|
||||
if (!err)
|
||||
err = btrfs_recover_balance(fs_info->tree_root);
|
||||
|
||||
if (err) {
|
||||
close_ctree(tree_root);
|
||||
return ERR_PTR(err);
|
||||
@@ -2631,7 +2656,7 @@ static int write_dev_supers(struct btrfs_device *device,
|
||||
* we fua the first super. The others we allow
|
||||
* to go down lazy.
|
||||
*/
|
||||
ret = submit_bh(WRITE_FUA, bh);
|
||||
ret = btrfsic_submit_bh(WRITE_FUA, bh);
|
||||
if (ret)
|
||||
errors++;
|
||||
}
|
||||
@@ -2708,7 +2733,7 @@ static int write_dev_flush(struct btrfs_device *device, int wait)
|
||||
device->flush_bio = bio;
|
||||
|
||||
bio_get(bio);
|
||||
submit_bio(WRITE_FLUSH, bio);
|
||||
btrfsic_submit_bio(WRITE_FLUSH, bio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2972,6 +2997,9 @@ int close_ctree(struct btrfs_root *root)
|
||||
fs_info->closing = 1;
|
||||
smp_mb();
|
||||
|
||||
/* pause restriper - we want to resume on mount */
|
||||
btrfs_pause_balance(root->fs_info);
|
||||
|
||||
btrfs_scrub_cancel(root);
|
||||
|
||||
/* wait for any defraggers to finish */
|
||||
@@ -3054,6 +3082,11 @@ int close_ctree(struct btrfs_root *root)
|
||||
btrfs_stop_workers(&fs_info->caching_workers);
|
||||
btrfs_stop_workers(&fs_info->readahead_workers);
|
||||
|
||||
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
|
||||
if (btrfs_test_opt(root, CHECK_INTEGRITY))
|
||||
btrfsic_unmount(root, fs_info->fs_devices);
|
||||
#endif
|
||||
|
||||
btrfs_close_devices(fs_info->fs_devices);
|
||||
btrfs_mapping_tree_free(&fs_info->mapping_tree);
|
||||
|
||||
|
||||
+346
-119
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@
|
||||
#include "ctree.h"
|
||||
#include "btrfs_inode.h"
|
||||
#include "volumes.h"
|
||||
#include "check-integrity.h"
|
||||
|
||||
static struct kmem_cache *extent_state_cache;
|
||||
static struct kmem_cache *extent_buffer_cache;
|
||||
@@ -1895,7 +1896,7 @@ int repair_io_failure(struct btrfs_mapping_tree *map_tree, u64 start,
|
||||
}
|
||||
bio->bi_bdev = dev->bdev;
|
||||
bio_add_page(bio, page, length, start-page_offset(page));
|
||||
submit_bio(WRITE_SYNC, bio);
|
||||
btrfsic_submit_bio(WRITE_SYNC, bio);
|
||||
wait_for_completion(&compl);
|
||||
|
||||
if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
|
||||
@@ -2393,7 +2394,7 @@ static int submit_one_bio(int rw, struct bio *bio, int mirror_num,
|
||||
ret = tree->ops->submit_bio_hook(page->mapping->host, rw, bio,
|
||||
mirror_num, bio_flags, start);
|
||||
else
|
||||
submit_bio(rw, bio);
|
||||
btrfsic_submit_bio(rw, bio);
|
||||
|
||||
if (bio_flagged(bio, BIO_EOPNOTSUPP))
|
||||
ret = -EOPNOTSUPP;
|
||||
@@ -3579,6 +3580,7 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
|
||||
atomic_set(&eb->blocking_writers, 0);
|
||||
atomic_set(&eb->spinning_readers, 0);
|
||||
atomic_set(&eb->spinning_writers, 0);
|
||||
eb->lock_nested = 0;
|
||||
init_waitqueue_head(&eb->write_lock_wq);
|
||||
init_waitqueue_head(&eb->read_lock_wq);
|
||||
|
||||
|
||||
@@ -129,6 +129,7 @@ struct extent_buffer {
|
||||
struct list_head leak_list;
|
||||
struct rcu_head rcu_head;
|
||||
atomic_t refs;
|
||||
pid_t lock_owner;
|
||||
|
||||
/* count of read lock holders on the extent buffer */
|
||||
atomic_t write_locks;
|
||||
@@ -137,6 +138,7 @@ struct extent_buffer {
|
||||
atomic_t blocking_readers;
|
||||
atomic_t spinning_readers;
|
||||
atomic_t spinning_writers;
|
||||
int lock_nested;
|
||||
|
||||
/* protects write locks */
|
||||
rwlock_t lock;
|
||||
|
||||
+5
-6
@@ -678,7 +678,7 @@ next_slot:
|
||||
disk_bytenr, num_bytes, 0,
|
||||
root->root_key.objectid,
|
||||
new_key.objectid,
|
||||
start - extent_offset);
|
||||
start - extent_offset, 0);
|
||||
BUG_ON(ret);
|
||||
*hint_byte = disk_bytenr;
|
||||
}
|
||||
@@ -753,7 +753,7 @@ next_slot:
|
||||
disk_bytenr, num_bytes, 0,
|
||||
root->root_key.objectid,
|
||||
key.objectid, key.offset -
|
||||
extent_offset);
|
||||
extent_offset, 0);
|
||||
BUG_ON(ret);
|
||||
inode_sub_bytes(inode,
|
||||
extent_end - key.offset);
|
||||
@@ -962,7 +962,7 @@ again:
|
||||
|
||||
ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
|
||||
root->root_key.objectid,
|
||||
ino, orig_offset);
|
||||
ino, orig_offset, 0);
|
||||
BUG_ON(ret);
|
||||
|
||||
if (split == start) {
|
||||
@@ -989,7 +989,7 @@ again:
|
||||
del_nr++;
|
||||
ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
|
||||
0, root->root_key.objectid,
|
||||
ino, orig_offset);
|
||||
ino, orig_offset, 0);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
other_start = 0;
|
||||
@@ -1006,7 +1006,7 @@ again:
|
||||
del_nr++;
|
||||
ret = btrfs_free_extent(trans, root, bytenr, num_bytes,
|
||||
0, root->root_key.objectid,
|
||||
ino, orig_offset);
|
||||
ino, orig_offset, 0);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
if (del_nr == 0) {
|
||||
@@ -1274,7 +1274,6 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
|
||||
dirty_pages);
|
||||
if (dirty_pages < (root->leafsize >> PAGE_CACHE_SHIFT) + 1)
|
||||
btrfs_btree_balance_dirty(root, 1);
|
||||
btrfs_throttle(root);
|
||||
|
||||
pos += copied;
|
||||
num_written += copied;
|
||||
|
||||
+257
-162
File diff suppressed because it is too large
Load Diff
@@ -438,6 +438,8 @@ int btrfs_save_ino_cache(struct btrfs_root *root,
|
||||
trans->bytes_reserved);
|
||||
if (ret)
|
||||
goto out;
|
||||
trace_btrfs_space_reservation(root->fs_info, "ino_cache", (u64)trans,
|
||||
trans->bytes_reserved, 1);
|
||||
again:
|
||||
inode = lookup_free_ino_inode(root, path);
|
||||
if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) {
|
||||
@@ -498,6 +500,8 @@ again:
|
||||
out_put:
|
||||
iput(inode);
|
||||
out_release:
|
||||
trace_btrfs_space_reservation(root->fs_info, "ino_cache", (u64)trans,
|
||||
trans->bytes_reserved, 0);
|
||||
btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved);
|
||||
out:
|
||||
trans->block_rsv = rsv;
|
||||
|
||||
+33
-33
@@ -1951,12 +1951,28 @@ enum btrfs_orphan_cleanup_state {
|
||||
void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
struct btrfs_block_rsv *block_rsv;
|
||||
int ret;
|
||||
|
||||
if (!list_empty(&root->orphan_list) ||
|
||||
root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE)
|
||||
return;
|
||||
|
||||
spin_lock(&root->orphan_lock);
|
||||
if (!list_empty(&root->orphan_list)) {
|
||||
spin_unlock(&root->orphan_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE) {
|
||||
spin_unlock(&root->orphan_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
block_rsv = root->orphan_block_rsv;
|
||||
root->orphan_block_rsv = NULL;
|
||||
spin_unlock(&root->orphan_lock);
|
||||
|
||||
if (root->orphan_item_inserted &&
|
||||
btrfs_root_refs(&root->root_item) > 0) {
|
||||
ret = btrfs_del_orphan_item(trans, root->fs_info->tree_root,
|
||||
@@ -1965,10 +1981,9 @@ void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans,
|
||||
root->orphan_item_inserted = 0;
|
||||
}
|
||||
|
||||
if (root->orphan_block_rsv) {
|
||||
WARN_ON(root->orphan_block_rsv->size > 0);
|
||||
btrfs_free_block_rsv(root, root->orphan_block_rsv);
|
||||
root->orphan_block_rsv = NULL;
|
||||
if (block_rsv) {
|
||||
WARN_ON(block_rsv->size > 0);
|
||||
btrfs_free_block_rsv(root, block_rsv);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2224,14 +2239,7 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
|
||||
continue;
|
||||
}
|
||||
nr_truncate++;
|
||||
/*
|
||||
* Need to hold the imutex for reservation purposes, not
|
||||
* a huge deal here but I have a WARN_ON in
|
||||
* btrfs_delalloc_reserve_space to catch offenders.
|
||||
*/
|
||||
mutex_lock(&inode->i_mutex);
|
||||
ret = btrfs_truncate(inode);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
} else {
|
||||
nr_unlink++;
|
||||
}
|
||||
@@ -2845,7 +2853,7 @@ static void __unlink_end_trans(struct btrfs_trans_handle *trans,
|
||||
BUG_ON(!root->fs_info->enospc_unlink);
|
||||
root->fs_info->enospc_unlink = 0;
|
||||
}
|
||||
btrfs_end_transaction_throttle(trans, root);
|
||||
btrfs_end_transaction(trans, root);
|
||||
}
|
||||
|
||||
static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
@@ -3009,7 +3017,6 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
|
||||
int pending_del_nr = 0;
|
||||
int pending_del_slot = 0;
|
||||
int extent_type = -1;
|
||||
int encoding;
|
||||
int ret;
|
||||
int err = 0;
|
||||
u64 ino = btrfs_ino(inode);
|
||||
@@ -3059,7 +3066,6 @@ search_again:
|
||||
leaf = path->nodes[0];
|
||||
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
||||
found_type = btrfs_key_type(&found_key);
|
||||
encoding = 0;
|
||||
|
||||
if (found_key.objectid != ino)
|
||||
break;
|
||||
@@ -3072,10 +3078,6 @@ search_again:
|
||||
fi = btrfs_item_ptr(leaf, path->slots[0],
|
||||
struct btrfs_file_extent_item);
|
||||
extent_type = btrfs_file_extent_type(leaf, fi);
|
||||
encoding = btrfs_file_extent_compression(leaf, fi);
|
||||
encoding |= btrfs_file_extent_encryption(leaf, fi);
|
||||
encoding |= btrfs_file_extent_other_encoding(leaf, fi);
|
||||
|
||||
if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
|
||||
item_end +=
|
||||
btrfs_file_extent_num_bytes(leaf, fi);
|
||||
@@ -3103,7 +3105,7 @@ search_again:
|
||||
if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
|
||||
u64 num_dec;
|
||||
extent_start = btrfs_file_extent_disk_bytenr(leaf, fi);
|
||||
if (!del_item && !encoding) {
|
||||
if (!del_item) {
|
||||
u64 orig_num_bytes =
|
||||
btrfs_file_extent_num_bytes(leaf, fi);
|
||||
extent_num_bytes = new_size -
|
||||
@@ -3179,7 +3181,7 @@ delete:
|
||||
ret = btrfs_free_extent(trans, root, extent_start,
|
||||
extent_num_bytes, 0,
|
||||
btrfs_header_owner(leaf),
|
||||
ino, extent_offset);
|
||||
ino, extent_offset, 0);
|
||||
BUG_ON(ret);
|
||||
}
|
||||
|
||||
@@ -3434,7 +3436,7 @@ static int btrfs_setsize(struct inode *inode, loff_t newsize)
|
||||
i_size_write(inode, newsize);
|
||||
btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL);
|
||||
ret = btrfs_update_inode(trans, root, inode);
|
||||
btrfs_end_transaction_throttle(trans, root);
|
||||
btrfs_end_transaction(trans, root);
|
||||
} else {
|
||||
|
||||
/*
|
||||
@@ -4655,7 +4657,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
|
||||
}
|
||||
out_unlock:
|
||||
nr = trans->blocks_used;
|
||||
btrfs_end_transaction_throttle(trans, root);
|
||||
btrfs_end_transaction(trans, root);
|
||||
btrfs_btree_balance_dirty(root, nr);
|
||||
if (drop_inode) {
|
||||
inode_dec_link_count(inode);
|
||||
@@ -4723,7 +4725,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
|
||||
}
|
||||
out_unlock:
|
||||
nr = trans->blocks_used;
|
||||
btrfs_end_transaction_throttle(trans, root);
|
||||
btrfs_end_transaction(trans, root);
|
||||
if (drop_inode) {
|
||||
inode_dec_link_count(inode);
|
||||
iput(inode);
|
||||
@@ -4782,7 +4784,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
}
|
||||
|
||||
nr = trans->blocks_used;
|
||||
btrfs_end_transaction_throttle(trans, root);
|
||||
btrfs_end_transaction(trans, root);
|
||||
fail:
|
||||
if (drop_inode) {
|
||||
inode_dec_link_count(inode);
|
||||
@@ -4848,7 +4850,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
|
||||
out_fail:
|
||||
nr = trans->blocks_used;
|
||||
btrfs_end_transaction_throttle(trans, root);
|
||||
btrfs_end_transaction(trans, root);
|
||||
if (drop_on_err)
|
||||
iput(inode);
|
||||
btrfs_btree_balance_dirty(root, nr);
|
||||
@@ -5121,7 +5123,7 @@ again:
|
||||
}
|
||||
flush_dcache_page(page);
|
||||
} else if (create && PageUptodate(page)) {
|
||||
WARN_ON(1);
|
||||
BUG();
|
||||
if (!trans) {
|
||||
kunmap(page);
|
||||
free_extent_map(em);
|
||||
@@ -6402,10 +6404,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
u64 page_start;
|
||||
u64 page_end;
|
||||
|
||||
/* Need this to keep space reservations serialized */
|
||||
mutex_lock(&inode->i_mutex);
|
||||
ret = btrfs_delalloc_reserve_space(inode, PAGE_CACHE_SIZE);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
if (!ret)
|
||||
ret = btrfs_update_time(vma->vm_file);
|
||||
if (ret) {
|
||||
@@ -6494,8 +6493,8 @@ out_unlock:
|
||||
if (!ret)
|
||||
return VM_FAULT_LOCKED;
|
||||
unlock_page(page);
|
||||
btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
|
||||
out:
|
||||
btrfs_delalloc_release_space(inode, PAGE_CACHE_SIZE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -6668,7 +6667,7 @@ end_trans:
|
||||
err = ret;
|
||||
|
||||
nr = trans->blocks_used;
|
||||
ret = btrfs_end_transaction_throttle(trans, root);
|
||||
ret = btrfs_end_transaction(trans, root);
|
||||
btrfs_btree_balance_dirty(root, nr);
|
||||
}
|
||||
|
||||
@@ -6749,6 +6748,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
|
||||
extent_io_tree_init(&ei->io_tree, &inode->i_data);
|
||||
extent_io_tree_init(&ei->io_failure_tree, &inode->i_data);
|
||||
mutex_init(&ei->log_mutex);
|
||||
mutex_init(&ei->delalloc_mutex);
|
||||
btrfs_ordered_inode_tree_init(&ei->ordered_tree);
|
||||
INIT_LIST_HEAD(&ei->i_orphan);
|
||||
INIT_LIST_HEAD(&ei->delalloc_inodes);
|
||||
@@ -7074,7 +7074,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
btrfs_end_log_trans(root);
|
||||
}
|
||||
out_fail:
|
||||
btrfs_end_transaction_throttle(trans, root);
|
||||
btrfs_end_transaction(trans, root);
|
||||
out_notrans:
|
||||
if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
|
||||
up_read(&root->fs_info->subvol_sem);
|
||||
@@ -7246,7 +7246,7 @@ out_unlock:
|
||||
if (!err)
|
||||
d_instantiate(dentry, inode);
|
||||
nr = trans->blocks_used;
|
||||
btrfs_end_transaction_throttle(trans, root);
|
||||
btrfs_end_transaction(trans, root);
|
||||
if (drop_inode) {
|
||||
inode_dec_link_count(inode);
|
||||
iput(inode);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user