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-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull btrfs updates from Chris Mason: "This has Jeff Mahoney's long standing trim patch that fixes corners where trims were missing. Omar has some raid5/6 fixes, especially for using scrub and device replace when devices are missing. Zhao Lie continues cleaning and fixing things, this series fixes some really hard to hit corners in xfstests. I had to pull it last merge window due to some deadlocks, but those are now resolved. I added support for Tejun's new blkio controllers. It seems to work well for single devices, we'll expand to multi-device as well" * 'for-linus-4.3' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: (47 commits) btrfs: fix compile when block cgroups are not enabled Btrfs: fix file read corruption after extent cloning and fsync Btrfs: check if previous transaction aborted to avoid fs corruption btrfs: use __GFP_NOFAIL in alloc_btrfs_bio btrfs: Prevent from early transaction abort btrfs: Remove unused arguments in tree-log.c btrfs: Remove useless condition in start_log_trans() Btrfs: add support for blkio controllers Btrfs: remove unused mutex from struct 'btrfs_fs_info' Btrfs: fix parity scrub of RAID 5/6 with missing device Btrfs: fix device replace of a missing RAID 5/6 device Btrfs: add RAID 5/6 BTRFS_RBIO_REBUILD_MISSING operation Btrfs: count devices correctly in readahead during RAID 5/6 replace Btrfs: remove misleading handling of missing device scrub btrfs: fix clone / extent-same deadlocks Btrfs: fix defrag to merge tail file extent Btrfs: fix warning in backref walking btrfs: Add WARN_ON() for double lock in btrfs_tree_lock() btrfs: Remove root argument in extent_data_ref_count() btrfs: Fix wrong comment of btrfs_alloc_tree_block() ...
This commit is contained in:
+27
-8
@@ -206,10 +206,33 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id,
|
||||
return -ENOMEM;
|
||||
|
||||
ref->root_id = root_id;
|
||||
if (key)
|
||||
if (key) {
|
||||
ref->key_for_search = *key;
|
||||
else
|
||||
/*
|
||||
* We can often find data backrefs with an offset that is too
|
||||
* large (>= LLONG_MAX, maximum allowed file offset) due to
|
||||
* underflows when subtracting a file's offset with the data
|
||||
* offset of its corresponding extent data item. This can
|
||||
* happen for example in the clone ioctl.
|
||||
* So if we detect such case we set the search key's offset to
|
||||
* zero to make sure we will find the matching file extent item
|
||||
* at add_all_parents(), otherwise we will miss it because the
|
||||
* offset taken form the backref is much larger then the offset
|
||||
* of the file extent item. This can make us scan a very large
|
||||
* number of file extent items, but at least it will not make
|
||||
* us miss any.
|
||||
* This is an ugly workaround for a behaviour that should have
|
||||
* never existed, but it does and a fix for the clone ioctl
|
||||
* would touch a lot of places, cause backwards incompatibility
|
||||
* and would not fix the problem for extents cloned with older
|
||||
* kernels.
|
||||
*/
|
||||
if (ref->key_for_search.type == BTRFS_EXTENT_DATA_KEY &&
|
||||
ref->key_for_search.offset >= LLONG_MAX)
|
||||
ref->key_for_search.offset = 0;
|
||||
} else {
|
||||
memset(&ref->key_for_search, 0, sizeof(ref->key_for_search));
|
||||
}
|
||||
|
||||
ref->inode_list = NULL;
|
||||
ref->level = level;
|
||||
@@ -632,7 +655,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
|
||||
struct btrfs_delayed_tree_ref *ref;
|
||||
|
||||
ref = btrfs_delayed_node_to_tree_ref(node);
|
||||
ret = __add_prelim_ref(prefs, ref->root, NULL,
|
||||
ret = __add_prelim_ref(prefs, 0, NULL,
|
||||
ref->level + 1, ref->parent,
|
||||
node->bytenr,
|
||||
node->ref_mod * sgn, GFP_ATOMIC);
|
||||
@@ -664,11 +687,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
|
||||
struct btrfs_delayed_data_ref *ref;
|
||||
|
||||
ref = btrfs_delayed_node_to_data_ref(node);
|
||||
|
||||
key.objectid = ref->objectid;
|
||||
key.type = BTRFS_EXTENT_DATA_KEY;
|
||||
key.offset = ref->offset;
|
||||
ret = __add_prelim_ref(prefs, ref->root, &key, 0,
|
||||
ret = __add_prelim_ref(prefs, 0, NULL, 0,
|
||||
ref->parent, node->bytenr,
|
||||
node->ref_mod * sgn, GFP_ATOMIC);
|
||||
break;
|
||||
|
||||
+3
-1
@@ -1159,8 +1159,10 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
|
||||
|
||||
if (test_bit(BTRFS_ROOT_REF_COWS, &root->state)) {
|
||||
ret = btrfs_reloc_cow_block(trans, root, buf, cow);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
btrfs_abort_transaction(trans, root, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (buf == root->node) {
|
||||
|
||||
+7
-11
@@ -1300,7 +1300,7 @@ struct btrfs_block_group_cache {
|
||||
/* for raid56, this is a full stripe, without parity */
|
||||
unsigned long full_stripe_len;
|
||||
|
||||
unsigned int ro:1;
|
||||
unsigned int ro;
|
||||
unsigned int iref:1;
|
||||
unsigned int has_caching_ctl:1;
|
||||
unsigned int removed:1;
|
||||
@@ -1518,12 +1518,6 @@ struct btrfs_fs_info {
|
||||
*/
|
||||
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 commit_root_sem;
|
||||
|
||||
struct rw_semaphore cleanup_work_sem;
|
||||
@@ -3437,6 +3431,8 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, u64 group_start,
|
||||
struct extent_map *em);
|
||||
void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info);
|
||||
void btrfs_get_block_group_trimming(struct btrfs_block_group_cache *cache);
|
||||
void btrfs_put_block_group_trimming(struct btrfs_block_group_cache *cache);
|
||||
void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root);
|
||||
u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data);
|
||||
@@ -3495,9 +3491,9 @@ int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info,
|
||||
void btrfs_block_rsv_release(struct btrfs_root *root,
|
||||
struct btrfs_block_rsv *block_rsv,
|
||||
u64 num_bytes);
|
||||
int btrfs_set_block_group_ro(struct btrfs_root *root,
|
||||
int btrfs_inc_block_group_ro(struct btrfs_root *root,
|
||||
struct btrfs_block_group_cache *cache);
|
||||
void btrfs_set_block_group_rw(struct btrfs_root *root,
|
||||
void btrfs_dec_block_group_ro(struct btrfs_root *root,
|
||||
struct btrfs_block_group_cache *cache);
|
||||
void btrfs_put_block_group_cache(struct btrfs_fs_info *info);
|
||||
u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo);
|
||||
@@ -4073,6 +4069,7 @@ __cold
|
||||
void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
|
||||
unsigned int line, int errno, const char *fmt, ...);
|
||||
|
||||
const char *btrfs_decode_error(int errno);
|
||||
|
||||
__cold
|
||||
void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
|
||||
@@ -4185,8 +4182,7 @@ int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len);
|
||||
int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root, struct extent_buffer *buf,
|
||||
struct extent_buffer *cow);
|
||||
void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_pending_snapshot *pending,
|
||||
void btrfs_reloc_pre_snapshot(struct btrfs_pending_snapshot *pending,
|
||||
u64 *bytes_to_reserve);
|
||||
int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_pending_snapshot *pending);
|
||||
|
||||
+13
-3
@@ -1730,6 +1730,7 @@ static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi)
|
||||
bdi->ra_pages = VM_MAX_READAHEAD * 1024 / PAGE_CACHE_SIZE;
|
||||
bdi->congested_fn = btrfs_congested_fn;
|
||||
bdi->congested_data = info;
|
||||
bdi->capabilities |= BDI_CAP_CGROUP_WRITEBACK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2613,7 +2614,6 @@ 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);
|
||||
@@ -2955,8 +2955,9 @@ retry_root_backup:
|
||||
if (fs_info->fs_devices->missing_devices >
|
||||
fs_info->num_tolerated_disk_barrier_failures &&
|
||||
!(sb->s_flags & MS_RDONLY)) {
|
||||
printk(KERN_WARNING "BTRFS: "
|
||||
"too many missing devices, writeable mount is not allowed\n");
|
||||
pr_warn("BTRFS: missing devices(%llu) exceeds the limit(%d), writeable mount is not allowed\n",
|
||||
fs_info->fs_devices->missing_devices,
|
||||
fs_info->num_tolerated_disk_barrier_failures);
|
||||
goto fail_sysfs;
|
||||
}
|
||||
|
||||
@@ -3763,6 +3764,15 @@ void close_ctree(struct btrfs_root *root)
|
||||
cancel_work_sync(&fs_info->async_reclaim_work);
|
||||
|
||||
if (!(fs_info->sb->s_flags & MS_RDONLY)) {
|
||||
/*
|
||||
* If the cleaner thread is stopped and there are
|
||||
* block groups queued for removal, the deletion will be
|
||||
* skipped when we quit the cleaner thread.
|
||||
*/
|
||||
mutex_lock(&root->fs_info->cleaner_mutex);
|
||||
btrfs_delete_unused_bgs(root->fs_info);
|
||||
mutex_unlock(&root->fs_info->cleaner_mutex);
|
||||
|
||||
ret = btrfs_commit_super(root);
|
||||
if (ret)
|
||||
btrfs_err(fs_info, "commit super ret %d", ret);
|
||||
|
||||
+262
-36
@@ -1316,8 +1316,7 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static noinline u32 extent_data_ref_count(struct btrfs_root *root,
|
||||
struct btrfs_path *path,
|
||||
static noinline u32 extent_data_ref_count(struct btrfs_path *path,
|
||||
struct btrfs_extent_inline_ref *iref)
|
||||
{
|
||||
struct btrfs_key key;
|
||||
@@ -1883,10 +1882,77 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_issue_discard(struct block_device *bdev,
|
||||
u64 start, u64 len)
|
||||
#define in_range(b, first, len) ((b) >= (first) && (b) < (first) + (len))
|
||||
static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len,
|
||||
u64 *discarded_bytes)
|
||||
{
|
||||
return blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_NOFS, 0);
|
||||
int j, ret = 0;
|
||||
u64 bytes_left, end;
|
||||
u64 aligned_start = ALIGN(start, 1 << 9);
|
||||
|
||||
if (WARN_ON(start != aligned_start)) {
|
||||
len -= aligned_start - start;
|
||||
len = round_down(len, 1 << 9);
|
||||
start = aligned_start;
|
||||
}
|
||||
|
||||
*discarded_bytes = 0;
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
end = start + len;
|
||||
bytes_left = len;
|
||||
|
||||
/* Skip any superblocks on this device. */
|
||||
for (j = 0; j < BTRFS_SUPER_MIRROR_MAX; j++) {
|
||||
u64 sb_start = btrfs_sb_offset(j);
|
||||
u64 sb_end = sb_start + BTRFS_SUPER_INFO_SIZE;
|
||||
u64 size = sb_start - start;
|
||||
|
||||
if (!in_range(sb_start, start, bytes_left) &&
|
||||
!in_range(sb_end, start, bytes_left) &&
|
||||
!in_range(start, sb_start, BTRFS_SUPER_INFO_SIZE))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Superblock spans beginning of range. Adjust start and
|
||||
* try again.
|
||||
*/
|
||||
if (sb_start <= start) {
|
||||
start += sb_end - start;
|
||||
if (start > end) {
|
||||
bytes_left = 0;
|
||||
break;
|
||||
}
|
||||
bytes_left = end - start;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
ret = blkdev_issue_discard(bdev, start >> 9, size >> 9,
|
||||
GFP_NOFS, 0);
|
||||
if (!ret)
|
||||
*discarded_bytes += size;
|
||||
else if (ret != -EOPNOTSUPP)
|
||||
return ret;
|
||||
}
|
||||
|
||||
start = sb_end;
|
||||
if (start > end) {
|
||||
bytes_left = 0;
|
||||
break;
|
||||
}
|
||||
bytes_left = end - start;
|
||||
}
|
||||
|
||||
if (bytes_left) {
|
||||
ret = blkdev_issue_discard(bdev, start >> 9, bytes_left >> 9,
|
||||
GFP_NOFS, 0);
|
||||
if (!ret)
|
||||
*discarded_bytes += bytes_left;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
|
||||
@@ -1907,14 +1973,16 @@ int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
|
||||
|
||||
|
||||
for (i = 0; i < bbio->num_stripes; i++, stripe++) {
|
||||
u64 bytes;
|
||||
if (!stripe->dev->can_discard)
|
||||
continue;
|
||||
|
||||
ret = btrfs_issue_discard(stripe->dev->bdev,
|
||||
stripe->physical,
|
||||
stripe->length);
|
||||
stripe->length,
|
||||
&bytes);
|
||||
if (!ret)
|
||||
discarded_bytes += stripe->length;
|
||||
discarded_bytes += bytes;
|
||||
else if (ret != -EOPNOTSUPP)
|
||||
break; /* Logic errors or -ENOMEM, or -EIO but I don't know how that could happen JDM */
|
||||
|
||||
@@ -6062,20 +6130,19 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
struct btrfs_block_group_cache *block_group, *tmp;
|
||||
struct list_head *deleted_bgs;
|
||||
struct extent_io_tree *unpin;
|
||||
u64 start;
|
||||
u64 end;
|
||||
int ret;
|
||||
|
||||
if (trans->aborted)
|
||||
return 0;
|
||||
|
||||
if (fs_info->pinned_extents == &fs_info->freed_extents[0])
|
||||
unpin = &fs_info->freed_extents[1];
|
||||
else
|
||||
unpin = &fs_info->freed_extents[0];
|
||||
|
||||
while (1) {
|
||||
while (!trans->aborted) {
|
||||
mutex_lock(&fs_info->unused_bg_unpin_mutex);
|
||||
ret = find_first_extent_bit(unpin, 0, &start, &end,
|
||||
EXTENT_DIRTY, NULL);
|
||||
@@ -6094,6 +6161,34 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans,
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
/*
|
||||
* Transaction is finished. We don't need the lock anymore. We
|
||||
* do need to clean up the block groups in case of a transaction
|
||||
* abort.
|
||||
*/
|
||||
deleted_bgs = &trans->transaction->deleted_bgs;
|
||||
list_for_each_entry_safe(block_group, tmp, deleted_bgs, bg_list) {
|
||||
u64 trimmed = 0;
|
||||
|
||||
ret = -EROFS;
|
||||
if (!trans->aborted)
|
||||
ret = btrfs_discard_extent(root,
|
||||
block_group->key.objectid,
|
||||
block_group->key.offset,
|
||||
&trimmed);
|
||||
|
||||
list_del_init(&block_group->bg_list);
|
||||
btrfs_put_block_group_trimming(block_group);
|
||||
btrfs_put_block_group(block_group);
|
||||
|
||||
if (ret) {
|
||||
const char *errstr = btrfs_decode_error(ret);
|
||||
btrfs_warn(fs_info,
|
||||
"Discard failed while removing blockgroup: errno=%d %s\n",
|
||||
ret, errstr);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6349,7 +6444,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
|
||||
} else {
|
||||
if (found_extent) {
|
||||
BUG_ON(is_data && refs_to_drop !=
|
||||
extent_data_ref_count(root, path, iref));
|
||||
extent_data_ref_count(path, iref));
|
||||
if (iref) {
|
||||
BUG_ON(path->slots[0] != extent_slot);
|
||||
} else {
|
||||
@@ -7567,9 +7662,6 @@ static void unuse_block_rsv(struct btrfs_fs_info *fs_info,
|
||||
|
||||
/*
|
||||
* finds a free extent and does all the dirty work required for allocation
|
||||
* returns the key for the extent through ins, and a tree buffer for
|
||||
* the first block of the extent through buf.
|
||||
*
|
||||
* returns the tree buffer or an ERR_PTR on error.
|
||||
*/
|
||||
struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
|
||||
@@ -8723,14 +8815,13 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
|
||||
return flags;
|
||||
}
|
||||
|
||||
static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force)
|
||||
static int inc_block_group_ro(struct btrfs_block_group_cache *cache, int force)
|
||||
{
|
||||
struct btrfs_space_info *sinfo = cache->space_info;
|
||||
u64 num_bytes;
|
||||
u64 min_allocable_bytes;
|
||||
int ret = -ENOSPC;
|
||||
|
||||
|
||||
/*
|
||||
* We need some metadata space and system metadata space for
|
||||
* allocating chunks in some corner cases until we force to set
|
||||
@@ -8747,6 +8838,7 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force)
|
||||
spin_lock(&cache->lock);
|
||||
|
||||
if (cache->ro) {
|
||||
cache->ro++;
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
@@ -8758,7 +8850,7 @@ static int set_block_group_ro(struct btrfs_block_group_cache *cache, int force)
|
||||
sinfo->bytes_may_use + sinfo->bytes_readonly + num_bytes +
|
||||
min_allocable_bytes <= sinfo->total_bytes) {
|
||||
sinfo->bytes_readonly += num_bytes;
|
||||
cache->ro = 1;
|
||||
cache->ro++;
|
||||
list_add_tail(&cache->ro_list, &sinfo->ro_bgs);
|
||||
ret = 0;
|
||||
}
|
||||
@@ -8768,7 +8860,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_set_block_group_ro(struct btrfs_root *root,
|
||||
int btrfs_inc_block_group_ro(struct btrfs_root *root,
|
||||
struct btrfs_block_group_cache *cache)
|
||||
|
||||
{
|
||||
@@ -8776,8 +8868,6 @@ int btrfs_set_block_group_ro(struct btrfs_root *root,
|
||||
u64 alloc_flags;
|
||||
int ret;
|
||||
|
||||
BUG_ON(cache->ro);
|
||||
|
||||
again:
|
||||
trans = btrfs_join_transaction(root);
|
||||
if (IS_ERR(trans))
|
||||
@@ -8820,7 +8910,7 @@ again:
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = set_block_group_ro(cache, 0);
|
||||
ret = inc_block_group_ro(cache, 0);
|
||||
if (!ret)
|
||||
goto out;
|
||||
alloc_flags = get_alloc_profile(root, cache->space_info->flags);
|
||||
@@ -8828,7 +8918,7 @@ again:
|
||||
CHUNK_ALLOC_FORCE);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = set_block_group_ro(cache, 0);
|
||||
ret = inc_block_group_ro(cache, 0);
|
||||
out:
|
||||
if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) {
|
||||
alloc_flags = update_block_group_flags(root, cache->flags);
|
||||
@@ -8891,7 +8981,7 @@ u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo)
|
||||
return free_bytes;
|
||||
}
|
||||
|
||||
void btrfs_set_block_group_rw(struct btrfs_root *root,
|
||||
void btrfs_dec_block_group_ro(struct btrfs_root *root,
|
||||
struct btrfs_block_group_cache *cache)
|
||||
{
|
||||
struct btrfs_space_info *sinfo = cache->space_info;
|
||||
@@ -8901,11 +8991,13 @@ void btrfs_set_block_group_rw(struct btrfs_root *root,
|
||||
|
||||
spin_lock(&sinfo->lock);
|
||||
spin_lock(&cache->lock);
|
||||
num_bytes = cache->key.offset - cache->reserved - cache->pinned -
|
||||
cache->bytes_super - btrfs_block_group_used(&cache->item);
|
||||
sinfo->bytes_readonly -= num_bytes;
|
||||
cache->ro = 0;
|
||||
list_del_init(&cache->ro_list);
|
||||
if (!--cache->ro) {
|
||||
num_bytes = cache->key.offset - cache->reserved -
|
||||
cache->pinned - cache->bytes_super -
|
||||
btrfs_block_group_used(&cache->item);
|
||||
sinfo->bytes_readonly -= num_bytes;
|
||||
list_del_init(&cache->ro_list);
|
||||
}
|
||||
spin_unlock(&cache->lock);
|
||||
spin_unlock(&sinfo->lock);
|
||||
}
|
||||
@@ -9421,7 +9513,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
||||
|
||||
set_avail_alloc_bits(root->fs_info, cache->flags);
|
||||
if (btrfs_chunk_readonly(root, cache->key.objectid)) {
|
||||
set_block_group_ro(cache, 1);
|
||||
inc_block_group_ro(cache, 1);
|
||||
} else if (btrfs_block_group_used(&cache->item) == 0) {
|
||||
spin_lock(&info->unused_bgs_lock);
|
||||
/* Should always be true but just in case. */
|
||||
@@ -9449,11 +9541,11 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
||||
list_for_each_entry(cache,
|
||||
&space_info->block_groups[BTRFS_RAID_RAID0],
|
||||
list)
|
||||
set_block_group_ro(cache, 1);
|
||||
inc_block_group_ro(cache, 1);
|
||||
list_for_each_entry(cache,
|
||||
&space_info->block_groups[BTRFS_RAID_SINGLE],
|
||||
list)
|
||||
set_block_group_ro(cache, 1);
|
||||
inc_block_group_ro(cache, 1);
|
||||
}
|
||||
|
||||
init_global_block_rsv(info);
|
||||
@@ -9834,6 +9926,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
|
||||
* currently running transaction might finish and a new one start,
|
||||
* allowing for new block groups to be created that can reuse the same
|
||||
* physical device locations unless we take this special care.
|
||||
*
|
||||
* There may also be an implicit trim operation if the file system
|
||||
* is mounted with -odiscard. The same protections must remain
|
||||
* in place until the extents have been discarded completely when
|
||||
* the transaction commit has completed.
|
||||
*/
|
||||
remove_em = (atomic_read(&block_group->trimming) == 0);
|
||||
/*
|
||||
@@ -9908,6 +10005,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
|
||||
spin_lock(&fs_info->unused_bgs_lock);
|
||||
while (!list_empty(&fs_info->unused_bgs)) {
|
||||
u64 start, end;
|
||||
int trimming;
|
||||
|
||||
block_group = list_first_entry(&fs_info->unused_bgs,
|
||||
struct btrfs_block_group_cache,
|
||||
@@ -9941,7 +10039,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
|
||||
spin_unlock(&block_group->lock);
|
||||
|
||||
/* We don't want to force the issue, only flip if it's ok. */
|
||||
ret = set_block_group_ro(block_group, 0);
|
||||
ret = inc_block_group_ro(block_group, 0);
|
||||
up_write(&space_info->groups_sem);
|
||||
if (ret < 0) {
|
||||
ret = 0;
|
||||
@@ -9955,7 +10053,7 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
|
||||
/* 1 for btrfs_orphan_reserve_metadata() */
|
||||
trans = btrfs_start_transaction(root, 1);
|
||||
if (IS_ERR(trans)) {
|
||||
btrfs_set_block_group_rw(root, block_group);
|
||||
btrfs_dec_block_group_ro(root, block_group);
|
||||
ret = PTR_ERR(trans);
|
||||
goto next;
|
||||
}
|
||||
@@ -9982,14 +10080,14 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
|
||||
EXTENT_DIRTY, GFP_NOFS);
|
||||
if (ret) {
|
||||
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
|
||||
btrfs_set_block_group_rw(root, block_group);
|
||||
btrfs_dec_block_group_ro(root, block_group);
|
||||
goto end_trans;
|
||||
}
|
||||
ret = clear_extent_bits(&fs_info->freed_extents[1], start, end,
|
||||
EXTENT_DIRTY, GFP_NOFS);
|
||||
if (ret) {
|
||||
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
|
||||
btrfs_set_block_group_rw(root, block_group);
|
||||
btrfs_dec_block_group_ro(root, block_group);
|
||||
goto end_trans;
|
||||
}
|
||||
mutex_unlock(&fs_info->unused_bg_unpin_mutex);
|
||||
@@ -10007,12 +10105,39 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
|
||||
spin_unlock(&block_group->lock);
|
||||
spin_unlock(&space_info->lock);
|
||||
|
||||
/* DISCARD can flip during remount */
|
||||
trimming = btrfs_test_opt(root, DISCARD);
|
||||
|
||||
/* Implicit trim during transaction commit. */
|
||||
if (trimming)
|
||||
btrfs_get_block_group_trimming(block_group);
|
||||
|
||||
/*
|
||||
* Btrfs_remove_chunk will abort the transaction if things go
|
||||
* horribly wrong.
|
||||
*/
|
||||
ret = btrfs_remove_chunk(trans, root,
|
||||
block_group->key.objectid);
|
||||
|
||||
if (ret) {
|
||||
if (trimming)
|
||||
btrfs_put_block_group_trimming(block_group);
|
||||
goto end_trans;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're not mounted with -odiscard, we can just forget
|
||||
* about this block group. Otherwise we'll need to wait
|
||||
* until transaction commit to do the actual discard.
|
||||
*/
|
||||
if (trimming) {
|
||||
WARN_ON(!list_empty(&block_group->bg_list));
|
||||
spin_lock(&trans->transaction->deleted_bgs_lock);
|
||||
list_move(&block_group->bg_list,
|
||||
&trans->transaction->deleted_bgs);
|
||||
spin_unlock(&trans->transaction->deleted_bgs_lock);
|
||||
btrfs_get_block_group(block_group);
|
||||
}
|
||||
end_trans:
|
||||
btrfs_end_transaction(trans, root);
|
||||
next:
|
||||
@@ -10066,10 +10191,99 @@ int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end)
|
||||
return unpin_extent_range(root, start, end, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* It used to be that old block groups would be left around forever.
|
||||
* Iterating over them would be enough to trim unused space. Since we
|
||||
* now automatically remove them, we also need to iterate over unallocated
|
||||
* space.
|
||||
*
|
||||
* We don't want a transaction for this since the discard may take a
|
||||
* substantial amount of time. We don't require that a transaction be
|
||||
* running, but we do need to take a running transaction into account
|
||||
* to ensure that we're not discarding chunks that were released in
|
||||
* the current transaction.
|
||||
*
|
||||
* Holding the chunks lock will prevent other threads from allocating
|
||||
* or releasing chunks, but it won't prevent a running transaction
|
||||
* from committing and releasing the memory that the pending chunks
|
||||
* list head uses. For that, we need to take a reference to the
|
||||
* transaction.
|
||||
*/
|
||||
static int btrfs_trim_free_extents(struct btrfs_device *device,
|
||||
u64 minlen, u64 *trimmed)
|
||||
{
|
||||
u64 start = 0, len = 0;
|
||||
int ret;
|
||||
|
||||
*trimmed = 0;
|
||||
|
||||
/* Not writeable = nothing to do. */
|
||||
if (!device->writeable)
|
||||
return 0;
|
||||
|
||||
/* No free space = nothing to do. */
|
||||
if (device->total_bytes <= device->bytes_used)
|
||||
return 0;
|
||||
|
||||
ret = 0;
|
||||
|
||||
while (1) {
|
||||
struct btrfs_fs_info *fs_info = device->dev_root->fs_info;
|
||||
struct btrfs_transaction *trans;
|
||||
u64 bytes;
|
||||
|
||||
ret = mutex_lock_interruptible(&fs_info->chunk_mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
down_read(&fs_info->commit_root_sem);
|
||||
|
||||
spin_lock(&fs_info->trans_lock);
|
||||
trans = fs_info->running_transaction;
|
||||
if (trans)
|
||||
atomic_inc(&trans->use_count);
|
||||
spin_unlock(&fs_info->trans_lock);
|
||||
|
||||
ret = find_free_dev_extent_start(trans, device, minlen, start,
|
||||
&start, &len);
|
||||
if (trans)
|
||||
btrfs_put_transaction(trans);
|
||||
|
||||
if (ret) {
|
||||
up_read(&fs_info->commit_root_sem);
|
||||
mutex_unlock(&fs_info->chunk_mutex);
|
||||
if (ret == -ENOSPC)
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
ret = btrfs_issue_discard(device->bdev, start, len, &bytes);
|
||||
up_read(&fs_info->commit_root_sem);
|
||||
mutex_unlock(&fs_info->chunk_mutex);
|
||||
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
start += len;
|
||||
*trimmed += bytes;
|
||||
|
||||
if (fatal_signal_pending(current)) {
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
struct btrfs_block_group_cache *cache = NULL;
|
||||
struct btrfs_device *device;
|
||||
struct list_head *devices;
|
||||
u64 group_trimmed;
|
||||
u64 start;
|
||||
u64 end;
|
||||
@@ -10124,6 +10338,18 @@ int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range)
|
||||
cache = next_block_group(fs_info->tree_root, cache);
|
||||
}
|
||||
|
||||
mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
|
||||
devices = &root->fs_info->fs_devices->alloc_list;
|
||||
list_for_each_entry(device, devices, dev_alloc_list) {
|
||||
ret = btrfs_trim_free_extents(device, range->minlen,
|
||||
&group_trimmed);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
trimmed += group_trimmed;
|
||||
}
|
||||
mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
|
||||
|
||||
range->len = trimmed;
|
||||
return ret;
|
||||
}
|
||||
|
||||
+18
-7
@@ -2723,6 +2723,12 @@ struct bio *btrfs_bio_clone(struct bio *bio, gfp_t gfp_mask)
|
||||
btrfs_bio->csum = NULL;
|
||||
btrfs_bio->csum_allocated = NULL;
|
||||
btrfs_bio->end_io = NULL;
|
||||
|
||||
#ifdef CONFIG_BLK_CGROUP
|
||||
/* FIXME, put this into bio_clone_bioset */
|
||||
if (bio->bi_css)
|
||||
bio_associate_blkcg(new, bio->bi_css);
|
||||
#endif
|
||||
}
|
||||
return new;
|
||||
}
|
||||
@@ -2783,6 +2789,7 @@ static int merge_bio(int rw, struct extent_io_tree *tree, struct page *page,
|
||||
}
|
||||
|
||||
static int submit_extent_page(int rw, struct extent_io_tree *tree,
|
||||
struct writeback_control *wbc,
|
||||
struct page *page, sector_t sector,
|
||||
size_t size, unsigned long offset,
|
||||
struct block_device *bdev,
|
||||
@@ -2817,6 +2824,8 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
|
||||
}
|
||||
bio = NULL;
|
||||
} else {
|
||||
if (wbc)
|
||||
wbc_account_io(wbc, page, page_size);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -2829,6 +2838,10 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
|
||||
bio_add_page(bio, page, page_size, offset);
|
||||
bio->bi_end_io = end_io_func;
|
||||
bio->bi_private = tree;
|
||||
if (wbc) {
|
||||
wbc_init_bio(wbc, bio);
|
||||
wbc_account_io(wbc, page, page_size);
|
||||
}
|
||||
|
||||
if (bio_ret)
|
||||
*bio_ret = bio;
|
||||
@@ -3039,7 +3052,7 @@ static int __do_readpage(struct extent_io_tree *tree,
|
||||
}
|
||||
|
||||
pnr -= page->index;
|
||||
ret = submit_extent_page(rw, tree, page,
|
||||
ret = submit_extent_page(rw, tree, NULL, page,
|
||||
sector, disk_io_size, pg_offset,
|
||||
bdev, bio, pnr,
|
||||
end_bio_extent_readpage, mirror_num,
|
||||
@@ -3434,7 +3447,7 @@ static noinline_for_stack int __extent_writepage_io(struct inode *inode,
|
||||
page->index, cur, end);
|
||||
}
|
||||
|
||||
ret = submit_extent_page(write_flags, tree, page,
|
||||
ret = submit_extent_page(write_flags, tree, wbc, page,
|
||||
sector, iosize, pg_offset,
|
||||
bdev, &epd->bio, max_nr,
|
||||
end_bio_extent_writepage,
|
||||
@@ -3738,7 +3751,7 @@ static noinline_for_stack int write_one_eb(struct extent_buffer *eb,
|
||||
|
||||
clear_page_dirty_for_io(p);
|
||||
set_page_writeback(p);
|
||||
ret = submit_extent_page(rw, tree, p, offset >> 9,
|
||||
ret = submit_extent_page(rw, tree, wbc, p, offset >> 9,
|
||||
PAGE_CACHE_SIZE, 0, bdev, &epd->bio,
|
||||
-1, end_bio_extent_buffer_writepage,
|
||||
0, epd->bio_flags, bio_flags);
|
||||
@@ -4603,9 +4616,7 @@ __alloc_extent_buffer(struct btrfs_fs_info *fs_info, u64 start,
|
||||
{
|
||||
struct extent_buffer *eb = NULL;
|
||||
|
||||
eb = kmem_cache_zalloc(extent_buffer_cache, GFP_NOFS);
|
||||
if (eb == NULL)
|
||||
return NULL;
|
||||
eb = kmem_cache_zalloc(extent_buffer_cache, GFP_NOFS|__GFP_NOFAIL);
|
||||
eb->start = start;
|
||||
eb->len = len;
|
||||
eb->fs_info = fs_info;
|
||||
@@ -4863,7 +4874,7 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < num_pages; i++, index++) {
|
||||
p = find_or_create_page(mapping, index, GFP_NOFS);
|
||||
p = find_or_create_page(mapping, index, GFP_NOFS|__GFP_NOFAIL);
|
||||
if (!p)
|
||||
goto free_eb;
|
||||
|
||||
|
||||
+34
-25
@@ -3272,35 +3272,23 @@ next:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
|
||||
u64 *trimmed, u64 start, u64 end, u64 minlen)
|
||||
void btrfs_get_block_group_trimming(struct btrfs_block_group_cache *cache)
|
||||
{
|
||||
int ret;
|
||||
atomic_inc(&cache->trimming);
|
||||
}
|
||||
|
||||
*trimmed = 0;
|
||||
void btrfs_put_block_group_trimming(struct btrfs_block_group_cache *block_group)
|
||||
{
|
||||
struct extent_map_tree *em_tree;
|
||||
struct extent_map *em;
|
||||
bool cleanup;
|
||||
|
||||
spin_lock(&block_group->lock);
|
||||
if (block_group->removed) {
|
||||
spin_unlock(&block_group->lock);
|
||||
return 0;
|
||||
}
|
||||
atomic_inc(&block_group->trimming);
|
||||
cleanup = (atomic_dec_and_test(&block_group->trimming) &&
|
||||
block_group->removed);
|
||||
spin_unlock(&block_group->lock);
|
||||
|
||||
ret = trim_no_bitmap(block_group, trimmed, start, end, minlen);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = trim_bitmaps(block_group, trimmed, start, end, minlen);
|
||||
out:
|
||||
spin_lock(&block_group->lock);
|
||||
if (atomic_dec_and_test(&block_group->trimming) &&
|
||||
block_group->removed) {
|
||||
struct extent_map_tree *em_tree;
|
||||
struct extent_map *em;
|
||||
|
||||
spin_unlock(&block_group->lock);
|
||||
|
||||
if (cleanup) {
|
||||
lock_chunks(block_group->fs_info->chunk_root);
|
||||
em_tree = &block_group->fs_info->mapping_tree.map_tree;
|
||||
write_lock(&em_tree->lock);
|
||||
@@ -3324,10 +3312,31 @@ out:
|
||||
* this block group have left 1 entry each one. Free them.
|
||||
*/
|
||||
__btrfs_remove_free_space_cache(block_group->free_space_ctl);
|
||||
} else {
|
||||
spin_unlock(&block_group->lock);
|
||||
}
|
||||
}
|
||||
|
||||
int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
|
||||
u64 *trimmed, u64 start, u64 end, u64 minlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
*trimmed = 0;
|
||||
|
||||
spin_lock(&block_group->lock);
|
||||
if (block_group->removed) {
|
||||
spin_unlock(&block_group->lock);
|
||||
return 0;
|
||||
}
|
||||
btrfs_get_block_group_trimming(block_group);
|
||||
spin_unlock(&block_group->lock);
|
||||
|
||||
ret = trim_no_bitmap(block_group, trimmed, start, end, minlen);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = trim_bitmaps(block_group, trimmed, start, end, minlen);
|
||||
out:
|
||||
btrfs_put_block_group_trimming(block_group);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+34
-1
@@ -3658,6 +3658,35 @@ cache_index:
|
||||
set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
|
||||
&BTRFS_I(inode)->runtime_flags);
|
||||
|
||||
/*
|
||||
* We don't persist the id of the transaction where an unlink operation
|
||||
* against the inode was last made. So here we assume the inode might
|
||||
* have been evicted, and therefore the exact value of last_unlink_trans
|
||||
* lost, and set it to last_trans to avoid metadata inconsistencies
|
||||
* between the inode and its parent if the inode is fsync'ed and the log
|
||||
* replayed. For example, in the scenario:
|
||||
*
|
||||
* touch mydir/foo
|
||||
* ln mydir/foo mydir/bar
|
||||
* sync
|
||||
* unlink mydir/bar
|
||||
* echo 2 > /proc/sys/vm/drop_caches # evicts inode
|
||||
* xfs_io -c fsync mydir/foo
|
||||
* <power failure>
|
||||
* mount fs, triggers fsync log replay
|
||||
*
|
||||
* We must make sure that when we fsync our inode foo we also log its
|
||||
* parent inode, otherwise after log replay the parent still has the
|
||||
* dentry with the "bar" name but our inode foo has a link count of 1
|
||||
* and doesn't have an inode ref with the name "bar" anymore.
|
||||
*
|
||||
* Setting last_unlink_trans to last_trans is a pessimistic approach,
|
||||
* but it guarantees correctness at the expense of ocassional full
|
||||
* transaction commits on fsync if our inode is a directory, or if our
|
||||
* inode is not a directory, logging its parent unnecessarily.
|
||||
*/
|
||||
BTRFS_I(inode)->last_unlink_trans = BTRFS_I(inode)->last_trans;
|
||||
|
||||
path->slots[0]++;
|
||||
if (inode->i_nlink != 1 ||
|
||||
path->slots[0] >= btrfs_header_nritems(leaf))
|
||||
@@ -7958,7 +7987,11 @@ out:
|
||||
static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev,
|
||||
u64 first_sector, gfp_t gfp_flags)
|
||||
{
|
||||
return btrfs_bio_alloc(bdev, first_sector, BIO_MAX_PAGES, gfp_flags);
|
||||
struct bio *bio;
|
||||
bio = btrfs_bio_alloc(bdev, first_sector, BIO_MAX_PAGES, gfp_flags);
|
||||
if (bio)
|
||||
bio_associate_current(bio);
|
||||
return bio;
|
||||
}
|
||||
|
||||
static inline int btrfs_lookup_and_bind_dio_csum(struct btrfs_root *root,
|
||||
|
||||
+22
-30
@@ -1030,6 +1030,7 @@ static int should_defrag_range(struct inode *inode, u64 start, u32 thresh,
|
||||
struct extent_map *em;
|
||||
int ret = 1;
|
||||
bool next_mergeable = true;
|
||||
bool prev_mergeable = true;
|
||||
|
||||
/*
|
||||
* make sure that once we start defragging an extent, we keep on
|
||||
@@ -1050,13 +1051,16 @@ static int should_defrag_range(struct inode *inode, u64 start, u32 thresh,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!*defrag_end)
|
||||
prev_mergeable = false;
|
||||
|
||||
next_mergeable = defrag_check_next_extent(inode, em);
|
||||
/*
|
||||
* we hit a real extent, if it is big or the next extent is not a
|
||||
* real extent, don't bother defragging it
|
||||
*/
|
||||
if (!compress && (*last_len == 0 || *last_len >= thresh) &&
|
||||
(em->len >= thresh || !next_mergeable))
|
||||
(em->len >= thresh || (!next_mergeable && !prev_mergeable)))
|
||||
ret = 0;
|
||||
out:
|
||||
/*
|
||||
@@ -1933,6 +1937,7 @@ static noinline int copy_to_sk(struct btrfs_root *root,
|
||||
u64 found_transid;
|
||||
struct extent_buffer *leaf;
|
||||
struct btrfs_ioctl_search_header sh;
|
||||
struct btrfs_key test;
|
||||
unsigned long item_off;
|
||||
unsigned long item_len;
|
||||
int nritems;
|
||||
@@ -2016,12 +2021,17 @@ static noinline int copy_to_sk(struct btrfs_root *root,
|
||||
}
|
||||
advance_key:
|
||||
ret = 0;
|
||||
if (key->offset < (u64)-1 && key->offset < sk->max_offset)
|
||||
test.objectid = sk->max_objectid;
|
||||
test.type = sk->max_type;
|
||||
test.offset = sk->max_offset;
|
||||
if (btrfs_comp_cpu_keys(key, &test) >= 0)
|
||||
ret = 1;
|
||||
else if (key->offset < (u64)-1)
|
||||
key->offset++;
|
||||
else if (key->type < (u8)-1 && key->type < sk->max_type) {
|
||||
else if (key->type < (u8)-1) {
|
||||
key->offset = 0;
|
||||
key->type++;
|
||||
} else if (key->objectid < (u64)-1 && key->objectid < sk->max_objectid) {
|
||||
} else if (key->objectid < (u64)-1) {
|
||||
key->offset = 0;
|
||||
key->type = 0;
|
||||
key->objectid++;
|
||||
@@ -2842,8 +2852,7 @@ static void btrfs_double_inode_lock(struct inode *inode1, struct inode *inode2)
|
||||
swap(inode1, inode2);
|
||||
|
||||
mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT);
|
||||
if (inode1 != inode2)
|
||||
mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
|
||||
mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
|
||||
}
|
||||
|
||||
static void btrfs_double_extent_unlock(struct inode *inode1, u64 loff1,
|
||||
@@ -2861,8 +2870,7 @@ static void btrfs_double_extent_lock(struct inode *inode1, u64 loff1,
|
||||
swap(loff1, loff2);
|
||||
}
|
||||
lock_extent_range(inode1, loff1, len);
|
||||
if (inode1 != inode2)
|
||||
lock_extent_range(inode2, loff2, len);
|
||||
lock_extent_range(inode2, loff2, len);
|
||||
}
|
||||
|
||||
struct cmp_pages {
|
||||
@@ -3787,13 +3795,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||
goto out_fput;
|
||||
|
||||
if (!same_inode) {
|
||||
if (inode < src) {
|
||||
mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
|
||||
mutex_lock_nested(&src->i_mutex, I_MUTEX_CHILD);
|
||||
} else {
|
||||
mutex_lock_nested(&src->i_mutex, I_MUTEX_PARENT);
|
||||
mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
|
||||
}
|
||||
btrfs_double_inode_lock(src, inode);
|
||||
} else {
|
||||
mutex_lock(&src->i_mutex);
|
||||
}
|
||||
@@ -3843,8 +3845,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||
|
||||
lock_extent_range(src, lock_start, lock_len);
|
||||
} else {
|
||||
lock_extent_range(src, off, len);
|
||||
lock_extent_range(inode, destoff, len);
|
||||
btrfs_double_extent_lock(src, off, inode, destoff, len);
|
||||
}
|
||||
|
||||
ret = btrfs_clone(src, inode, off, olen, len, destoff, 0);
|
||||
@@ -3855,9 +3856,7 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||
|
||||
unlock_extent(&BTRFS_I(src)->io_tree, lock_start, lock_end);
|
||||
} else {
|
||||
unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
|
||||
unlock_extent(&BTRFS_I(inode)->io_tree, destoff,
|
||||
destoff + len - 1);
|
||||
btrfs_double_extent_unlock(src, off, inode, destoff, len);
|
||||
}
|
||||
/*
|
||||
* Truncate page cache pages so that future reads will see the cloned
|
||||
@@ -3866,17 +3865,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
|
||||
truncate_inode_pages_range(&inode->i_data, destoff,
|
||||
PAGE_CACHE_ALIGN(destoff + len) - 1);
|
||||
out_unlock:
|
||||
if (!same_inode) {
|
||||
if (inode < src) {
|
||||
mutex_unlock(&src->i_mutex);
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
} else {
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
mutex_unlock(&src->i_mutex);
|
||||
}
|
||||
} else {
|
||||
if (!same_inode)
|
||||
btrfs_double_inode_unlock(src, inode);
|
||||
else
|
||||
mutex_unlock(&src->i_mutex);
|
||||
}
|
||||
out_fput:
|
||||
fdput(src_file);
|
||||
out_drop_write:
|
||||
|
||||
@@ -241,6 +241,7 @@ void btrfs_tree_read_unlock_blocking(struct extent_buffer *eb)
|
||||
*/
|
||||
void btrfs_tree_lock(struct extent_buffer *eb)
|
||||
{
|
||||
WARN_ON(eb->lock_owner == current->pid);
|
||||
again:
|
||||
wait_event(eb->read_lock_wq, atomic_read(&eb->blocking_readers) == 0);
|
||||
wait_event(eb->write_lock_wq, atomic_read(&eb->blocking_writers) == 0);
|
||||
|
||||
+77
-10
@@ -61,9 +61,10 @@
|
||||
#define RBIO_CACHE_SIZE 1024
|
||||
|
||||
enum btrfs_rbio_ops {
|
||||
BTRFS_RBIO_WRITE = 0,
|
||||
BTRFS_RBIO_READ_REBUILD = 1,
|
||||
BTRFS_RBIO_PARITY_SCRUB = 2,
|
||||
BTRFS_RBIO_WRITE,
|
||||
BTRFS_RBIO_READ_REBUILD,
|
||||
BTRFS_RBIO_PARITY_SCRUB,
|
||||
BTRFS_RBIO_REBUILD_MISSING,
|
||||
};
|
||||
|
||||
struct btrfs_raid_bio {
|
||||
@@ -602,6 +603,10 @@ static int rbio_can_merge(struct btrfs_raid_bio *last,
|
||||
cur->operation == BTRFS_RBIO_PARITY_SCRUB)
|
||||
return 0;
|
||||
|
||||
if (last->operation == BTRFS_RBIO_REBUILD_MISSING ||
|
||||
cur->operation == BTRFS_RBIO_REBUILD_MISSING)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -793,7 +798,10 @@ static noinline void unlock_stripe(struct btrfs_raid_bio *rbio)
|
||||
|
||||
if (next->operation == BTRFS_RBIO_READ_REBUILD)
|
||||
async_read_rebuild(next);
|
||||
else if (next->operation == BTRFS_RBIO_WRITE) {
|
||||
else if (next->operation == BTRFS_RBIO_REBUILD_MISSING) {
|
||||
steal_rbio(rbio, next);
|
||||
async_read_rebuild(next);
|
||||
} else if (next->operation == BTRFS_RBIO_WRITE) {
|
||||
steal_rbio(rbio, next);
|
||||
async_rmw_stripe(next);
|
||||
} else if (next->operation == BTRFS_RBIO_PARITY_SCRUB) {
|
||||
@@ -1805,7 +1813,8 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)
|
||||
faila = rbio->faila;
|
||||
failb = rbio->failb;
|
||||
|
||||
if (rbio->operation == BTRFS_RBIO_READ_REBUILD) {
|
||||
if (rbio->operation == BTRFS_RBIO_READ_REBUILD ||
|
||||
rbio->operation == BTRFS_RBIO_REBUILD_MISSING) {
|
||||
spin_lock_irq(&rbio->bio_list_lock);
|
||||
set_bit(RBIO_RMW_LOCKED_BIT, &rbio->flags);
|
||||
spin_unlock_irq(&rbio->bio_list_lock);
|
||||
@@ -1830,7 +1839,8 @@ static void __raid_recover_end_io(struct btrfs_raid_bio *rbio)
|
||||
* if we're rebuilding a read, we have to use
|
||||
* pages from the bio list
|
||||
*/
|
||||
if (rbio->operation == BTRFS_RBIO_READ_REBUILD &&
|
||||
if ((rbio->operation == BTRFS_RBIO_READ_REBUILD ||
|
||||
rbio->operation == BTRFS_RBIO_REBUILD_MISSING) &&
|
||||
(stripe == faila || stripe == failb)) {
|
||||
page = page_in_rbio(rbio, stripe, pagenr, 0);
|
||||
} else {
|
||||
@@ -1939,7 +1949,8 @@ pstripe:
|
||||
* if we're rebuilding a read, we have to use
|
||||
* pages from the bio list
|
||||
*/
|
||||
if (rbio->operation == BTRFS_RBIO_READ_REBUILD &&
|
||||
if ((rbio->operation == BTRFS_RBIO_READ_REBUILD ||
|
||||
rbio->operation == BTRFS_RBIO_REBUILD_MISSING) &&
|
||||
(stripe == faila || stripe == failb)) {
|
||||
page = page_in_rbio(rbio, stripe, pagenr, 0);
|
||||
} else {
|
||||
@@ -1960,6 +1971,8 @@ cleanup_io:
|
||||
else
|
||||
clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags);
|
||||
|
||||
rbio_orig_end_io(rbio, err);
|
||||
} else if (rbio->operation == BTRFS_RBIO_REBUILD_MISSING) {
|
||||
rbio_orig_end_io(rbio, err);
|
||||
} else if (err == 0) {
|
||||
rbio->faila = -1;
|
||||
@@ -2096,7 +2109,8 @@ out:
|
||||
return 0;
|
||||
|
||||
cleanup:
|
||||
if (rbio->operation == BTRFS_RBIO_READ_REBUILD)
|
||||
if (rbio->operation == BTRFS_RBIO_READ_REBUILD ||
|
||||
rbio->operation == BTRFS_RBIO_REBUILD_MISSING)
|
||||
rbio_orig_end_io(rbio, -EIO);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -2227,8 +2241,9 @@ raid56_parity_alloc_scrub_rbio(struct btrfs_root *root, struct bio *bio,
|
||||
return rbio;
|
||||
}
|
||||
|
||||
void raid56_parity_add_scrub_pages(struct btrfs_raid_bio *rbio,
|
||||
struct page *page, u64 logical)
|
||||
/* Used for both parity scrub and missing. */
|
||||
void raid56_add_scrub_pages(struct btrfs_raid_bio *rbio, struct page *page,
|
||||
u64 logical)
|
||||
{
|
||||
int stripe_offset;
|
||||
int index;
|
||||
@@ -2662,3 +2677,55 @@ void raid56_parity_submit_scrub_rbio(struct btrfs_raid_bio *rbio)
|
||||
if (!lock_stripe_add(rbio))
|
||||
async_scrub_parity(rbio);
|
||||
}
|
||||
|
||||
/* The following code is used for dev replace of a missing RAID 5/6 device. */
|
||||
|
||||
struct btrfs_raid_bio *
|
||||
raid56_alloc_missing_rbio(struct btrfs_root *root, struct bio *bio,
|
||||
struct btrfs_bio *bbio, u64 length)
|
||||
{
|
||||
struct btrfs_raid_bio *rbio;
|
||||
|
||||
rbio = alloc_rbio(root, bbio, length);
|
||||
if (IS_ERR(rbio))
|
||||
return NULL;
|
||||
|
||||
rbio->operation = BTRFS_RBIO_REBUILD_MISSING;
|
||||
bio_list_add(&rbio->bio_list, bio);
|
||||
/*
|
||||
* This is a special bio which is used to hold the completion handler
|
||||
* and make the scrub rbio is similar to the other types
|
||||
*/
|
||||
ASSERT(!bio->bi_iter.bi_size);
|
||||
|
||||
rbio->faila = find_logical_bio_stripe(rbio, bio);
|
||||
if (rbio->faila == -1) {
|
||||
BUG();
|
||||
kfree(rbio);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return rbio;
|
||||
}
|
||||
|
||||
static void missing_raid56_work(struct btrfs_work *work)
|
||||
{
|
||||
struct btrfs_raid_bio *rbio;
|
||||
|
||||
rbio = container_of(work, struct btrfs_raid_bio, work);
|
||||
__raid56_parity_recover(rbio);
|
||||
}
|
||||
|
||||
static void async_missing_raid56(struct btrfs_raid_bio *rbio)
|
||||
{
|
||||
btrfs_init_work(&rbio->work, btrfs_rmw_helper,
|
||||
missing_raid56_work, NULL, NULL);
|
||||
|
||||
btrfs_queue_work(rbio->fs_info->rmw_workers, &rbio->work);
|
||||
}
|
||||
|
||||
void raid56_submit_missing_rbio(struct btrfs_raid_bio *rbio)
|
||||
{
|
||||
if (!lock_stripe_add(rbio))
|
||||
async_missing_raid56(rbio);
|
||||
}
|
||||
|
||||
+8
-2
@@ -48,15 +48,21 @@ int raid56_parity_recover(struct btrfs_root *root, struct bio *bio,
|
||||
int raid56_parity_write(struct btrfs_root *root, struct bio *bio,
|
||||
struct btrfs_bio *bbio, u64 stripe_len);
|
||||
|
||||
void raid56_add_scrub_pages(struct btrfs_raid_bio *rbio, struct page *page,
|
||||
u64 logical);
|
||||
|
||||
struct btrfs_raid_bio *
|
||||
raid56_parity_alloc_scrub_rbio(struct btrfs_root *root, struct bio *bio,
|
||||
struct btrfs_bio *bbio, u64 stripe_len,
|
||||
struct btrfs_device *scrub_dev,
|
||||
unsigned long *dbitmap, int stripe_nsectors);
|
||||
void raid56_parity_add_scrub_pages(struct btrfs_raid_bio *rbio,
|
||||
struct page *page, u64 logical);
|
||||
void raid56_parity_submit_scrub_rbio(struct btrfs_raid_bio *rbio);
|
||||
|
||||
struct btrfs_raid_bio *
|
||||
raid56_alloc_missing_rbio(struct btrfs_root *root, struct bio *bio,
|
||||
struct btrfs_bio *bbio, u64 length);
|
||||
void raid56_submit_missing_rbio(struct btrfs_raid_bio *rbio);
|
||||
|
||||
int btrfs_alloc_stripe_hash_table(struct btrfs_fs_info *info);
|
||||
void btrfs_free_stripe_hash_table(struct btrfs_fs_info *info);
|
||||
#endif
|
||||
|
||||
+3
-1
@@ -328,6 +328,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
|
||||
struct btrfs_device *prev_dev;
|
||||
u32 blocksize;
|
||||
u64 length;
|
||||
int real_stripes;
|
||||
int nzones = 0;
|
||||
int i;
|
||||
unsigned long index = logical >> PAGE_CACHE_SHIFT;
|
||||
@@ -369,7 +370,8 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (nzones = 0; nzones < bbio->num_stripes; ++nzones) {
|
||||
real_stripes = bbio->num_stripes - bbio->num_tgtdevs;
|
||||
for (nzones = 0; nzones < real_stripes; ++nzones) {
|
||||
struct reada_zone *zone;
|
||||
|
||||
dev = bbio->stripes[nzones].dev;
|
||||
|
||||
+16
-17
@@ -2523,8 +2523,7 @@ struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans,
|
||||
* counted. return -ENOENT if the block is root of reloc tree.
|
||||
*/
|
||||
static noinline_for_stack
|
||||
struct btrfs_root *select_one_root(struct btrfs_trans_handle *trans,
|
||||
struct backref_node *node)
|
||||
struct btrfs_root *select_one_root(struct backref_node *node)
|
||||
{
|
||||
struct backref_node *next;
|
||||
struct btrfs_root *root;
|
||||
@@ -2912,7 +2911,7 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,
|
||||
return 0;
|
||||
|
||||
BUG_ON(node->processed);
|
||||
root = select_one_root(trans, node);
|
||||
root = select_one_root(node);
|
||||
if (root == ERR_PTR(-ENOENT)) {
|
||||
update_processed_blocks(rc, node);
|
||||
goto out;
|
||||
@@ -3755,8 +3754,7 @@ out:
|
||||
* helper to find next unprocessed extent
|
||||
*/
|
||||
static noinline_for_stack
|
||||
int find_next_extent(struct btrfs_trans_handle *trans,
|
||||
struct reloc_control *rc, struct btrfs_path *path,
|
||||
int find_next_extent(struct reloc_control *rc, struct btrfs_path *path,
|
||||
struct btrfs_key *extent_key)
|
||||
{
|
||||
struct btrfs_key key;
|
||||
@@ -3951,7 +3949,7 @@ restart:
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = find_next_extent(trans, rc, path, &key);
|
||||
ret = find_next_extent(rc, path, &key);
|
||||
if (ret < 0)
|
||||
err = ret;
|
||||
if (ret != 0)
|
||||
@@ -3976,6 +3974,10 @@ restart:
|
||||
sizeof(struct btrfs_extent_item_v0));
|
||||
ret = get_ref_objectid_v0(rc, path, &key, &ref_owner,
|
||||
&path_change);
|
||||
if (ret < 0) {
|
||||
err = ret;
|
||||
break;
|
||||
}
|
||||
if (ref_owner < BTRFS_FIRST_FREE_OBJECTID)
|
||||
flags = BTRFS_EXTENT_FLAG_TREE_BLOCK;
|
||||
else
|
||||
@@ -4140,7 +4142,7 @@ struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_key key;
|
||||
u64 objectid = BTRFS_FIRST_FREE_OBJECTID;
|
||||
u64 objectid;
|
||||
int err = 0;
|
||||
|
||||
root = read_fs_root(fs_info, BTRFS_DATA_RELOC_TREE_OBJECTID);
|
||||
@@ -4215,14 +4217,12 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
|
||||
rc->block_group = btrfs_lookup_block_group(fs_info, group_start);
|
||||
BUG_ON(!rc->block_group);
|
||||
|
||||
if (!rc->block_group->ro) {
|
||||
ret = btrfs_set_block_group_ro(extent_root, rc->block_group);
|
||||
if (ret) {
|
||||
err = ret;
|
||||
goto out;
|
||||
}
|
||||
rw = 1;
|
||||
ret = btrfs_inc_block_group_ro(extent_root, rc->block_group);
|
||||
if (ret) {
|
||||
err = ret;
|
||||
goto out;
|
||||
}
|
||||
rw = 1;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path) {
|
||||
@@ -4294,7 +4294,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
|
||||
WARN_ON(btrfs_block_group_used(&rc->block_group->item) > 0);
|
||||
out:
|
||||
if (err && rw)
|
||||
btrfs_set_block_group_rw(extent_root, rc->block_group);
|
||||
btrfs_dec_block_group_ro(extent_root, rc->block_group);
|
||||
iput(rc->data_inode);
|
||||
btrfs_put_block_group(rc->block_group);
|
||||
kfree(rc);
|
||||
@@ -4594,8 +4594,7 @@ int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans,
|
||||
* called before creating snapshot. it calculates metadata reservation
|
||||
* requried for relocating tree blocks in the snapshot
|
||||
*/
|
||||
void btrfs_reloc_pre_snapshot(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_pending_snapshot *pending,
|
||||
void btrfs_reloc_pre_snapshot(struct btrfs_pending_snapshot *pending,
|
||||
u64 *bytes_to_reserve)
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
|
||||
+262
-86
File diff suppressed because it is too large
Load Diff
+13
-1
@@ -69,7 +69,7 @@ static struct file_system_type btrfs_fs_type;
|
||||
|
||||
static int btrfs_remount(struct super_block *sb, int *flags, char *data);
|
||||
|
||||
static const char *btrfs_decode_error(int errno)
|
||||
const char *btrfs_decode_error(int errno)
|
||||
{
|
||||
char *errstr = "unknown";
|
||||
|
||||
@@ -1033,6 +1033,7 @@ static int btrfs_fill_super(struct super_block *sb,
|
||||
sb->s_flags |= MS_POSIXACL;
|
||||
#endif
|
||||
sb->s_flags |= MS_I_VERSION;
|
||||
sb->s_iflags |= SB_I_CGROUPWB;
|
||||
err = open_ctree(sb, fs_devices, (char *)data);
|
||||
if (err) {
|
||||
printk(KERN_ERR "BTRFS: open_ctree failed\n");
|
||||
@@ -1650,6 +1651,17 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
|
||||
|
||||
sb->s_flags |= MS_RDONLY;
|
||||
|
||||
/*
|
||||
* Setting MS_RDONLY will put the cleaner thread to
|
||||
* sleep at the next loop if it's already active.
|
||||
* If it's already asleep, we'll leave unused block
|
||||
* groups on disk until we're mounted read-write again
|
||||
* unless we clean them up here.
|
||||
*/
|
||||
mutex_lock(&root->fs_info->cleaner_mutex);
|
||||
btrfs_delete_unused_bgs(fs_info);
|
||||
mutex_unlock(&root->fs_info->cleaner_mutex);
|
||||
|
||||
btrfs_dev_replace_suspend_for_unmount(fs_info);
|
||||
btrfs_scrub_cancel(fs_info);
|
||||
btrfs_pause_balance(fs_info);
|
||||
|
||||
@@ -258,6 +258,8 @@ loop:
|
||||
mutex_init(&cur_trans->cache_write_mutex);
|
||||
cur_trans->num_dirty_bgs = 0;
|
||||
spin_lock_init(&cur_trans->dirty_bgs_lock);
|
||||
INIT_LIST_HEAD(&cur_trans->deleted_bgs);
|
||||
spin_lock_init(&cur_trans->deleted_bgs_lock);
|
||||
list_add_tail(&cur_trans->list, &fs_info->trans_list);
|
||||
extent_io_tree_init(&cur_trans->dirty_pages,
|
||||
fs_info->btree_inode->i_mapping);
|
||||
@@ -1301,7 +1303,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||
*/
|
||||
btrfs_set_skip_qgroup(trans, objectid);
|
||||
|
||||
btrfs_reloc_pre_snapshot(trans, pending, &to_reserve);
|
||||
btrfs_reloc_pre_snapshot(pending, &to_reserve);
|
||||
|
||||
if (to_reserve > 0) {
|
||||
pending->error = btrfs_block_rsv_add(root,
|
||||
@@ -1893,8 +1895,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
|
||||
spin_unlock(&root->fs_info->trans_lock);
|
||||
|
||||
wait_for_commit(root, prev_trans);
|
||||
ret = prev_trans->aborted;
|
||||
|
||||
btrfs_put_transaction(prev_trans);
|
||||
if (ret)
|
||||
goto cleanup_transaction;
|
||||
} else {
|
||||
spin_unlock(&root->fs_info->trans_lock);
|
||||
}
|
||||
|
||||
@@ -74,6 +74,8 @@ struct btrfs_transaction {
|
||||
*/
|
||||
struct mutex cache_write_mutex;
|
||||
spinlock_t dirty_bgs_lock;
|
||||
struct list_head deleted_bgs;
|
||||
spinlock_t deleted_bgs_lock;
|
||||
struct btrfs_delayed_ref_root delayed_refs;
|
||||
int aborted;
|
||||
int dirty_bg_run;
|
||||
|
||||
+280
-64
File diff suppressed because it is too large
Load Diff
+44
-35
@@ -1116,15 +1116,18 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int contains_pending_extent(struct btrfs_trans_handle *trans,
|
||||
static int contains_pending_extent(struct btrfs_transaction *transaction,
|
||||
struct btrfs_device *device,
|
||||
u64 *start, u64 len)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = device->dev_root->fs_info;
|
||||
struct extent_map *em;
|
||||
struct list_head *search_list = &trans->transaction->pending_chunks;
|
||||
struct list_head *search_list = &fs_info->pinned_chunks;
|
||||
int ret = 0;
|
||||
u64 physical_start = *start;
|
||||
|
||||
if (transaction)
|
||||
search_list = &transaction->pending_chunks;
|
||||
again:
|
||||
list_for_each_entry(em, search_list, list) {
|
||||
struct map_lookup *map;
|
||||
@@ -1159,8 +1162,8 @@ again:
|
||||
}
|
||||
}
|
||||
}
|
||||
if (search_list == &trans->transaction->pending_chunks) {
|
||||
search_list = &trans->root->fs_info->pinned_chunks;
|
||||
if (search_list != &fs_info->pinned_chunks) {
|
||||
search_list = &fs_info->pinned_chunks;
|
||||
goto again;
|
||||
}
|
||||
|
||||
@@ -1169,12 +1172,13 @@ again:
|
||||
|
||||
|
||||
/*
|
||||
* find_free_dev_extent - find free space in the specified device
|
||||
* @device: the device which we search the free space in
|
||||
* @num_bytes: the size of the free space that we need
|
||||
* @start: store the start of the free space.
|
||||
* @len: the size of the free space. that we find, or the size of the max
|
||||
* free space if we don't find suitable free space
|
||||
* find_free_dev_extent_start - find free space in the specified device
|
||||
* @device: the device which we search the free space in
|
||||
* @num_bytes: the size of the free space that we need
|
||||
* @search_start: the position from which to begin the search
|
||||
* @start: store the start of the free space.
|
||||
* @len: the size of the free space. that we find, or the size
|
||||
* of the max free space if we don't find suitable free space
|
||||
*
|
||||
* this uses a pretty simple search, the expectation is that it is
|
||||
* called very infrequently and that a given device has a small number
|
||||
@@ -1188,9 +1192,9 @@ again:
|
||||
* But if we don't find suitable free space, it is used to store the size of
|
||||
* the max free space.
|
||||
*/
|
||||
int find_free_dev_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_device *device, u64 num_bytes,
|
||||
u64 *start, u64 *len)
|
||||
int find_free_dev_extent_start(struct btrfs_transaction *transaction,
|
||||
struct btrfs_device *device, u64 num_bytes,
|
||||
u64 search_start, u64 *start, u64 *len)
|
||||
{
|
||||
struct btrfs_key key;
|
||||
struct btrfs_root *root = device->dev_root;
|
||||
@@ -1200,19 +1204,11 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
|
||||
u64 max_hole_start;
|
||||
u64 max_hole_size;
|
||||
u64 extent_end;
|
||||
u64 search_start;
|
||||
u64 search_end = device->total_bytes;
|
||||
int ret;
|
||||
int slot;
|
||||
struct extent_buffer *l;
|
||||
|
||||
/* FIXME use last free of some kind */
|
||||
|
||||
/* we don't want to overwrite the superblock on the drive,
|
||||
* so we make sure to start at an offset of at least 1MB
|
||||
*/
|
||||
search_start = max(root->fs_info->alloc_start, 1024ull * 1024);
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
@@ -1273,7 +1269,7 @@ again:
|
||||
* Have to check before we set max_hole_start, otherwise
|
||||
* we could end up sending back this offset anyway.
|
||||
*/
|
||||
if (contains_pending_extent(trans, device,
|
||||
if (contains_pending_extent(transaction, device,
|
||||
&search_start,
|
||||
hole_size)) {
|
||||
if (key.offset >= search_start) {
|
||||
@@ -1322,7 +1318,7 @@ next:
|
||||
if (search_end > search_start) {
|
||||
hole_size = search_end - search_start;
|
||||
|
||||
if (contains_pending_extent(trans, device, &search_start,
|
||||
if (contains_pending_extent(transaction, device, &search_start,
|
||||
hole_size)) {
|
||||
btrfs_release_path(path);
|
||||
goto again;
|
||||
@@ -1348,6 +1344,24 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int find_free_dev_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_device *device, u64 num_bytes,
|
||||
u64 *start, u64 *len)
|
||||
{
|
||||
struct btrfs_root *root = device->dev_root;
|
||||
u64 search_start;
|
||||
|
||||
/* FIXME use last free of some kind */
|
||||
|
||||
/*
|
||||
* we don't want to overwrite the superblock on the drive,
|
||||
* so we make sure to start at an offset of at least 1MB
|
||||
*/
|
||||
search_start = max(root->fs_info->alloc_start, 1024ull * 1024);
|
||||
return find_free_dev_extent_start(trans->transaction, device,
|
||||
num_bytes, search_start, start, len);
|
||||
}
|
||||
|
||||
static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_device *device,
|
||||
u64 start, u64 *dev_extent_len)
|
||||
@@ -2755,9 +2769,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int btrfs_relocate_chunk(struct btrfs_root *root,
|
||||
u64 chunk_objectid,
|
||||
u64 chunk_offset)
|
||||
static int btrfs_relocate_chunk(struct btrfs_root *root, u64 chunk_offset)
|
||||
{
|
||||
struct btrfs_root *extent_root;
|
||||
struct btrfs_trans_handle *trans;
|
||||
@@ -2785,7 +2797,9 @@ static int btrfs_relocate_chunk(struct btrfs_root *root,
|
||||
return -ENOSPC;
|
||||
|
||||
/* step one, relocate all the extents inside this chunk */
|
||||
btrfs_scrub_pause(root);
|
||||
ret = btrfs_relocate_block_group(extent_root, chunk_offset);
|
||||
btrfs_scrub_continue(root);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -2855,7 +2869,6 @@ again:
|
||||
|
||||
if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) {
|
||||
ret = btrfs_relocate_chunk(chunk_root,
|
||||
found_key.objectid,
|
||||
found_key.offset);
|
||||
if (ret == -ENOSPC)
|
||||
failed++;
|
||||
@@ -3375,7 +3388,6 @@ again:
|
||||
}
|
||||
|
||||
ret = btrfs_relocate_chunk(chunk_root,
|
||||
found_key.objectid,
|
||||
found_key.offset);
|
||||
mutex_unlock(&fs_info->delete_unused_bgs_mutex);
|
||||
if (ret && ret != -ENOSPC)
|
||||
@@ -4077,7 +4089,6 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size)
|
||||
struct btrfs_dev_extent *dev_extent = NULL;
|
||||
struct btrfs_path *path;
|
||||
u64 length;
|
||||
u64 chunk_objectid;
|
||||
u64 chunk_offset;
|
||||
int ret;
|
||||
int slot;
|
||||
@@ -4154,11 +4165,10 @@ again:
|
||||
break;
|
||||
}
|
||||
|
||||
chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent);
|
||||
chunk_offset = btrfs_dev_extent_chunk_offset(l, dev_extent);
|
||||
btrfs_release_path(path);
|
||||
|
||||
ret = btrfs_relocate_chunk(root, chunk_objectid, chunk_offset);
|
||||
ret = btrfs_relocate_chunk(root, chunk_offset);
|
||||
mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
|
||||
if (ret && ret != -ENOSPC)
|
||||
goto done;
|
||||
@@ -4200,7 +4210,8 @@ again:
|
||||
u64 start = new_size;
|
||||
u64 len = old_size - new_size;
|
||||
|
||||
if (contains_pending_extent(trans, device, &start, len)) {
|
||||
if (contains_pending_extent(trans->transaction, device,
|
||||
&start, len)) {
|
||||
unlock_chunks(root);
|
||||
checked_pending_chunks = true;
|
||||
failed = 0;
|
||||
@@ -5071,9 +5082,7 @@ static struct btrfs_bio *alloc_btrfs_bio(int total_stripes, int real_stripes)
|
||||
* and the stripes
|
||||
*/
|
||||
sizeof(u64) * (total_stripes),
|
||||
GFP_NOFS);
|
||||
if (!bbio)
|
||||
return NULL;
|
||||
GFP_NOFS|__GFP_NOFAIL);
|
||||
|
||||
atomic_set(&bbio->error, 0);
|
||||
atomic_set(&bbio->refs, 1);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user