You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull btrfs updates from Chris Mason: "This is against 3.11-rc7, but was pulled and tested against your tree as of yesterday. We do have two small incrementals queued up, but I wanted to get this bunch out the door before I hop on an airplane. This is a fairly large batch of fixes, performance improvements, and cleanups from the usual Btrfs suspects. We've included Stefan Behren's work to index subvolume UUIDs, which is targeted at speeding up send/receive with many subvolumes or snapshots in place. It closes a long standing performance issue that was built in to the disk format. Mark Fasheh's offline dedup work is also here. In this case offline means the FS is mounted and active, but the dedup work is not done inline during file IO. This is a building block where utilities are able to ask the FS to dedup a series of extents. The kernel takes care of verifying the data involved really is the same. Today this involves reading both extents, but we'll continue to evolve the patches" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (118 commits) Btrfs: optimize key searches in btrfs_search_slot Btrfs: don't use an async starter for most of our workers Btrfs: only update disk_i_size as we remove extents Btrfs: fix deadlock in uuid scan kthread Btrfs: stop refusing the relocation of chunk 0 Btrfs: fix memory leak of uuid_root in free_fs_info btrfs: reuse kbasename helper btrfs: return btrfs error code for dev excl ops err Btrfs: allow partial ordered extent completion Btrfs: convert all bug_ons in free-space-cache.c Btrfs: add support for asserts Btrfs: adjust the fs_devices->missing count on unmount Btrf: cleanup: don't check for root_refs == 0 twice Btrfs: fix for patch "cleanup: don't check the same thing twice" Btrfs: get rid of one BUG() in write_all_supers() Btrfs: allocate prelim_ref with a slab allocater Btrfs: pass gfp_t to __add_prelim_ref() to avoid always using GFP_ATOMIC Btrfs: fix race conditions in BTRFS_IOC_FS_INFO ioctl Btrfs: fix race between removing a dev and writing sbs Btrfs: remove ourselves from the cluster list under lock ...
This commit is contained in:
@@ -72,3 +72,12 @@ config BTRFS_DEBUG
|
||||
performance, or export extra information via sysfs.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config BTRFS_ASSERT
|
||||
bool "Btrfs assert support"
|
||||
depends on BTRFS_FS
|
||||
help
|
||||
Enable run-time assertion checking. This will result in panics if
|
||||
any of the assertions trip. This is meant for btrfs developers only.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
+4
-1
@@ -8,7 +8,10 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
|
||||
extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
|
||||
export.o tree-log.o free-space-cache.o zlib.o lzo.o \
|
||||
compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
|
||||
reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o
|
||||
reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
|
||||
uuid-tree.o
|
||||
|
||||
btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
|
||||
btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
|
||||
|
||||
btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o
|
||||
|
||||
+55
-38
@@ -119,6 +119,26 @@ struct __prelim_ref {
|
||||
u64 wanted_disk_byte;
|
||||
};
|
||||
|
||||
static struct kmem_cache *btrfs_prelim_ref_cache;
|
||||
|
||||
int __init btrfs_prelim_ref_init(void)
|
||||
{
|
||||
btrfs_prelim_ref_cache = kmem_cache_create("btrfs_prelim_ref",
|
||||
sizeof(struct __prelim_ref),
|
||||
0,
|
||||
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
|
||||
NULL);
|
||||
if (!btrfs_prelim_ref_cache)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void btrfs_prelim_ref_exit(void)
|
||||
{
|
||||
if (btrfs_prelim_ref_cache)
|
||||
kmem_cache_destroy(btrfs_prelim_ref_cache);
|
||||
}
|
||||
|
||||
/*
|
||||
* the rules for all callers of this function are:
|
||||
* - obtaining the parent is the goal
|
||||
@@ -160,12 +180,12 @@ struct __prelim_ref {
|
||||
|
||||
static int __add_prelim_ref(struct list_head *head, u64 root_id,
|
||||
struct btrfs_key *key, int level,
|
||||
u64 parent, u64 wanted_disk_byte, int count)
|
||||
u64 parent, u64 wanted_disk_byte, int count,
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
struct __prelim_ref *ref;
|
||||
|
||||
/* in case we're adding delayed refs, we're holding the refs spinlock */
|
||||
ref = kmalloc(sizeof(*ref), GFP_ATOMIC);
|
||||
ref = kmem_cache_alloc(btrfs_prelim_ref_cache, gfp_mask);
|
||||
if (!ref)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -295,10 +315,9 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
|
||||
ret = btrfs_search_old_slot(root, &ref->key_for_search, path, time_seq);
|
||||
pr_debug("search slot in root %llu (level %d, ref count %d) returned "
|
||||
"%d for key (%llu %u %llu)\n",
|
||||
(unsigned long long)ref->root_id, level, ref->count, ret,
|
||||
(unsigned long long)ref->key_for_search.objectid,
|
||||
ref->key_for_search.type,
|
||||
(unsigned long long)ref->key_for_search.offset);
|
||||
ref->root_id, level, ref->count, ret,
|
||||
ref->key_for_search.objectid, ref->key_for_search.type,
|
||||
ref->key_for_search.offset);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
@@ -365,11 +384,12 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
|
||||
node = ulist_next(parents, &uiter);
|
||||
ref->parent = node ? node->val : 0;
|
||||
ref->inode_list = node ?
|
||||
(struct extent_inode_elem *)(uintptr_t)node->aux : 0;
|
||||
(struct extent_inode_elem *)(uintptr_t)node->aux : NULL;
|
||||
|
||||
/* additional parents require new refs being added here */
|
||||
while ((node = ulist_next(parents, &uiter))) {
|
||||
new_ref = kmalloc(sizeof(*new_ref), GFP_NOFS);
|
||||
new_ref = kmem_cache_alloc(btrfs_prelim_ref_cache,
|
||||
GFP_NOFS);
|
||||
if (!new_ref) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
@@ -493,7 +513,7 @@ static void __merge_refs(struct list_head *head, int mode)
|
||||
ref1->count += ref2->count;
|
||||
|
||||
list_del(&ref2->list);
|
||||
kfree(ref2);
|
||||
kmem_cache_free(btrfs_prelim_ref_cache, ref2);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -548,7 +568,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
|
||||
ref = btrfs_delayed_node_to_tree_ref(node);
|
||||
ret = __add_prelim_ref(prefs, ref->root, &op_key,
|
||||
ref->level + 1, 0, node->bytenr,
|
||||
node->ref_mod * sgn);
|
||||
node->ref_mod * sgn, GFP_ATOMIC);
|
||||
break;
|
||||
}
|
||||
case BTRFS_SHARED_BLOCK_REF_KEY: {
|
||||
@@ -558,7 +578,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
|
||||
ret = __add_prelim_ref(prefs, ref->root, NULL,
|
||||
ref->level + 1, ref->parent,
|
||||
node->bytenr,
|
||||
node->ref_mod * sgn);
|
||||
node->ref_mod * sgn, GFP_ATOMIC);
|
||||
break;
|
||||
}
|
||||
case BTRFS_EXTENT_DATA_REF_KEY: {
|
||||
@@ -570,7 +590,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
|
||||
key.offset = ref->offset;
|
||||
ret = __add_prelim_ref(prefs, ref->root, &key, 0, 0,
|
||||
node->bytenr,
|
||||
node->ref_mod * sgn);
|
||||
node->ref_mod * sgn, GFP_ATOMIC);
|
||||
break;
|
||||
}
|
||||
case BTRFS_SHARED_DATA_REF_KEY: {
|
||||
@@ -583,7 +603,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
|
||||
key.offset = ref->offset;
|
||||
ret = __add_prelim_ref(prefs, ref->root, &key, 0,
|
||||
ref->parent, node->bytenr,
|
||||
node->ref_mod * sgn);
|
||||
node->ref_mod * sgn, GFP_ATOMIC);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -657,7 +677,7 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
|
||||
case BTRFS_SHARED_BLOCK_REF_KEY:
|
||||
ret = __add_prelim_ref(prefs, 0, NULL,
|
||||
*info_level + 1, offset,
|
||||
bytenr, 1);
|
||||
bytenr, 1, GFP_NOFS);
|
||||
break;
|
||||
case BTRFS_SHARED_DATA_REF_KEY: {
|
||||
struct btrfs_shared_data_ref *sdref;
|
||||
@@ -666,13 +686,13 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
|
||||
sdref = (struct btrfs_shared_data_ref *)(iref + 1);
|
||||
count = btrfs_shared_data_ref_count(leaf, sdref);
|
||||
ret = __add_prelim_ref(prefs, 0, NULL, 0, offset,
|
||||
bytenr, count);
|
||||
bytenr, count, GFP_NOFS);
|
||||
break;
|
||||
}
|
||||
case BTRFS_TREE_BLOCK_REF_KEY:
|
||||
ret = __add_prelim_ref(prefs, offset, NULL,
|
||||
*info_level + 1, 0,
|
||||
bytenr, 1);
|
||||
bytenr, 1, GFP_NOFS);
|
||||
break;
|
||||
case BTRFS_EXTENT_DATA_REF_KEY: {
|
||||
struct btrfs_extent_data_ref *dref;
|
||||
@@ -687,7 +707,7 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
|
||||
key.offset = btrfs_extent_data_ref_offset(leaf, dref);
|
||||
root = btrfs_extent_data_ref_root(leaf, dref);
|
||||
ret = __add_prelim_ref(prefs, root, &key, 0, 0,
|
||||
bytenr, count);
|
||||
bytenr, count, GFP_NOFS);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -738,7 +758,7 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
|
||||
case BTRFS_SHARED_BLOCK_REF_KEY:
|
||||
ret = __add_prelim_ref(prefs, 0, NULL,
|
||||
info_level + 1, key.offset,
|
||||
bytenr, 1);
|
||||
bytenr, 1, GFP_NOFS);
|
||||
break;
|
||||
case BTRFS_SHARED_DATA_REF_KEY: {
|
||||
struct btrfs_shared_data_ref *sdref;
|
||||
@@ -748,13 +768,13 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_shared_data_ref);
|
||||
count = btrfs_shared_data_ref_count(leaf, sdref);
|
||||
ret = __add_prelim_ref(prefs, 0, NULL, 0, key.offset,
|
||||
bytenr, count);
|
||||
bytenr, count, GFP_NOFS);
|
||||
break;
|
||||
}
|
||||
case BTRFS_TREE_BLOCK_REF_KEY:
|
||||
ret = __add_prelim_ref(prefs, key.offset, NULL,
|
||||
info_level + 1, 0,
|
||||
bytenr, 1);
|
||||
bytenr, 1, GFP_NOFS);
|
||||
break;
|
||||
case BTRFS_EXTENT_DATA_REF_KEY: {
|
||||
struct btrfs_extent_data_ref *dref;
|
||||
@@ -770,7 +790,7 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
|
||||
key.offset = btrfs_extent_data_ref_offset(leaf, dref);
|
||||
root = btrfs_extent_data_ref_root(leaf, dref);
|
||||
ret = __add_prelim_ref(prefs, root, &key, 0, 0,
|
||||
bytenr, count);
|
||||
bytenr, count, GFP_NOFS);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -911,7 +931,6 @@ again:
|
||||
|
||||
while (!list_empty(&prefs)) {
|
||||
ref = list_first_entry(&prefs, struct __prelim_ref, list);
|
||||
list_del(&ref->list);
|
||||
WARN_ON(ref->count < 0);
|
||||
if (ref->count && ref->root_id && ref->parent == 0) {
|
||||
/* no parent == root of tree */
|
||||
@@ -935,8 +954,10 @@ again:
|
||||
}
|
||||
ret = find_extent_in_eb(eb, bytenr,
|
||||
*extent_item_pos, &eie);
|
||||
ref->inode_list = eie;
|
||||
free_extent_buffer(eb);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ref->inode_list = eie;
|
||||
}
|
||||
ret = ulist_add_merge(refs, ref->parent,
|
||||
(uintptr_t)ref->inode_list,
|
||||
@@ -954,7 +975,8 @@ again:
|
||||
eie->next = ref->inode_list;
|
||||
}
|
||||
}
|
||||
kfree(ref);
|
||||
list_del(&ref->list);
|
||||
kmem_cache_free(btrfs_prelim_ref_cache, ref);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -962,13 +984,13 @@ out:
|
||||
while (!list_empty(&prefs)) {
|
||||
ref = list_first_entry(&prefs, struct __prelim_ref, list);
|
||||
list_del(&ref->list);
|
||||
kfree(ref);
|
||||
kmem_cache_free(btrfs_prelim_ref_cache, ref);
|
||||
}
|
||||
while (!list_empty(&prefs_delayed)) {
|
||||
ref = list_first_entry(&prefs_delayed, struct __prelim_ref,
|
||||
list);
|
||||
list_del(&ref->list);
|
||||
kfree(ref);
|
||||
kmem_cache_free(btrfs_prelim_ref_cache, ref);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -1326,8 +1348,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
|
||||
found_key->type != BTRFS_METADATA_ITEM_KEY) ||
|
||||
found_key->objectid > logical ||
|
||||
found_key->objectid + size <= logical) {
|
||||
pr_debug("logical %llu is not within any extent\n",
|
||||
(unsigned long long)logical);
|
||||
pr_debug("logical %llu is not within any extent\n", logical);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
@@ -1340,11 +1361,8 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
|
||||
|
||||
pr_debug("logical %llu is at position %llu within the extent (%llu "
|
||||
"EXTENT_ITEM %llu) flags %#llx size %u\n",
|
||||
(unsigned long long)logical,
|
||||
(unsigned long long)(logical - found_key->objectid),
|
||||
(unsigned long long)found_key->objectid,
|
||||
(unsigned long long)found_key->offset,
|
||||
(unsigned long long)flags, item_size);
|
||||
logical, logical - found_key->objectid, found_key->objectid,
|
||||
found_key->offset, flags, item_size);
|
||||
|
||||
WARN_ON(!flags_ret);
|
||||
if (flags_ret) {
|
||||
@@ -1516,7 +1534,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
|
||||
while (!ret && (root_node = ulist_next(roots, &root_uiter))) {
|
||||
pr_debug("root %llu references leaf %llu, data list "
|
||||
"%#llx\n", root_node->val, ref_node->val,
|
||||
(long long)ref_node->aux);
|
||||
ref_node->aux);
|
||||
ret = iterate_leaf_refs((struct extent_inode_elem *)
|
||||
(uintptr_t)ref_node->aux,
|
||||
root_node->val,
|
||||
@@ -1608,9 +1626,8 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
|
||||
name_len = btrfs_inode_ref_name_len(eb, iref);
|
||||
/* path must be released before calling iterate()! */
|
||||
pr_debug("following ref at offset %u for inode %llu in "
|
||||
"tree %llu\n", cur,
|
||||
(unsigned long long)found_key.objectid,
|
||||
(unsigned long long)fs_root->objectid);
|
||||
"tree %llu\n", cur, found_key.objectid,
|
||||
fs_root->objectid);
|
||||
ret = iterate(parent, name_len,
|
||||
(unsigned long)(iref + 1), eb, ctx);
|
||||
if (ret)
|
||||
|
||||
@@ -72,4 +72,6 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
|
||||
struct btrfs_inode_extref **ret_extref,
|
||||
u64 *found_off);
|
||||
|
||||
int __init btrfs_prelim_ref_init(void);
|
||||
void btrfs_prelim_ref_exit(void);
|
||||
#endif
|
||||
|
||||
@@ -218,6 +218,27 @@ static inline int btrfs_inode_in_log(struct inode *inode, u64 generation)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct btrfs_dio_private {
|
||||
struct inode *inode;
|
||||
u64 logical_offset;
|
||||
u64 disk_bytenr;
|
||||
u64 bytes;
|
||||
void *private;
|
||||
|
||||
/* number of bios pending for this dio */
|
||||
atomic_t pending_bios;
|
||||
|
||||
/* IO errors */
|
||||
int errors;
|
||||
|
||||
/* orig_bio is our btrfs_io_bio */
|
||||
struct bio *orig_bio;
|
||||
|
||||
/* dio_bio came from fs/direct-io.c */
|
||||
struct bio *dio_bio;
|
||||
u8 csum[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* Disable DIO read nolock optimization, so new dio readers will be forced
|
||||
* to grab i_mutex. It is used to avoid the endless truncate due to
|
||||
|
||||
+164
-258
File diff suppressed because it is too large
Load Diff
@@ -132,9 +132,8 @@ static int check_compressed_csum(struct inode *inode,
|
||||
printk(KERN_INFO "btrfs csum failed ino %llu "
|
||||
"extent %llu csum %u "
|
||||
"wanted %u mirror %d\n",
|
||||
(unsigned long long)btrfs_ino(inode),
|
||||
(unsigned long long)disk_start,
|
||||
csum, *cb_sum, cb->mirror_num);
|
||||
btrfs_ino(inode), disk_start, csum, *cb_sum,
|
||||
cb->mirror_num);
|
||||
ret = -EIO;
|
||||
goto fail;
|
||||
}
|
||||
@@ -639,7 +638,11 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
||||
faili = nr_pages - 1;
|
||||
cb->nr_pages = nr_pages;
|
||||
|
||||
add_ra_bio_pages(inode, em_start + em_len, cb);
|
||||
/* In the parent-locked case, we only locked the range we are
|
||||
* interested in. In all other cases, we can opportunistically
|
||||
* cache decompressed data that goes beyond the requested range. */
|
||||
if (!(bio_flags & EXTENT_BIO_PARENT_LOCKED))
|
||||
add_ra_bio_pages(inode, em_start + em_len, cb);
|
||||
|
||||
/* include any pages we added in add_ra-bio_pages */
|
||||
uncompressed_len = bio->bi_vcnt * PAGE_CACHE_SIZE;
|
||||
|
||||
+144
-145
File diff suppressed because it is too large
Load Diff
+136
-25
@@ -23,6 +23,7 @@
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/backing-dev.h>
|
||||
#include <linux/wait.h>
|
||||
@@ -91,6 +92,9 @@ struct btrfs_ordered_sum;
|
||||
/* holds quota configuration and tracking */
|
||||
#define BTRFS_QUOTA_TREE_OBJECTID 8ULL
|
||||
|
||||
/* for storing items that use the BTRFS_UUID_KEY* types */
|
||||
#define BTRFS_UUID_TREE_OBJECTID 9ULL
|
||||
|
||||
/* for storing balance parameters in the root tree */
|
||||
#define BTRFS_BALANCE_OBJECTID -4ULL
|
||||
|
||||
@@ -142,7 +146,7 @@ struct btrfs_ordered_sum;
|
||||
|
||||
#define BTRFS_EMPTY_SUBVOL_DIR_OBJECTID 2
|
||||
|
||||
#define BTRFS_DEV_REPLACE_DEVID 0
|
||||
#define BTRFS_DEV_REPLACE_DEVID 0ULL
|
||||
|
||||
/*
|
||||
* the max metadata block size. This limit is somewhat artificial,
|
||||
@@ -478,9 +482,10 @@ struct btrfs_super_block {
|
||||
char label[BTRFS_LABEL_SIZE];
|
||||
|
||||
__le64 cache_generation;
|
||||
__le64 uuid_tree_generation;
|
||||
|
||||
/* future expansion */
|
||||
__le64 reserved[31];
|
||||
__le64 reserved[30];
|
||||
u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE];
|
||||
struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS];
|
||||
} __attribute__ ((__packed__));
|
||||
@@ -1188,6 +1193,7 @@ enum btrfs_caching_type {
|
||||
BTRFS_CACHE_STARTED = 1,
|
||||
BTRFS_CACHE_FAST = 2,
|
||||
BTRFS_CACHE_FINISHED = 3,
|
||||
BTRFS_CACHE_ERROR = 4,
|
||||
};
|
||||
|
||||
enum btrfs_disk_cache_state {
|
||||
@@ -1302,6 +1308,7 @@ struct btrfs_fs_info {
|
||||
struct btrfs_root *fs_root;
|
||||
struct btrfs_root *csum_root;
|
||||
struct btrfs_root *quota_root;
|
||||
struct btrfs_root *uuid_root;
|
||||
|
||||
/* the log root tree is a directory of all the other log roots */
|
||||
struct btrfs_root *log_root_tree;
|
||||
@@ -1350,6 +1357,7 @@ struct btrfs_fs_info {
|
||||
u64 last_trans_log_full_commit;
|
||||
unsigned long mount_opt;
|
||||
unsigned long compress_type:4;
|
||||
int commit_interval;
|
||||
/*
|
||||
* It is a suggestive number, the read side is safe even it gets a
|
||||
* wrong number because we will write out the data into a regular
|
||||
@@ -1411,6 +1419,13 @@ struct btrfs_fs_info {
|
||||
* before jumping into the main commit.
|
||||
*/
|
||||
struct mutex ordered_operations_mutex;
|
||||
|
||||
/*
|
||||
* Same as ordered_operations_mutex except this is for ordered extents
|
||||
* and not the operations.
|
||||
*/
|
||||
struct mutex ordered_extent_flush_mutex;
|
||||
|
||||
struct rw_semaphore extent_commit_sem;
|
||||
|
||||
struct rw_semaphore cleanup_work_sem;
|
||||
@@ -1641,6 +1656,9 @@ struct btrfs_fs_info {
|
||||
struct btrfs_dev_replace dev_replace;
|
||||
|
||||
atomic_t mutually_exclusive_operation_running;
|
||||
|
||||
struct semaphore uuid_tree_rescan_sem;
|
||||
unsigned int update_uuid_tree_gen:1;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1933,6 +1951,19 @@ struct btrfs_ioctl_defrag_range_args {
|
||||
*/
|
||||
#define BTRFS_DEV_REPLACE_KEY 250
|
||||
|
||||
/*
|
||||
* Stores items that allow to quickly map UUIDs to something else.
|
||||
* These items are part of the filesystem UUID tree.
|
||||
* The key is built like this:
|
||||
* (UUID_upper_64_bits, BTRFS_UUID_KEY*, UUID_lower_64_bits).
|
||||
*/
|
||||
#if BTRFS_UUID_SIZE != 16
|
||||
#error "UUID items require BTRFS_UUID_SIZE == 16!"
|
||||
#endif
|
||||
#define BTRFS_UUID_KEY_SUBVOL 251 /* for UUIDs assigned to subvols */
|
||||
#define BTRFS_UUID_KEY_RECEIVED_SUBVOL 252 /* for UUIDs assigned to
|
||||
* received subvols */
|
||||
|
||||
/*
|
||||
* string items are for debugging. They just store a short string of
|
||||
* data in the FS
|
||||
@@ -1967,6 +1998,9 @@ struct btrfs_ioctl_defrag_range_args {
|
||||
#define BTRFS_MOUNT_CHECK_INTEGRITY (1 << 20)
|
||||
#define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21)
|
||||
#define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR (1 << 22)
|
||||
#define BTRFS_MOUNT_RESCAN_UUID_TREE (1 << 23)
|
||||
|
||||
#define BTRFS_DEFAULT_COMMIT_INTERVAL (30)
|
||||
|
||||
#define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt)
|
||||
#define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt)
|
||||
@@ -2130,14 +2164,14 @@ BTRFS_SETGET_STACK_FUNCS(stack_device_bandwidth, struct btrfs_dev_item,
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_device_generation, struct btrfs_dev_item,
|
||||
generation, 64);
|
||||
|
||||
static inline char *btrfs_device_uuid(struct btrfs_dev_item *d)
|
||||
static inline unsigned long btrfs_device_uuid(struct btrfs_dev_item *d)
|
||||
{
|
||||
return (char *)d + offsetof(struct btrfs_dev_item, uuid);
|
||||
return (unsigned long)d + offsetof(struct btrfs_dev_item, uuid);
|
||||
}
|
||||
|
||||
static inline char *btrfs_device_fsid(struct btrfs_dev_item *d)
|
||||
static inline unsigned long btrfs_device_fsid(struct btrfs_dev_item *d)
|
||||
{
|
||||
return (char *)d + offsetof(struct btrfs_dev_item, fsid);
|
||||
return (unsigned long)d + offsetof(struct btrfs_dev_item, fsid);
|
||||
}
|
||||
|
||||
BTRFS_SETGET_FUNCS(chunk_length, struct btrfs_chunk, length, 64);
|
||||
@@ -2240,6 +2274,23 @@ BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32);
|
||||
BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32);
|
||||
BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64);
|
||||
BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_generation, struct btrfs_inode_item,
|
||||
generation, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence, struct btrfs_inode_item,
|
||||
sequence, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_transid, struct btrfs_inode_item,
|
||||
transid, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_size, struct btrfs_inode_item, size, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes, struct btrfs_inode_item,
|
||||
nbytes, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group, struct btrfs_inode_item,
|
||||
block_group, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink, struct btrfs_inode_item, nlink, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_uid, struct btrfs_inode_item, uid, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, struct btrfs_inode_item, gid, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, struct btrfs_inode_item, mode, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, struct btrfs_inode_item, rdev, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, struct btrfs_inode_item, flags, 64);
|
||||
|
||||
static inline struct btrfs_timespec *
|
||||
btrfs_inode_atime(struct btrfs_inode_item *inode_item)
|
||||
@@ -2267,6 +2318,8 @@ btrfs_inode_ctime(struct btrfs_inode_item *inode_item)
|
||||
|
||||
BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64);
|
||||
BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, nsec, 32);
|
||||
|
||||
/* struct btrfs_dev_extent */
|
||||
BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent,
|
||||
@@ -2277,10 +2330,10 @@ BTRFS_SETGET_FUNCS(dev_extent_chunk_offset, struct btrfs_dev_extent,
|
||||
chunk_offset, 64);
|
||||
BTRFS_SETGET_FUNCS(dev_extent_length, struct btrfs_dev_extent, length, 64);
|
||||
|
||||
static inline u8 *btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev)
|
||||
static inline unsigned long btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev)
|
||||
{
|
||||
unsigned long ptr = offsetof(struct btrfs_dev_extent, chunk_tree_uuid);
|
||||
return (u8 *)((unsigned long)dev + ptr);
|
||||
return (unsigned long)dev + ptr;
|
||||
}
|
||||
|
||||
BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 64);
|
||||
@@ -2348,6 +2401,10 @@ BTRFS_SETGET_FUNCS(ref_count_v0, struct btrfs_extent_ref_v0, count, 32);
|
||||
/* struct btrfs_node */
|
||||
BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64);
|
||||
BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_key_blockptr, struct btrfs_key_ptr,
|
||||
blockptr, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_key_generation, struct btrfs_key_ptr,
|
||||
generation, 64);
|
||||
|
||||
static inline u64 btrfs_node_blockptr(struct extent_buffer *eb, int nr)
|
||||
{
|
||||
@@ -2404,6 +2461,8 @@ static inline void btrfs_set_node_key(struct extent_buffer *eb,
|
||||
/* struct btrfs_item */
|
||||
BTRFS_SETGET_FUNCS(item_offset, struct btrfs_item, offset, 32);
|
||||
BTRFS_SETGET_FUNCS(item_size, struct btrfs_item, size, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_item_offset, struct btrfs_item, offset, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_item_size, struct btrfs_item, size, 32);
|
||||
|
||||
static inline unsigned long btrfs_item_nr_offset(int nr)
|
||||
{
|
||||
@@ -2466,6 +2525,13 @@ BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
|
||||
BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
|
||||
BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
|
||||
BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dir_type, struct btrfs_dir_item, type, 8);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dir_data_len, struct btrfs_dir_item,
|
||||
data_len, 16);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item,
|
||||
name_len, 16);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item,
|
||||
transid, 64);
|
||||
|
||||
static inline void btrfs_dir_item_key(struct extent_buffer *eb,
|
||||
struct btrfs_dir_item *item,
|
||||
@@ -2568,6 +2634,12 @@ BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64);
|
||||
BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32);
|
||||
BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64);
|
||||
BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_header_generation, struct btrfs_header,
|
||||
generation, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_header_owner, struct btrfs_header, owner, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_header_nritems, struct btrfs_header,
|
||||
nritems, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64);
|
||||
|
||||
static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag)
|
||||
{
|
||||
@@ -2603,16 +2675,14 @@ static inline void btrfs_set_header_backref_rev(struct extent_buffer *eb,
|
||||
btrfs_set_header_flags(eb, flags);
|
||||
}
|
||||
|
||||
static inline u8 *btrfs_header_fsid(struct extent_buffer *eb)
|
||||
static inline unsigned long btrfs_header_fsid(struct extent_buffer *eb)
|
||||
{
|
||||
unsigned long ptr = offsetof(struct btrfs_header, fsid);
|
||||
return (u8 *)ptr;
|
||||
return offsetof(struct btrfs_header, fsid);
|
||||
}
|
||||
|
||||
static inline u8 *btrfs_header_chunk_tree_uuid(struct extent_buffer *eb)
|
||||
static inline unsigned long btrfs_header_chunk_tree_uuid(struct extent_buffer *eb)
|
||||
{
|
||||
unsigned long ptr = offsetof(struct btrfs_header, chunk_tree_uuid);
|
||||
return (u8 *)ptr;
|
||||
return offsetof(struct btrfs_header, chunk_tree_uuid);
|
||||
}
|
||||
|
||||
static inline int btrfs_is_leaf(struct extent_buffer *eb)
|
||||
@@ -2830,6 +2900,9 @@ BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block,
|
||||
csum_type, 16);
|
||||
BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block,
|
||||
cache_generation, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
|
||||
uuid_tree_generation, 64);
|
||||
|
||||
static inline int btrfs_super_csum_size(struct btrfs_super_block *s)
|
||||
{
|
||||
@@ -2847,6 +2920,14 @@ static inline unsigned long btrfs_leaf_data(struct extent_buffer *l)
|
||||
|
||||
/* struct btrfs_file_extent_item */
|
||||
BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr,
|
||||
struct btrfs_file_extent_item, disk_bytenr, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_file_extent_offset,
|
||||
struct btrfs_file_extent_item, offset, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation,
|
||||
struct btrfs_file_extent_item, generation, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes,
|
||||
struct btrfs_file_extent_item, num_bytes, 64);
|
||||
|
||||
static inline unsigned long
|
||||
btrfs_file_extent_inline_start(struct btrfs_file_extent_item *e)
|
||||
@@ -3107,11 +3188,9 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 root_objectid, u64 owner, u64 offset,
|
||||
struct btrfs_key *ins);
|
||||
int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 num_bytes, u64 min_alloc_size,
|
||||
u64 empty_size, u64 hint_byte,
|
||||
struct btrfs_key *ins, int is_data);
|
||||
int btrfs_reserve_extent(struct btrfs_root *root, u64 num_bytes,
|
||||
u64 min_alloc_size, u64 empty_size, u64 hint_byte,
|
||||
struct btrfs_key *ins, int is_data);
|
||||
int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
struct extent_buffer *buf, int full_backref, int for_cow);
|
||||
int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
|
||||
@@ -3175,7 +3254,7 @@ void btrfs_orphan_release_metadata(struct inode *inode);
|
||||
int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *rsv,
|
||||
int nitems,
|
||||
u64 *qgroup_reserved);
|
||||
u64 *qgroup_reserved, bool use_global_rsv);
|
||||
void btrfs_subvolume_release_metadata(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *rsv,
|
||||
u64 qgroup_reserved);
|
||||
@@ -3245,6 +3324,7 @@ enum btrfs_compare_tree_result {
|
||||
BTRFS_COMPARE_TREE_NEW,
|
||||
BTRFS_COMPARE_TREE_DELETED,
|
||||
BTRFS_COMPARE_TREE_CHANGED,
|
||||
BTRFS_COMPARE_TREE_SAME,
|
||||
};
|
||||
typedef int (*btrfs_changed_cb_t)(struct btrfs_root *left_root,
|
||||
struct btrfs_root *right_root,
|
||||
@@ -3380,6 +3460,7 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info)
|
||||
kfree(fs_info->dev_root);
|
||||
kfree(fs_info->csum_root);
|
||||
kfree(fs_info->quota_root);
|
||||
kfree(fs_info->uuid_root);
|
||||
kfree(fs_info->super_copy);
|
||||
kfree(fs_info->super_for_commit);
|
||||
kfree(fs_info);
|
||||
@@ -3414,8 +3495,6 @@ int __must_check btrfs_update_root(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
struct btrfs_key *key,
|
||||
struct btrfs_root_item *item);
|
||||
void btrfs_read_root_item(struct extent_buffer *eb, int slot,
|
||||
struct btrfs_root_item *item);
|
||||
int btrfs_find_root(struct btrfs_root *root, struct btrfs_key *search_key,
|
||||
struct btrfs_path *path, struct btrfs_root_item *root_item,
|
||||
struct btrfs_key *root_key);
|
||||
@@ -3426,6 +3505,17 @@ void btrfs_check_and_init_root_item(struct btrfs_root_item *item);
|
||||
void btrfs_update_root_times(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
|
||||
/* uuid-tree.c */
|
||||
int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *uuid_root, u8 *uuid, u8 type,
|
||||
u64 subid);
|
||||
int btrfs_uuid_tree_rem(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *uuid_root, u8 *uuid, u8 type,
|
||||
u64 subid);
|
||||
int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
|
||||
int (*check_func)(struct btrfs_fs_info *, u8 *, u8,
|
||||
u64));
|
||||
|
||||
/* dir-item.c */
|
||||
int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
|
||||
const char *name, int name_len);
|
||||
@@ -3509,12 +3599,14 @@ int btrfs_find_name_in_ext_backref(struct btrfs_path *path,
|
||||
struct btrfs_inode_extref **extref_ret);
|
||||
|
||||
/* file-item.c */
|
||||
struct btrfs_dio_private;
|
||||
int btrfs_del_csums(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 bytenr, u64 len);
|
||||
int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
|
||||
struct bio *bio, u32 *dst);
|
||||
int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
|
||||
struct bio *bio, u64 logical_offset);
|
||||
struct btrfs_dio_private *dip, struct bio *bio,
|
||||
u64 logical_offset);
|
||||
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
u64 objectid, u64 pos,
|
||||
@@ -3552,8 +3644,7 @@ void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work);
|
||||
struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
|
||||
size_t pg_offset, u64 start, u64 len,
|
||||
int create);
|
||||
noinline int can_nocow_extent(struct btrfs_trans_handle *trans,
|
||||
struct inode *inode, u64 offset, u64 *len,
|
||||
noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
|
||||
u64 *orig_start, u64 *orig_block_len,
|
||||
u64 *ram_bytes);
|
||||
|
||||
@@ -3643,11 +3734,15 @@ extern const struct dentry_operations btrfs_dentry_operations;
|
||||
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
|
||||
void btrfs_update_iflags(struct inode *inode);
|
||||
void btrfs_inherit_iflags(struct inode *inode, struct inode *dir);
|
||||
int btrfs_is_empty_uuid(u8 *uuid);
|
||||
int btrfs_defrag_file(struct inode *inode, struct file *file,
|
||||
struct btrfs_ioctl_defrag_range_args *range,
|
||||
u64 newer_than, unsigned long max_pages);
|
||||
void btrfs_get_block_group_info(struct list_head *groups_list,
|
||||
struct btrfs_ioctl_space_info *space);
|
||||
void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,
|
||||
struct btrfs_ioctl_balance_args *bargs);
|
||||
|
||||
|
||||
/* file.c */
|
||||
int btrfs_auto_defrag_init(void);
|
||||
@@ -3720,6 +3815,22 @@ void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
|
||||
#define btrfs_debug(fs_info, fmt, args...) \
|
||||
btrfs_printk(fs_info, KERN_DEBUG fmt, ##args)
|
||||
|
||||
#ifdef CONFIG_BTRFS_ASSERT
|
||||
|
||||
static inline void assfail(char *expr, char *file, int line)
|
||||
{
|
||||
printk(KERN_ERR "BTRFS assertion failed: %s, file: %s, line: %d",
|
||||
expr, file, line);
|
||||
BUG();
|
||||
}
|
||||
|
||||
#define ASSERT(expr) \
|
||||
(likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
|
||||
#else
|
||||
#define ASSERT(expr) ((void)0)
|
||||
#endif
|
||||
|
||||
#define btrfs_assert()
|
||||
__printf(5, 6)
|
||||
void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
|
||||
unsigned int line, int errno, const char *fmt, ...);
|
||||
|
||||
+11
-35
@@ -21,6 +21,7 @@
|
||||
#include "delayed-inode.h"
|
||||
#include "disk-io.h"
|
||||
#include "transaction.h"
|
||||
#include "ctree.h"
|
||||
|
||||
#define BTRFS_DELAYED_WRITEBACK 512
|
||||
#define BTRFS_DELAYED_BACKGROUND 128
|
||||
@@ -1453,10 +1454,10 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
|
||||
|
||||
dir_item = (struct btrfs_dir_item *)delayed_item->data;
|
||||
dir_item->location = *disk_key;
|
||||
dir_item->transid = cpu_to_le64(trans->transid);
|
||||
dir_item->data_len = 0;
|
||||
dir_item->name_len = cpu_to_le16(name_len);
|
||||
dir_item->type = type;
|
||||
btrfs_set_stack_dir_transid(dir_item, trans->transid);
|
||||
btrfs_set_stack_dir_data_len(dir_item, 0);
|
||||
btrfs_set_stack_dir_name_len(dir_item, name_len);
|
||||
btrfs_set_stack_dir_type(dir_item, type);
|
||||
memcpy((char *)(dir_item + 1), name, name_len);
|
||||
|
||||
ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item);
|
||||
@@ -1470,13 +1471,11 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
|
||||
mutex_lock(&delayed_node->mutex);
|
||||
ret = __btrfs_add_delayed_insertion_item(delayed_node, delayed_item);
|
||||
if (unlikely(ret)) {
|
||||
printk(KERN_ERR "err add delayed dir index item(name: %s) into "
|
||||
"the insertion tree of the delayed node"
|
||||
printk(KERN_ERR "err add delayed dir index item(name: %.*s) "
|
||||
"into the insertion tree of the delayed node"
|
||||
"(root id: %llu, inode id: %llu, errno: %d)\n",
|
||||
name,
|
||||
(unsigned long long)delayed_node->root->objectid,
|
||||
(unsigned long long)delayed_node->inode_id,
|
||||
ret);
|
||||
name_len, name, delayed_node->root->objectid,
|
||||
delayed_node->inode_id, ret);
|
||||
BUG();
|
||||
}
|
||||
mutex_unlock(&delayed_node->mutex);
|
||||
@@ -1547,9 +1546,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
|
||||
printk(KERN_ERR "err add delayed dir index item(index: %llu) "
|
||||
"into the deletion tree of the delayed node"
|
||||
"(root id: %llu, inode id: %llu, errno: %d)\n",
|
||||
(unsigned long long)index,
|
||||
(unsigned long long)node->root->objectid,
|
||||
(unsigned long long)node->inode_id,
|
||||
index, node->root->objectid, node->inode_id,
|
||||
ret);
|
||||
BUG();
|
||||
}
|
||||
@@ -1699,7 +1696,7 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
|
||||
|
||||
di = (struct btrfs_dir_item *)curr->data;
|
||||
name = (char *)(di + 1);
|
||||
name_len = le16_to_cpu(di->name_len);
|
||||
name_len = btrfs_stack_dir_name_len(di);
|
||||
|
||||
d_type = btrfs_filetype_table[di->type];
|
||||
btrfs_disk_key_to_cpu(&location, &di->location);
|
||||
@@ -1716,27 +1713,6 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_generation, struct btrfs_inode_item,
|
||||
generation, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence, struct btrfs_inode_item,
|
||||
sequence, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_transid, struct btrfs_inode_item,
|
||||
transid, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_size, struct btrfs_inode_item, size, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes, struct btrfs_inode_item,
|
||||
nbytes, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group, struct btrfs_inode_item,
|
||||
block_group, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink, struct btrfs_inode_item, nlink, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_uid, struct btrfs_inode_item, uid, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, struct btrfs_inode_item, gid, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, struct btrfs_inode_item, mode, 32);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, struct btrfs_inode_item, rdev, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, struct btrfs_inode_item, flags, 64);
|
||||
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64);
|
||||
BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, nsec, 32);
|
||||
|
||||
static void fill_stack_inode_item(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_inode_item *inode_item,
|
||||
struct inode *inode)
|
||||
|
||||
@@ -241,7 +241,7 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void inline drop_delayed_ref(struct btrfs_trans_handle *trans,
|
||||
static inline void drop_delayed_ref(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_delayed_ref_root *delayed_refs,
|
||||
struct btrfs_delayed_ref_node *ref)
|
||||
{
|
||||
@@ -600,7 +600,7 @@ static noinline void add_delayed_ref_head(struct btrfs_fs_info *fs_info,
|
||||
INIT_LIST_HEAD(&head_ref->cluster);
|
||||
mutex_init(&head_ref->mutex);
|
||||
|
||||
trace_btrfs_delayed_ref_head(ref, head_ref, action);
|
||||
trace_add_delayed_ref_head(ref, head_ref, action);
|
||||
|
||||
existing = tree_insert(&delayed_refs->root, &ref->rb_node);
|
||||
|
||||
@@ -661,7 +661,7 @@ static noinline void add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
|
||||
ref->type = BTRFS_TREE_BLOCK_REF_KEY;
|
||||
full_ref->level = level;
|
||||
|
||||
trace_btrfs_delayed_tree_ref(ref, full_ref, action);
|
||||
trace_add_delayed_tree_ref(ref, full_ref, action);
|
||||
|
||||
existing = tree_insert(&delayed_refs->root, &ref->rb_node);
|
||||
|
||||
@@ -722,7 +722,7 @@ static noinline void add_delayed_data_ref(struct btrfs_fs_info *fs_info,
|
||||
full_ref->objectid = owner;
|
||||
full_ref->offset = offset;
|
||||
|
||||
trace_btrfs_delayed_data_ref(ref, full_ref, action);
|
||||
trace_add_delayed_data_ref(ref, full_ref, action);
|
||||
|
||||
existing = tree_insert(&delayed_refs->root, &ref->rb_node);
|
||||
|
||||
|
||||
@@ -148,13 +148,13 @@ no_valid_dev_replace_entry_found:
|
||||
!btrfs_test_opt(dev_root, DEGRADED)) {
|
||||
ret = -EIO;
|
||||
pr_warn("btrfs: cannot mount because device replace operation is ongoing and\n" "srcdev (devid %llu) is missing, need to run 'btrfs dev scan'?\n",
|
||||
(unsigned long long)src_devid);
|
||||
src_devid);
|
||||
}
|
||||
if (!dev_replace->tgtdev &&
|
||||
!btrfs_test_opt(dev_root, DEGRADED)) {
|
||||
ret = -EIO;
|
||||
pr_warn("btrfs: cannot mount because device replace operation is ongoing and\n" "tgtdev (devid %llu) is missing, need to run btrfs dev scan?\n",
|
||||
(unsigned long long)BTRFS_DEV_REPLACE_DEVID);
|
||||
BTRFS_DEV_REPLACE_DEVID);
|
||||
}
|
||||
if (dev_replace->tgtdev) {
|
||||
if (dev_replace->srcdev) {
|
||||
|
||||
+119
-55
@@ -31,6 +31,7 @@
|
||||
#include <linux/migrate.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include "compat.h"
|
||||
#include "ctree.h"
|
||||
@@ -302,9 +303,8 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
|
||||
printk_ratelimited(KERN_INFO "btrfs: %s checksum verify "
|
||||
"failed on %llu wanted %X found %X "
|
||||
"level %d\n",
|
||||
root->fs_info->sb->s_id,
|
||||
(unsigned long long)buf->start, val, found,
|
||||
btrfs_header_level(buf));
|
||||
root->fs_info->sb->s_id, buf->start,
|
||||
val, found, btrfs_header_level(buf));
|
||||
if (result != (char *)&inline_result)
|
||||
kfree(result);
|
||||
return 1;
|
||||
@@ -345,9 +345,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
|
||||
}
|
||||
printk_ratelimited("parent transid verify failed on %llu wanted %llu "
|
||||
"found %llu\n",
|
||||
(unsigned long long)eb->start,
|
||||
(unsigned long long)parent_transid,
|
||||
(unsigned long long)btrfs_header_generation(eb));
|
||||
eb->start, parent_transid, btrfs_header_generation(eb));
|
||||
ret = 1;
|
||||
clear_extent_buffer_uptodate(eb);
|
||||
out:
|
||||
@@ -497,8 +495,7 @@ static int check_tree_block_fsid(struct btrfs_root *root,
|
||||
u8 fsid[BTRFS_UUID_SIZE];
|
||||
int ret = 1;
|
||||
|
||||
read_extent_buffer(eb, fsid, (unsigned long)btrfs_header_fsid(eb),
|
||||
BTRFS_FSID_SIZE);
|
||||
read_extent_buffer(eb, fsid, btrfs_header_fsid(eb), BTRFS_FSID_SIZE);
|
||||
while (fs_devices) {
|
||||
if (!memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE)) {
|
||||
ret = 0;
|
||||
@@ -512,8 +509,7 @@ static int check_tree_block_fsid(struct btrfs_root *root,
|
||||
#define CORRUPT(reason, eb, root, slot) \
|
||||
printk(KERN_CRIT "btrfs: corrupt leaf, %s: block=%llu," \
|
||||
"root=%llu, slot=%d\n", reason, \
|
||||
(unsigned long long)btrfs_header_bytenr(eb), \
|
||||
(unsigned long long)root->objectid, slot)
|
||||
btrfs_header_bytenr(eb), root->objectid, slot)
|
||||
|
||||
static noinline int check_leaf(struct btrfs_root *root,
|
||||
struct extent_buffer *leaf)
|
||||
@@ -576,8 +572,9 @@ static noinline int check_leaf(struct btrfs_root *root,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
|
||||
struct extent_state *state, int mirror)
|
||||
static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
|
||||
u64 phy_offset, struct page *page,
|
||||
u64 start, u64 end, int mirror)
|
||||
{
|
||||
struct extent_io_tree *tree;
|
||||
u64 found_start;
|
||||
@@ -612,14 +609,13 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
|
||||
if (found_start != eb->start) {
|
||||
printk_ratelimited(KERN_INFO "btrfs bad tree block start "
|
||||
"%llu %llu\n",
|
||||
(unsigned long long)found_start,
|
||||
(unsigned long long)eb->start);
|
||||
found_start, eb->start);
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
if (check_tree_block_fsid(root, eb)) {
|
||||
printk_ratelimited(KERN_INFO "btrfs bad fsid on block %llu\n",
|
||||
(unsigned long long)eb->start);
|
||||
eb->start);
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
@@ -1148,6 +1144,10 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
|
||||
return NULL;
|
||||
|
||||
ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
|
||||
if (ret) {
|
||||
free_extent_buffer(buf);
|
||||
return NULL;
|
||||
}
|
||||
return buf;
|
||||
|
||||
}
|
||||
@@ -1291,11 +1291,10 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
|
||||
btrfs_set_header_owner(leaf, objectid);
|
||||
root->node = leaf;
|
||||
|
||||
write_extent_buffer(leaf, fs_info->fsid,
|
||||
(unsigned long)btrfs_header_fsid(leaf),
|
||||
write_extent_buffer(leaf, fs_info->fsid, 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_header_chunk_tree_uuid(leaf),
|
||||
BTRFS_UUID_SIZE);
|
||||
btrfs_mark_buffer_dirty(leaf);
|
||||
|
||||
@@ -1379,8 +1378,7 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
|
||||
root->node = leaf;
|
||||
|
||||
write_extent_buffer(root->node, root->fs_info->fsid,
|
||||
(unsigned long)btrfs_header_fsid(root->node),
|
||||
BTRFS_FSID_SIZE);
|
||||
btrfs_header_fsid(root->node), BTRFS_FSID_SIZE);
|
||||
btrfs_mark_buffer_dirty(root->node);
|
||||
btrfs_tree_unlock(root->node);
|
||||
return root;
|
||||
@@ -1413,11 +1411,11 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
|
||||
log_root->root_key.offset = root->root_key.objectid;
|
||||
|
||||
inode_item = &log_root->root_item.inode;
|
||||
inode_item->generation = cpu_to_le64(1);
|
||||
inode_item->size = cpu_to_le64(3);
|
||||
inode_item->nlink = cpu_to_le32(1);
|
||||
inode_item->nbytes = cpu_to_le64(root->leafsize);
|
||||
inode_item->mode = cpu_to_le32(S_IFDIR | 0755);
|
||||
btrfs_set_stack_inode_generation(inode_item, 1);
|
||||
btrfs_set_stack_inode_size(inode_item, 3);
|
||||
btrfs_set_stack_inode_nlink(inode_item, 1);
|
||||
btrfs_set_stack_inode_nbytes(inode_item, root->leafsize);
|
||||
btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755);
|
||||
|
||||
btrfs_set_root_node(&log_root->root_item, log_root->node);
|
||||
|
||||
@@ -1428,8 +1426,8 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
|
||||
struct btrfs_key *key)
|
||||
static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
|
||||
struct btrfs_key *key)
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_fs_info *fs_info = tree_root->fs_info;
|
||||
@@ -1529,8 +1527,8 @@ fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
|
||||
u64 root_id)
|
||||
static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
|
||||
u64 root_id)
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
|
||||
@@ -1581,10 +1579,16 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
|
||||
if (location->objectid == BTRFS_QUOTA_TREE_OBJECTID)
|
||||
return fs_info->quota_root ? fs_info->quota_root :
|
||||
ERR_PTR(-ENOENT);
|
||||
if (location->objectid == BTRFS_UUID_TREE_OBJECTID)
|
||||
return fs_info->uuid_root ? fs_info->uuid_root :
|
||||
ERR_PTR(-ENOENT);
|
||||
again:
|
||||
root = btrfs_lookup_fs_root(fs_info, location->objectid);
|
||||
if (root)
|
||||
if (root) {
|
||||
if (btrfs_root_refs(&root->root_item) == 0)
|
||||
return ERR_PTR(-ENOENT);
|
||||
return root;
|
||||
}
|
||||
|
||||
root = btrfs_read_fs_root(fs_info->tree_root, location);
|
||||
if (IS_ERR(root))
|
||||
@@ -1737,7 +1741,7 @@ static int transaction_kthread(void *arg)
|
||||
|
||||
do {
|
||||
cannot_commit = false;
|
||||
delay = HZ * 30;
|
||||
delay = HZ * root->fs_info->commit_interval;
|
||||
mutex_lock(&root->fs_info->transaction_kthread_mutex);
|
||||
|
||||
spin_lock(&root->fs_info->trans_lock);
|
||||
@@ -1749,7 +1753,8 @@ static int transaction_kthread(void *arg)
|
||||
|
||||
now = get_seconds();
|
||||
if (cur->state < TRANS_STATE_BLOCKED &&
|
||||
(now < cur->start_time || now - cur->start_time < 30)) {
|
||||
(now < cur->start_time ||
|
||||
now - cur->start_time < root->fs_info->commit_interval)) {
|
||||
spin_unlock(&root->fs_info->trans_lock);
|
||||
delay = HZ * 5;
|
||||
goto sleep;
|
||||
@@ -2038,6 +2043,12 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
|
||||
info->quota_root->node = NULL;
|
||||
info->quota_root->commit_root = NULL;
|
||||
}
|
||||
if (info->uuid_root) {
|
||||
free_extent_buffer(info->uuid_root->node);
|
||||
free_extent_buffer(info->uuid_root->commit_root);
|
||||
info->uuid_root->node = NULL;
|
||||
info->uuid_root->commit_root = NULL;
|
||||
}
|
||||
if (chunk_root) {
|
||||
free_extent_buffer(info->chunk_root->node);
|
||||
free_extent_buffer(info->chunk_root->commit_root);
|
||||
@@ -2098,11 +2109,14 @@ int open_ctree(struct super_block *sb,
|
||||
struct btrfs_root *chunk_root;
|
||||
struct btrfs_root *dev_root;
|
||||
struct btrfs_root *quota_root;
|
||||
struct btrfs_root *uuid_root;
|
||||
struct btrfs_root *log_tree_root;
|
||||
int ret;
|
||||
int err = -EINVAL;
|
||||
int num_backups_tried = 0;
|
||||
int backup_index = 0;
|
||||
bool create_uuid_tree;
|
||||
bool check_uuid_tree;
|
||||
|
||||
tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info);
|
||||
chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info);
|
||||
@@ -2189,6 +2203,7 @@ int open_ctree(struct super_block *sb,
|
||||
fs_info->defrag_inodes = RB_ROOT;
|
||||
fs_info->free_chunk_space = 0;
|
||||
fs_info->tree_mod_log = RB_ROOT;
|
||||
fs_info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
|
||||
|
||||
/* readahead state */
|
||||
INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_WAIT);
|
||||
@@ -2270,6 +2285,7 @@ int open_ctree(struct super_block *sb,
|
||||
|
||||
|
||||
mutex_init(&fs_info->ordered_operations_mutex);
|
||||
mutex_init(&fs_info->ordered_extent_flush_mutex);
|
||||
mutex_init(&fs_info->tree_log_mutex);
|
||||
mutex_init(&fs_info->chunk_mutex);
|
||||
mutex_init(&fs_info->transaction_kthread_mutex);
|
||||
@@ -2278,6 +2294,7 @@ int open_ctree(struct super_block *sb,
|
||||
init_rwsem(&fs_info->extent_commit_sem);
|
||||
init_rwsem(&fs_info->cleanup_work_sem);
|
||||
init_rwsem(&fs_info->subvol_sem);
|
||||
sema_init(&fs_info->uuid_tree_rescan_sem, 1);
|
||||
fs_info->dev_replace.lock_owner = 0;
|
||||
atomic_set(&fs_info->dev_replace.nesting_level, 0);
|
||||
mutex_init(&fs_info->dev_replace.lock_finishing_cancel_unmount);
|
||||
@@ -2383,7 +2400,7 @@ int open_ctree(struct super_block *sb,
|
||||
if (features) {
|
||||
printk(KERN_ERR "BTRFS: couldn't mount because of "
|
||||
"unsupported optional features (%Lx).\n",
|
||||
(unsigned long long)features);
|
||||
features);
|
||||
err = -EINVAL;
|
||||
goto fail_alloc;
|
||||
}
|
||||
@@ -2453,7 +2470,7 @@ int open_ctree(struct super_block *sb,
|
||||
if (!(sb->s_flags & MS_RDONLY) && features) {
|
||||
printk(KERN_ERR "BTRFS: couldn't mount RDWR because of "
|
||||
"unsupported option features (%Lx).\n",
|
||||
(unsigned long long)features);
|
||||
features);
|
||||
err = -EINVAL;
|
||||
goto fail_alloc;
|
||||
}
|
||||
@@ -2466,20 +2483,17 @@ int open_ctree(struct super_block *sb,
|
||||
&fs_info->generic_worker);
|
||||
|
||||
btrfs_init_workers(&fs_info->delalloc_workers, "delalloc",
|
||||
fs_info->thread_pool_size,
|
||||
&fs_info->generic_worker);
|
||||
fs_info->thread_pool_size, NULL);
|
||||
|
||||
btrfs_init_workers(&fs_info->flush_workers, "flush_delalloc",
|
||||
fs_info->thread_pool_size,
|
||||
&fs_info->generic_worker);
|
||||
fs_info->thread_pool_size, NULL);
|
||||
|
||||
btrfs_init_workers(&fs_info->submit_workers, "submit",
|
||||
min_t(u64, fs_devices->num_devices,
|
||||
fs_info->thread_pool_size),
|
||||
&fs_info->generic_worker);
|
||||
fs_info->thread_pool_size), NULL);
|
||||
|
||||
btrfs_init_workers(&fs_info->caching_workers, "cache",
|
||||
2, &fs_info->generic_worker);
|
||||
fs_info->thread_pool_size, NULL);
|
||||
|
||||
/* a higher idle thresh on the submit workers makes it much more
|
||||
* likely that bios will be send down in a sane order to the
|
||||
@@ -2575,7 +2589,7 @@ int open_ctree(struct super_block *sb,
|
||||
sb->s_blocksize = sectorsize;
|
||||
sb->s_blocksize_bits = blksize_bits(sectorsize);
|
||||
|
||||
if (disk_super->magic != cpu_to_le64(BTRFS_MAGIC)) {
|
||||
if (btrfs_super_magic(disk_super) != BTRFS_MAGIC) {
|
||||
printk(KERN_INFO "btrfs: valid FS not found on %s\n", sb->s_id);
|
||||
goto fail_sb_buffer;
|
||||
}
|
||||
@@ -2615,8 +2629,7 @@ int open_ctree(struct super_block *sb,
|
||||
chunk_root->commit_root = btrfs_root_node(chunk_root);
|
||||
|
||||
read_extent_buffer(chunk_root->node, fs_info->chunk_tree_uuid,
|
||||
(unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node),
|
||||
BTRFS_UUID_SIZE);
|
||||
btrfs_header_chunk_tree_uuid(chunk_root->node), BTRFS_UUID_SIZE);
|
||||
|
||||
ret = btrfs_read_chunk_tree(chunk_root);
|
||||
if (ret) {
|
||||
@@ -2696,6 +2709,22 @@ retry_root_backup:
|
||||
fs_info->quota_root = quota_root;
|
||||
}
|
||||
|
||||
location.objectid = BTRFS_UUID_TREE_OBJECTID;
|
||||
uuid_root = btrfs_read_tree_root(tree_root, &location);
|
||||
if (IS_ERR(uuid_root)) {
|
||||
ret = PTR_ERR(uuid_root);
|
||||
if (ret != -ENOENT)
|
||||
goto recovery_tree_root;
|
||||
create_uuid_tree = true;
|
||||
check_uuid_tree = false;
|
||||
} else {
|
||||
uuid_root->track_dirty = 1;
|
||||
fs_info->uuid_root = uuid_root;
|
||||
create_uuid_tree = false;
|
||||
check_uuid_tree =
|
||||
generation != btrfs_super_uuid_tree_generation(disk_super);
|
||||
}
|
||||
|
||||
fs_info->generation = generation;
|
||||
fs_info->last_trans_committed = generation;
|
||||
|
||||
@@ -2882,6 +2911,29 @@ retry_root_backup:
|
||||
|
||||
btrfs_qgroup_rescan_resume(fs_info);
|
||||
|
||||
if (create_uuid_tree) {
|
||||
pr_info("btrfs: creating UUID tree\n");
|
||||
ret = btrfs_create_uuid_tree(fs_info);
|
||||
if (ret) {
|
||||
pr_warn("btrfs: failed to create the UUID tree %d\n",
|
||||
ret);
|
||||
close_ctree(tree_root);
|
||||
return ret;
|
||||
}
|
||||
} else if (check_uuid_tree ||
|
||||
btrfs_test_opt(tree_root, RESCAN_UUID_TREE)) {
|
||||
pr_info("btrfs: checking UUID tree\n");
|
||||
ret = btrfs_check_uuid_tree(fs_info);
|
||||
if (ret) {
|
||||
pr_warn("btrfs: failed to check the UUID tree %d\n",
|
||||
ret);
|
||||
close_ctree(tree_root);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
fs_info->update_uuid_tree_gen = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_qgroup:
|
||||
@@ -2983,15 +3035,17 @@ struct buffer_head *btrfs_read_dev_super(struct block_device *bdev)
|
||||
*/
|
||||
for (i = 0; i < 1; i++) {
|
||||
bytenr = btrfs_sb_offset(i);
|
||||
if (bytenr + 4096 >= i_size_read(bdev->bd_inode))
|
||||
if (bytenr + BTRFS_SUPER_INFO_SIZE >=
|
||||
i_size_read(bdev->bd_inode))
|
||||
break;
|
||||
bh = __bread(bdev, bytenr / 4096, 4096);
|
||||
bh = __bread(bdev, bytenr / 4096,
|
||||
BTRFS_SUPER_INFO_SIZE);
|
||||
if (!bh)
|
||||
continue;
|
||||
|
||||
super = (struct btrfs_super_block *)bh->b_data;
|
||||
if (btrfs_super_bytenr(super) != bytenr ||
|
||||
super->magic != cpu_to_le64(BTRFS_MAGIC)) {
|
||||
btrfs_super_magic(super) != BTRFS_MAGIC) {
|
||||
brelse(bh);
|
||||
continue;
|
||||
}
|
||||
@@ -3311,7 +3365,6 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
|
||||
int total_errors = 0;
|
||||
u64 flags;
|
||||
|
||||
max_errors = btrfs_super_num_devices(root->fs_info->super_copy) - 1;
|
||||
do_barriers = !btrfs_test_opt(root, NOBARRIER);
|
||||
backup_super_roots(root->fs_info);
|
||||
|
||||
@@ -3320,6 +3373,7 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
|
||||
|
||||
mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
|
||||
head = &root->fs_info->fs_devices->devices;
|
||||
max_errors = btrfs_super_num_devices(root->fs_info->super_copy) - 1;
|
||||
|
||||
if (do_barriers) {
|
||||
ret = barrier_all_devices(root->fs_info);
|
||||
@@ -3362,8 +3416,10 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
|
||||
printk(KERN_ERR "btrfs: %d errors while writing supers\n",
|
||||
total_errors);
|
||||
|
||||
/* This shouldn't happen. FUA is masked off if unsupported */
|
||||
BUG();
|
||||
/* FUA is masked off if unsupported and can't be the reason */
|
||||
btrfs_error(root->fs_info, -EIO,
|
||||
"%d errors while writing supers", total_errors);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
total_errors = 0;
|
||||
@@ -3421,6 +3477,8 @@ static void free_fs_root(struct btrfs_root *root)
|
||||
{
|
||||
iput(root->cache_inode);
|
||||
WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree));
|
||||
btrfs_free_block_rsv(root, root->orphan_block_rsv);
|
||||
root->orphan_block_rsv = NULL;
|
||||
if (root->anon_dev)
|
||||
free_anon_bdev(root->anon_dev);
|
||||
free_extent_buffer(root->node);
|
||||
@@ -3510,6 +3568,11 @@ int close_ctree(struct btrfs_root *root)
|
||||
fs_info->closing = 1;
|
||||
smp_mb();
|
||||
|
||||
/* wait for the uuid_scan task to finish */
|
||||
down(&fs_info->uuid_tree_rescan_sem);
|
||||
/* avoid complains from lockdep et al., set sem back to initial state */
|
||||
up(&fs_info->uuid_tree_rescan_sem);
|
||||
|
||||
/* pause restriper - we want to resume on mount */
|
||||
btrfs_pause_balance(fs_info);
|
||||
|
||||
@@ -3573,6 +3636,9 @@ int close_ctree(struct btrfs_root *root)
|
||||
|
||||
btrfs_free_stripe_hash_table(fs_info);
|
||||
|
||||
btrfs_free_block_rsv(root, root->orphan_block_rsv);
|
||||
root->orphan_block_rsv = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3608,9 +3674,7 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
|
||||
if (transid != root->fs_info->generation)
|
||||
WARN(1, KERN_CRIT "btrfs transid mismatch buffer %llu, "
|
||||
"found %llu running %llu\n",
|
||||
(unsigned long long)buf->start,
|
||||
(unsigned long long)transid,
|
||||
(unsigned long long)root->fs_info->generation);
|
||||
buf->start, transid, root->fs_info->generation);
|
||||
was_dirty = set_extent_buffer_dirty(buf);
|
||||
if (!was_dirty)
|
||||
__percpu_counter_add(&root->fs_info->dirty_metadata_bytes,
|
||||
@@ -3744,8 +3808,8 @@ static void btrfs_destroy_all_ordered_extents(struct btrfs_fs_info *fs_info)
|
||||
spin_unlock(&fs_info->ordered_root_lock);
|
||||
}
|
||||
|
||||
int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||
struct btrfs_root *root)
|
||||
static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
struct rb_node *node;
|
||||
struct btrfs_delayed_ref_root *delayed_refs;
|
||||
|
||||
+122
-62
@@ -113,7 +113,8 @@ static noinline int
|
||||
block_group_cache_done(struct btrfs_block_group_cache *cache)
|
||||
{
|
||||
smp_mb();
|
||||
return cache->cached == BTRFS_CACHE_FINISHED;
|
||||
return cache->cached == BTRFS_CACHE_FINISHED ||
|
||||
cache->cached == BTRFS_CACHE_ERROR;
|
||||
}
|
||||
|
||||
static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits)
|
||||
@@ -389,7 +390,7 @@ static noinline void caching_thread(struct btrfs_work *work)
|
||||
u64 total_found = 0;
|
||||
u64 last = 0;
|
||||
u32 nritems;
|
||||
int ret = 0;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
caching_ctl = container_of(work, struct btrfs_caching_control, work);
|
||||
block_group = caching_ctl->block_group;
|
||||
@@ -420,6 +421,7 @@ again:
|
||||
/* need to make sure the commit_root doesn't disappear */
|
||||
down_read(&fs_info->extent_commit_sem);
|
||||
|
||||
next:
|
||||
ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
@@ -459,6 +461,16 @@ again:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key.objectid < last) {
|
||||
key.objectid = last;
|
||||
key.offset = 0;
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
|
||||
caching_ctl->progress = last;
|
||||
btrfs_release_path(path);
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (key.objectid < block_group->key.objectid) {
|
||||
path->slots[0]++;
|
||||
continue;
|
||||
@@ -506,6 +518,12 @@ err:
|
||||
|
||||
mutex_unlock(&caching_ctl->mutex);
|
||||
out:
|
||||
if (ret) {
|
||||
spin_lock(&block_group->lock);
|
||||
block_group->caching_ctl = NULL;
|
||||
block_group->cached = BTRFS_CACHE_ERROR;
|
||||
spin_unlock(&block_group->lock);
|
||||
}
|
||||
wake_up(&caching_ctl->wait);
|
||||
|
||||
put_caching_control(caching_ctl);
|
||||
@@ -771,10 +789,23 @@ again:
|
||||
goto out_free;
|
||||
|
||||
if (ret > 0 && metadata && key.type == BTRFS_METADATA_ITEM_KEY) {
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
key.offset = root->leafsize;
|
||||
btrfs_release_path(path);
|
||||
goto again;
|
||||
metadata = 0;
|
||||
if (path->slots[0]) {
|
||||
path->slots[0]--;
|
||||
btrfs_item_key_to_cpu(path->nodes[0], &key,
|
||||
path->slots[0]);
|
||||
if (key.objectid == bytenr &&
|
||||
key.type == BTRFS_EXTENT_ITEM_KEY &&
|
||||
key.offset == root->leafsize)
|
||||
ret = 0;
|
||||
}
|
||||
if (ret) {
|
||||
key.objectid = bytenr;
|
||||
key.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
key.offset = root->leafsize;
|
||||
btrfs_release_path(path);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
@@ -2011,6 +2042,8 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
|
||||
ins.type = BTRFS_EXTENT_ITEM_KEY;
|
||||
|
||||
ref = btrfs_delayed_node_to_data_ref(node);
|
||||
trace_run_delayed_data_ref(node, ref, node->action);
|
||||
|
||||
if (node->type == BTRFS_SHARED_DATA_REF_KEY)
|
||||
parent = ref->parent;
|
||||
else
|
||||
@@ -2154,6 +2187,8 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
|
||||
SKINNY_METADATA);
|
||||
|
||||
ref = btrfs_delayed_node_to_tree_ref(node);
|
||||
trace_run_delayed_tree_ref(node, ref, node->action);
|
||||
|
||||
if (node->type == BTRFS_SHARED_BLOCK_REF_KEY)
|
||||
parent = ref->parent;
|
||||
else
|
||||
@@ -2212,6 +2247,8 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
|
||||
*/
|
||||
BUG_ON(extent_op);
|
||||
head = btrfs_delayed_node_to_head(node);
|
||||
trace_run_delayed_ref_head(node, head, node->action);
|
||||
|
||||
if (insert_reserved) {
|
||||
btrfs_pin_extent(root, node->bytenr,
|
||||
node->num_bytes, 1);
|
||||
@@ -2403,6 +2440,8 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
} else {
|
||||
list_del_init(&locked_ref->cluster);
|
||||
}
|
||||
spin_unlock(&delayed_refs->lock);
|
||||
|
||||
@@ -2425,7 +2464,6 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
|
||||
* list before we release it.
|
||||
*/
|
||||
if (btrfs_delayed_ref_is_head(ref)) {
|
||||
list_del_init(&locked_ref->cluster);
|
||||
btrfs_delayed_ref_unlock(locked_ref);
|
||||
locked_ref = NULL;
|
||||
}
|
||||
@@ -3799,8 +3837,12 @@ again:
|
||||
if (force < space_info->force_alloc)
|
||||
force = space_info->force_alloc;
|
||||
if (space_info->full) {
|
||||
if (should_alloc_chunk(extent_root, space_info, force))
|
||||
ret = -ENOSPC;
|
||||
else
|
||||
ret = 0;
|
||||
spin_unlock(&space_info->lock);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!should_alloc_chunk(extent_root, space_info, force)) {
|
||||
@@ -4320,6 +4362,9 @@ static struct btrfs_block_rsv *get_block_rsv(
|
||||
if (root == root->fs_info->csum_root && trans->adding_csums)
|
||||
block_rsv = trans->block_rsv;
|
||||
|
||||
if (root == root->fs_info->uuid_root)
|
||||
block_rsv = trans->block_rsv;
|
||||
|
||||
if (!block_rsv)
|
||||
block_rsv = root->block_rsv;
|
||||
|
||||
@@ -4729,10 +4774,12 @@ void btrfs_orphan_release_metadata(struct inode *inode)
|
||||
int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *rsv,
|
||||
int items,
|
||||
u64 *qgroup_reserved)
|
||||
u64 *qgroup_reserved,
|
||||
bool use_global_rsv)
|
||||
{
|
||||
u64 num_bytes;
|
||||
int ret;
|
||||
struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv;
|
||||
|
||||
if (root->fs_info->quota_enabled) {
|
||||
/* One for parent inode, two for dir entries */
|
||||
@@ -4751,6 +4798,10 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
|
||||
BTRFS_BLOCK_GROUP_METADATA);
|
||||
ret = btrfs_block_rsv_add(root, rsv, num_bytes,
|
||||
BTRFS_RESERVE_FLUSH_ALL);
|
||||
|
||||
if (ret == -ENOSPC && use_global_rsv)
|
||||
ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes);
|
||||
|
||||
if (ret) {
|
||||
if (*qgroup_reserved)
|
||||
btrfs_qgroup_free(root, *qgroup_reserved);
|
||||
@@ -5668,7 +5719,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||
|
||||
if (ret) {
|
||||
btrfs_err(info, "umm, got %d back from search, was looking for %llu",
|
||||
ret, (unsigned long long)bytenr);
|
||||
ret, bytenr);
|
||||
if (ret > 0)
|
||||
btrfs_print_leaf(extent_root,
|
||||
path->nodes[0]);
|
||||
@@ -5684,11 +5735,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||
WARN_ON(1);
|
||||
btrfs_err(info,
|
||||
"unable to find ref byte nr %llu parent %llu root %llu owner %llu offset %llu",
|
||||
(unsigned long long)bytenr,
|
||||
(unsigned long long)parent,
|
||||
(unsigned long long)root_objectid,
|
||||
(unsigned long long)owner_objectid,
|
||||
(unsigned long long)owner_offset);
|
||||
bytenr, parent, root_objectid, owner_objectid,
|
||||
owner_offset);
|
||||
} else {
|
||||
btrfs_abort_transaction(trans, extent_root, ret);
|
||||
goto out;
|
||||
@@ -5717,7 +5765,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||
-1, 1);
|
||||
if (ret) {
|
||||
btrfs_err(info, "umm, got %d back from search, was looking for %llu",
|
||||
ret, (unsigned long long)bytenr);
|
||||
ret, bytenr);
|
||||
btrfs_print_leaf(extent_root, path->nodes[0]);
|
||||
}
|
||||
if (ret < 0) {
|
||||
@@ -5999,8 +6047,11 @@ static u64 stripe_align(struct btrfs_root *root,
|
||||
* for our min num_bytes. Another option is to have it go ahead
|
||||
* and look in the rbtree for a free extent of a given size, but this
|
||||
* is a good start.
|
||||
*
|
||||
* Callers of this must check if cache->cached == BTRFS_CACHE_ERROR before using
|
||||
* any of the information in this block group.
|
||||
*/
|
||||
static noinline int
|
||||
static noinline void
|
||||
wait_block_group_cache_progress(struct btrfs_block_group_cache *cache,
|
||||
u64 num_bytes)
|
||||
{
|
||||
@@ -6008,28 +6059,29 @@ wait_block_group_cache_progress(struct btrfs_block_group_cache *cache,
|
||||
|
||||
caching_ctl = get_caching_control(cache);
|
||||
if (!caching_ctl)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
wait_event(caching_ctl->wait, block_group_cache_done(cache) ||
|
||||
(cache->free_space_ctl->free_space >= num_bytes));
|
||||
|
||||
put_caching_control(caching_ctl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static noinline int
|
||||
wait_block_group_cache_done(struct btrfs_block_group_cache *cache)
|
||||
{
|
||||
struct btrfs_caching_control *caching_ctl;
|
||||
int ret = 0;
|
||||
|
||||
caching_ctl = get_caching_control(cache);
|
||||
if (!caching_ctl)
|
||||
return 0;
|
||||
return (cache->cached == BTRFS_CACHE_ERROR) ? -EIO : 0;
|
||||
|
||||
wait_event(caching_ctl->wait, block_group_cache_done(cache));
|
||||
|
||||
if (cache->cached == BTRFS_CACHE_ERROR)
|
||||
ret = -EIO;
|
||||
put_caching_control(caching_ctl);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int __get_raid_index(u64 flags)
|
||||
@@ -6070,8 +6122,7 @@ enum btrfs_loop_type {
|
||||
* ins->offset == number of blocks
|
||||
* Any available blocks before search_start are skipped.
|
||||
*/
|
||||
static noinline int find_free_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *orig_root,
|
||||
static noinline int find_free_extent(struct btrfs_root *orig_root,
|
||||
u64 num_bytes, u64 empty_size,
|
||||
u64 hint_byte, struct btrfs_key *ins,
|
||||
u64 flags)
|
||||
@@ -6212,6 +6263,8 @@ have_block_group:
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (unlikely(block_group->cached == BTRFS_CACHE_ERROR))
|
||||
goto loop;
|
||||
if (unlikely(block_group->ro))
|
||||
goto loop;
|
||||
|
||||
@@ -6292,10 +6345,10 @@ refill_cluster:
|
||||
block_group->full_stripe_len);
|
||||
|
||||
/* allocate a cluster in this block group */
|
||||
ret = btrfs_find_space_cluster(trans, root,
|
||||
block_group, last_ptr,
|
||||
search_start, num_bytes,
|
||||
aligned_cluster);
|
||||
ret = btrfs_find_space_cluster(root, block_group,
|
||||
last_ptr, search_start,
|
||||
num_bytes,
|
||||
aligned_cluster);
|
||||
if (ret == 0) {
|
||||
/*
|
||||
* now pull our allocation out of this
|
||||
@@ -6426,17 +6479,28 @@ loop:
|
||||
index = 0;
|
||||
loop++;
|
||||
if (loop == LOOP_ALLOC_CHUNK) {
|
||||
struct btrfs_trans_handle *trans;
|
||||
|
||||
trans = btrfs_join_transaction(root);
|
||||
if (IS_ERR(trans)) {
|
||||
ret = PTR_ERR(trans);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = do_chunk_alloc(trans, root, flags,
|
||||
CHUNK_ALLOC_FORCE);
|
||||
/*
|
||||
* Do not bail out on ENOSPC since we
|
||||
* can do more things.
|
||||
*/
|
||||
if (ret < 0 && ret != -ENOSPC) {
|
||||
if (ret < 0 && ret != -ENOSPC)
|
||||
btrfs_abort_transaction(trans,
|
||||
root, ret);
|
||||
else
|
||||
ret = 0;
|
||||
btrfs_end_transaction(trans, root);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (loop == LOOP_NO_EMPTY_SIZE) {
|
||||
@@ -6463,19 +6527,15 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes,
|
||||
|
||||
spin_lock(&info->lock);
|
||||
printk(KERN_INFO "space_info %llu has %llu free, is %sfull\n",
|
||||
(unsigned long long)info->flags,
|
||||
(unsigned long long)(info->total_bytes - info->bytes_used -
|
||||
info->bytes_pinned - info->bytes_reserved -
|
||||
info->bytes_readonly),
|
||||
info->flags,
|
||||
info->total_bytes - info->bytes_used - info->bytes_pinned -
|
||||
info->bytes_reserved - info->bytes_readonly,
|
||||
(info->full) ? "" : "not ");
|
||||
printk(KERN_INFO "space_info total=%llu, used=%llu, pinned=%llu, "
|
||||
"reserved=%llu, may_use=%llu, readonly=%llu\n",
|
||||
(unsigned long long)info->total_bytes,
|
||||
(unsigned long long)info->bytes_used,
|
||||
(unsigned long long)info->bytes_pinned,
|
||||
(unsigned long long)info->bytes_reserved,
|
||||
(unsigned long long)info->bytes_may_use,
|
||||
(unsigned long long)info->bytes_readonly);
|
||||
info->total_bytes, info->bytes_used, info->bytes_pinned,
|
||||
info->bytes_reserved, info->bytes_may_use,
|
||||
info->bytes_readonly);
|
||||
spin_unlock(&info->lock);
|
||||
|
||||
if (!dump_block_groups)
|
||||
@@ -6486,12 +6546,9 @@ again:
|
||||
list_for_each_entry(cache, &info->block_groups[index], list) {
|
||||
spin_lock(&cache->lock);
|
||||
printk(KERN_INFO "block group %llu has %llu bytes, %llu used %llu pinned %llu reserved %s\n",
|
||||
(unsigned long long)cache->key.objectid,
|
||||
(unsigned long long)cache->key.offset,
|
||||
(unsigned long long)btrfs_block_group_used(&cache->item),
|
||||
(unsigned long long)cache->pinned,
|
||||
(unsigned long long)cache->reserved,
|
||||
cache->ro ? "[readonly]" : "");
|
||||
cache->key.objectid, cache->key.offset,
|
||||
btrfs_block_group_used(&cache->item), cache->pinned,
|
||||
cache->reserved, cache->ro ? "[readonly]" : "");
|
||||
btrfs_dump_free_space(cache, bytes);
|
||||
spin_unlock(&cache->lock);
|
||||
}
|
||||
@@ -6500,8 +6557,7 @@ again:
|
||||
up_read(&info->groups_sem);
|
||||
}
|
||||
|
||||
int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
int btrfs_reserve_extent(struct btrfs_root *root,
|
||||
u64 num_bytes, u64 min_alloc_size,
|
||||
u64 empty_size, u64 hint_byte,
|
||||
struct btrfs_key *ins, int is_data)
|
||||
@@ -6513,8 +6569,8 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
|
||||
flags = btrfs_get_alloc_profile(root, is_data);
|
||||
again:
|
||||
WARN_ON(num_bytes < root->sectorsize);
|
||||
ret = find_free_extent(trans, root, num_bytes, empty_size,
|
||||
hint_byte, ins, flags);
|
||||
ret = find_free_extent(root, num_bytes, empty_size, hint_byte, ins,
|
||||
flags);
|
||||
|
||||
if (ret == -ENOSPC) {
|
||||
if (!final_tried) {
|
||||
@@ -6529,8 +6585,7 @@ again:
|
||||
|
||||
sinfo = __find_space_info(root->fs_info, flags);
|
||||
btrfs_err(root->fs_info, "allocation failed flags %llu, wanted %llu",
|
||||
(unsigned long long)flags,
|
||||
(unsigned long long)num_bytes);
|
||||
flags, num_bytes);
|
||||
if (sinfo)
|
||||
dump_space_info(sinfo, num_bytes, 1);
|
||||
}
|
||||
@@ -6550,7 +6605,7 @@ static int __btrfs_free_reserved_extent(struct btrfs_root *root,
|
||||
cache = btrfs_lookup_block_group(root->fs_info, start);
|
||||
if (!cache) {
|
||||
btrfs_err(root->fs_info, "Unable to find block group for %llu",
|
||||
(unsigned long long)start);
|
||||
start);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
@@ -6646,8 +6701,7 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
|
||||
ret = update_block_group(root, ins->objectid, ins->offset, 1);
|
||||
if (ret) { /* -ENOENT, logic error */
|
||||
btrfs_err(fs_info, "update block group failed for %llu %llu",
|
||||
(unsigned long long)ins->objectid,
|
||||
(unsigned long long)ins->offset);
|
||||
ins->objectid, ins->offset);
|
||||
BUG();
|
||||
}
|
||||
return ret;
|
||||
@@ -6719,8 +6773,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
|
||||
ret = update_block_group(root, ins->objectid, root->leafsize, 1);
|
||||
if (ret) { /* -ENOENT, logic error */
|
||||
btrfs_err(fs_info, "update block group failed for %llu %llu",
|
||||
(unsigned long long)ins->objectid,
|
||||
(unsigned long long)ins->offset);
|
||||
ins->objectid, ins->offset);
|
||||
BUG();
|
||||
}
|
||||
return ret;
|
||||
@@ -6902,7 +6955,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
|
||||
if (IS_ERR(block_rsv))
|
||||
return ERR_CAST(block_rsv);
|
||||
|
||||
ret = btrfs_reserve_extent(trans, root, blocksize, blocksize,
|
||||
ret = btrfs_reserve_extent(root, blocksize, blocksize,
|
||||
empty_size, hint, &ins, 0);
|
||||
if (ret) {
|
||||
unuse_block_rsv(root->fs_info, block_rsv, blocksize);
|
||||
@@ -7173,6 +7226,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
|
||||
next = btrfs_find_create_tree_block(root, bytenr, blocksize);
|
||||
if (!next)
|
||||
return -ENOMEM;
|
||||
btrfs_set_buffer_lockdep_class(root->root_key.objectid, next,
|
||||
level - 1);
|
||||
reada = 1;
|
||||
}
|
||||
btrfs_tree_lock(next);
|
||||
@@ -7658,7 +7713,7 @@ out:
|
||||
* don't have it in the radix (like when we recover after a power fail
|
||||
* or unmount) so we don't leak memory.
|
||||
*/
|
||||
if (root_dropped == false)
|
||||
if (!for_reloc && root_dropped == false)
|
||||
btrfs_add_dead_root(root);
|
||||
if (err)
|
||||
btrfs_std_error(root->fs_info, err);
|
||||
@@ -8192,7 +8247,8 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
|
||||
* We haven't cached this block group, which means we could
|
||||
* possibly have excluded extents on this block group.
|
||||
*/
|
||||
if (block_group->cached == BTRFS_CACHE_NO)
|
||||
if (block_group->cached == BTRFS_CACHE_NO ||
|
||||
block_group->cached == BTRFS_CACHE_ERROR)
|
||||
free_excluded_extents(info->extent_root, block_group);
|
||||
|
||||
btrfs_remove_free_space_cache(block_group);
|
||||
@@ -8409,9 +8465,13 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
||||
* avoid allocating from un-mirrored block group if there are
|
||||
* mirrored block groups.
|
||||
*/
|
||||
list_for_each_entry(cache, &space_info->block_groups[3], list)
|
||||
list_for_each_entry(cache,
|
||||
&space_info->block_groups[BTRFS_RAID_RAID0],
|
||||
list)
|
||||
set_block_group_ro(cache, 1);
|
||||
list_for_each_entry(cache, &space_info->block_groups[4], list)
|
||||
list_for_each_entry(cache,
|
||||
&space_info->block_groups[BTRFS_RAID_SINGLE],
|
||||
list)
|
||||
set_block_group_ro(cache, 1);
|
||||
}
|
||||
|
||||
|
||||
+403
-301
File diff suppressed because it is too large
Load Diff
+16
-19
@@ -29,6 +29,7 @@
|
||||
*/
|
||||
#define EXTENT_BIO_COMPRESSED 1
|
||||
#define EXTENT_BIO_TREE_LOG 2
|
||||
#define EXTENT_BIO_PARENT_LOCKED 4
|
||||
#define EXTENT_BIO_FLAG_SHIFT 16
|
||||
|
||||
/* these are bit numbers for test/set bit */
|
||||
@@ -44,14 +45,11 @@
|
||||
#define EXTENT_BUFFER_DUMMY 9
|
||||
|
||||
/* these are flags for extent_clear_unlock_delalloc */
|
||||
#define EXTENT_CLEAR_UNLOCK_PAGE 0x1
|
||||
#define EXTENT_CLEAR_UNLOCK 0x2
|
||||
#define EXTENT_CLEAR_DELALLOC 0x4
|
||||
#define EXTENT_CLEAR_DIRTY 0x8
|
||||
#define EXTENT_SET_WRITEBACK 0x10
|
||||
#define EXTENT_END_WRITEBACK 0x20
|
||||
#define EXTENT_SET_PRIVATE2 0x40
|
||||
#define EXTENT_CLEAR_ACCOUNTING 0x80
|
||||
#define PAGE_UNLOCK (1 << 0)
|
||||
#define PAGE_CLEAR_DIRTY (1 << 1)
|
||||
#define PAGE_SET_WRITEBACK (1 << 2)
|
||||
#define PAGE_END_WRITEBACK (1 << 3)
|
||||
#define PAGE_SET_PRIVATE2 (1 << 4)
|
||||
|
||||
/*
|
||||
* page->private values. Every page that is controlled by the extent
|
||||
@@ -62,6 +60,7 @@
|
||||
|
||||
struct extent_state;
|
||||
struct btrfs_root;
|
||||
struct btrfs_io_bio;
|
||||
|
||||
typedef int (extent_submit_bio_hook_t)(struct inode *inode, int rw,
|
||||
struct bio *bio, int mirror_num,
|
||||
@@ -77,8 +76,9 @@ struct extent_io_ops {
|
||||
size_t size, struct bio *bio,
|
||||
unsigned long bio_flags);
|
||||
int (*readpage_io_failed_hook)(struct page *page, int failed_mirror);
|
||||
int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end,
|
||||
struct extent_state *state, int mirror);
|
||||
int (*readpage_end_io_hook)(struct btrfs_io_bio *io_bio, u64 phy_offset,
|
||||
struct page *page, u64 start, u64 end,
|
||||
int mirror);
|
||||
int (*writepage_end_io_hook)(struct page *page, u64 start, u64 end,
|
||||
struct extent_state *state, int uptodate);
|
||||
void (*set_bit_hook)(struct inode *inode, struct extent_state *state,
|
||||
@@ -200,6 +200,8 @@ int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end,
|
||||
int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end);
|
||||
int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
|
||||
get_extent_t *get_extent, int mirror_num);
|
||||
int extent_read_full_page_nolock(struct extent_io_tree *tree, struct page *page,
|
||||
get_extent_t *get_extent, int mirror_num);
|
||||
int __init extent_io_init(void);
|
||||
void extent_io_exit(void);
|
||||
|
||||
@@ -261,11 +263,6 @@ int extent_readpages(struct extent_io_tree *tree,
|
||||
get_extent_t get_extent);
|
||||
int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||
__u64 start, __u64 len, get_extent_t *get_extent);
|
||||
int set_state_private(struct extent_io_tree *tree, u64 start, u64 private);
|
||||
void extent_cache_csums_dio(struct extent_io_tree *tree, u64 start, u32 csums[],
|
||||
int count);
|
||||
void extent_cache_csums(struct extent_io_tree *tree, struct bio *bio,
|
||||
int bvec_index, u32 csums[], int count);
|
||||
int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private);
|
||||
void set_page_extent_mapped(struct page *page);
|
||||
|
||||
@@ -330,10 +327,10 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
|
||||
unsigned long *map_len);
|
||||
int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);
|
||||
int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end);
|
||||
int extent_clear_unlock_delalloc(struct inode *inode,
|
||||
struct extent_io_tree *tree,
|
||||
u64 start, u64 end, struct page *locked_page,
|
||||
unsigned long op);
|
||||
int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
|
||||
struct page *locked_page,
|
||||
unsigned long bits_to_clear,
|
||||
unsigned long page_ops);
|
||||
struct bio *
|
||||
btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
|
||||
gfp_t gfp_flags);
|
||||
|
||||
+55
-30
@@ -23,6 +23,7 @@
|
||||
#include "ctree.h"
|
||||
#include "disk-io.h"
|
||||
#include "transaction.h"
|
||||
#include "volumes.h"
|
||||
#include "print-tree.h"
|
||||
|
||||
#define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \
|
||||
@@ -152,28 +153,54 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void btrfs_io_bio_endio_readpage(struct btrfs_io_bio *bio, int err)
|
||||
{
|
||||
kfree(bio->csum_allocated);
|
||||
}
|
||||
|
||||
static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
|
||||
struct inode *inode, struct bio *bio,
|
||||
u64 logical_offset, u32 *dst, int dio)
|
||||
{
|
||||
u32 sum[16];
|
||||
int len;
|
||||
struct bio_vec *bvec = bio->bi_io_vec;
|
||||
int bio_index = 0;
|
||||
struct btrfs_io_bio *btrfs_bio = btrfs_io_bio(bio);
|
||||
struct btrfs_csum_item *item = NULL;
|
||||
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
|
||||
struct btrfs_path *path;
|
||||
u8 *csum;
|
||||
u64 offset = 0;
|
||||
u64 item_start_offset = 0;
|
||||
u64 item_last_offset = 0;
|
||||
u64 disk_bytenr;
|
||||
u32 diff;
|
||||
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
|
||||
int nblocks;
|
||||
int bio_index = 0;
|
||||
int count;
|
||||
struct btrfs_path *path;
|
||||
struct btrfs_csum_item *item = NULL;
|
||||
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
|
||||
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
nblocks = bio->bi_size >> inode->i_sb->s_blocksize_bits;
|
||||
if (!dst) {
|
||||
if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) {
|
||||
btrfs_bio->csum_allocated = kmalloc(nblocks * csum_size,
|
||||
GFP_NOFS);
|
||||
if (!btrfs_bio->csum_allocated) {
|
||||
btrfs_free_path(path);
|
||||
return -ENOMEM;
|
||||
}
|
||||
btrfs_bio->csum = btrfs_bio->csum_allocated;
|
||||
btrfs_bio->end_io = btrfs_io_bio_endio_readpage;
|
||||
} else {
|
||||
btrfs_bio->csum = btrfs_bio->csum_inline;
|
||||
}
|
||||
csum = btrfs_bio->csum;
|
||||
} else {
|
||||
csum = (u8 *)dst;
|
||||
}
|
||||
|
||||
if (bio->bi_size > PAGE_CACHE_SIZE * 8)
|
||||
path->reada = 2;
|
||||
|
||||
@@ -194,11 +221,10 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
|
||||
if (dio)
|
||||
offset = logical_offset;
|
||||
while (bio_index < bio->bi_vcnt) {
|
||||
len = min_t(int, ARRAY_SIZE(sum), bio->bi_vcnt - bio_index);
|
||||
if (!dio)
|
||||
offset = page_offset(bvec->bv_page) + bvec->bv_offset;
|
||||
count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, sum,
|
||||
len);
|
||||
count = btrfs_find_ordered_sum(inode, offset, disk_bytenr,
|
||||
(u32 *)csum, nblocks);
|
||||
if (count)
|
||||
goto found;
|
||||
|
||||
@@ -213,7 +239,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
|
||||
path, disk_bytenr, 0);
|
||||
if (IS_ERR(item)) {
|
||||
count = 1;
|
||||
sum[0] = 0;
|
||||
memset(csum, 0, csum_size);
|
||||
if (BTRFS_I(inode)->root->root_key.objectid ==
|
||||
BTRFS_DATA_RELOC_TREE_OBJECTID) {
|
||||
set_extent_bits(io_tree, offset,
|
||||
@@ -222,9 +248,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
|
||||
} else {
|
||||
printk(KERN_INFO "btrfs no csum found "
|
||||
"for inode %llu start %llu\n",
|
||||
(unsigned long long)
|
||||
btrfs_ino(inode),
|
||||
(unsigned long long)offset);
|
||||
btrfs_ino(inode), offset);
|
||||
}
|
||||
item = NULL;
|
||||
btrfs_release_path(path);
|
||||
@@ -249,23 +273,14 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
|
||||
diff = disk_bytenr - item_start_offset;
|
||||
diff = diff / root->sectorsize;
|
||||
diff = diff * csum_size;
|
||||
count = min_t(int, len, (item_last_offset - disk_bytenr) >>
|
||||
inode->i_sb->s_blocksize_bits);
|
||||
read_extent_buffer(path->nodes[0], sum,
|
||||
count = min_t(int, nblocks, (item_last_offset - disk_bytenr) >>
|
||||
inode->i_sb->s_blocksize_bits);
|
||||
read_extent_buffer(path->nodes[0], csum,
|
||||
((unsigned long)item) + diff,
|
||||
csum_size * count);
|
||||
found:
|
||||
if (dst) {
|
||||
memcpy(dst, sum, count * csum_size);
|
||||
dst += count;
|
||||
} else {
|
||||
if (dio)
|
||||
extent_cache_csums_dio(io_tree, offset, sum,
|
||||
count);
|
||||
else
|
||||
extent_cache_csums(io_tree, bio, bio_index, sum,
|
||||
count);
|
||||
}
|
||||
csum += count * csum_size;
|
||||
nblocks -= count;
|
||||
while (count--) {
|
||||
disk_bytenr += bvec->bv_len;
|
||||
offset += bvec->bv_len;
|
||||
@@ -284,9 +299,19 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
|
||||
}
|
||||
|
||||
int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
|
||||
struct bio *bio, u64 offset)
|
||||
struct btrfs_dio_private *dip, struct bio *bio,
|
||||
u64 offset)
|
||||
{
|
||||
return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1);
|
||||
int len = (bio->bi_sector << 9) - dip->disk_bytenr;
|
||||
u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
|
||||
int ret;
|
||||
|
||||
len >>= inode->i_sb->s_blocksize_bits;
|
||||
len *= csum_size;
|
||||
|
||||
ret = __btrfs_lookup_bio_sums(root, inode, bio, offset,
|
||||
(u32 *)(dip->csum + len), 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
|
||||
|
||||
+1
-10
@@ -1334,7 +1334,6 @@ fail:
|
||||
static noinline int check_can_nocow(struct inode *inode, loff_t pos,
|
||||
size_t *write_bytes)
|
||||
{
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_ordered_extent *ordered;
|
||||
u64 lockstart, lockend;
|
||||
@@ -1356,16 +1355,8 @@ static noinline int check_can_nocow(struct inode *inode, loff_t pos,
|
||||
btrfs_put_ordered_extent(ordered);
|
||||
}
|
||||
|
||||
trans = btrfs_join_transaction(root);
|
||||
if (IS_ERR(trans)) {
|
||||
unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend);
|
||||
return PTR_ERR(trans);
|
||||
}
|
||||
|
||||
num_bytes = lockend - lockstart + 1;
|
||||
ret = can_nocow_extent(trans, inode, lockstart, &num_bytes, NULL, NULL,
|
||||
NULL);
|
||||
btrfs_end_transaction(trans, root);
|
||||
ret = can_nocow_extent(inode, lockstart, &num_bytes, NULL, NULL, NULL);
|
||||
if (ret <= 0) {
|
||||
ret = 0;
|
||||
} else {
|
||||
|
||||
+75
-450
File diff suppressed because it is too large
Load Diff
@@ -98,8 +98,7 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
|
||||
u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root);
|
||||
void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
|
||||
u64 bytes);
|
||||
int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root,
|
||||
int btrfs_find_space_cluster(struct btrfs_root *root,
|
||||
struct btrfs_block_group_cache *block_group,
|
||||
struct btrfs_free_cluster *cluster,
|
||||
u64 offset, u64 bytes, u64 empty_size);
|
||||
@@ -113,6 +112,12 @@ int btrfs_return_cluster_to_free_space(
|
||||
int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
|
||||
u64 *trimmed, u64 start, u64 end, u64 minlen);
|
||||
|
||||
void btrfs_test_free_space_cache(void);
|
||||
/* Support functions for runnint our sanity tests */
|
||||
#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
|
||||
int test_add_free_space_entry(struct btrfs_block_group_cache *cache,
|
||||
u64 offset, u64 bytes, bool bitmap);
|
||||
int test_check_exists(struct btrfs_block_group_cache *cache,
|
||||
u64 offset, u64 bytes);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user