mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs: Btrfs: remove free-space-cache.c WARN during log replay Btrfs: sectorsize align offsets in fiemap Btrfs: clear pages dirty for io and set them extent mapped Btrfs: wait on caching if we're loading the free space cache Btrfs: prefix resize related printks with btrfs: btrfs: fix stat blocks accounting Btrfs: avoid unnecessary bitmap search for cluster setup Btrfs: fix to search one more bitmap for cluster setup btrfs: mirror_num should be int, not u64 btrfs: Fix up 32/64-bit compatibility for new ioctls Btrfs: fix barrier flushes Btrfs: fix tree corruption after multi-thread snapshots and inode_cache flush
This commit is contained in:
commit
af36d15f58
|
@ -683,7 +683,7 @@ static int inode_to_path(u64 inum, struct btrfs_inode_ref *iref,
|
||||||
return PTR_ERR(fspath);
|
return PTR_ERR(fspath);
|
||||||
|
|
||||||
if (fspath > fspath_min) {
|
if (fspath > fspath_min) {
|
||||||
ipath->fspath->val[i] = (u64)fspath;
|
ipath->fspath->val[i] = (u64)(unsigned long)fspath;
|
||||||
++ipath->fspath->elem_cnt;
|
++ipath->fspath->elem_cnt;
|
||||||
ipath->fspath->bytes_left = fspath - fspath_min;
|
ipath->fspath->bytes_left = fspath - fspath_min;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -514,10 +514,25 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct extent_buffer *buf)
|
struct extent_buffer *buf)
|
||||||
{
|
{
|
||||||
|
/* ensure we can see the force_cow */
|
||||||
|
smp_rmb();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We do not need to cow a block if
|
||||||
|
* 1) this block is not created or changed in this transaction;
|
||||||
|
* 2) this block does not belong to TREE_RELOC tree;
|
||||||
|
* 3) the root is not forced COW.
|
||||||
|
*
|
||||||
|
* What is forced COW:
|
||||||
|
* when we create snapshot during commiting the transaction,
|
||||||
|
* after we've finished coping src root, we must COW the shared
|
||||||
|
* block to ensure the metadata consistency.
|
||||||
|
*/
|
||||||
if (btrfs_header_generation(buf) == trans->transid &&
|
if (btrfs_header_generation(buf) == trans->transid &&
|
||||||
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) &&
|
!btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) &&
|
||||||
!(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID &&
|
!(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID &&
|
||||||
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)))
|
btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)) &&
|
||||||
|
!root->force_cow)
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -848,7 +848,8 @@ struct btrfs_free_cluster {
|
||||||
enum btrfs_caching_type {
|
enum btrfs_caching_type {
|
||||||
BTRFS_CACHE_NO = 0,
|
BTRFS_CACHE_NO = 0,
|
||||||
BTRFS_CACHE_STARTED = 1,
|
BTRFS_CACHE_STARTED = 1,
|
||||||
BTRFS_CACHE_FINISHED = 2,
|
BTRFS_CACHE_FAST = 2,
|
||||||
|
BTRFS_CACHE_FINISHED = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum btrfs_disk_cache_state {
|
enum btrfs_disk_cache_state {
|
||||||
|
@ -1271,6 +1272,8 @@ struct btrfs_root {
|
||||||
* for stat. It may be used for more later
|
* for stat. It may be used for more later
|
||||||
*/
|
*/
|
||||||
dev_t anon_dev;
|
dev_t anon_dev;
|
||||||
|
|
||||||
|
int force_cow;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct btrfs_ioctl_defrag_range_args {
|
struct btrfs_ioctl_defrag_range_args {
|
||||||
|
|
|
@ -620,7 +620,7 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
|
||||||
|
|
||||||
static int btree_io_failed_hook(struct bio *failed_bio,
|
static int btree_io_failed_hook(struct bio *failed_bio,
|
||||||
struct page *page, u64 start, u64 end,
|
struct page *page, u64 start, u64 end,
|
||||||
u64 mirror_num, struct extent_state *state)
|
int mirror_num, struct extent_state *state)
|
||||||
{
|
{
|
||||||
struct extent_io_tree *tree;
|
struct extent_io_tree *tree;
|
||||||
unsigned long len;
|
unsigned long len;
|
||||||
|
@ -2573,22 +2573,10 @@ static int write_dev_supers(struct btrfs_device *device,
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
u32 crc;
|
u32 crc;
|
||||||
u64 bytenr;
|
u64 bytenr;
|
||||||
int last_barrier = 0;
|
|
||||||
|
|
||||||
if (max_mirrors == 0)
|
if (max_mirrors == 0)
|
||||||
max_mirrors = BTRFS_SUPER_MIRROR_MAX;
|
max_mirrors = BTRFS_SUPER_MIRROR_MAX;
|
||||||
|
|
||||||
/* make sure only the last submit_bh does a barrier */
|
|
||||||
if (do_barriers) {
|
|
||||||
for (i = 0; i < max_mirrors; i++) {
|
|
||||||
bytenr = btrfs_sb_offset(i);
|
|
||||||
if (bytenr + BTRFS_SUPER_INFO_SIZE >=
|
|
||||||
device->total_bytes)
|
|
||||||
break;
|
|
||||||
last_barrier = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < max_mirrors; i++) {
|
for (i = 0; i < max_mirrors; i++) {
|
||||||
bytenr = btrfs_sb_offset(i);
|
bytenr = btrfs_sb_offset(i);
|
||||||
if (bytenr + BTRFS_SUPER_INFO_SIZE >= device->total_bytes)
|
if (bytenr + BTRFS_SUPER_INFO_SIZE >= device->total_bytes)
|
||||||
|
@ -2634,17 +2622,136 @@ static int write_dev_supers(struct btrfs_device *device,
|
||||||
bh->b_end_io = btrfs_end_buffer_write_sync;
|
bh->b_end_io = btrfs_end_buffer_write_sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == last_barrier && do_barriers)
|
/*
|
||||||
ret = submit_bh(WRITE_FLUSH_FUA, bh);
|
* we fua the first super. The others we allow
|
||||||
else
|
* to go down lazy.
|
||||||
ret = submit_bh(WRITE_SYNC, bh);
|
*/
|
||||||
|
ret = submit_bh(WRITE_FUA, bh);
|
||||||
if (ret)
|
if (ret)
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
return errors < i ? 0 : -1;
|
return errors < i ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* endio for the write_dev_flush, this will wake anyone waiting
|
||||||
|
* for the barrier when it is done
|
||||||
|
*/
|
||||||
|
static void btrfs_end_empty_barrier(struct bio *bio, int err)
|
||||||
|
{
|
||||||
|
if (err) {
|
||||||
|
if (err == -EOPNOTSUPP)
|
||||||
|
set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
|
||||||
|
clear_bit(BIO_UPTODATE, &bio->bi_flags);
|
||||||
|
}
|
||||||
|
if (bio->bi_private)
|
||||||
|
complete(bio->bi_private);
|
||||||
|
bio_put(bio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* trigger flushes for one the devices. If you pass wait == 0, the flushes are
|
||||||
|
* sent down. With wait == 1, it waits for the previous flush.
|
||||||
|
*
|
||||||
|
* any device where the flush fails with eopnotsupp are flagged as not-barrier
|
||||||
|
* capable
|
||||||
|
*/
|
||||||
|
static int write_dev_flush(struct btrfs_device *device, int wait)
|
||||||
|
{
|
||||||
|
struct bio *bio;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (device->nobarriers)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (wait) {
|
||||||
|
bio = device->flush_bio;
|
||||||
|
if (!bio)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
wait_for_completion(&device->flush_wait);
|
||||||
|
|
||||||
|
if (bio_flagged(bio, BIO_EOPNOTSUPP)) {
|
||||||
|
printk("btrfs: disabling barriers on dev %s\n",
|
||||||
|
device->name);
|
||||||
|
device->nobarriers = 1;
|
||||||
|
}
|
||||||
|
if (!bio_flagged(bio, BIO_UPTODATE)) {
|
||||||
|
ret = -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* drop the reference from the wait == 0 run */
|
||||||
|
bio_put(bio);
|
||||||
|
device->flush_bio = NULL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* one reference for us, and we leave it for the
|
||||||
|
* caller
|
||||||
|
*/
|
||||||
|
device->flush_bio = NULL;;
|
||||||
|
bio = bio_alloc(GFP_NOFS, 0);
|
||||||
|
if (!bio)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
bio->bi_end_io = btrfs_end_empty_barrier;
|
||||||
|
bio->bi_bdev = device->bdev;
|
||||||
|
init_completion(&device->flush_wait);
|
||||||
|
bio->bi_private = &device->flush_wait;
|
||||||
|
device->flush_bio = bio;
|
||||||
|
|
||||||
|
bio_get(bio);
|
||||||
|
submit_bio(WRITE_FLUSH, bio);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* send an empty flush down to each device in parallel,
|
||||||
|
* then wait for them
|
||||||
|
*/
|
||||||
|
static int barrier_all_devices(struct btrfs_fs_info *info)
|
||||||
|
{
|
||||||
|
struct list_head *head;
|
||||||
|
struct btrfs_device *dev;
|
||||||
|
int errors = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* send down all the barriers */
|
||||||
|
head = &info->fs_devices->devices;
|
||||||
|
list_for_each_entry_rcu(dev, head, dev_list) {
|
||||||
|
if (!dev->bdev) {
|
||||||
|
errors++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!dev->in_fs_metadata || !dev->writeable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = write_dev_flush(dev, 0);
|
||||||
|
if (ret)
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait for all the barriers */
|
||||||
|
list_for_each_entry_rcu(dev, head, dev_list) {
|
||||||
|
if (!dev->bdev) {
|
||||||
|
errors++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!dev->in_fs_metadata || !dev->writeable)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = write_dev_flush(dev, 1);
|
||||||
|
if (ret)
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
if (errors)
|
||||||
|
return -EIO;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int write_all_supers(struct btrfs_root *root, int max_mirrors)
|
int write_all_supers(struct btrfs_root *root, int max_mirrors)
|
||||||
{
|
{
|
||||||
struct list_head *head;
|
struct list_head *head;
|
||||||
|
@ -2666,6 +2773,10 @@ int write_all_supers(struct btrfs_root *root, int max_mirrors)
|
||||||
|
|
||||||
mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
|
mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
|
||||||
head = &root->fs_info->fs_devices->devices;
|
head = &root->fs_info->fs_devices->devices;
|
||||||
|
|
||||||
|
if (do_barriers)
|
||||||
|
barrier_all_devices(root->fs_info);
|
||||||
|
|
||||||
list_for_each_entry_rcu(dev, head, dev_list) {
|
list_for_each_entry_rcu(dev, head, dev_list) {
|
||||||
if (!dev->bdev) {
|
if (!dev->bdev) {
|
||||||
total_errors++;
|
total_errors++;
|
||||||
|
|
|
@ -467,13 +467,59 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
int load_cache_only)
|
int load_cache_only)
|
||||||
{
|
{
|
||||||
|
DEFINE_WAIT(wait);
|
||||||
struct btrfs_fs_info *fs_info = cache->fs_info;
|
struct btrfs_fs_info *fs_info = cache->fs_info;
|
||||||
struct btrfs_caching_control *caching_ctl;
|
struct btrfs_caching_control *caching_ctl;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
smp_mb();
|
caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS);
|
||||||
if (cache->cached != BTRFS_CACHE_NO)
|
BUG_ON(!caching_ctl);
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&caching_ctl->list);
|
||||||
|
mutex_init(&caching_ctl->mutex);
|
||||||
|
init_waitqueue_head(&caching_ctl->wait);
|
||||||
|
caching_ctl->block_group = cache;
|
||||||
|
caching_ctl->progress = cache->key.objectid;
|
||||||
|
atomic_set(&caching_ctl->count, 1);
|
||||||
|
caching_ctl->work.func = caching_thread;
|
||||||
|
|
||||||
|
spin_lock(&cache->lock);
|
||||||
|
/*
|
||||||
|
* This should be a rare occasion, but this could happen I think in the
|
||||||
|
* case where one thread starts to load the space cache info, and then
|
||||||
|
* some other thread starts a transaction commit which tries to do an
|
||||||
|
* allocation while the other thread is still loading the space cache
|
||||||
|
* info. The previous loop should have kept us from choosing this block
|
||||||
|
* group, but if we've moved to the state where we will wait on caching
|
||||||
|
* block groups we need to first check if we're doing a fast load here,
|
||||||
|
* so we can wait for it to finish, otherwise we could end up allocating
|
||||||
|
* from a block group who's cache gets evicted for one reason or
|
||||||
|
* another.
|
||||||
|
*/
|
||||||
|
while (cache->cached == BTRFS_CACHE_FAST) {
|
||||||
|
struct btrfs_caching_control *ctl;
|
||||||
|
|
||||||
|
ctl = cache->caching_ctl;
|
||||||
|
atomic_inc(&ctl->count);
|
||||||
|
prepare_to_wait(&ctl->wait, &wait, TASK_UNINTERRUPTIBLE);
|
||||||
|
spin_unlock(&cache->lock);
|
||||||
|
|
||||||
|
schedule();
|
||||||
|
|
||||||
|
finish_wait(&ctl->wait, &wait);
|
||||||
|
put_caching_control(ctl);
|
||||||
|
spin_lock(&cache->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cache->cached != BTRFS_CACHE_NO) {
|
||||||
|
spin_unlock(&cache->lock);
|
||||||
|
kfree(caching_ctl);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
WARN_ON(cache->caching_ctl);
|
||||||
|
cache->caching_ctl = caching_ctl;
|
||||||
|
cache->cached = BTRFS_CACHE_FAST;
|
||||||
|
spin_unlock(&cache->lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't do the read from on-disk cache during a commit since we need
|
* We can't do the read from on-disk cache during a commit since we need
|
||||||
|
@ -484,56 +530,51 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
|
||||||
if (trans && (!trans->transaction->in_commit) &&
|
if (trans && (!trans->transaction->in_commit) &&
|
||||||
(root && root != root->fs_info->tree_root) &&
|
(root && root != root->fs_info->tree_root) &&
|
||||||
btrfs_test_opt(root, SPACE_CACHE)) {
|
btrfs_test_opt(root, SPACE_CACHE)) {
|
||||||
spin_lock(&cache->lock);
|
|
||||||
if (cache->cached != BTRFS_CACHE_NO) {
|
|
||||||
spin_unlock(&cache->lock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
cache->cached = BTRFS_CACHE_STARTED;
|
|
||||||
spin_unlock(&cache->lock);
|
|
||||||
|
|
||||||
ret = load_free_space_cache(fs_info, cache);
|
ret = load_free_space_cache(fs_info, cache);
|
||||||
|
|
||||||
spin_lock(&cache->lock);
|
spin_lock(&cache->lock);
|
||||||
if (ret == 1) {
|
if (ret == 1) {
|
||||||
|
cache->caching_ctl = NULL;
|
||||||
cache->cached = BTRFS_CACHE_FINISHED;
|
cache->cached = BTRFS_CACHE_FINISHED;
|
||||||
cache->last_byte_to_unpin = (u64)-1;
|
cache->last_byte_to_unpin = (u64)-1;
|
||||||
} else {
|
} else {
|
||||||
|
if (load_cache_only) {
|
||||||
|
cache->caching_ctl = NULL;
|
||||||
cache->cached = BTRFS_CACHE_NO;
|
cache->cached = BTRFS_CACHE_NO;
|
||||||
|
} else {
|
||||||
|
cache->cached = BTRFS_CACHE_STARTED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
spin_unlock(&cache->lock);
|
spin_unlock(&cache->lock);
|
||||||
|
wake_up(&caching_ctl->wait);
|
||||||
if (ret == 1) {
|
if (ret == 1) {
|
||||||
|
put_caching_control(caching_ctl);
|
||||||
free_excluded_extents(fs_info->extent_root, cache);
|
free_excluded_extents(fs_info->extent_root, cache);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
/*
|
||||||
if (load_cache_only)
|
* We are not going to do the fast caching, set cached to the
|
||||||
return 0;
|
* appropriate value and wakeup any waiters.
|
||||||
|
*/
|
||||||
caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS);
|
|
||||||
BUG_ON(!caching_ctl);
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&caching_ctl->list);
|
|
||||||
mutex_init(&caching_ctl->mutex);
|
|
||||||
init_waitqueue_head(&caching_ctl->wait);
|
|
||||||
caching_ctl->block_group = cache;
|
|
||||||
caching_ctl->progress = cache->key.objectid;
|
|
||||||
/* one for caching kthread, one for caching block group list */
|
|
||||||
atomic_set(&caching_ctl->count, 2);
|
|
||||||
caching_ctl->work.func = caching_thread;
|
|
||||||
|
|
||||||
spin_lock(&cache->lock);
|
spin_lock(&cache->lock);
|
||||||
if (cache->cached != BTRFS_CACHE_NO) {
|
if (load_cache_only) {
|
||||||
|
cache->caching_ctl = NULL;
|
||||||
|
cache->cached = BTRFS_CACHE_NO;
|
||||||
|
} else {
|
||||||
|
cache->cached = BTRFS_CACHE_STARTED;
|
||||||
|
}
|
||||||
spin_unlock(&cache->lock);
|
spin_unlock(&cache->lock);
|
||||||
kfree(caching_ctl);
|
wake_up(&caching_ctl->wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (load_cache_only) {
|
||||||
|
put_caching_control(caching_ctl);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
cache->caching_ctl = caching_ctl;
|
|
||||||
cache->cached = BTRFS_CACHE_STARTED;
|
|
||||||
spin_unlock(&cache->lock);
|
|
||||||
|
|
||||||
down_write(&fs_info->extent_commit_sem);
|
down_write(&fs_info->extent_commit_sem);
|
||||||
|
atomic_inc(&caching_ctl->count);
|
||||||
list_add_tail(&caching_ctl->list, &fs_info->caching_block_groups);
|
list_add_tail(&caching_ctl->list, &fs_info->caching_block_groups);
|
||||||
up_write(&fs_info->extent_commit_sem);
|
up_write(&fs_info->extent_commit_sem);
|
||||||
|
|
||||||
|
@ -5178,13 +5219,15 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
|
||||||
}
|
}
|
||||||
|
|
||||||
have_block_group:
|
have_block_group:
|
||||||
if (unlikely(block_group->cached == BTRFS_CACHE_NO)) {
|
cached = block_group_cache_done(block_group);
|
||||||
|
if (unlikely(!cached)) {
|
||||||
u64 free_percent;
|
u64 free_percent;
|
||||||
|
|
||||||
|
found_uncached_bg = true;
|
||||||
ret = cache_block_group(block_group, trans,
|
ret = cache_block_group(block_group, trans,
|
||||||
orig_root, 1);
|
orig_root, 1);
|
||||||
if (block_group->cached == BTRFS_CACHE_FINISHED)
|
if (block_group->cached == BTRFS_CACHE_FINISHED)
|
||||||
goto have_block_group;
|
goto alloc;
|
||||||
|
|
||||||
free_percent = btrfs_block_group_used(&block_group->item);
|
free_percent = btrfs_block_group_used(&block_group->item);
|
||||||
free_percent *= 100;
|
free_percent *= 100;
|
||||||
|
@ -5206,7 +5249,6 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
|
||||||
orig_root, 0);
|
orig_root, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
}
|
}
|
||||||
found_uncached_bg = true;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If loop is set for cached only, try the next block
|
* If loop is set for cached only, try the next block
|
||||||
|
@ -5216,10 +5258,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
|
||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
cached = block_group_cache_done(block_group);
|
alloc:
|
||||||
if (unlikely(!cached))
|
|
||||||
found_uncached_bg = true;
|
|
||||||
|
|
||||||
if (unlikely(block_group->ro))
|
if (unlikely(block_group->ro))
|
||||||
goto loop;
|
goto loop;
|
||||||
|
|
||||||
|
|
|
@ -2285,8 +2285,8 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
|
||||||
clean_io_failure(start, page);
|
clean_io_failure(start, page);
|
||||||
}
|
}
|
||||||
if (!uptodate) {
|
if (!uptodate) {
|
||||||
u64 failed_mirror;
|
int failed_mirror;
|
||||||
failed_mirror = (u64)bio->bi_bdev;
|
failed_mirror = (int)(unsigned long)bio->bi_bdev;
|
||||||
if (tree->ops && tree->ops->readpage_io_failed_hook)
|
if (tree->ops && tree->ops->readpage_io_failed_hook)
|
||||||
ret = tree->ops->readpage_io_failed_hook(
|
ret = tree->ops->readpage_io_failed_hook(
|
||||||
bio, page, start, end,
|
bio, page, start, end,
|
||||||
|
@ -3366,6 +3366,9 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
path->leave_spinning = 1;
|
path->leave_spinning = 1;
|
||||||
|
|
||||||
|
start = ALIGN(start, BTRFS_I(inode)->root->sectorsize);
|
||||||
|
len = ALIGN(len, BTRFS_I(inode)->root->sectorsize);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* lookup the last file extent. We're not using i_size here
|
* lookup the last file extent. We're not using i_size here
|
||||||
* because there might be preallocation past i_size
|
* because there might be preallocation past i_size
|
||||||
|
@ -3413,7 +3416,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
|
||||||
lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0,
|
lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len, 0,
|
||||||
&cached_state, GFP_NOFS);
|
&cached_state, GFP_NOFS);
|
||||||
|
|
||||||
em = get_extent_skip_holes(inode, off, last_for_get_extent,
|
em = get_extent_skip_holes(inode, start, last_for_get_extent,
|
||||||
get_extent);
|
get_extent);
|
||||||
if (!em)
|
if (!em)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
@ -70,7 +70,7 @@ struct extent_io_ops {
|
||||||
unsigned long bio_flags);
|
unsigned long bio_flags);
|
||||||
int (*readpage_io_hook)(struct page *page, u64 start, u64 end);
|
int (*readpage_io_hook)(struct page *page, u64 start, u64 end);
|
||||||
int (*readpage_io_failed_hook)(struct bio *bio, struct page *page,
|
int (*readpage_io_failed_hook)(struct bio *bio, struct page *page,
|
||||||
u64 start, u64 end, u64 failed_mirror,
|
u64 start, u64 end, int failed_mirror,
|
||||||
struct extent_state *state);
|
struct extent_state *state);
|
||||||
int (*writepage_io_failed_hook)(struct bio *bio, struct page *page,
|
int (*writepage_io_failed_hook)(struct bio *bio, struct page *page,
|
||||||
u64 start, u64 end,
|
u64 start, u64 end,
|
||||||
|
|
|
@ -351,6 +351,11 @@ static int io_ctl_prepare_pages(struct io_ctl *io_ctl, struct inode *inode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < io_ctl->num_pages; i++) {
|
||||||
|
clear_page_dirty_for_io(io_ctl->pages[i]);
|
||||||
|
set_page_extent_mapped(io_ctl->pages[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1844,7 +1849,13 @@ int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group,
|
||||||
info = tree_search_offset(ctl, offset_to_bitmap(ctl, offset),
|
info = tree_search_offset(ctl, offset_to_bitmap(ctl, offset),
|
||||||
1, 0);
|
1, 0);
|
||||||
if (!info) {
|
if (!info) {
|
||||||
WARN_ON(1);
|
/* the tree logging code might be calling us before we
|
||||||
|
* have fully loaded the free space rbtree for this
|
||||||
|
* block group. So it is possible the entry won't
|
||||||
|
* be in the rbtree yet at all. The caching code
|
||||||
|
* will make sure not to put it in the rbtree if
|
||||||
|
* the logging code has pinned it.
|
||||||
|
*/
|
||||||
goto out_lock;
|
goto out_lock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2451,16 +2462,23 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
|
||||||
{
|
{
|
||||||
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
|
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
|
||||||
struct btrfs_free_space *entry;
|
struct btrfs_free_space *entry;
|
||||||
struct rb_node *node;
|
|
||||||
int ret = -ENOSPC;
|
int ret = -ENOSPC;
|
||||||
|
u64 bitmap_offset = offset_to_bitmap(ctl, offset);
|
||||||
|
|
||||||
if (ctl->total_bitmaps == 0)
|
if (ctl->total_bitmaps == 0)
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First check our cached list of bitmaps and see if there is an entry
|
* The bitmap that covers offset won't be in the list unless offset
|
||||||
* here that will work.
|
* is just its start offset.
|
||||||
*/
|
*/
|
||||||
|
entry = list_first_entry(bitmaps, struct btrfs_free_space, list);
|
||||||
|
if (entry->offset != bitmap_offset) {
|
||||||
|
entry = tree_search_offset(ctl, bitmap_offset, 1, 0);
|
||||||
|
if (entry && list_empty(&entry->list))
|
||||||
|
list_add(&entry->list, bitmaps);
|
||||||
|
}
|
||||||
|
|
||||||
list_for_each_entry(entry, bitmaps, list) {
|
list_for_each_entry(entry, bitmaps, list) {
|
||||||
if (entry->bytes < min_bytes)
|
if (entry->bytes < min_bytes)
|
||||||
continue;
|
continue;
|
||||||
|
@ -2471,38 +2489,10 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we do have entries on our list and we are here then we didn't find
|
* The bitmaps list has all the bitmaps that record free space
|
||||||
* anything, so go ahead and get the next entry after the last entry in
|
* starting after offset, so no more search is required.
|
||||||
* this list and start the search from there.
|
|
||||||
*/
|
*/
|
||||||
if (!list_empty(bitmaps)) {
|
|
||||||
entry = list_entry(bitmaps->prev, struct btrfs_free_space,
|
|
||||||
list);
|
|
||||||
node = rb_next(&entry->offset_index);
|
|
||||||
if (!node)
|
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
entry = rb_entry(node, struct btrfs_free_space, offset_index);
|
|
||||||
goto search;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry = tree_search_offset(ctl, offset_to_bitmap(ctl, offset), 0, 1);
|
|
||||||
if (!entry)
|
|
||||||
return -ENOSPC;
|
|
||||||
|
|
||||||
search:
|
|
||||||
node = &entry->offset_index;
|
|
||||||
do {
|
|
||||||
entry = rb_entry(node, struct btrfs_free_space, offset_index);
|
|
||||||
node = rb_next(&entry->offset_index);
|
|
||||||
if (!entry->bitmap)
|
|
||||||
continue;
|
|
||||||
if (entry->bytes < min_bytes)
|
|
||||||
continue;
|
|
||||||
ret = btrfs_bitmap_cluster(block_group, entry, cluster, offset,
|
|
||||||
bytes, min_bytes);
|
|
||||||
} while (ret && node);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2520,8 +2510,8 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
|
||||||
u64 offset, u64 bytes, u64 empty_size)
|
u64 offset, u64 bytes, u64 empty_size)
|
||||||
{
|
{
|
||||||
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
|
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
|
||||||
struct list_head bitmaps;
|
|
||||||
struct btrfs_free_space *entry, *tmp;
|
struct btrfs_free_space *entry, *tmp;
|
||||||
|
LIST_HEAD(bitmaps);
|
||||||
u64 min_bytes;
|
u64 min_bytes;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -2560,7 +2550,6 @@ int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_LIST_HEAD(&bitmaps);
|
|
||||||
ret = setup_cluster_no_bitmap(block_group, cluster, &bitmaps, offset,
|
ret = setup_cluster_no_bitmap(block_group, cluster, &bitmaps, offset,
|
||||||
bytes, min_bytes);
|
bytes, min_bytes);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
|
@ -6794,11 +6794,13 @@ static int btrfs_getattr(struct vfsmount *mnt,
|
||||||
struct dentry *dentry, struct kstat *stat)
|
struct dentry *dentry, struct kstat *stat)
|
||||||
{
|
{
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
|
u32 blocksize = inode->i_sb->s_blocksize;
|
||||||
|
|
||||||
generic_fillattr(inode, stat);
|
generic_fillattr(inode, stat);
|
||||||
stat->dev = BTRFS_I(inode)->root->anon_dev;
|
stat->dev = BTRFS_I(inode)->root->anon_dev;
|
||||||
stat->blksize = PAGE_CACHE_SIZE;
|
stat->blksize = PAGE_CACHE_SIZE;
|
||||||
stat->blocks = (inode_get_bytes(inode) +
|
stat->blocks = (ALIGN(inode_get_bytes(inode), blocksize) +
|
||||||
BTRFS_I(inode)->delalloc_bytes) >> 9;
|
ALIGN(BTRFS_I(inode)->delalloc_bytes, blocksize)) >> 9;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1216,12 +1216,12 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
|
||||||
*devstr = '\0';
|
*devstr = '\0';
|
||||||
devstr = vol_args->name;
|
devstr = vol_args->name;
|
||||||
devid = simple_strtoull(devstr, &end, 10);
|
devid = simple_strtoull(devstr, &end, 10);
|
||||||
printk(KERN_INFO "resizing devid %llu\n",
|
printk(KERN_INFO "btrfs: resizing devid %llu\n",
|
||||||
(unsigned long long)devid);
|
(unsigned long long)devid);
|
||||||
}
|
}
|
||||||
device = btrfs_find_device(root, devid, NULL, NULL);
|
device = btrfs_find_device(root, devid, NULL, NULL);
|
||||||
if (!device) {
|
if (!device) {
|
||||||
printk(KERN_INFO "resizer unable to find device %llu\n",
|
printk(KERN_INFO "btrfs: resizer unable to find device %llu\n",
|
||||||
(unsigned long long)devid);
|
(unsigned long long)devid);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
@ -1267,7 +1267,7 @@ static noinline int btrfs_ioctl_resize(struct btrfs_root *root,
|
||||||
do_div(new_size, root->sectorsize);
|
do_div(new_size, root->sectorsize);
|
||||||
new_size *= root->sectorsize;
|
new_size *= root->sectorsize;
|
||||||
|
|
||||||
printk(KERN_INFO "new size for %s is %llu\n",
|
printk(KERN_INFO "btrfs: new size for %s is %llu\n",
|
||||||
device->name, (unsigned long long)new_size);
|
device->name, (unsigned long long)new_size);
|
||||||
|
|
||||||
if (new_size > old_size) {
|
if (new_size > old_size) {
|
||||||
|
@ -2930,11 +2930,13 @@ static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
for (i = 0; i < ipath->fspath->elem_cnt; ++i) {
|
for (i = 0; i < ipath->fspath->elem_cnt; ++i) {
|
||||||
rel_ptr = ipath->fspath->val[i] - (u64)ipath->fspath->val;
|
rel_ptr = ipath->fspath->val[i] -
|
||||||
|
(u64)(unsigned long)ipath->fspath->val;
|
||||||
ipath->fspath->val[i] = rel_ptr;
|
ipath->fspath->val[i] = rel_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = copy_to_user((void *)ipa->fspath, (void *)ipath->fspath, size);
|
ret = copy_to_user((void *)(unsigned long)ipa->fspath,
|
||||||
|
(void *)(unsigned long)ipath->fspath, size);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -3017,7 +3019,8 @@ static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = copy_to_user((void *)loi->inodes, (void *)inodes, size);
|
ret = copy_to_user((void *)(unsigned long)loi->inodes,
|
||||||
|
(void *)(unsigned long)inodes, size);
|
||||||
if (ret)
|
if (ret)
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
|
|
||||||
|
|
|
@ -272,7 +272,7 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, void *ctx)
|
||||||
swarn->logical, swarn->dev->name,
|
swarn->logical, swarn->dev->name,
|
||||||
(unsigned long long)swarn->sector, root, inum, offset,
|
(unsigned long long)swarn->sector, root, inum, offset,
|
||||||
min(isize - offset, (u64)PAGE_SIZE), nlink,
|
min(isize - offset, (u64)PAGE_SIZE), nlink,
|
||||||
(char *)ipath->fspath->val[i]);
|
(char *)(unsigned long)ipath->fspath->val[i]);
|
||||||
|
|
||||||
free_ipath(ipath);
|
free_ipath(ipath);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -785,6 +785,10 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
|
||||||
|
|
||||||
btrfs_save_ino_cache(root, trans);
|
btrfs_save_ino_cache(root, trans);
|
||||||
|
|
||||||
|
/* see comments in should_cow_block() */
|
||||||
|
root->force_cow = 0;
|
||||||
|
smp_wmb();
|
||||||
|
|
||||||
if (root->commit_root != root->node) {
|
if (root->commit_root != root->node) {
|
||||||
mutex_lock(&root->fs_commit_mutex);
|
mutex_lock(&root->fs_commit_mutex);
|
||||||
switch_commit_root(root);
|
switch_commit_root(root);
|
||||||
|
@ -947,6 +951,10 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
|
||||||
btrfs_tree_unlock(old);
|
btrfs_tree_unlock(old);
|
||||||
free_extent_buffer(old);
|
free_extent_buffer(old);
|
||||||
|
|
||||||
|
/* see comments in should_cow_block() */
|
||||||
|
root->force_cow = 1;
|
||||||
|
smp_wmb();
|
||||||
|
|
||||||
btrfs_set_root_node(new_root_item, tmp);
|
btrfs_set_root_node(new_root_item, tmp);
|
||||||
/* record when the snapshot was created in key.offset */
|
/* record when the snapshot was created in key.offset */
|
||||||
key.offset = trans->transid;
|
key.offset = trans->transid;
|
||||||
|
|
|
@ -100,6 +100,12 @@ struct btrfs_device {
|
||||||
struct reada_zone *reada_curr_zone;
|
struct reada_zone *reada_curr_zone;
|
||||||
struct radix_tree_root reada_zones;
|
struct radix_tree_root reada_zones;
|
||||||
struct radix_tree_root reada_extents;
|
struct radix_tree_root reada_extents;
|
||||||
|
|
||||||
|
/* for sending down flush barriers */
|
||||||
|
struct bio *flush_bio;
|
||||||
|
struct completion flush_wait;
|
||||||
|
int nobarriers;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct btrfs_fs_devices {
|
struct btrfs_fs_devices {
|
||||||
|
|
Loading…
Reference in New Issue