for-4.15-rc2-tag
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE8rQSAMVO+zA4DBdWxWXV+ddtWDsFAlofBpkACgkQxWXV+ddt WDvtTQ//emI1QsD4N0e4BxMcZ1bcigiEk3jc4gj+biRapnMHHAHOqJbVtpK1v8gS PCTw+4uD5UOGvhBtS4kXJn8e2qxWCESWJDXwVlW0RHmWLfwd9z7ly0sBMi3oiIqH qief8CIkk3oTexiuuJ3mZGxqnDQjRGtWx2LM+bRJBWMk+jN32v2ObSlv9V505a5M 1daDBsjWojFWa8d4r3YZNJq1df2om/dwVQZ0Wk59bacIo9Xbvok0X459cOlWuv0p mjx8m8uA/z+HVdkTYlzyKpq08O8Z4shj3GrBbSnZ511gKzV+c9jJPxij5pKm3Z2z KW4Mp17+/7GSNcSsJiqnOYi+wtOrak2lD0COlZTijnY2jrv18h8ianoIM6CpzUdy +b09yuFXbPLoUfyl6vFaO/JHuvAkQdaR2tJbds6lvW+liC1ReoL4W1WcUjY6nv9f 6wTaIv0vwgrHaxeIzxKNpnsTlpHAgorFFk0/w8nLb40WX8AoJ/95lo2zws8oaFDN 0Fylu3NYhoDrJZK+D8dbsWx2eTsFVCqep4w0+iEVZl3lfuy3FZl1pu8CL7ru9vJl DNieh+lUvK1Fk+SYIoilGoriW96RbU8+jPo2W4A1ENzeMJfrNCSWtUSZZp4XT4tO 8m1PGud07XBLSxd62bAEDV3KZO2DnY1WxgXbKuIHSi9D5CI1LMo= =7UW+ -----END PGP SIGNATURE----- Merge tag 'for-4.15-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux Pull btrfs fixes from David Sterba: "We've collected some fixes in since the pre-merge window freeze. There's technically only one regression fix for 4.15, but the rest seems important and candidates for stable. - fix missing flush bio puts in error cases (is serious, but rarely happens) - fix reporting stat::st_blocks for buffered append writes - fix space cache invalidation - fix out of bound memory access when setting zlib level - fix potential memory corruption when fsync fails in the middle - fix crash in integrity checker - incremetnal send fix, path mixup for certain unlink/rename combination - pass flags to writeback so compressed writes can be throttled properly - error handling fixes" * tag 'for-4.15-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux: Btrfs: incremental send, fix wrong unlink path after renaming file btrfs: tree-checker: Fix false panic for sanity test Btrfs: fix list_add corruption and soft lockups in fsync btrfs: Fix wild memory access in compression level parser btrfs: fix deadlock when writing out space cache btrfs: clear space cache inode generation always Btrfs: fix reported number of inode blocks after buffered append writes Btrfs: move definition of the function btrfs_find_new_delalloc_bytes Btrfs: bail out gracefully rather than BUG_ON btrfs: dev_alloc_list is not protected by RCU, use normal list_del btrfs: add missing device::flush_bio puts btrfs: Fix transaction abort during failure in btrfs_rm_dev_item Btrfs: add write_flags for compression bio
This commit is contained in:
commit
26cd94744e
@ -295,7 +295,8 @@ blk_status_t btrfs_submit_compressed_write(struct inode *inode, u64 start,
|
|||||||
unsigned long len, u64 disk_start,
|
unsigned long len, u64 disk_start,
|
||||||
unsigned long compressed_len,
|
unsigned long compressed_len,
|
||||||
struct page **compressed_pages,
|
struct page **compressed_pages,
|
||||||
unsigned long nr_pages)
|
unsigned long nr_pages,
|
||||||
|
unsigned int write_flags)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
||||||
struct bio *bio = NULL;
|
struct bio *bio = NULL;
|
||||||
@ -327,7 +328,7 @@ blk_status_t btrfs_submit_compressed_write(struct inode *inode, u64 start,
|
|||||||
bdev = fs_info->fs_devices->latest_bdev;
|
bdev = fs_info->fs_devices->latest_bdev;
|
||||||
|
|
||||||
bio = btrfs_bio_alloc(bdev, first_byte);
|
bio = btrfs_bio_alloc(bdev, first_byte);
|
||||||
bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
|
bio->bi_opf = REQ_OP_WRITE | write_flags;
|
||||||
bio->bi_private = cb;
|
bio->bi_private = cb;
|
||||||
bio->bi_end_io = end_compressed_bio_write;
|
bio->bi_end_io = end_compressed_bio_write;
|
||||||
refcount_set(&cb->pending_bios, 1);
|
refcount_set(&cb->pending_bios, 1);
|
||||||
@ -374,7 +375,7 @@ blk_status_t btrfs_submit_compressed_write(struct inode *inode, u64 start,
|
|||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
|
|
||||||
bio = btrfs_bio_alloc(bdev, first_byte);
|
bio = btrfs_bio_alloc(bdev, first_byte);
|
||||||
bio_set_op_attrs(bio, REQ_OP_WRITE, 0);
|
bio->bi_opf = REQ_OP_WRITE | write_flags;
|
||||||
bio->bi_private = cb;
|
bio->bi_private = cb;
|
||||||
bio->bi_end_io = end_compressed_bio_write;
|
bio->bi_end_io = end_compressed_bio_write;
|
||||||
bio_add_page(bio, page, PAGE_SIZE, 0);
|
bio_add_page(bio, page, PAGE_SIZE, 0);
|
||||||
@ -1528,5 +1529,5 @@ unsigned int btrfs_compress_str2level(const char *str)
|
|||||||
if (str[4] == ':' && '1' <= str[5] && str[5] <= '9' && str[6] == 0)
|
if (str[4] == ':' && '1' <= str[5] && str[5] <= '9' && str[6] == 0)
|
||||||
return str[5] - '0';
|
return str[5] - '0';
|
||||||
|
|
||||||
return 0;
|
return BTRFS_ZLIB_DEFAULT_LEVEL;
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
/* Maximum size of data before compression */
|
/* Maximum size of data before compression */
|
||||||
#define BTRFS_MAX_UNCOMPRESSED (SZ_128K)
|
#define BTRFS_MAX_UNCOMPRESSED (SZ_128K)
|
||||||
|
|
||||||
|
#define BTRFS_ZLIB_DEFAULT_LEVEL 3
|
||||||
|
|
||||||
struct compressed_bio {
|
struct compressed_bio {
|
||||||
/* number of bios pending for this compressed extent */
|
/* number of bios pending for this compressed extent */
|
||||||
refcount_t pending_bios;
|
refcount_t pending_bios;
|
||||||
@ -91,7 +93,8 @@ blk_status_t btrfs_submit_compressed_write(struct inode *inode, u64 start,
|
|||||||
unsigned long len, u64 disk_start,
|
unsigned long len, u64 disk_start,
|
||||||
unsigned long compressed_len,
|
unsigned long compressed_len,
|
||||||
struct page **compressed_pages,
|
struct page **compressed_pages,
|
||||||
unsigned long nr_pages);
|
unsigned long nr_pages,
|
||||||
|
unsigned int write_flags);
|
||||||
blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
blk_status_t btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
|
||||||
int mirror_num, unsigned long bio_flags);
|
int mirror_num, unsigned long bio_flags);
|
||||||
|
|
||||||
|
@ -3180,6 +3180,7 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput);
|
|||||||
int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput,
|
int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput,
|
||||||
int nr);
|
int nr);
|
||||||
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
|
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
|
||||||
|
unsigned int extra_bits,
|
||||||
struct extent_state **cached_state, int dedupe);
|
struct extent_state **cached_state, int dedupe);
|
||||||
int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
|
int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *new_root,
|
struct btrfs_root *new_root,
|
||||||
|
@ -610,7 +610,7 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
|
|||||||
* that we don't try and read the other copies of this block, just
|
* that we don't try and read the other copies of this block, just
|
||||||
* return -EIO.
|
* return -EIO.
|
||||||
*/
|
*/
|
||||||
if (found_level == 0 && btrfs_check_leaf(root, eb)) {
|
if (found_level == 0 && btrfs_check_leaf_full(root, eb)) {
|
||||||
set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
|
set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
}
|
}
|
||||||
@ -3848,7 +3848,13 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
|
|||||||
buf->len,
|
buf->len,
|
||||||
fs_info->dirty_metadata_batch);
|
fs_info->dirty_metadata_batch);
|
||||||
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
|
#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
|
||||||
if (btrfs_header_level(buf) == 0 && btrfs_check_leaf(root, buf)) {
|
/*
|
||||||
|
* Since btrfs_mark_buffer_dirty() can be called with item pointer set
|
||||||
|
* but item data not updated.
|
||||||
|
* So here we should only check item pointers, not item data.
|
||||||
|
*/
|
||||||
|
if (btrfs_header_level(buf) == 0 &&
|
||||||
|
btrfs_check_leaf_relaxed(root, buf)) {
|
||||||
btrfs_print_leaf(buf);
|
btrfs_print_leaf(buf);
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
}
|
}
|
||||||
|
@ -3502,13 +3502,6 @@ again:
|
|||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We've already setup this transaction, go ahead and exit */
|
|
||||||
if (block_group->cache_generation == trans->transid &&
|
|
||||||
i_size_read(inode)) {
|
|
||||||
dcs = BTRFS_DC_SETUP;
|
|
||||||
goto out_put;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We want to set the generation to 0, that way if anything goes wrong
|
* We want to set the generation to 0, that way if anything goes wrong
|
||||||
* from here on out we know not to trust this cache when we load up next
|
* from here on out we know not to trust this cache when we load up next
|
||||||
@ -3532,6 +3525,13 @@ again:
|
|||||||
}
|
}
|
||||||
WARN_ON(ret);
|
WARN_ON(ret);
|
||||||
|
|
||||||
|
/* We've already setup this transaction, go ahead and exit */
|
||||||
|
if (block_group->cache_generation == trans->transid &&
|
||||||
|
i_size_read(inode)) {
|
||||||
|
dcs = BTRFS_DC_SETUP;
|
||||||
|
goto out_put;
|
||||||
|
}
|
||||||
|
|
||||||
if (i_size_read(inode) > 0) {
|
if (i_size_read(inode) > 0) {
|
||||||
ret = btrfs_check_trunc_cache_free_space(fs_info,
|
ret = btrfs_check_trunc_cache_free_space(fs_info,
|
||||||
&fs_info->global_block_rsv);
|
&fs_info->global_block_rsv);
|
||||||
|
@ -3253,7 +3253,7 @@ static noinline_for_stack int writepage_delalloc(struct inode *inode,
|
|||||||
delalloc_start,
|
delalloc_start,
|
||||||
delalloc_end,
|
delalloc_end,
|
||||||
&page_started,
|
&page_started,
|
||||||
nr_written);
|
nr_written, wbc);
|
||||||
/* File system has been set read-only */
|
/* File system has been set read-only */
|
||||||
if (ret) {
|
if (ret) {
|
||||||
SetPageError(page);
|
SetPageError(page);
|
||||||
|
@ -116,7 +116,8 @@ struct extent_io_ops {
|
|||||||
*/
|
*/
|
||||||
int (*fill_delalloc)(void *private_data, struct page *locked_page,
|
int (*fill_delalloc)(void *private_data, struct page *locked_page,
|
||||||
u64 start, u64 end, int *page_started,
|
u64 start, u64 end, int *page_started,
|
||||||
unsigned long *nr_written);
|
unsigned long *nr_written,
|
||||||
|
struct writeback_control *wbc);
|
||||||
|
|
||||||
int (*writepage_start_hook)(struct page *page, u64 start, u64 end);
|
int (*writepage_start_hook)(struct page *page, u64 start, u64 end);
|
||||||
void (*writepage_end_io_hook)(struct page *page, u64 start, u64 end,
|
void (*writepage_end_io_hook)(struct page *page, u64 start, u64 end,
|
||||||
@ -365,10 +366,11 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
|
|||||||
struct extent_state **cached_state);
|
struct extent_state **cached_state);
|
||||||
|
|
||||||
static inline int set_extent_delalloc(struct extent_io_tree *tree, u64 start,
|
static inline int set_extent_delalloc(struct extent_io_tree *tree, u64 start,
|
||||||
u64 end, struct extent_state **cached_state)
|
u64 end, unsigned int extra_bits,
|
||||||
|
struct extent_state **cached_state)
|
||||||
{
|
{
|
||||||
return set_extent_bit(tree, start, end,
|
return set_extent_bit(tree, start, end,
|
||||||
EXTENT_DELALLOC | EXTENT_UPTODATE,
|
EXTENT_DELALLOC | EXTENT_UPTODATE | extra_bits,
|
||||||
NULL, cached_state, GFP_NOFS);
|
NULL, cached_state, GFP_NOFS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
130
fs/btrfs/file.c
130
fs/btrfs/file.c
@ -477,6 +477,47 @@ static void btrfs_drop_pages(struct page **pages, size_t num_pages)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int btrfs_find_new_delalloc_bytes(struct btrfs_inode *inode,
|
||||||
|
const u64 start,
|
||||||
|
const u64 len,
|
||||||
|
struct extent_state **cached_state)
|
||||||
|
{
|
||||||
|
u64 search_start = start;
|
||||||
|
const u64 end = start + len - 1;
|
||||||
|
|
||||||
|
while (search_start < end) {
|
||||||
|
const u64 search_len = end - search_start + 1;
|
||||||
|
struct extent_map *em;
|
||||||
|
u64 em_len;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
em = btrfs_get_extent(inode, NULL, 0, search_start,
|
||||||
|
search_len, 0);
|
||||||
|
if (IS_ERR(em))
|
||||||
|
return PTR_ERR(em);
|
||||||
|
|
||||||
|
if (em->block_start != EXTENT_MAP_HOLE)
|
||||||
|
goto next;
|
||||||
|
|
||||||
|
em_len = em->len;
|
||||||
|
if (em->start < search_start)
|
||||||
|
em_len -= search_start - em->start;
|
||||||
|
if (em_len > search_len)
|
||||||
|
em_len = search_len;
|
||||||
|
|
||||||
|
ret = set_extent_bit(&inode->io_tree, search_start,
|
||||||
|
search_start + em_len - 1,
|
||||||
|
EXTENT_DELALLOC_NEW,
|
||||||
|
NULL, cached_state, GFP_NOFS);
|
||||||
|
next:
|
||||||
|
search_start = extent_map_end(em);
|
||||||
|
free_extent_map(em);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* after copy_from_user, pages need to be dirtied and we need to make
|
* after copy_from_user, pages need to be dirtied and we need to make
|
||||||
* sure holes are created between the current EOF and the start of
|
* sure holes are created between the current EOF and the start of
|
||||||
@ -497,14 +538,34 @@ int btrfs_dirty_pages(struct inode *inode, struct page **pages,
|
|||||||
u64 end_of_last_block;
|
u64 end_of_last_block;
|
||||||
u64 end_pos = pos + write_bytes;
|
u64 end_pos = pos + write_bytes;
|
||||||
loff_t isize = i_size_read(inode);
|
loff_t isize = i_size_read(inode);
|
||||||
|
unsigned int extra_bits = 0;
|
||||||
|
|
||||||
start_pos = pos & ~((u64) fs_info->sectorsize - 1);
|
start_pos = pos & ~((u64) fs_info->sectorsize - 1);
|
||||||
num_bytes = round_up(write_bytes + pos - start_pos,
|
num_bytes = round_up(write_bytes + pos - start_pos,
|
||||||
fs_info->sectorsize);
|
fs_info->sectorsize);
|
||||||
|
|
||||||
end_of_last_block = start_pos + num_bytes - 1;
|
end_of_last_block = start_pos + num_bytes - 1;
|
||||||
|
|
||||||
|
if (!btrfs_is_free_space_inode(BTRFS_I(inode))) {
|
||||||
|
if (start_pos >= isize &&
|
||||||
|
!(BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC)) {
|
||||||
|
/*
|
||||||
|
* There can't be any extents following eof in this case
|
||||||
|
* so just set the delalloc new bit for the range
|
||||||
|
* directly.
|
||||||
|
*/
|
||||||
|
extra_bits |= EXTENT_DELALLOC_NEW;
|
||||||
|
} else {
|
||||||
|
err = btrfs_find_new_delalloc_bytes(BTRFS_I(inode),
|
||||||
|
start_pos,
|
||||||
|
num_bytes, cached);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
|
err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
|
||||||
cached, 0);
|
extra_bits, cached, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -1404,47 +1465,6 @@ fail:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int btrfs_find_new_delalloc_bytes(struct btrfs_inode *inode,
|
|
||||||
const u64 start,
|
|
||||||
const u64 len,
|
|
||||||
struct extent_state **cached_state)
|
|
||||||
{
|
|
||||||
u64 search_start = start;
|
|
||||||
const u64 end = start + len - 1;
|
|
||||||
|
|
||||||
while (search_start < end) {
|
|
||||||
const u64 search_len = end - search_start + 1;
|
|
||||||
struct extent_map *em;
|
|
||||||
u64 em_len;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
em = btrfs_get_extent(inode, NULL, 0, search_start,
|
|
||||||
search_len, 0);
|
|
||||||
if (IS_ERR(em))
|
|
||||||
return PTR_ERR(em);
|
|
||||||
|
|
||||||
if (em->block_start != EXTENT_MAP_HOLE)
|
|
||||||
goto next;
|
|
||||||
|
|
||||||
em_len = em->len;
|
|
||||||
if (em->start < search_start)
|
|
||||||
em_len -= search_start - em->start;
|
|
||||||
if (em_len > search_len)
|
|
||||||
em_len = search_len;
|
|
||||||
|
|
||||||
ret = set_extent_bit(&inode->io_tree, search_start,
|
|
||||||
search_start + em_len - 1,
|
|
||||||
EXTENT_DELALLOC_NEW,
|
|
||||||
NULL, cached_state, GFP_NOFS);
|
|
||||||
next:
|
|
||||||
search_start = extent_map_end(em);
|
|
||||||
free_extent_map(em);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function locks the extent and properly waits for data=ordered extents
|
* This function locks the extent and properly waits for data=ordered extents
|
||||||
* to finish before allowing the pages to be modified if need.
|
* to finish before allowing the pages to be modified if need.
|
||||||
@ -1473,10 +1493,8 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages,
|
|||||||
+ round_up(pos + write_bytes - start_pos,
|
+ round_up(pos + write_bytes - start_pos,
|
||||||
fs_info->sectorsize) - 1;
|
fs_info->sectorsize) - 1;
|
||||||
|
|
||||||
if (start_pos < inode->vfs_inode.i_size ||
|
if (start_pos < inode->vfs_inode.i_size) {
|
||||||
(inode->flags & BTRFS_INODE_PREALLOC)) {
|
|
||||||
struct btrfs_ordered_extent *ordered;
|
struct btrfs_ordered_extent *ordered;
|
||||||
unsigned int clear_bits;
|
|
||||||
|
|
||||||
lock_extent_bits(&inode->io_tree, start_pos, last_pos,
|
lock_extent_bits(&inode->io_tree, start_pos, last_pos,
|
||||||
cached_state);
|
cached_state);
|
||||||
@ -1498,19 +1516,10 @@ lock_and_cleanup_extent_if_need(struct btrfs_inode *inode, struct page **pages,
|
|||||||
}
|
}
|
||||||
if (ordered)
|
if (ordered)
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
ret = btrfs_find_new_delalloc_bytes(inode, start_pos,
|
clear_extent_bit(&inode->io_tree, start_pos, last_pos,
|
||||||
last_pos - start_pos + 1,
|
EXTENT_DIRTY | EXTENT_DELALLOC |
|
||||||
cached_state);
|
EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
|
||||||
clear_bits = EXTENT_DIRTY | EXTENT_DELALLOC |
|
0, 0, cached_state, GFP_NOFS);
|
||||||
EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG;
|
|
||||||
if (ret)
|
|
||||||
clear_bits |= EXTENT_DELALLOC_NEW | EXTENT_LOCKED;
|
|
||||||
clear_extent_bit(&inode->io_tree, start_pos,
|
|
||||||
last_pos, clear_bits,
|
|
||||||
(clear_bits & EXTENT_LOCKED) ? 1 : 0,
|
|
||||||
0, cached_state, GFP_NOFS);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
*lockstart = start_pos;
|
*lockstart = start_pos;
|
||||||
*lockend = last_pos;
|
*lockend = last_pos;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
@ -2048,6 +2057,8 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
len = (u64)end - (u64)start + 1;
|
len = (u64)end - (u64)start + 1;
|
||||||
trace_btrfs_sync_file(file, datasync);
|
trace_btrfs_sync_file(file, datasync);
|
||||||
|
|
||||||
|
btrfs_init_log_ctx(&ctx, inode);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We write the dirty pages in the range and wait until they complete
|
* We write the dirty pages in the range and wait until they complete
|
||||||
* out of the ->i_mutex. If so, we can flush the dirty pages by
|
* out of the ->i_mutex. If so, we can flush the dirty pages by
|
||||||
@ -2194,8 +2205,6 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
}
|
}
|
||||||
trans->sync = true;
|
trans->sync = true;
|
||||||
|
|
||||||
btrfs_init_log_ctx(&ctx, inode);
|
|
||||||
|
|
||||||
ret = btrfs_log_dentry_safe(trans, root, dentry, start, end, &ctx);
|
ret = btrfs_log_dentry_safe(trans, root, dentry, start, end, &ctx);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
/* Fallthrough and commit/free transaction. */
|
/* Fallthrough and commit/free transaction. */
|
||||||
@ -2253,6 +2262,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||||||
ret = btrfs_end_transaction(trans);
|
ret = btrfs_end_transaction(trans);
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
ASSERT(list_empty(&ctx.list));
|
||||||
err = file_check_and_advance_wb_err(file);
|
err = file_check_and_advance_wb_err(file);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = err;
|
ret = err;
|
||||||
|
@ -1264,7 +1264,7 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
|
|||||||
/* Lock all pages first so we can lock the extent safely. */
|
/* Lock all pages first so we can lock the extent safely. */
|
||||||
ret = io_ctl_prepare_pages(io_ctl, inode, 0);
|
ret = io_ctl_prepare_pages(io_ctl, inode, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out_unlock;
|
||||||
|
|
||||||
lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1,
|
||||||
&cached_state);
|
&cached_state);
|
||||||
@ -1358,6 +1358,7 @@ out_nospc_locked:
|
|||||||
out_nospc:
|
out_nospc:
|
||||||
cleanup_write_cache_enospc(inode, io_ctl, &cached_state);
|
cleanup_write_cache_enospc(inode, io_ctl, &cached_state);
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA))
|
if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA))
|
||||||
up_write(&block_group->data_rwsem);
|
up_write(&block_group->data_rwsem);
|
||||||
|
|
||||||
|
@ -378,6 +378,7 @@ struct async_cow {
|
|||||||
struct page *locked_page;
|
struct page *locked_page;
|
||||||
u64 start;
|
u64 start;
|
||||||
u64 end;
|
u64 end;
|
||||||
|
unsigned int write_flags;
|
||||||
struct list_head extents;
|
struct list_head extents;
|
||||||
struct btrfs_work work;
|
struct btrfs_work work;
|
||||||
};
|
};
|
||||||
@ -857,7 +858,8 @@ retry:
|
|||||||
async_extent->ram_size,
|
async_extent->ram_size,
|
||||||
ins.objectid,
|
ins.objectid,
|
||||||
ins.offset, async_extent->pages,
|
ins.offset, async_extent->pages,
|
||||||
async_extent->nr_pages)) {
|
async_extent->nr_pages,
|
||||||
|
async_cow->write_flags)) {
|
||||||
struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
|
struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
|
||||||
struct page *p = async_extent->pages[0];
|
struct page *p = async_extent->pages[0];
|
||||||
const u64 start = async_extent->start;
|
const u64 start = async_extent->start;
|
||||||
@ -1191,7 +1193,8 @@ static noinline void async_cow_free(struct btrfs_work *work)
|
|||||||
|
|
||||||
static int cow_file_range_async(struct inode *inode, struct page *locked_page,
|
static int cow_file_range_async(struct inode *inode, struct page *locked_page,
|
||||||
u64 start, u64 end, int *page_started,
|
u64 start, u64 end, int *page_started,
|
||||||
unsigned long *nr_written)
|
unsigned long *nr_written,
|
||||||
|
unsigned int write_flags)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
|
||||||
struct async_cow *async_cow;
|
struct async_cow *async_cow;
|
||||||
@ -1208,6 +1211,7 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
|
|||||||
async_cow->root = root;
|
async_cow->root = root;
|
||||||
async_cow->locked_page = locked_page;
|
async_cow->locked_page = locked_page;
|
||||||
async_cow->start = start;
|
async_cow->start = start;
|
||||||
|
async_cow->write_flags = write_flags;
|
||||||
|
|
||||||
if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS &&
|
if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS &&
|
||||||
!btrfs_test_opt(fs_info, FORCE_COMPRESS))
|
!btrfs_test_opt(fs_info, FORCE_COMPRESS))
|
||||||
@ -1577,11 +1581,13 @@ static inline int need_force_cow(struct inode *inode, u64 start, u64 end)
|
|||||||
*/
|
*/
|
||||||
static int run_delalloc_range(void *private_data, struct page *locked_page,
|
static int run_delalloc_range(void *private_data, struct page *locked_page,
|
||||||
u64 start, u64 end, int *page_started,
|
u64 start, u64 end, int *page_started,
|
||||||
unsigned long *nr_written)
|
unsigned long *nr_written,
|
||||||
|
struct writeback_control *wbc)
|
||||||
{
|
{
|
||||||
struct inode *inode = private_data;
|
struct inode *inode = private_data;
|
||||||
int ret;
|
int ret;
|
||||||
int force_cow = need_force_cow(inode, start, end);
|
int force_cow = need_force_cow(inode, start, end);
|
||||||
|
unsigned int write_flags = wbc_to_write_flags(wbc);
|
||||||
|
|
||||||
if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW && !force_cow) {
|
if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW && !force_cow) {
|
||||||
ret = run_delalloc_nocow(inode, locked_page, start, end,
|
ret = run_delalloc_nocow(inode, locked_page, start, end,
|
||||||
@ -1596,7 +1602,8 @@ static int run_delalloc_range(void *private_data, struct page *locked_page,
|
|||||||
set_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
|
set_bit(BTRFS_INODE_HAS_ASYNC_EXTENT,
|
||||||
&BTRFS_I(inode)->runtime_flags);
|
&BTRFS_I(inode)->runtime_flags);
|
||||||
ret = cow_file_range_async(inode, locked_page, start, end,
|
ret = cow_file_range_async(inode, locked_page, start, end,
|
||||||
page_started, nr_written);
|
page_started, nr_written,
|
||||||
|
write_flags);
|
||||||
}
|
}
|
||||||
if (ret)
|
if (ret)
|
||||||
btrfs_cleanup_ordered_extents(inode, start, end - start + 1);
|
btrfs_cleanup_ordered_extents(inode, start, end - start + 1);
|
||||||
@ -2025,11 +2032,12 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
|
int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
|
||||||
|
unsigned int extra_bits,
|
||||||
struct extent_state **cached_state, int dedupe)
|
struct extent_state **cached_state, int dedupe)
|
||||||
{
|
{
|
||||||
WARN_ON((end & (PAGE_SIZE - 1)) == 0);
|
WARN_ON((end & (PAGE_SIZE - 1)) == 0);
|
||||||
return set_extent_delalloc(&BTRFS_I(inode)->io_tree, start, end,
|
return set_extent_delalloc(&BTRFS_I(inode)->io_tree, start, end,
|
||||||
cached_state);
|
extra_bits, cached_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see btrfs_writepage_start_hook for details on why this is required */
|
/* see btrfs_writepage_start_hook for details on why this is required */
|
||||||
@ -2090,7 +2098,7 @@ again:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state,
|
btrfs_set_extent_delalloc(inode, page_start, page_end, 0, &cached_state,
|
||||||
0);
|
0);
|
||||||
ClearPageChecked(page);
|
ClearPageChecked(page);
|
||||||
set_page_dirty(page);
|
set_page_dirty(page);
|
||||||
@ -4790,7 +4798,7 @@ again:
|
|||||||
EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
|
EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
|
||||||
0, 0, &cached_state, GFP_NOFS);
|
0, 0, &cached_state, GFP_NOFS);
|
||||||
|
|
||||||
ret = btrfs_set_extent_delalloc(inode, block_start, block_end,
|
ret = btrfs_set_extent_delalloc(inode, block_start, block_end, 0,
|
||||||
&cached_state, 0);
|
&cached_state, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
unlock_extent_cached(io_tree, block_start, block_end,
|
unlock_extent_cached(io_tree, block_start, block_end,
|
||||||
@ -5438,6 +5446,14 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
|
|||||||
goto out_err;
|
goto out_err;
|
||||||
|
|
||||||
btrfs_dir_item_key_to_cpu(path->nodes[0], di, location);
|
btrfs_dir_item_key_to_cpu(path->nodes[0], di, location);
|
||||||
|
if (location->type != BTRFS_INODE_ITEM_KEY &&
|
||||||
|
location->type != BTRFS_ROOT_ITEM_KEY) {
|
||||||
|
btrfs_warn(root->fs_info,
|
||||||
|
"%s gets something invalid in DIR_ITEM (name %s, directory ino %llu, location(%llu %u %llu))",
|
||||||
|
__func__, name, btrfs_ino(BTRFS_I(dir)),
|
||||||
|
location->objectid, location->type, location->offset);
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
return ret;
|
return ret;
|
||||||
@ -5754,8 +5770,6 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
|
|||||||
return inode;
|
return inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
BUG_ON(location.type != BTRFS_ROOT_ITEM_KEY);
|
|
||||||
|
|
||||||
index = srcu_read_lock(&fs_info->subvol_srcu);
|
index = srcu_read_lock(&fs_info->subvol_srcu);
|
||||||
ret = fixup_tree_root_location(fs_info, dir, dentry,
|
ret = fixup_tree_root_location(fs_info, dir, dentry,
|
||||||
&location, &sub_root);
|
&location, &sub_root);
|
||||||
@ -9150,7 +9164,7 @@ again:
|
|||||||
EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
|
EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
|
||||||
0, 0, &cached_state, GFP_NOFS);
|
0, 0, &cached_state, GFP_NOFS);
|
||||||
|
|
||||||
ret = btrfs_set_extent_delalloc(inode, page_start, end,
|
ret = btrfs_set_extent_delalloc(inode, page_start, end, 0,
|
||||||
&cached_state, 0);
|
&cached_state, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
unlock_extent_cached(io_tree, page_start, page_end,
|
unlock_extent_cached(io_tree, page_start, page_end,
|
||||||
|
@ -3268,7 +3268,8 @@ static int relocate_file_extent_cluster(struct inode *inode,
|
|||||||
nr++;
|
nr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_set_extent_delalloc(inode, page_start, page_end, NULL, 0);
|
btrfs_set_extent_delalloc(inode, page_start, page_end, 0, NULL,
|
||||||
|
0);
|
||||||
set_page_dirty(page);
|
set_page_dirty(page);
|
||||||
|
|
||||||
unlock_extent(&BTRFS_I(inode)->io_tree,
|
unlock_extent(&BTRFS_I(inode)->io_tree,
|
||||||
|
130
fs/btrfs/send.c
130
fs/btrfs/send.c
@ -3521,7 +3521,40 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if ino ino1 is an ancestor of inode ino2 in the given root.
|
* Check if inode ino2, or any of its ancestors, is inode ino1.
|
||||||
|
* Return 1 if true, 0 if false and < 0 on error.
|
||||||
|
*/
|
||||||
|
static int check_ino_in_path(struct btrfs_root *root,
|
||||||
|
const u64 ino1,
|
||||||
|
const u64 ino1_gen,
|
||||||
|
const u64 ino2,
|
||||||
|
const u64 ino2_gen,
|
||||||
|
struct fs_path *fs_path)
|
||||||
|
{
|
||||||
|
u64 ino = ino2;
|
||||||
|
|
||||||
|
if (ino1 == ino2)
|
||||||
|
return ino1_gen == ino2_gen;
|
||||||
|
|
||||||
|
while (ino > BTRFS_FIRST_FREE_OBJECTID) {
|
||||||
|
u64 parent;
|
||||||
|
u64 parent_gen;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
fs_path_reset(fs_path);
|
||||||
|
ret = get_first_ref(root, ino, &parent, &parent_gen, fs_path);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
if (parent == ino1)
|
||||||
|
return parent_gen == ino1_gen;
|
||||||
|
ino = parent;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if ino ino1 is an ancestor of inode ino2 in the given root for any
|
||||||
|
* possible path (in case ino2 is not a directory and has multiple hard links).
|
||||||
* Return 1 if true, 0 if false and < 0 on error.
|
* Return 1 if true, 0 if false and < 0 on error.
|
||||||
*/
|
*/
|
||||||
static int is_ancestor(struct btrfs_root *root,
|
static int is_ancestor(struct btrfs_root *root,
|
||||||
@ -3530,36 +3563,91 @@ static int is_ancestor(struct btrfs_root *root,
|
|||||||
const u64 ino2,
|
const u64 ino2,
|
||||||
struct fs_path *fs_path)
|
struct fs_path *fs_path)
|
||||||
{
|
{
|
||||||
u64 ino = ino2;
|
bool free_fs_path = false;
|
||||||
bool free_path = false;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct btrfs_path *path = NULL;
|
||||||
|
struct btrfs_key key;
|
||||||
|
|
||||||
if (!fs_path) {
|
if (!fs_path) {
|
||||||
fs_path = fs_path_alloc();
|
fs_path = fs_path_alloc();
|
||||||
if (!fs_path)
|
if (!fs_path)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
free_path = true;
|
free_fs_path = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ino > BTRFS_FIRST_FREE_OBJECTID) {
|
path = alloc_path_for_send();
|
||||||
u64 parent;
|
if (!path) {
|
||||||
u64 parent_gen;
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
fs_path_reset(fs_path);
|
|
||||||
ret = get_first_ref(root, ino, &parent, &parent_gen, fs_path);
|
|
||||||
if (ret < 0) {
|
|
||||||
if (ret == -ENOENT && ino == ino2)
|
|
||||||
ret = 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
if (parent == ino1) {
|
|
||||||
ret = parent_gen == ino1_gen ? 1 : 0;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
ino = parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
key.objectid = ino2;
|
||||||
|
key.type = BTRFS_INODE_REF_KEY;
|
||||||
|
key.offset = 0;
|
||||||
|
|
||||||
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
struct extent_buffer *leaf = path->nodes[0];
|
||||||
|
int slot = path->slots[0];
|
||||||
|
u32 cur_offset = 0;
|
||||||
|
u32 item_size;
|
||||||
|
|
||||||
|
if (slot >= btrfs_header_nritems(leaf)) {
|
||||||
|
ret = btrfs_next_leaf(root, path);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
if (ret > 0)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
btrfs_item_key_to_cpu(leaf, &key, slot);
|
||||||
|
if (key.objectid != ino2)
|
||||||
|
break;
|
||||||
|
if (key.type != BTRFS_INODE_REF_KEY &&
|
||||||
|
key.type != BTRFS_INODE_EXTREF_KEY)
|
||||||
|
break;
|
||||||
|
|
||||||
|
item_size = btrfs_item_size_nr(leaf, slot);
|
||||||
|
while (cur_offset < item_size) {
|
||||||
|
u64 parent;
|
||||||
|
u64 parent_gen;
|
||||||
|
|
||||||
|
if (key.type == BTRFS_INODE_EXTREF_KEY) {
|
||||||
|
unsigned long ptr;
|
||||||
|
struct btrfs_inode_extref *extref;
|
||||||
|
|
||||||
|
ptr = btrfs_item_ptr_offset(leaf, slot);
|
||||||
|
extref = (struct btrfs_inode_extref *)
|
||||||
|
(ptr + cur_offset);
|
||||||
|
parent = btrfs_inode_extref_parent(leaf,
|
||||||
|
extref);
|
||||||
|
cur_offset += sizeof(*extref);
|
||||||
|
cur_offset += btrfs_inode_extref_name_len(leaf,
|
||||||
|
extref);
|
||||||
|
} else {
|
||||||
|
parent = key.offset;
|
||||||
|
cur_offset = item_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = get_inode_info(root, parent, NULL, &parent_gen,
|
||||||
|
NULL, NULL, NULL, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
goto out;
|
||||||
|
ret = check_ino_in_path(root, ino1, ino1_gen,
|
||||||
|
parent, parent_gen, fs_path);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
path->slots[0]++;
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
if (free_path)
|
btrfs_free_path(path);
|
||||||
|
if (free_fs_path)
|
||||||
fs_path_free(fs_path);
|
fs_path_free(fs_path);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -507,9 +507,18 @@ int btrfs_parse_options(struct btrfs_fs_info *info, char *options,
|
|||||||
token == Opt_compress_force ||
|
token == Opt_compress_force ||
|
||||||
strncmp(args[0].from, "zlib", 4) == 0) {
|
strncmp(args[0].from, "zlib", 4) == 0) {
|
||||||
compress_type = "zlib";
|
compress_type = "zlib";
|
||||||
|
|
||||||
info->compress_type = BTRFS_COMPRESS_ZLIB;
|
info->compress_type = BTRFS_COMPRESS_ZLIB;
|
||||||
info->compress_level =
|
info->compress_level = BTRFS_ZLIB_DEFAULT_LEVEL;
|
||||||
btrfs_compress_str2level(args[0].from);
|
/*
|
||||||
|
* args[0] contains uninitialized data since
|
||||||
|
* for these tokens we don't expect any
|
||||||
|
* parameter.
|
||||||
|
*/
|
||||||
|
if (token != Opt_compress &&
|
||||||
|
token != Opt_compress_force)
|
||||||
|
info->compress_level =
|
||||||
|
btrfs_compress_str2level(args[0].from);
|
||||||
btrfs_set_opt(info->mount_opt, COMPRESS);
|
btrfs_set_opt(info->mount_opt, COMPRESS);
|
||||||
btrfs_clear_opt(info->mount_opt, NODATACOW);
|
btrfs_clear_opt(info->mount_opt, NODATACOW);
|
||||||
btrfs_clear_opt(info->mount_opt, NODATASUM);
|
btrfs_clear_opt(info->mount_opt, NODATASUM);
|
||||||
|
@ -114,7 +114,7 @@ static int test_find_delalloc(u32 sectorsize)
|
|||||||
* |--- delalloc ---|
|
* |--- delalloc ---|
|
||||||
* |--- search ---|
|
* |--- search ---|
|
||||||
*/
|
*/
|
||||||
set_extent_delalloc(&tmp, 0, sectorsize - 1, NULL);
|
set_extent_delalloc(&tmp, 0, sectorsize - 1, 0, NULL);
|
||||||
start = 0;
|
start = 0;
|
||||||
end = 0;
|
end = 0;
|
||||||
found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
|
found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
|
||||||
@ -145,7 +145,7 @@ static int test_find_delalloc(u32 sectorsize)
|
|||||||
test_msg("Couldn't find the locked page\n");
|
test_msg("Couldn't find the locked page\n");
|
||||||
goto out_bits;
|
goto out_bits;
|
||||||
}
|
}
|
||||||
set_extent_delalloc(&tmp, sectorsize, max_bytes - 1, NULL);
|
set_extent_delalloc(&tmp, sectorsize, max_bytes - 1, 0, NULL);
|
||||||
start = test_start;
|
start = test_start;
|
||||||
end = 0;
|
end = 0;
|
||||||
found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
|
found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
|
||||||
@ -200,7 +200,7 @@ static int test_find_delalloc(u32 sectorsize)
|
|||||||
*
|
*
|
||||||
* We are re-using our test_start from above since it works out well.
|
* We are re-using our test_start from above since it works out well.
|
||||||
*/
|
*/
|
||||||
set_extent_delalloc(&tmp, max_bytes, total_dirty - 1, NULL);
|
set_extent_delalloc(&tmp, max_bytes, total_dirty - 1, 0, NULL);
|
||||||
start = test_start;
|
start = test_start;
|
||||||
end = 0;
|
end = 0;
|
||||||
found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
|
found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
|
||||||
|
@ -968,7 +968,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
|
|||||||
btrfs_test_inode_set_ops(inode);
|
btrfs_test_inode_set_ops(inode);
|
||||||
|
|
||||||
/* [BTRFS_MAX_EXTENT_SIZE] */
|
/* [BTRFS_MAX_EXTENT_SIZE] */
|
||||||
ret = btrfs_set_extent_delalloc(inode, 0, BTRFS_MAX_EXTENT_SIZE - 1,
|
ret = btrfs_set_extent_delalloc(inode, 0, BTRFS_MAX_EXTENT_SIZE - 1, 0,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
|
test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
|
||||||
@ -984,7 +984,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
|
|||||||
/* [BTRFS_MAX_EXTENT_SIZE][sectorsize] */
|
/* [BTRFS_MAX_EXTENT_SIZE][sectorsize] */
|
||||||
ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE,
|
ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE,
|
||||||
BTRFS_MAX_EXTENT_SIZE + sectorsize - 1,
|
BTRFS_MAX_EXTENT_SIZE + sectorsize - 1,
|
||||||
NULL, 0);
|
0, NULL, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
|
test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
@ -1018,7 +1018,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
|
|||||||
ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE >> 1,
|
ret = btrfs_set_extent_delalloc(inode, BTRFS_MAX_EXTENT_SIZE >> 1,
|
||||||
(BTRFS_MAX_EXTENT_SIZE >> 1)
|
(BTRFS_MAX_EXTENT_SIZE >> 1)
|
||||||
+ sectorsize - 1,
|
+ sectorsize - 1,
|
||||||
NULL, 0);
|
0, NULL, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
|
test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
@ -1036,7 +1036,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
|
|||||||
ret = btrfs_set_extent_delalloc(inode,
|
ret = btrfs_set_extent_delalloc(inode,
|
||||||
BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize,
|
BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize,
|
||||||
(BTRFS_MAX_EXTENT_SIZE << 1) + 3 * sectorsize - 1,
|
(BTRFS_MAX_EXTENT_SIZE << 1) + 3 * sectorsize - 1,
|
||||||
NULL, 0);
|
0, NULL, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
|
test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
@ -1053,7 +1053,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
|
|||||||
*/
|
*/
|
||||||
ret = btrfs_set_extent_delalloc(inode,
|
ret = btrfs_set_extent_delalloc(inode,
|
||||||
BTRFS_MAX_EXTENT_SIZE + sectorsize,
|
BTRFS_MAX_EXTENT_SIZE + sectorsize,
|
||||||
BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1, NULL, 0);
|
BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1, 0, NULL, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
|
test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
@ -1089,7 +1089,7 @@ static int test_extent_accounting(u32 sectorsize, u32 nodesize)
|
|||||||
*/
|
*/
|
||||||
ret = btrfs_set_extent_delalloc(inode,
|
ret = btrfs_set_extent_delalloc(inode,
|
||||||
BTRFS_MAX_EXTENT_SIZE + sectorsize,
|
BTRFS_MAX_EXTENT_SIZE + sectorsize,
|
||||||
BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1, NULL, 0);
|
BTRFS_MAX_EXTENT_SIZE + 2 * sectorsize - 1, 0, NULL, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
|
test_msg("btrfs_set_extent_delalloc returned %d\n", ret);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -242,7 +242,8 @@ static int check_leaf_item(struct btrfs_root *root,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf)
|
static int check_leaf(struct btrfs_root *root, struct extent_buffer *leaf,
|
||||||
|
bool check_item_data)
|
||||||
{
|
{
|
||||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||||
/* No valid key type is 0, so all key should be larger than this key */
|
/* No valid key type is 0, so all key should be larger than this key */
|
||||||
@ -361,10 +362,15 @@ int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf)
|
|||||||
return -EUCLEAN;
|
return -EUCLEAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the item size and content meet other criteria */
|
if (check_item_data) {
|
||||||
ret = check_leaf_item(root, leaf, &key, slot);
|
/*
|
||||||
if (ret < 0)
|
* Check if the item size and content meet other
|
||||||
return ret;
|
* criteria
|
||||||
|
*/
|
||||||
|
ret = check_leaf_item(root, leaf, &key, slot);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
prev_key.objectid = key.objectid;
|
prev_key.objectid = key.objectid;
|
||||||
prev_key.type = key.type;
|
prev_key.type = key.type;
|
||||||
@ -374,6 +380,17 @@ int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf)
|
||||||
|
{
|
||||||
|
return check_leaf(root, leaf, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int btrfs_check_leaf_relaxed(struct btrfs_root *root,
|
||||||
|
struct extent_buffer *leaf)
|
||||||
|
{
|
||||||
|
return check_leaf(root, leaf, false);
|
||||||
|
}
|
||||||
|
|
||||||
int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
|
int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node)
|
||||||
{
|
{
|
||||||
unsigned long nr = btrfs_header_nritems(node);
|
unsigned long nr = btrfs_header_nritems(node);
|
||||||
|
@ -20,7 +20,19 @@
|
|||||||
#include "ctree.h"
|
#include "ctree.h"
|
||||||
#include "extent_io.h"
|
#include "extent_io.h"
|
||||||
|
|
||||||
int btrfs_check_leaf(struct btrfs_root *root, struct extent_buffer *leaf);
|
/*
|
||||||
|
* Comprehensive leaf checker.
|
||||||
|
* Will check not only the item pointers, but also every possible member
|
||||||
|
* in item data.
|
||||||
|
*/
|
||||||
|
int btrfs_check_leaf_full(struct btrfs_root *root, struct extent_buffer *leaf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Less strict leaf checker.
|
||||||
|
* Will only check item pointers, not reading item data.
|
||||||
|
*/
|
||||||
|
int btrfs_check_leaf_relaxed(struct btrfs_root *root,
|
||||||
|
struct extent_buffer *leaf);
|
||||||
int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node);
|
int btrfs_check_node(struct btrfs_root *root, struct extent_buffer *node);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4102,7 +4102,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
|
|||||||
|
|
||||||
if (ordered_io_err) {
|
if (ordered_io_err) {
|
||||||
ctx->io_err = -EIO;
|
ctx->io_err = -EIO;
|
||||||
return 0;
|
return ctx->io_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
btrfs_init_map_token(&token);
|
btrfs_init_map_token(&token);
|
||||||
|
@ -189,6 +189,7 @@ static void free_fs_devices(struct btrfs_fs_devices *fs_devices)
|
|||||||
struct btrfs_device, dev_list);
|
struct btrfs_device, dev_list);
|
||||||
list_del(&device->dev_list);
|
list_del(&device->dev_list);
|
||||||
rcu_string_free(device->name);
|
rcu_string_free(device->name);
|
||||||
|
bio_put(device->flush_bio);
|
||||||
kfree(device);
|
kfree(device);
|
||||||
}
|
}
|
||||||
kfree(fs_devices);
|
kfree(fs_devices);
|
||||||
@ -578,6 +579,7 @@ static void btrfs_free_stale_device(struct btrfs_device *cur_dev)
|
|||||||
fs_devs->num_devices--;
|
fs_devs->num_devices--;
|
||||||
list_del(&dev->dev_list);
|
list_del(&dev->dev_list);
|
||||||
rcu_string_free(dev->name);
|
rcu_string_free(dev->name);
|
||||||
|
bio_put(dev->flush_bio);
|
||||||
kfree(dev);
|
kfree(dev);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -630,6 +632,7 @@ static noinline int device_list_add(const char *path,
|
|||||||
|
|
||||||
name = rcu_string_strdup(path, GFP_NOFS);
|
name = rcu_string_strdup(path, GFP_NOFS);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
|
bio_put(device->flush_bio);
|
||||||
kfree(device);
|
kfree(device);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
@ -742,6 +745,7 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
|
|||||||
name = rcu_string_strdup(orig_dev->name->str,
|
name = rcu_string_strdup(orig_dev->name->str,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
|
bio_put(device->flush_bio);
|
||||||
kfree(device);
|
kfree(device);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -807,6 +811,7 @@ again:
|
|||||||
list_del_init(&device->dev_list);
|
list_del_init(&device->dev_list);
|
||||||
fs_devices->num_devices--;
|
fs_devices->num_devices--;
|
||||||
rcu_string_free(device->name);
|
rcu_string_free(device->name);
|
||||||
|
bio_put(device->flush_bio);
|
||||||
kfree(device);
|
kfree(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1750,20 +1755,24 @@ static int btrfs_rm_dev_item(struct btrfs_fs_info *fs_info,
|
|||||||
key.offset = device->devid;
|
key.offset = device->devid;
|
||||||
|
|
||||||
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
|
||||||
if (ret < 0)
|
if (ret) {
|
||||||
goto out;
|
if (ret > 0)
|
||||||
|
ret = -ENOENT;
|
||||||
if (ret > 0) {
|
btrfs_abort_transaction(trans, ret);
|
||||||
ret = -ENOENT;
|
btrfs_end_transaction(trans);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = btrfs_del_item(trans, root, path);
|
ret = btrfs_del_item(trans, root, path);
|
||||||
if (ret)
|
if (ret) {
|
||||||
goto out;
|
btrfs_abort_transaction(trans, ret);
|
||||||
|
btrfs_end_transaction(trans);
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
btrfs_commit_transaction(trans);
|
if (!ret)
|
||||||
|
ret = btrfs_commit_transaction(trans);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1993,7 +2002,7 @@ void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info,
|
|||||||
fs_devices = srcdev->fs_devices;
|
fs_devices = srcdev->fs_devices;
|
||||||
|
|
||||||
list_del_rcu(&srcdev->dev_list);
|
list_del_rcu(&srcdev->dev_list);
|
||||||
list_del_rcu(&srcdev->dev_alloc_list);
|
list_del(&srcdev->dev_alloc_list);
|
||||||
fs_devices->num_devices--;
|
fs_devices->num_devices--;
|
||||||
if (srcdev->missing)
|
if (srcdev->missing)
|
||||||
fs_devices->missing_devices--;
|
fs_devices->missing_devices--;
|
||||||
@ -2349,6 +2358,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
|
|||||||
|
|
||||||
name = rcu_string_strdup(device_path, GFP_KERNEL);
|
name = rcu_string_strdup(device_path, GFP_KERNEL);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
|
bio_put(device->flush_bio);
|
||||||
kfree(device);
|
kfree(device);
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
@ -2358,6 +2368,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path
|
|||||||
trans = btrfs_start_transaction(root, 0);
|
trans = btrfs_start_transaction(root, 0);
|
||||||
if (IS_ERR(trans)) {
|
if (IS_ERR(trans)) {
|
||||||
rcu_string_free(device->name);
|
rcu_string_free(device->name);
|
||||||
|
bio_put(device->flush_bio);
|
||||||
kfree(device);
|
kfree(device);
|
||||||
ret = PTR_ERR(trans);
|
ret = PTR_ERR(trans);
|
||||||
goto error;
|
goto error;
|
||||||
@ -2501,6 +2512,7 @@ error_trans:
|
|||||||
if (trans)
|
if (trans)
|
||||||
btrfs_end_transaction(trans);
|
btrfs_end_transaction(trans);
|
||||||
rcu_string_free(device->name);
|
rcu_string_free(device->name);
|
||||||
|
bio_put(device->flush_bio);
|
||||||
kfree(device);
|
kfree(device);
|
||||||
error:
|
error:
|
||||||
blkdev_put(bdev, FMODE_EXCL);
|
blkdev_put(bdev, FMODE_EXCL);
|
||||||
@ -2567,6 +2579,7 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
|
|||||||
|
|
||||||
name = rcu_string_strdup(device_path, GFP_KERNEL);
|
name = rcu_string_strdup(device_path, GFP_KERNEL);
|
||||||
if (!name) {
|
if (!name) {
|
||||||
|
bio_put(device->flush_bio);
|
||||||
kfree(device);
|
kfree(device);
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
@ -6284,6 +6297,7 @@ struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
|
|||||||
|
|
||||||
ret = find_next_devid(fs_info, &tmp);
|
ret = find_next_devid(fs_info, &tmp);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
bio_put(dev->flush_bio);
|
||||||
kfree(dev);
|
kfree(dev);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user