Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
* git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable: Btrfs: prevent RAID level downgrades when space is low Btrfs: account for missing devices in RAID allocation profiles Btrfs: EIO when we fail to read tree roots Btrfs: fix compiler warnings Btrfs: Make async snapshot ioctl more generic Btrfs: pwrite blocked when writing from the mmaped buffer of the same page Btrfs: Fix a crash when mounting a subvolume Btrfs: fix sync subvol/snapshot creation Btrfs: Fix page leak in compressed writeback path Btrfs: do not BUG if we fail to remove the orphan item for dead snapshots Btrfs: fixup return code for btrfs_del_orphan_item Btrfs: do not do fast caching if we are allocating blocks for tree_root Btrfs: deal with space cache errors better Btrfs: fix use after free in O_DIRECT
This commit is contained in:
commit
e13cf63f2b
|
@ -696,6 +696,7 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio,
|
||||||
__btree_submit_bio_done);
|
__btree_submit_bio_done);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_MIGRATION
|
||||||
static int btree_migratepage(struct address_space *mapping,
|
static int btree_migratepage(struct address_space *mapping,
|
||||||
struct page *newpage, struct page *page)
|
struct page *newpage, struct page *page)
|
||||||
{
|
{
|
||||||
|
@ -712,12 +713,9 @@ static int btree_migratepage(struct address_space *mapping,
|
||||||
if (page_has_private(page) &&
|
if (page_has_private(page) &&
|
||||||
!try_to_release_page(page, GFP_KERNEL))
|
!try_to_release_page(page, GFP_KERNEL))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
#ifdef CONFIG_MIGRATION
|
|
||||||
return migrate_page(mapping, newpage, page);
|
return migrate_page(mapping, newpage, page);
|
||||||
#else
|
|
||||||
return -ENOSYS;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int btree_writepage(struct page *page, struct writeback_control *wbc)
|
static int btree_writepage(struct page *page, struct writeback_control *wbc)
|
||||||
{
|
{
|
||||||
|
@ -1009,7 +1007,10 @@ static int find_and_setup_root(struct btrfs_root *tree_root,
|
||||||
blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
|
blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
|
||||||
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
|
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
|
||||||
blocksize, generation);
|
blocksize, generation);
|
||||||
BUG_ON(!root->node);
|
if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) {
|
||||||
|
free_extent_buffer(root->node);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
root->commit_root = btrfs_root_node(root);
|
root->commit_root = btrfs_root_node(root);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -429,6 +429,7 @@ err:
|
||||||
|
|
||||||
static int cache_block_group(struct btrfs_block_group_cache *cache,
|
static int cache_block_group(struct btrfs_block_group_cache *cache,
|
||||||
struct btrfs_trans_handle *trans,
|
struct btrfs_trans_handle *trans,
|
||||||
|
struct btrfs_root *root,
|
||||||
int load_cache_only)
|
int load_cache_only)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = cache->fs_info;
|
struct btrfs_fs_info *fs_info = cache->fs_info;
|
||||||
|
@ -442,9 +443,12 @@ static int cache_block_group(struct btrfs_block_group_cache *cache,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
||||||
* to have the normal tree locking.
|
* to have the normal tree locking. Also if we are currently trying to
|
||||||
|
* allocate blocks for the tree root we can't do the fast caching since
|
||||||
|
* we likely hold important locks.
|
||||||
*/
|
*/
|
||||||
if (!trans->transaction->in_commit) {
|
if (!trans->transaction->in_commit &&
|
||||||
|
(root && root != root->fs_info->tree_root)) {
|
||||||
spin_lock(&cache->lock);
|
spin_lock(&cache->lock);
|
||||||
if (cache->cached != BTRFS_CACHE_NO) {
|
if (cache->cached != BTRFS_CACHE_NO) {
|
||||||
spin_unlock(&cache->lock);
|
spin_unlock(&cache->lock);
|
||||||
|
@ -2741,6 +2745,7 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group,
|
||||||
struct btrfs_root *root = block_group->fs_info->tree_root;
|
struct btrfs_root *root = block_group->fs_info->tree_root;
|
||||||
struct inode *inode = NULL;
|
struct inode *inode = NULL;
|
||||||
u64 alloc_hint = 0;
|
u64 alloc_hint = 0;
|
||||||
|
int dcs = BTRFS_DC_ERROR;
|
||||||
int num_pages = 0;
|
int num_pages = 0;
|
||||||
int retries = 0;
|
int retries = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -2795,6 +2800,8 @@ again:
|
||||||
|
|
||||||
spin_lock(&block_group->lock);
|
spin_lock(&block_group->lock);
|
||||||
if (block_group->cached != BTRFS_CACHE_FINISHED) {
|
if (block_group->cached != BTRFS_CACHE_FINISHED) {
|
||||||
|
/* We're not cached, don't bother trying to write stuff out */
|
||||||
|
dcs = BTRFS_DC_WRITTEN;
|
||||||
spin_unlock(&block_group->lock);
|
spin_unlock(&block_group->lock);
|
||||||
goto out_put;
|
goto out_put;
|
||||||
}
|
}
|
||||||
|
@ -2821,6 +2828,8 @@ again:
|
||||||
ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages,
|
ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages,
|
||||||
num_pages, num_pages,
|
num_pages, num_pages,
|
||||||
&alloc_hint);
|
&alloc_hint);
|
||||||
|
if (!ret)
|
||||||
|
dcs = BTRFS_DC_SETUP;
|
||||||
btrfs_free_reserved_data_space(inode, num_pages);
|
btrfs_free_reserved_data_space(inode, num_pages);
|
||||||
out_put:
|
out_put:
|
||||||
iput(inode);
|
iput(inode);
|
||||||
|
@ -2828,10 +2837,7 @@ out_free:
|
||||||
btrfs_release_path(root, path);
|
btrfs_release_path(root, path);
|
||||||
out:
|
out:
|
||||||
spin_lock(&block_group->lock);
|
spin_lock(&block_group->lock);
|
||||||
if (ret)
|
block_group->disk_cache_state = dcs;
|
||||||
block_group->disk_cache_state = BTRFS_DC_ERROR;
|
|
||||||
else
|
|
||||||
block_group->disk_cache_state = BTRFS_DC_SETUP;
|
|
||||||
spin_unlock(&block_group->lock);
|
spin_unlock(&block_group->lock);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -3037,7 +3043,13 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
|
||||||
|
|
||||||
u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
|
u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
|
||||||
{
|
{
|
||||||
u64 num_devices = root->fs_info->fs_devices->rw_devices;
|
/*
|
||||||
|
* we add in the count of missing devices because we want
|
||||||
|
* to make sure that any RAID levels on a degraded FS
|
||||||
|
* continue to be honored.
|
||||||
|
*/
|
||||||
|
u64 num_devices = root->fs_info->fs_devices->rw_devices +
|
||||||
|
root->fs_info->fs_devices->missing_devices;
|
||||||
|
|
||||||
if (num_devices == 1)
|
if (num_devices == 1)
|
||||||
flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0);
|
flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0);
|
||||||
|
@ -4080,7 +4092,7 @@ static int update_block_group(struct btrfs_trans_handle *trans,
|
||||||
* space back to the block group, otherwise we will leak space.
|
* space back to the block group, otherwise we will leak space.
|
||||||
*/
|
*/
|
||||||
if (!alloc && cache->cached == BTRFS_CACHE_NO)
|
if (!alloc && cache->cached == BTRFS_CACHE_NO)
|
||||||
cache_block_group(cache, trans, 1);
|
cache_block_group(cache, trans, NULL, 1);
|
||||||
|
|
||||||
byte_in_group = bytenr - cache->key.objectid;
|
byte_in_group = bytenr - cache->key.objectid;
|
||||||
WARN_ON(byte_in_group > cache->key.offset);
|
WARN_ON(byte_in_group > cache->key.offset);
|
||||||
|
@ -4930,11 +4942,31 @@ search:
|
||||||
btrfs_get_block_group(block_group);
|
btrfs_get_block_group(block_group);
|
||||||
search_start = block_group->key.objectid;
|
search_start = block_group->key.objectid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this can happen if we end up cycling through all the
|
||||||
|
* raid types, but we want to make sure we only allocate
|
||||||
|
* for the proper type.
|
||||||
|
*/
|
||||||
|
if (!block_group_bits(block_group, data)) {
|
||||||
|
u64 extra = BTRFS_BLOCK_GROUP_DUP |
|
||||||
|
BTRFS_BLOCK_GROUP_RAID1 |
|
||||||
|
BTRFS_BLOCK_GROUP_RAID10;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if they asked for extra copies and this block group
|
||||||
|
* doesn't provide them, bail. This does allow us to
|
||||||
|
* fill raid0 from raid1.
|
||||||
|
*/
|
||||||
|
if ((data & extra) && !(block_group->flags & extra))
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
||||||
have_block_group:
|
have_block_group:
|
||||||
if (unlikely(block_group->cached == BTRFS_CACHE_NO)) {
|
if (unlikely(block_group->cached == BTRFS_CACHE_NO)) {
|
||||||
u64 free_percent;
|
u64 free_percent;
|
||||||
|
|
||||||
ret = cache_block_group(block_group, trans, 1);
|
ret = cache_block_group(block_group, trans,
|
||||||
|
orig_root, 1);
|
||||||
if (block_group->cached == BTRFS_CACHE_FINISHED)
|
if (block_group->cached == BTRFS_CACHE_FINISHED)
|
||||||
goto have_block_group;
|
goto have_block_group;
|
||||||
|
|
||||||
|
@ -4958,7 +4990,8 @@ have_block_group:
|
||||||
if (loop > LOOP_CACHING_NOWAIT ||
|
if (loop > LOOP_CACHING_NOWAIT ||
|
||||||
(loop > LOOP_FIND_IDEAL &&
|
(loop > LOOP_FIND_IDEAL &&
|
||||||
atomic_read(&space_info->caching_threads) < 2)) {
|
atomic_read(&space_info->caching_threads) < 2)) {
|
||||||
ret = cache_block_group(block_group, trans, 0);
|
ret = cache_block_group(block_group, trans,
|
||||||
|
orig_root, 0);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
}
|
}
|
||||||
found_uncached_bg = true;
|
found_uncached_bg = true;
|
||||||
|
@ -5515,7 +5548,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
|
||||||
u64 num_bytes = ins->offset;
|
u64 num_bytes = ins->offset;
|
||||||
|
|
||||||
block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid);
|
block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid);
|
||||||
cache_block_group(block_group, trans, 0);
|
cache_block_group(block_group, trans, NULL, 0);
|
||||||
caching_ctl = get_caching_control(block_group);
|
caching_ctl = get_caching_control(block_group);
|
||||||
|
|
||||||
if (!caching_ctl) {
|
if (!caching_ctl) {
|
||||||
|
@ -6300,9 +6333,13 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
BUG_ON(ret < 0);
|
BUG_ON(ret < 0);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
ret = btrfs_del_orphan_item(trans, tree_root,
|
/* if we fail to delete the orphan item this time
|
||||||
|
* around, it'll get picked up the next time.
|
||||||
|
*
|
||||||
|
* The most common failure here is just -ENOENT.
|
||||||
|
*/
|
||||||
|
btrfs_del_orphan_item(trans, tree_root,
|
||||||
root->root_key.objectid);
|
root->root_key.objectid);
|
||||||
BUG_ON(ret);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7878,7 +7915,14 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags)
|
||||||
u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
|
u64 stripped = BTRFS_BLOCK_GROUP_RAID0 |
|
||||||
BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
|
BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10;
|
||||||
|
|
||||||
num_devices = root->fs_info->fs_devices->rw_devices;
|
/*
|
||||||
|
* we add in the count of missing devices because we want
|
||||||
|
* to make sure that any RAID levels on a degraded FS
|
||||||
|
* continue to be honored.
|
||||||
|
*/
|
||||||
|
num_devices = root->fs_info->fs_devices->rw_devices +
|
||||||
|
root->fs_info->fs_devices->missing_devices;
|
||||||
|
|
||||||
if (num_devices == 1) {
|
if (num_devices == 1) {
|
||||||
stripped |= BTRFS_BLOCK_GROUP_DUP;
|
stripped |= BTRFS_BLOCK_GROUP_DUP;
|
||||||
stripped = flags & ~stripped;
|
stripped = flags & ~stripped;
|
||||||
|
@ -8247,7 +8291,6 @@ int btrfs_read_block_groups(struct btrfs_root *root)
|
||||||
break;
|
break;
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
|
||||||
cache = kzalloc(sizeof(*cache), GFP_NOFS);
|
cache = kzalloc(sizeof(*cache), GFP_NOFS);
|
||||||
|
|
|
@ -48,30 +48,34 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages,
|
||||||
struct page **prepared_pages,
|
struct page **prepared_pages,
|
||||||
struct iov_iter *i)
|
struct iov_iter *i)
|
||||||
{
|
{
|
||||||
size_t copied;
|
size_t copied = 0;
|
||||||
int pg = 0;
|
int pg = 0;
|
||||||
int offset = pos & (PAGE_CACHE_SIZE - 1);
|
int offset = pos & (PAGE_CACHE_SIZE - 1);
|
||||||
|
int total_copied = 0;
|
||||||
|
|
||||||
while (write_bytes > 0) {
|
while (write_bytes > 0) {
|
||||||
size_t count = min_t(size_t,
|
size_t count = min_t(size_t,
|
||||||
PAGE_CACHE_SIZE - offset, write_bytes);
|
PAGE_CACHE_SIZE - offset, write_bytes);
|
||||||
struct page *page = prepared_pages[pg];
|
struct page *page = prepared_pages[pg];
|
||||||
again:
|
/*
|
||||||
if (unlikely(iov_iter_fault_in_readable(i, count)))
|
* Copy data from userspace to the current page
|
||||||
return -EFAULT;
|
*
|
||||||
|
* Disable pagefault to avoid recursive lock since
|
||||||
/* Copy data from userspace to the current page */
|
* the pages are already locked
|
||||||
copied = iov_iter_copy_from_user(page, i, offset, count);
|
*/
|
||||||
|
pagefault_disable();
|
||||||
|
copied = iov_iter_copy_from_user_atomic(page, i, offset, count);
|
||||||
|
pagefault_enable();
|
||||||
|
|
||||||
/* Flush processor's dcache for this page */
|
/* Flush processor's dcache for this page */
|
||||||
flush_dcache_page(page);
|
flush_dcache_page(page);
|
||||||
iov_iter_advance(i, copied);
|
iov_iter_advance(i, copied);
|
||||||
write_bytes -= copied;
|
write_bytes -= copied;
|
||||||
|
total_copied += copied;
|
||||||
|
|
||||||
|
/* Return to btrfs_file_aio_write to fault page */
|
||||||
if (unlikely(copied == 0)) {
|
if (unlikely(copied == 0)) {
|
||||||
count = min_t(size_t, PAGE_CACHE_SIZE - offset,
|
break;
|
||||||
iov_iter_single_seg_count(i));
|
|
||||||
goto again;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(copied < PAGE_CACHE_SIZE - offset)) {
|
if (unlikely(copied < PAGE_CACHE_SIZE - offset)) {
|
||||||
|
@ -81,7 +85,7 @@ again:
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return total_copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -854,6 +858,8 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
|
||||||
unsigned long last_index;
|
unsigned long last_index;
|
||||||
int will_write;
|
int will_write;
|
||||||
int buffered = 0;
|
int buffered = 0;
|
||||||
|
int copied = 0;
|
||||||
|
int dirty_pages = 0;
|
||||||
|
|
||||||
will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) ||
|
will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) ||
|
||||||
(file->f_flags & O_DIRECT));
|
(file->f_flags & O_DIRECT));
|
||||||
|
@ -970,7 +976,17 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
|
||||||
WARN_ON(num_pages > nrptrs);
|
WARN_ON(num_pages > nrptrs);
|
||||||
memset(pages, 0, sizeof(struct page *) * nrptrs);
|
memset(pages, 0, sizeof(struct page *) * nrptrs);
|
||||||
|
|
||||||
ret = btrfs_delalloc_reserve_space(inode, write_bytes);
|
/*
|
||||||
|
* Fault pages before locking them in prepare_pages
|
||||||
|
* to avoid recursive lock
|
||||||
|
*/
|
||||||
|
if (unlikely(iov_iter_fault_in_readable(&i, write_bytes))) {
|
||||||
|
ret = -EFAULT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = btrfs_delalloc_reserve_space(inode,
|
||||||
|
num_pages << PAGE_CACHE_SHIFT);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -978,37 +994,49 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb,
|
||||||
pos, first_index, last_index,
|
pos, first_index, last_index,
|
||||||
write_bytes);
|
write_bytes);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
btrfs_delalloc_release_space(inode, write_bytes);
|
btrfs_delalloc_release_space(inode,
|
||||||
|
num_pages << PAGE_CACHE_SHIFT);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_copy_from_user(pos, num_pages,
|
copied = btrfs_copy_from_user(pos, num_pages,
|
||||||
write_bytes, pages, &i);
|
write_bytes, pages, &i);
|
||||||
if (ret == 0) {
|
dirty_pages = (copied + PAGE_CACHE_SIZE - 1) >>
|
||||||
|
PAGE_CACHE_SHIFT;
|
||||||
|
|
||||||
|
if (num_pages > dirty_pages) {
|
||||||
|
if (copied > 0)
|
||||||
|
atomic_inc(
|
||||||
|
&BTRFS_I(inode)->outstanding_extents);
|
||||||
|
btrfs_delalloc_release_space(inode,
|
||||||
|
(num_pages - dirty_pages) <<
|
||||||
|
PAGE_CACHE_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copied > 0) {
|
||||||
dirty_and_release_pages(NULL, root, file, pages,
|
dirty_and_release_pages(NULL, root, file, pages,
|
||||||
num_pages, pos, write_bytes);
|
dirty_pages, pos, copied);
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_drop_pages(pages, num_pages);
|
btrfs_drop_pages(pages, num_pages);
|
||||||
if (ret) {
|
|
||||||
btrfs_delalloc_release_space(inode, write_bytes);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (copied > 0) {
|
||||||
if (will_write) {
|
if (will_write) {
|
||||||
filemap_fdatawrite_range(inode->i_mapping, pos,
|
filemap_fdatawrite_range(inode->i_mapping, pos,
|
||||||
pos + write_bytes - 1);
|
pos + copied - 1);
|
||||||
} else {
|
} else {
|
||||||
balance_dirty_pages_ratelimited_nr(inode->i_mapping,
|
balance_dirty_pages_ratelimited_nr(
|
||||||
num_pages);
|
inode->i_mapping,
|
||||||
if (num_pages <
|
dirty_pages);
|
||||||
|
if (dirty_pages <
|
||||||
(root->leafsize >> PAGE_CACHE_SHIFT) + 1)
|
(root->leafsize >> PAGE_CACHE_SHIFT) + 1)
|
||||||
btrfs_btree_balance_dirty(root, 1);
|
btrfs_btree_balance_dirty(root, 1);
|
||||||
btrfs_throttle(root);
|
btrfs_throttle(root);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pos += write_bytes;
|
pos += copied;
|
||||||
num_written += write_bytes;
|
num_written += copied;
|
||||||
|
|
||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
|
|
|
@ -290,7 +290,7 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info,
|
||||||
(unsigned long long)BTRFS_I(inode)->generation,
|
(unsigned long long)BTRFS_I(inode)->generation,
|
||||||
(unsigned long long)generation,
|
(unsigned long long)generation,
|
||||||
(unsigned long long)block_group->key.objectid);
|
(unsigned long long)block_group->key.objectid);
|
||||||
goto out;
|
goto free_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!num_entries)
|
if (!num_entries)
|
||||||
|
@ -524,6 +524,12 @@ int btrfs_write_out_cache(struct btrfs_root *root,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node = rb_first(&block_group->free_space_offset);
|
||||||
|
if (!node) {
|
||||||
|
iput(inode);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
last_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT;
|
last_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT;
|
||||||
filemap_write_and_wait(inode->i_mapping);
|
filemap_write_and_wait(inode->i_mapping);
|
||||||
btrfs_wait_ordered_range(inode, inode->i_size &
|
btrfs_wait_ordered_range(inode, inode->i_size &
|
||||||
|
@ -543,10 +549,6 @@ int btrfs_write_out_cache(struct btrfs_root *root,
|
||||||
*/
|
*/
|
||||||
first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64);
|
first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64);
|
||||||
|
|
||||||
node = rb_first(&block_group->free_space_offset);
|
|
||||||
if (!node)
|
|
||||||
goto out_free;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lock all pages first so we can lock the extent safely.
|
* Lock all pages first so we can lock the extent safely.
|
||||||
*
|
*
|
||||||
|
|
|
@ -495,7 +495,7 @@ again:
|
||||||
add_async_extent(async_cow, start, num_bytes,
|
add_async_extent(async_cow, start, num_bytes,
|
||||||
total_compressed, pages, nr_pages_ret);
|
total_compressed, pages, nr_pages_ret);
|
||||||
|
|
||||||
if (start + num_bytes < end && start + num_bytes < actual_end) {
|
if (start + num_bytes < end) {
|
||||||
start += num_bytes;
|
start += num_bytes;
|
||||||
pages = NULL;
|
pages = NULL;
|
||||||
cond_resched();
|
cond_resched();
|
||||||
|
@ -5712,9 +5712,9 @@ static void btrfs_end_dio_bio(struct bio *bio, int err)
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_ERR "btrfs direct IO failed ino %lu rw %lu "
|
printk(KERN_ERR "btrfs direct IO failed ino %lu rw %lu "
|
||||||
"disk_bytenr %lu len %u err no %d\n",
|
"sector %#Lx len %u err no %d\n",
|
||||||
dip->inode->i_ino, bio->bi_rw, bio->bi_sector,
|
dip->inode->i_ino, bio->bi_rw,
|
||||||
bio->bi_size, err);
|
(unsigned long long)bio->bi_sector, bio->bi_size, err);
|
||||||
dip->errors = 1;
|
dip->errors = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -5934,8 +5934,7 @@ free_ordered:
|
||||||
*/
|
*/
|
||||||
if (write) {
|
if (write) {
|
||||||
struct btrfs_ordered_extent *ordered;
|
struct btrfs_ordered_extent *ordered;
|
||||||
ordered = btrfs_lookup_ordered_extent(inode,
|
ordered = btrfs_lookup_ordered_extent(inode, file_offset);
|
||||||
dip->logical_offset);
|
|
||||||
if (!test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags) &&
|
if (!test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags) &&
|
||||||
!test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags))
|
!test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags))
|
||||||
btrfs_free_reserved_extent(root, ordered->start,
|
btrfs_free_reserved_extent(root, ordered->start,
|
||||||
|
|
|
@ -947,23 +947,42 @@ out:
|
||||||
|
|
||||||
static noinline int btrfs_ioctl_snap_create(struct file *file,
|
static noinline int btrfs_ioctl_snap_create(struct file *file,
|
||||||
void __user *arg, int subvol,
|
void __user *arg, int subvol,
|
||||||
int async)
|
int v2)
|
||||||
{
|
{
|
||||||
struct btrfs_ioctl_vol_args *vol_args = NULL;
|
struct btrfs_ioctl_vol_args *vol_args = NULL;
|
||||||
struct btrfs_ioctl_async_vol_args *async_vol_args = NULL;
|
struct btrfs_ioctl_vol_args_v2 *vol_args_v2 = NULL;
|
||||||
char *name;
|
char *name;
|
||||||
u64 fd;
|
u64 fd;
|
||||||
u64 transid = 0;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (async) {
|
if (v2) {
|
||||||
async_vol_args = memdup_user(arg, sizeof(*async_vol_args));
|
u64 transid = 0;
|
||||||
if (IS_ERR(async_vol_args))
|
u64 *ptr = NULL;
|
||||||
return PTR_ERR(async_vol_args);
|
|
||||||
|
|
||||||
name = async_vol_args->name;
|
vol_args_v2 = memdup_user(arg, sizeof(*vol_args_v2));
|
||||||
fd = async_vol_args->fd;
|
if (IS_ERR(vol_args_v2))
|
||||||
async_vol_args->name[BTRFS_SNAPSHOT_NAME_MAX] = '\0';
|
return PTR_ERR(vol_args_v2);
|
||||||
|
|
||||||
|
if (vol_args_v2->flags & ~BTRFS_SUBVOL_CREATE_ASYNC) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = vol_args_v2->name;
|
||||||
|
fd = vol_args_v2->fd;
|
||||||
|
vol_args_v2->name[BTRFS_SUBVOL_NAME_MAX] = '\0';
|
||||||
|
|
||||||
|
if (vol_args_v2->flags & BTRFS_SUBVOL_CREATE_ASYNC)
|
||||||
|
ptr = &transid;
|
||||||
|
|
||||||
|
ret = btrfs_ioctl_snap_create_transid(file, name, fd,
|
||||||
|
subvol, ptr);
|
||||||
|
|
||||||
|
if (ret == 0 && ptr &&
|
||||||
|
copy_to_user(arg +
|
||||||
|
offsetof(struct btrfs_ioctl_vol_args_v2,
|
||||||
|
transid), ptr, sizeof(*ptr)))
|
||||||
|
ret = -EFAULT;
|
||||||
} else {
|
} else {
|
||||||
vol_args = memdup_user(arg, sizeof(*vol_args));
|
vol_args = memdup_user(arg, sizeof(*vol_args));
|
||||||
if (IS_ERR(vol_args))
|
if (IS_ERR(vol_args))
|
||||||
|
@ -971,20 +990,13 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
|
||||||
name = vol_args->name;
|
name = vol_args->name;
|
||||||
fd = vol_args->fd;
|
fd = vol_args->fd;
|
||||||
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
|
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
|
||||||
}
|
|
||||||
|
|
||||||
ret = btrfs_ioctl_snap_create_transid(file, name, fd,
|
ret = btrfs_ioctl_snap_create_transid(file, name, fd,
|
||||||
subvol, &transid);
|
subvol, NULL);
|
||||||
|
|
||||||
if (!ret && async) {
|
|
||||||
if (copy_to_user(arg +
|
|
||||||
offsetof(struct btrfs_ioctl_async_vol_args,
|
|
||||||
transid), &transid, sizeof(transid)))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
kfree(vol_args);
|
kfree(vol_args);
|
||||||
kfree(async_vol_args);
|
kfree(vol_args_v2);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2246,7 +2258,7 @@ long btrfs_ioctl(struct file *file, unsigned int
|
||||||
return btrfs_ioctl_getversion(file, argp);
|
return btrfs_ioctl_getversion(file, argp);
|
||||||
case BTRFS_IOC_SNAP_CREATE:
|
case BTRFS_IOC_SNAP_CREATE:
|
||||||
return btrfs_ioctl_snap_create(file, argp, 0, 0);
|
return btrfs_ioctl_snap_create(file, argp, 0, 0);
|
||||||
case BTRFS_IOC_SNAP_CREATE_ASYNC:
|
case BTRFS_IOC_SNAP_CREATE_V2:
|
||||||
return btrfs_ioctl_snap_create(file, argp, 0, 1);
|
return btrfs_ioctl_snap_create(file, argp, 0, 1);
|
||||||
case BTRFS_IOC_SUBVOL_CREATE:
|
case BTRFS_IOC_SUBVOL_CREATE:
|
||||||
return btrfs_ioctl_snap_create(file, argp, 1, 0);
|
return btrfs_ioctl_snap_create(file, argp, 1, 0);
|
||||||
|
|
|
@ -30,11 +30,15 @@ struct btrfs_ioctl_vol_args {
|
||||||
char name[BTRFS_PATH_NAME_MAX + 1];
|
char name[BTRFS_PATH_NAME_MAX + 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BTRFS_SNAPSHOT_NAME_MAX 4079
|
#define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0)
|
||||||
struct btrfs_ioctl_async_vol_args {
|
|
||||||
|
#define BTRFS_SUBVOL_NAME_MAX 4039
|
||||||
|
struct btrfs_ioctl_vol_args_v2 {
|
||||||
__s64 fd;
|
__s64 fd;
|
||||||
__u64 transid;
|
__u64 transid;
|
||||||
char name[BTRFS_SNAPSHOT_NAME_MAX + 1];
|
__u64 flags;
|
||||||
|
__u64 unused[4];
|
||||||
|
char name[BTRFS_SUBVOL_NAME_MAX + 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BTRFS_INO_LOOKUP_PATH_MAX 4080
|
#define BTRFS_INO_LOOKUP_PATH_MAX 4080
|
||||||
|
@ -187,6 +191,6 @@ struct btrfs_ioctl_space_args {
|
||||||
struct btrfs_ioctl_space_args)
|
struct btrfs_ioctl_space_args)
|
||||||
#define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64)
|
#define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64)
|
||||||
#define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)
|
#define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)
|
||||||
#define BTRFS_IOC_SNAP_CREATE_ASYNC _IOW(BTRFS_IOCTL_MAGIC, 23, \
|
#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
|
||||||
struct btrfs_ioctl_async_vol_args)
|
struct btrfs_ioctl_vol_args_v2)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -56,8 +56,12 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
||||||
if (ret)
|
if (ret < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
if (ret) {
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
ret = btrfs_del_item(trans, root, path);
|
ret = btrfs_del_item(trans, root, path);
|
||||||
|
|
||||||
|
|
|
@ -685,9 +685,9 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
|
||||||
mutex_unlock(&root->d_inode->i_mutex);
|
mutex_unlock(&root->d_inode->i_mutex);
|
||||||
|
|
||||||
if (IS_ERR(new_root)) {
|
if (IS_ERR(new_root)) {
|
||||||
|
dput(root);
|
||||||
deactivate_locked_super(s);
|
deactivate_locked_super(s);
|
||||||
error = PTR_ERR(new_root);
|
error = PTR_ERR(new_root);
|
||||||
dput(root);
|
|
||||||
goto error_free_subvol_name;
|
goto error_free_subvol_name;
|
||||||
}
|
}
|
||||||
if (!new_root->d_inode) {
|
if (!new_root->d_inode) {
|
||||||
|
|
|
@ -412,12 +412,16 @@ static noinline int device_list_add(const char *path,
|
||||||
|
|
||||||
device->fs_devices = fs_devices;
|
device->fs_devices = fs_devices;
|
||||||
fs_devices->num_devices++;
|
fs_devices->num_devices++;
|
||||||
} else if (strcmp(device->name, path)) {
|
} else if (!device->name || strcmp(device->name, path)) {
|
||||||
name = kstrdup(path, GFP_NOFS);
|
name = kstrdup(path, GFP_NOFS);
|
||||||
if (!name)
|
if (!name)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
kfree(device->name);
|
kfree(device->name);
|
||||||
device->name = name;
|
device->name = name;
|
||||||
|
if (device->missing) {
|
||||||
|
fs_devices->missing_devices--;
|
||||||
|
device->missing = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_transid > fs_devices->latest_trans) {
|
if (found_transid > fs_devices->latest_trans) {
|
||||||
|
@ -1236,6 +1240,9 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
|
||||||
|
|
||||||
device->fs_devices->num_devices--;
|
device->fs_devices->num_devices--;
|
||||||
|
|
||||||
|
if (device->missing)
|
||||||
|
root->fs_info->fs_devices->missing_devices--;
|
||||||
|
|
||||||
next_device = list_entry(root->fs_info->fs_devices->devices.next,
|
next_device = list_entry(root->fs_info->fs_devices->devices.next,
|
||||||
struct btrfs_device, dev_list);
|
struct btrfs_device, dev_list);
|
||||||
if (device->bdev == root->fs_info->sb->s_bdev)
|
if (device->bdev == root->fs_info->sb->s_bdev)
|
||||||
|
@ -3080,7 +3087,9 @@ static struct btrfs_device *add_missing_dev(struct btrfs_root *root,
|
||||||
device->devid = devid;
|
device->devid = devid;
|
||||||
device->work.func = pending_bios_fn;
|
device->work.func = pending_bios_fn;
|
||||||
device->fs_devices = fs_devices;
|
device->fs_devices = fs_devices;
|
||||||
|
device->missing = 1;
|
||||||
fs_devices->num_devices++;
|
fs_devices->num_devices++;
|
||||||
|
fs_devices->missing_devices++;
|
||||||
spin_lock_init(&device->io_lock);
|
spin_lock_init(&device->io_lock);
|
||||||
INIT_LIST_HEAD(&device->dev_alloc_list);
|
INIT_LIST_HEAD(&device->dev_alloc_list);
|
||||||
memcpy(device->uuid, dev_uuid, BTRFS_UUID_SIZE);
|
memcpy(device->uuid, dev_uuid, BTRFS_UUID_SIZE);
|
||||||
|
@ -3278,6 +3287,15 @@ static int read_one_dev(struct btrfs_root *root,
|
||||||
device = add_missing_dev(root, devid, dev_uuid);
|
device = add_missing_dev(root, devid, dev_uuid);
|
||||||
if (!device)
|
if (!device)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
} else if (!device->missing) {
|
||||||
|
/*
|
||||||
|
* this happens when a device that was properly setup
|
||||||
|
* in the device info lists suddenly goes bad.
|
||||||
|
* device->bdev is NULL, and so we have to set
|
||||||
|
* device->missing to one here
|
||||||
|
*/
|
||||||
|
root->fs_info->fs_devices->missing_devices++;
|
||||||
|
device->missing = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ struct btrfs_device {
|
||||||
|
|
||||||
int writeable;
|
int writeable;
|
||||||
int in_fs_metadata;
|
int in_fs_metadata;
|
||||||
|
int missing;
|
||||||
|
|
||||||
spinlock_t io_lock;
|
spinlock_t io_lock;
|
||||||
|
|
||||||
|
@ -93,6 +94,7 @@ struct btrfs_fs_devices {
|
||||||
u64 num_devices;
|
u64 num_devices;
|
||||||
u64 open_devices;
|
u64 open_devices;
|
||||||
u64 rw_devices;
|
u64 rw_devices;
|
||||||
|
u64 missing_devices;
|
||||||
u64 total_rw_bytes;
|
u64 total_rw_bytes;
|
||||||
struct block_device *latest_bdev;
|
struct block_device *latest_bdev;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue