|
@@ -263,7 +263,7 @@ static noinline int cow_file_range_inline(struct btrfs_root *root,
|
|
|
data_len = compressed_size;
|
|
|
|
|
|
if (start > 0 ||
|
|
|
- actual_end > PAGE_CACHE_SIZE ||
|
|
|
+ actual_end > root->sectorsize ||
|
|
|
data_len > BTRFS_MAX_INLINE_DATA_SIZE(root) ||
|
|
|
(!compressed_size &&
|
|
|
(actual_end & (root->sectorsize - 1)) == 0) ||
|
|
@@ -2002,7 +2002,8 @@ again:
|
|
|
if (PagePrivate2(page))
|
|
|
goto out;
|
|
|
|
|
|
- ordered = btrfs_lookup_ordered_extent(inode, page_start);
|
|
|
+ ordered = btrfs_lookup_ordered_range(inode, page_start,
|
|
|
+ PAGE_CACHE_SIZE);
|
|
|
if (ordered) {
|
|
|
unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start,
|
|
|
page_end, &cached_state, GFP_NOFS);
|
|
@@ -4013,7 +4014,8 @@ err:
|
|
|
btrfs_i_size_write(dir, dir->i_size - name_len * 2);
|
|
|
inode_inc_iversion(inode);
|
|
|
inode_inc_iversion(dir);
|
|
|
- inode->i_ctime = dir->i_mtime = dir->i_ctime = CURRENT_TIME;
|
|
|
+ inode->i_ctime = dir->i_mtime =
|
|
|
+ dir->i_ctime = current_fs_time(inode->i_sb);
|
|
|
ret = btrfs_update_inode(trans, root, dir);
|
|
|
out:
|
|
|
return ret;
|
|
@@ -4156,7 +4158,7 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
|
|
|
|
|
|
btrfs_i_size_write(dir, dir->i_size - name_len * 2);
|
|
|
inode_inc_iversion(dir);
|
|
|
- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
|
|
|
+ dir->i_mtime = dir->i_ctime = current_fs_time(dir->i_sb);
|
|
|
ret = btrfs_update_inode_fallback(trans, root, dir);
|
|
|
if (ret)
|
|
|
btrfs_abort_transaction(trans, root, ret);
|
|
@@ -4211,11 +4213,20 @@ static int truncate_space_check(struct btrfs_trans_handle *trans,
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
|
+ /*
|
|
|
+ * This is only used to apply pressure to the enospc system, we don't
|
|
|
+ * intend to use this reservation at all.
|
|
|
+ */
|
|
|
bytes_deleted = btrfs_csum_bytes_to_leaves(root, bytes_deleted);
|
|
|
+ bytes_deleted *= root->nodesize;
|
|
|
ret = btrfs_block_rsv_add(root, &root->fs_info->trans_block_rsv,
|
|
|
bytes_deleted, BTRFS_RESERVE_NO_FLUSH);
|
|
|
- if (!ret)
|
|
|
+ if (!ret) {
|
|
|
+ trace_btrfs_space_reservation(root->fs_info, "transaction",
|
|
|
+ trans->transid,
|
|
|
+ bytes_deleted, 1);
|
|
|
trans->bytes_reserved += bytes_deleted;
|
|
|
+ }
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
@@ -4248,7 +4259,8 @@ static int truncate_inline_extent(struct inode *inode,
|
|
|
* read the extent item from disk (data not in the page cache).
|
|
|
*/
|
|
|
btrfs_release_path(path);
|
|
|
- return btrfs_truncate_page(inode, offset, page_end - offset, 0);
|
|
|
+ return btrfs_truncate_block(inode, offset, page_end - offset,
|
|
|
+ 0);
|
|
|
}
|
|
|
|
|
|
btrfs_set_file_extent_ram_bytes(leaf, fi, size);
|
|
@@ -4601,17 +4613,17 @@ error:
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * btrfs_truncate_page - read, zero a chunk and write a page
|
|
|
+ * btrfs_truncate_block - read, zero a chunk and write a block
|
|
|
* @inode - inode that we're zeroing
|
|
|
* @from - the offset to start zeroing
|
|
|
* @len - the length to zero, 0 to zero the entire range respective to the
|
|
|
* offset
|
|
|
* @front - zero up to the offset instead of from the offset on
|
|
|
*
|
|
|
- * This will find the page for the "from" offset and cow the page and zero the
|
|
|
+ * This will find the block for the "from" offset and cow the block and zero the
|
|
|
* part we want to zero. This is used with truncate and hole punching.
|
|
|
*/
|
|
|
-int btrfs_truncate_page(struct inode *inode, loff_t from, loff_t len,
|
|
|
+int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len,
|
|
|
int front)
|
|
|
{
|
|
|
struct address_space *mapping = inode->i_mapping;
|
|
@@ -4622,18 +4634,19 @@ int btrfs_truncate_page(struct inode *inode, loff_t from, loff_t len,
|
|
|
char *kaddr;
|
|
|
u32 blocksize = root->sectorsize;
|
|
|
pgoff_t index = from >> PAGE_CACHE_SHIFT;
|
|
|
- unsigned offset = from & (PAGE_CACHE_SIZE-1);
|
|
|
+ unsigned offset = from & (blocksize - 1);
|
|
|
struct page *page;
|
|
|
gfp_t mask = btrfs_alloc_write_mask(mapping);
|
|
|
int ret = 0;
|
|
|
- u64 page_start;
|
|
|
- u64 page_end;
|
|
|
+ u64 block_start;
|
|
|
+ u64 block_end;
|
|
|
|
|
|
if ((offset & (blocksize - 1)) == 0 &&
|
|
|
(!len || ((len & (blocksize - 1)) == 0)))
|
|
|
goto out;
|
|
|
+
|
|
|
ret = btrfs_delalloc_reserve_space(inode,
|
|
|
- round_down(from, PAGE_CACHE_SIZE), PAGE_CACHE_SIZE);
|
|
|
+ round_down(from, blocksize), blocksize);
|
|
|
if (ret)
|
|
|
goto out;
|
|
|
|
|
@@ -4641,14 +4654,14 @@ again:
|
|
|
page = find_or_create_page(mapping, index, mask);
|
|
|
if (!page) {
|
|
|
btrfs_delalloc_release_space(inode,
|
|
|
- round_down(from, PAGE_CACHE_SIZE),
|
|
|
- PAGE_CACHE_SIZE);
|
|
|
+ round_down(from, blocksize),
|
|
|
+ blocksize);
|
|
|
ret = -ENOMEM;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- page_start = page_offset(page);
|
|
|
- page_end = page_start + PAGE_CACHE_SIZE - 1;
|
|
|
+ block_start = round_down(from, blocksize);
|
|
|
+ block_end = block_start + blocksize - 1;
|
|
|
|
|
|
if (!PageUptodate(page)) {
|
|
|
ret = btrfs_readpage(NULL, page);
|
|
@@ -4665,12 +4678,12 @@ again:
|
|
|
}
|
|
|
wait_on_page_writeback(page);
|
|
|
|
|
|
- lock_extent_bits(io_tree, page_start, page_end, &cached_state);
|
|
|
+ lock_extent_bits(io_tree, block_start, block_end, &cached_state);
|
|
|
set_page_extent_mapped(page);
|
|
|
|
|
|
- ordered = btrfs_lookup_ordered_extent(inode, page_start);
|
|
|
+ ordered = btrfs_lookup_ordered_extent(inode, block_start);
|
|
|
if (ordered) {
|
|
|
- unlock_extent_cached(io_tree, page_start, page_end,
|
|
|
+ unlock_extent_cached(io_tree, block_start, block_end,
|
|
|
&cached_state, GFP_NOFS);
|
|
|
unlock_page(page);
|
|
|
page_cache_release(page);
|
|
@@ -4679,39 +4692,41 @@ again:
|
|
|
goto again;
|
|
|
}
|
|
|
|
|
|
- clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, page_end,
|
|
|
+ clear_extent_bit(&BTRFS_I(inode)->io_tree, block_start, block_end,
|
|
|
EXTENT_DIRTY | EXTENT_DELALLOC |
|
|
|
EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
|
|
|
0, 0, &cached_state, GFP_NOFS);
|
|
|
|
|
|
- ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
|
|
|
+ ret = btrfs_set_extent_delalloc(inode, block_start, block_end,
|
|
|
&cached_state);
|
|
|
if (ret) {
|
|
|
- unlock_extent_cached(io_tree, page_start, page_end,
|
|
|
+ unlock_extent_cached(io_tree, block_start, block_end,
|
|
|
&cached_state, GFP_NOFS);
|
|
|
goto out_unlock;
|
|
|
}
|
|
|
|
|
|
- if (offset != PAGE_CACHE_SIZE) {
|
|
|
+ if (offset != blocksize) {
|
|
|
if (!len)
|
|
|
- len = PAGE_CACHE_SIZE - offset;
|
|
|
+ len = blocksize - offset;
|
|
|
kaddr = kmap(page);
|
|
|
if (front)
|
|
|
- memset(kaddr, 0, offset);
|
|
|
+ memset(kaddr + (block_start - page_offset(page)),
|
|
|
+ 0, offset);
|
|
|
else
|
|
|
- memset(kaddr + offset, 0, len);
|
|
|
+ memset(kaddr + (block_start - page_offset(page)) + offset,
|
|
|
+ 0, len);
|
|
|
flush_dcache_page(page);
|
|
|
kunmap(page);
|
|
|
}
|
|
|
ClearPageChecked(page);
|
|
|
set_page_dirty(page);
|
|
|
- unlock_extent_cached(io_tree, page_start, page_end, &cached_state,
|
|
|
+ unlock_extent_cached(io_tree, block_start, block_end, &cached_state,
|
|
|
GFP_NOFS);
|
|
|
|
|
|
out_unlock:
|
|
|
if (ret)
|
|
|
- btrfs_delalloc_release_space(inode, page_start,
|
|
|
- PAGE_CACHE_SIZE);
|
|
|
+ btrfs_delalloc_release_space(inode, block_start,
|
|
|
+ blocksize);
|
|
|
unlock_page(page);
|
|
|
page_cache_release(page);
|
|
|
out:
|
|
@@ -4782,11 +4797,11 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
|
|
|
int err = 0;
|
|
|
|
|
|
/*
|
|
|
- * If our size started in the middle of a page we need to zero out the
|
|
|
- * rest of the page before we expand the i_size, otherwise we could
|
|
|
+ * If our size started in the middle of a block we need to zero out the
|
|
|
+ * rest of the block before we expand the i_size, otherwise we could
|
|
|
* expose stale data.
|
|
|
*/
|
|
|
- err = btrfs_truncate_page(inode, oldsize, 0, 0);
|
|
|
+ err = btrfs_truncate_block(inode, oldsize, 0, 0);
|
|
|
if (err)
|
|
|
return err;
|
|
|
|
|
@@ -4895,7 +4910,6 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
|
|
|
}
|
|
|
|
|
|
if (newsize > oldsize) {
|
|
|
- truncate_pagecache(inode, newsize);
|
|
|
/*
|
|
|
* Don't do an expanding truncate while snapshoting is ongoing.
|
|
|
* This is to ensure the snapshot captures a fully consistent
|
|
@@ -4918,6 +4932,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
|
|
|
|
|
|
i_size_write(inode, newsize);
|
|
|
btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL);
|
|
|
+ pagecache_isize_extended(inode, oldsize, newsize);
|
|
|
ret = btrfs_update_inode(trans, root, inode);
|
|
|
btrfs_end_write_no_snapshoting(root);
|
|
|
btrfs_end_transaction(trans, root);
|
|
@@ -5588,7 +5603,7 @@ static struct inode *new_simple_dir(struct super_block *s,
|
|
|
inode->i_op = &btrfs_dir_ro_inode_operations;
|
|
|
inode->i_fop = &simple_dir_operations;
|
|
|
inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO;
|
|
|
- inode->i_mtime = CURRENT_TIME;
|
|
|
+ inode->i_mtime = current_fs_time(inode->i_sb);
|
|
|
inode->i_atime = inode->i_mtime;
|
|
|
inode->i_ctime = inode->i_mtime;
|
|
|
BTRFS_I(inode)->i_otime = inode->i_mtime;
|
|
@@ -5790,7 +5805,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
|
|
|
if (name_len <= sizeof(tmp_name)) {
|
|
|
name_ptr = tmp_name;
|
|
|
} else {
|
|
|
- name_ptr = kmalloc(name_len, GFP_NOFS);
|
|
|
+ name_ptr = kmalloc(name_len, GFP_KERNEL);
|
|
|
if (!name_ptr) {
|
|
|
ret = -ENOMEM;
|
|
|
goto err;
|
|
@@ -6172,7 +6187,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
|
|
inode_init_owner(inode, dir, mode);
|
|
|
inode_set_bytes(inode, 0);
|
|
|
|
|
|
- inode->i_mtime = CURRENT_TIME;
|
|
|
+ inode->i_mtime = current_fs_time(inode->i_sb);
|
|
|
inode->i_atime = inode->i_mtime;
|
|
|
inode->i_ctime = inode->i_mtime;
|
|
|
BTRFS_I(inode)->i_otime = inode->i_mtime;
|
|
@@ -6285,7 +6300,8 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
|
|
|
btrfs_i_size_write(parent_inode, parent_inode->i_size +
|
|
|
name_len * 2);
|
|
|
inode_inc_iversion(parent_inode);
|
|
|
- parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
|
|
|
+ parent_inode->i_mtime = parent_inode->i_ctime =
|
|
|
+ current_fs_time(parent_inode->i_sb);
|
|
|
ret = btrfs_update_inode(trans, root, parent_inode);
|
|
|
if (ret)
|
|
|
btrfs_abort_transaction(trans, root, ret);
|
|
@@ -6503,7 +6519,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
|
|
BTRFS_I(inode)->dir_index = 0ULL;
|
|
|
inc_nlink(inode);
|
|
|
inode_inc_iversion(inode);
|
|
|
- inode->i_ctime = CURRENT_TIME;
|
|
|
+ inode->i_ctime = current_fs_time(inode->i_sb);
|
|
|
ihold(inode);
|
|
|
set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags);
|
|
|
|
|
@@ -7414,7 +7430,26 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
|
|
|
cached_state, GFP_NOFS);
|
|
|
|
|
|
if (ordered) {
|
|
|
- btrfs_start_ordered_extent(inode, ordered, 1);
|
|
|
+ /*
|
|
|
+ * If we are doing a DIO read and the ordered extent we
|
|
|
+ * found is for a buffered write, we can not wait for it
|
|
|
+ * to complete and retry, because if we do so we can
|
|
|
+ * deadlock with concurrent buffered writes on page
|
|
|
+ * locks. This happens only if our DIO read covers more
|
|
|
+ * than one extent map, if at this point has already
|
|
|
+ * created an ordered extent for a previous extent map
|
|
|
+ * and locked its range in the inode's io tree, and a
|
|
|
+ * concurrent write against that previous extent map's
|
|
|
+ * range and this range started (we unlock the ranges
|
|
|
+ * in the io tree only when the bios complete and
|
|
|
+ * buffered writes always lock pages before attempting
|
|
|
+ * to lock range in the io tree).
|
|
|
+ */
|
|
|
+ if (writing ||
|
|
|
+ test_bit(BTRFS_ORDERED_DIRECT, &ordered->flags))
|
|
|
+ btrfs_start_ordered_extent(inode, ordered, 1);
|
|
|
+ else
|
|
|
+ ret = -ENOTBLK;
|
|
|
btrfs_put_ordered_extent(ordered);
|
|
|
} else {
|
|
|
/*
|
|
@@ -7431,9 +7466,11 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
|
|
|
* that page.
|
|
|
*/
|
|
|
ret = -ENOTBLK;
|
|
|
- break;
|
|
|
}
|
|
|
|
|
|
+ if (ret)
|
|
|
+ break;
|
|
|
+
|
|
|
cond_resched();
|
|
|
}
|
|
|
|
|
@@ -7764,9 +7801,9 @@ static int btrfs_check_dio_repairable(struct inode *inode,
|
|
|
}
|
|
|
|
|
|
static int dio_read_error(struct inode *inode, struct bio *failed_bio,
|
|
|
- struct page *page, u64 start, u64 end,
|
|
|
- int failed_mirror, bio_end_io_t *repair_endio,
|
|
|
- void *repair_arg)
|
|
|
+ struct page *page, unsigned int pgoff,
|
|
|
+ u64 start, u64 end, int failed_mirror,
|
|
|
+ bio_end_io_t *repair_endio, void *repair_arg)
|
|
|
{
|
|
|
struct io_failure_record *failrec;
|
|
|
struct bio *bio;
|
|
@@ -7787,7 +7824,9 @@ static int dio_read_error(struct inode *inode, struct bio *failed_bio,
|
|
|
return -EIO;
|
|
|
}
|
|
|
|
|
|
- if (failed_bio->bi_vcnt > 1)
|
|
|
+ if ((failed_bio->bi_vcnt > 1)
|
|
|
+ || (failed_bio->bi_io_vec->bv_len
|
|
|
+ > BTRFS_I(inode)->root->sectorsize))
|
|
|
read_mode = READ_SYNC | REQ_FAILFAST_DEV;
|
|
|
else
|
|
|
read_mode = READ_SYNC;
|
|
@@ -7795,7 +7834,7 @@ static int dio_read_error(struct inode *inode, struct bio *failed_bio,
|
|
|
isector = start - btrfs_io_bio(failed_bio)->logical;
|
|
|
isector >>= inode->i_sb->s_blocksize_bits;
|
|
|
bio = btrfs_create_repair_bio(inode, failed_bio, failrec, page,
|
|
|
- 0, isector, repair_endio, repair_arg);
|
|
|
+ pgoff, isector, repair_endio, repair_arg);
|
|
|
if (!bio) {
|
|
|
free_io_failure(inode, failrec);
|
|
|
return -EIO;
|
|
@@ -7825,12 +7864,17 @@ struct btrfs_retry_complete {
|
|
|
static void btrfs_retry_endio_nocsum(struct bio *bio)
|
|
|
{
|
|
|
struct btrfs_retry_complete *done = bio->bi_private;
|
|
|
+ struct inode *inode;
|
|
|
struct bio_vec *bvec;
|
|
|
int i;
|
|
|
|
|
|
if (bio->bi_error)
|
|
|
goto end;
|
|
|
|
|
|
+ ASSERT(bio->bi_vcnt == 1);
|
|
|
+ inode = bio->bi_io_vec->bv_page->mapping->host;
|
|
|
+ ASSERT(bio->bi_io_vec->bv_len == BTRFS_I(inode)->root->sectorsize);
|
|
|
+
|
|
|
done->uptodate = 1;
|
|
|
bio_for_each_segment_all(bvec, bio, i)
|
|
|
clean_io_failure(done->inode, done->start, bvec->bv_page, 0);
|
|
@@ -7842,25 +7886,35 @@ end:
|
|
|
static int __btrfs_correct_data_nocsum(struct inode *inode,
|
|
|
struct btrfs_io_bio *io_bio)
|
|
|
{
|
|
|
+ struct btrfs_fs_info *fs_info;
|
|
|
struct bio_vec *bvec;
|
|
|
struct btrfs_retry_complete done;
|
|
|
u64 start;
|
|
|
+ unsigned int pgoff;
|
|
|
+ u32 sectorsize;
|
|
|
+ int nr_sectors;
|
|
|
int i;
|
|
|
int ret;
|
|
|
|
|
|
+ fs_info = BTRFS_I(inode)->root->fs_info;
|
|
|
+ sectorsize = BTRFS_I(inode)->root->sectorsize;
|
|
|
+
|
|
|
start = io_bio->logical;
|
|
|
done.inode = inode;
|
|
|
|
|
|
bio_for_each_segment_all(bvec, &io_bio->bio, i) {
|
|
|
-try_again:
|
|
|
+ nr_sectors = BTRFS_BYTES_TO_BLKS(fs_info, bvec->bv_len);
|
|
|
+ pgoff = bvec->bv_offset;
|
|
|
+
|
|
|
+next_block_or_try_again:
|
|
|
done.uptodate = 0;
|
|
|
done.start = start;
|
|
|
init_completion(&done.done);
|
|
|
|
|
|
- ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page, start,
|
|
|
- start + bvec->bv_len - 1,
|
|
|
- io_bio->mirror_num,
|
|
|
- btrfs_retry_endio_nocsum, &done);
|
|
|
+ ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page,
|
|
|
+ pgoff, start, start + sectorsize - 1,
|
|
|
+ io_bio->mirror_num,
|
|
|
+ btrfs_retry_endio_nocsum, &done);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -7868,10 +7922,15 @@ try_again:
|
|
|
|
|
|
if (!done.uptodate) {
|
|
|
/* We might have another mirror, so try again */
|
|
|
- goto try_again;
|
|
|
+ goto next_block_or_try_again;
|
|
|
}
|
|
|
|
|
|
- start += bvec->bv_len;
|
|
|
+ start += sectorsize;
|
|
|
+
|
|
|
+ if (nr_sectors--) {
|
|
|
+ pgoff += sectorsize;
|
|
|
+ goto next_block_or_try_again;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -7881,7 +7940,9 @@ static void btrfs_retry_endio(struct bio *bio)
|
|
|
{
|
|
|
struct btrfs_retry_complete *done = bio->bi_private;
|
|
|
struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
|
|
|
+ struct inode *inode;
|
|
|
struct bio_vec *bvec;
|
|
|
+ u64 start;
|
|
|
int uptodate;
|
|
|
int ret;
|
|
|
int i;
|
|
@@ -7890,13 +7951,20 @@ static void btrfs_retry_endio(struct bio *bio)
|
|
|
goto end;
|
|
|
|
|
|
uptodate = 1;
|
|
|
+
|
|
|
+ start = done->start;
|
|
|
+
|
|
|
+ ASSERT(bio->bi_vcnt == 1);
|
|
|
+ inode = bio->bi_io_vec->bv_page->mapping->host;
|
|
|
+ ASSERT(bio->bi_io_vec->bv_len == BTRFS_I(inode)->root->sectorsize);
|
|
|
+
|
|
|
bio_for_each_segment_all(bvec, bio, i) {
|
|
|
ret = __readpage_endio_check(done->inode, io_bio, i,
|
|
|
- bvec->bv_page, 0,
|
|
|
- done->start, bvec->bv_len);
|
|
|
+ bvec->bv_page, bvec->bv_offset,
|
|
|
+ done->start, bvec->bv_len);
|
|
|
if (!ret)
|
|
|
clean_io_failure(done->inode, done->start,
|
|
|
- bvec->bv_page, 0);
|
|
|
+ bvec->bv_page, bvec->bv_offset);
|
|
|
else
|
|
|
uptodate = 0;
|
|
|
}
|
|
@@ -7910,20 +7978,34 @@ end:
|
|
|
static int __btrfs_subio_endio_read(struct inode *inode,
|
|
|
struct btrfs_io_bio *io_bio, int err)
|
|
|
{
|
|
|
+ struct btrfs_fs_info *fs_info;
|
|
|
struct bio_vec *bvec;
|
|
|
struct btrfs_retry_complete done;
|
|
|
u64 start;
|
|
|
u64 offset = 0;
|
|
|
+ u32 sectorsize;
|
|
|
+ int nr_sectors;
|
|
|
+ unsigned int pgoff;
|
|
|
+ int csum_pos;
|
|
|
int i;
|
|
|
int ret;
|
|
|
|
|
|
+ fs_info = BTRFS_I(inode)->root->fs_info;
|
|
|
+ sectorsize = BTRFS_I(inode)->root->sectorsize;
|
|
|
+
|
|
|
err = 0;
|
|
|
start = io_bio->logical;
|
|
|
done.inode = inode;
|
|
|
|
|
|
bio_for_each_segment_all(bvec, &io_bio->bio, i) {
|
|
|
- ret = __readpage_endio_check(inode, io_bio, i, bvec->bv_page,
|
|
|
- 0, start, bvec->bv_len);
|
|
|
+ nr_sectors = BTRFS_BYTES_TO_BLKS(fs_info, bvec->bv_len);
|
|
|
+
|
|
|
+ pgoff = bvec->bv_offset;
|
|
|
+next_block:
|
|
|
+ csum_pos = BTRFS_BYTES_TO_BLKS(fs_info, offset);
|
|
|
+ ret = __readpage_endio_check(inode, io_bio, csum_pos,
|
|
|
+ bvec->bv_page, pgoff, start,
|
|
|
+ sectorsize);
|
|
|
if (likely(!ret))
|
|
|
goto next;
|
|
|
try_again:
|
|
@@ -7931,10 +8013,10 @@ try_again:
|
|
|
done.start = start;
|
|
|
init_completion(&done.done);
|
|
|
|
|
|
- ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page, start,
|
|
|
- start + bvec->bv_len - 1,
|
|
|
- io_bio->mirror_num,
|
|
|
- btrfs_retry_endio, &done);
|
|
|
+ ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page,
|
|
|
+ pgoff, start, start + sectorsize - 1,
|
|
|
+ io_bio->mirror_num,
|
|
|
+ btrfs_retry_endio, &done);
|
|
|
if (ret) {
|
|
|
err = ret;
|
|
|
goto next;
|
|
@@ -7947,8 +8029,15 @@ try_again:
|
|
|
goto try_again;
|
|
|
}
|
|
|
next:
|
|
|
- offset += bvec->bv_len;
|
|
|
- start += bvec->bv_len;
|
|
|
+ offset += sectorsize;
|
|
|
+ start += sectorsize;
|
|
|
+
|
|
|
+ ASSERT(nr_sectors);
|
|
|
+
|
|
|
+ if (--nr_sectors) {
|
|
|
+ pgoff += sectorsize;
|
|
|
+ goto next_block;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
return err;
|
|
@@ -8202,9 +8291,11 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
|
|
u64 file_offset = dip->logical_offset;
|
|
|
u64 submit_len = 0;
|
|
|
u64 map_length;
|
|
|
- int nr_pages = 0;
|
|
|
- int ret;
|
|
|
+ u32 blocksize = root->sectorsize;
|
|
|
int async_submit = 0;
|
|
|
+ int nr_sectors;
|
|
|
+ int ret;
|
|
|
+ int i;
|
|
|
|
|
|
map_length = orig_bio->bi_iter.bi_size;
|
|
|
ret = btrfs_map_block(root->fs_info, rw, start_sector << 9,
|
|
@@ -8234,9 +8325,12 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
|
|
atomic_inc(&dip->pending_bios);
|
|
|
|
|
|
while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) {
|
|
|
- if (map_length < submit_len + bvec->bv_len ||
|
|
|
- bio_add_page(bio, bvec->bv_page, bvec->bv_len,
|
|
|
- bvec->bv_offset) < bvec->bv_len) {
|
|
|
+ nr_sectors = BTRFS_BYTES_TO_BLKS(root->fs_info, bvec->bv_len);
|
|
|
+ i = 0;
|
|
|
+next_block:
|
|
|
+ if (unlikely(map_length < submit_len + blocksize ||
|
|
|
+ bio_add_page(bio, bvec->bv_page, blocksize,
|
|
|
+ bvec->bv_offset + (i * blocksize)) < blocksize)) {
|
|
|
/*
|
|
|
* inc the count before we submit the bio so
|
|
|
* we know the end IO handler won't happen before
|
|
@@ -8257,7 +8351,6 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
|
|
file_offset += submit_len;
|
|
|
|
|
|
submit_len = 0;
|
|
|
- nr_pages = 0;
|
|
|
|
|
|
bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev,
|
|
|
start_sector, GFP_NOFS);
|
|
@@ -8275,9 +8368,14 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
|
|
bio_put(bio);
|
|
|
goto out_err;
|
|
|
}
|
|
|
+
|
|
|
+ goto next_block;
|
|
|
} else {
|
|
|
- submit_len += bvec->bv_len;
|
|
|
- nr_pages++;
|
|
|
+ submit_len += blocksize;
|
|
|
+ if (--nr_sectors) {
|
|
|
+ i++;
|
|
|
+ goto next_block;
|
|
|
+ }
|
|
|
bvec++;
|
|
|
}
|
|
|
}
|
|
@@ -8642,6 +8740,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
|
|
|
struct extent_state *cached_state = NULL;
|
|
|
u64 page_start = page_offset(page);
|
|
|
u64 page_end = page_start + PAGE_CACHE_SIZE - 1;
|
|
|
+ u64 start;
|
|
|
+ u64 end;
|
|
|
int inode_evicting = inode->i_state & I_FREEING;
|
|
|
|
|
|
/*
|
|
@@ -8661,14 +8761,18 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
|
|
|
|
|
|
if (!inode_evicting)
|
|
|
lock_extent_bits(tree, page_start, page_end, &cached_state);
|
|
|
- ordered = btrfs_lookup_ordered_extent(inode, page_start);
|
|
|
+again:
|
|
|
+ start = page_start;
|
|
|
+ ordered = btrfs_lookup_ordered_range(inode, start,
|
|
|
+ page_end - start + 1);
|
|
|
if (ordered) {
|
|
|
+ end = min(page_end, ordered->file_offset + ordered->len - 1);
|
|
|
/*
|
|
|
* IO on this page will never be started, so we need
|
|
|
* to account for any ordered extents now
|
|
|
*/
|
|
|
if (!inode_evicting)
|
|
|
- clear_extent_bit(tree, page_start, page_end,
|
|
|
+ clear_extent_bit(tree, start, end,
|
|
|
EXTENT_DIRTY | EXTENT_DELALLOC |
|
|
|
EXTENT_LOCKED | EXTENT_DO_ACCOUNTING |
|
|
|
EXTENT_DEFRAG, 1, 0, &cached_state,
|
|
@@ -8685,22 +8789,26 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
|
|
|
|
|
|
spin_lock_irq(&tree->lock);
|
|
|
set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags);
|
|
|
- new_len = page_start - ordered->file_offset;
|
|
|
+ new_len = start - ordered->file_offset;
|
|
|
if (new_len < ordered->truncated_len)
|
|
|
ordered->truncated_len = new_len;
|
|
|
spin_unlock_irq(&tree->lock);
|
|
|
|
|
|
if (btrfs_dec_test_ordered_pending(inode, &ordered,
|
|
|
- page_start,
|
|
|
- PAGE_CACHE_SIZE, 1))
|
|
|
+ start,
|
|
|
+ end - start + 1, 1))
|
|
|
btrfs_finish_ordered_io(ordered);
|
|
|
}
|
|
|
btrfs_put_ordered_extent(ordered);
|
|
|
if (!inode_evicting) {
|
|
|
cached_state = NULL;
|
|
|
- lock_extent_bits(tree, page_start, page_end,
|
|
|
+ lock_extent_bits(tree, start, end,
|
|
|
&cached_state);
|
|
|
}
|
|
|
+
|
|
|
+ start = end + 1;
|
|
|
+ if (start < page_end)
|
|
|
+ goto again;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -8761,15 +8869,28 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|
|
loff_t size;
|
|
|
int ret;
|
|
|
int reserved = 0;
|
|
|
+ u64 reserved_space;
|
|
|
u64 page_start;
|
|
|
u64 page_end;
|
|
|
+ u64 end;
|
|
|
+
|
|
|
+ reserved_space = PAGE_CACHE_SIZE;
|
|
|
|
|
|
sb_start_pagefault(inode->i_sb);
|
|
|
page_start = page_offset(page);
|
|
|
page_end = page_start + PAGE_CACHE_SIZE - 1;
|
|
|
+ end = page_end;
|
|
|
|
|
|
+ /*
|
|
|
+ * Reserving delalloc space after obtaining the page lock can lead to
|
|
|
+ * deadlock. For example, if a dirty page is locked by this function
|
|
|
+ * and the call to btrfs_delalloc_reserve_space() ends up triggering
|
|
|
+ * dirty page write out, then the btrfs_writepage() function could
|
|
|
+ * end up waiting indefinitely to get a lock on the page currently
|
|
|
+ * being processed by btrfs_page_mkwrite() function.
|
|
|
+ */
|
|
|
ret = btrfs_delalloc_reserve_space(inode, page_start,
|
|
|
- PAGE_CACHE_SIZE);
|
|
|
+ reserved_space);
|
|
|
if (!ret) {
|
|
|
ret = file_update_time(vma->vm_file);
|
|
|
reserved = 1;
|
|
@@ -8803,7 +8924,7 @@ again:
|
|
|
* we can't set the delalloc bits if there are pending ordered
|
|
|
* extents. Drop our locks and wait for them to finish
|
|
|
*/
|
|
|
- ordered = btrfs_lookup_ordered_extent(inode, page_start);
|
|
|
+ ordered = btrfs_lookup_ordered_range(inode, page_start, page_end);
|
|
|
if (ordered) {
|
|
|
unlock_extent_cached(io_tree, page_start, page_end,
|
|
|
&cached_state, GFP_NOFS);
|
|
@@ -8813,6 +8934,18 @@ again:
|
|
|
goto again;
|
|
|
}
|
|
|
|
|
|
+ if (page->index == ((size - 1) >> PAGE_CACHE_SHIFT)) {
|
|
|
+ reserved_space = round_up(size - page_start, root->sectorsize);
|
|
|
+ if (reserved_space < PAGE_CACHE_SIZE) {
|
|
|
+ end = page_start + reserved_space - 1;
|
|
|
+ spin_lock(&BTRFS_I(inode)->lock);
|
|
|
+ BTRFS_I(inode)->outstanding_extents++;
|
|
|
+ spin_unlock(&BTRFS_I(inode)->lock);
|
|
|
+ btrfs_delalloc_release_space(inode, page_start,
|
|
|
+ PAGE_CACHE_SIZE - reserved_space);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* XXX - page_mkwrite gets called every time the page is dirtied, even
|
|
|
* if it was already dirty, so for space accounting reasons we need to
|
|
@@ -8820,12 +8953,12 @@ again:
|
|
|
* is probably a better way to do this, but for now keep consistent with
|
|
|
* prepare_pages in the normal write path.
|
|
|
*/
|
|
|
- clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, page_end,
|
|
|
+ clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, end,
|
|
|
EXTENT_DIRTY | EXTENT_DELALLOC |
|
|
|
EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
|
|
|
0, 0, &cached_state, GFP_NOFS);
|
|
|
|
|
|
- ret = btrfs_set_extent_delalloc(inode, page_start, page_end,
|
|
|
+ ret = btrfs_set_extent_delalloc(inode, page_start, end,
|
|
|
&cached_state);
|
|
|
if (ret) {
|
|
|
unlock_extent_cached(io_tree, page_start, page_end,
|
|
@@ -8864,7 +8997,7 @@ out_unlock:
|
|
|
}
|
|
|
unlock_page(page);
|
|
|
out:
|
|
|
- btrfs_delalloc_release_space(inode, page_start, PAGE_CACHE_SIZE);
|
|
|
+ btrfs_delalloc_release_space(inode, page_start, reserved_space);
|
|
|
out_noreserve:
|
|
|
sb_end_pagefault(inode->i_sb);
|
|
|
return ret;
|
|
@@ -9190,16 +9323,11 @@ void btrfs_destroy_cachep(void)
|
|
|
* destroy cache.
|
|
|
*/
|
|
|
rcu_barrier();
|
|
|
- if (btrfs_inode_cachep)
|
|
|
- kmem_cache_destroy(btrfs_inode_cachep);
|
|
|
- if (btrfs_trans_handle_cachep)
|
|
|
- kmem_cache_destroy(btrfs_trans_handle_cachep);
|
|
|
- if (btrfs_transaction_cachep)
|
|
|
- kmem_cache_destroy(btrfs_transaction_cachep);
|
|
|
- if (btrfs_path_cachep)
|
|
|
- kmem_cache_destroy(btrfs_path_cachep);
|
|
|
- if (btrfs_free_space_cachep)
|
|
|
- kmem_cache_destroy(btrfs_free_space_cachep);
|
|
|
+ kmem_cache_destroy(btrfs_inode_cachep);
|
|
|
+ kmem_cache_destroy(btrfs_trans_handle_cachep);
|
|
|
+ kmem_cache_destroy(btrfs_transaction_cachep);
|
|
|
+ kmem_cache_destroy(btrfs_path_cachep);
|
|
|
+ kmem_cache_destroy(btrfs_free_space_cachep);
|
|
|
}
|
|
|
|
|
|
int btrfs_init_cachep(void)
|
|
@@ -9250,7 +9378,6 @@ static int btrfs_getattr(struct vfsmount *mnt,
|
|
|
|
|
|
generic_fillattr(inode, stat);
|
|
|
stat->dev = BTRFS_I(inode)->root->anon_dev;
|
|
|
- stat->blksize = PAGE_CACHE_SIZE;
|
|
|
|
|
|
spin_lock(&BTRFS_I(inode)->lock);
|
|
|
delalloc_bytes = BTRFS_I(inode)->delalloc_bytes;
|
|
@@ -9268,7 +9395,6 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
struct btrfs_root *dest = BTRFS_I(new_dir)->root;
|
|
|
struct inode *new_inode = d_inode(new_dentry);
|
|
|
struct inode *old_inode = d_inode(old_dentry);
|
|
|
- struct timespec ctime = CURRENT_TIME;
|
|
|
u64 index = 0;
|
|
|
u64 root_objectid;
|
|
|
int ret;
|
|
@@ -9365,9 +9491,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
inode_inc_iversion(old_dir);
|
|
|
inode_inc_iversion(new_dir);
|
|
|
inode_inc_iversion(old_inode);
|
|
|
- old_dir->i_ctime = old_dir->i_mtime = ctime;
|
|
|
- new_dir->i_ctime = new_dir->i_mtime = ctime;
|
|
|
- old_inode->i_ctime = ctime;
|
|
|
+ old_dir->i_ctime = old_dir->i_mtime =
|
|
|
+ new_dir->i_ctime = new_dir->i_mtime =
|
|
|
+ old_inode->i_ctime = current_fs_time(old_dir->i_sb);
|
|
|
|
|
|
if (old_dentry->d_parent != new_dentry->d_parent)
|
|
|
btrfs_record_unlink_dir(trans, old_dir, old_inode, 1);
|
|
@@ -9392,7 +9518,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|
|
|
|
|
if (new_inode) {
|
|
|
inode_inc_iversion(new_inode);
|
|
|
- new_inode->i_ctime = CURRENT_TIME;
|
|
|
+ new_inode->i_ctime = current_fs_time(new_inode->i_sb);
|
|
|
if (unlikely(btrfs_ino(new_inode) ==
|
|
|
BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
|
|
|
root_objectid = BTRFS_I(new_inode)->location.objectid;
|
|
@@ -9870,7 +9996,7 @@ next:
|
|
|
*alloc_hint = ins.objectid + ins.offset;
|
|
|
|
|
|
inode_inc_iversion(inode);
|
|
|
- inode->i_ctime = CURRENT_TIME;
|
|
|
+ inode->i_ctime = current_fs_time(inode->i_sb);
|
|
|
BTRFS_I(inode)->flags |= BTRFS_INODE_PREALLOC;
|
|
|
if (!(mode & FALLOC_FL_KEEP_SIZE) &&
|
|
|
(actual_len > inode->i_size) &&
|