mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-25 20:30:57 +07:00
Merge branch 'chandan/prep-subpage-blocksize' into for-chris-4.6
# Conflicts: # fs/btrfs/file.c
This commit is contained in:
commit
5f1b5664d9
@ -311,7 +311,7 @@ struct tree_mod_root {
|
|||||||
|
|
||||||
struct tree_mod_elem {
|
struct tree_mod_elem {
|
||||||
struct rb_node node;
|
struct rb_node node;
|
||||||
u64 index; /* shifted logical */
|
u64 logical;
|
||||||
u64 seq;
|
u64 seq;
|
||||||
enum mod_log_op op;
|
enum mod_log_op op;
|
||||||
|
|
||||||
@ -435,11 +435,11 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* key order of the log:
|
* key order of the log:
|
||||||
* index -> sequence
|
* node/leaf start address -> sequence
|
||||||
*
|
*
|
||||||
* the index is the shifted logical of the *new* root node for root replace
|
* The 'start address' is the logical address of the *new* root node
|
||||||
* operations, or the shifted logical of the affected block for all other
|
* for root replace operations, or the logical address of the affected
|
||||||
* operations.
|
* block for all other operations.
|
||||||
*
|
*
|
||||||
* Note: must be called with write lock (tree_mod_log_write_lock).
|
* Note: must be called with write lock (tree_mod_log_write_lock).
|
||||||
*/
|
*/
|
||||||
@ -460,9 +460,9 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
|
|||||||
while (*new) {
|
while (*new) {
|
||||||
cur = container_of(*new, struct tree_mod_elem, node);
|
cur = container_of(*new, struct tree_mod_elem, node);
|
||||||
parent = *new;
|
parent = *new;
|
||||||
if (cur->index < tm->index)
|
if (cur->logical < tm->logical)
|
||||||
new = &((*new)->rb_left);
|
new = &((*new)->rb_left);
|
||||||
else if (cur->index > tm->index)
|
else if (cur->logical > tm->logical)
|
||||||
new = &((*new)->rb_right);
|
new = &((*new)->rb_right);
|
||||||
else if (cur->seq < tm->seq)
|
else if (cur->seq < tm->seq)
|
||||||
new = &((*new)->rb_left);
|
new = &((*new)->rb_left);
|
||||||
@ -523,7 +523,7 @@ alloc_tree_mod_elem(struct extent_buffer *eb, int slot,
|
|||||||
if (!tm)
|
if (!tm)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
tm->index = eb->start >> PAGE_CACHE_SHIFT;
|
tm->logical = eb->start;
|
||||||
if (op != MOD_LOG_KEY_ADD) {
|
if (op != MOD_LOG_KEY_ADD) {
|
||||||
btrfs_node_key(eb, &tm->key, slot);
|
btrfs_node_key(eb, &tm->key, slot);
|
||||||
tm->blockptr = btrfs_node_blockptr(eb, slot);
|
tm->blockptr = btrfs_node_blockptr(eb, slot);
|
||||||
@ -588,7 +588,7 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
|
|||||||
goto free_tms;
|
goto free_tms;
|
||||||
}
|
}
|
||||||
|
|
||||||
tm->index = eb->start >> PAGE_CACHE_SHIFT;
|
tm->logical = eb->start;
|
||||||
tm->slot = src_slot;
|
tm->slot = src_slot;
|
||||||
tm->move.dst_slot = dst_slot;
|
tm->move.dst_slot = dst_slot;
|
||||||
tm->move.nr_items = nr_items;
|
tm->move.nr_items = nr_items;
|
||||||
@ -699,7 +699,7 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
|
|||||||
goto free_tms;
|
goto free_tms;
|
||||||
}
|
}
|
||||||
|
|
||||||
tm->index = new_root->start >> PAGE_CACHE_SHIFT;
|
tm->logical = new_root->start;
|
||||||
tm->old_root.logical = old_root->start;
|
tm->old_root.logical = old_root->start;
|
||||||
tm->old_root.level = btrfs_header_level(old_root);
|
tm->old_root.level = btrfs_header_level(old_root);
|
||||||
tm->generation = btrfs_header_generation(old_root);
|
tm->generation = btrfs_header_generation(old_root);
|
||||||
@ -739,16 +739,15 @@ __tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq,
|
|||||||
struct rb_node *node;
|
struct rb_node *node;
|
||||||
struct tree_mod_elem *cur = NULL;
|
struct tree_mod_elem *cur = NULL;
|
||||||
struct tree_mod_elem *found = NULL;
|
struct tree_mod_elem *found = NULL;
|
||||||
u64 index = start >> PAGE_CACHE_SHIFT;
|
|
||||||
|
|
||||||
tree_mod_log_read_lock(fs_info);
|
tree_mod_log_read_lock(fs_info);
|
||||||
tm_root = &fs_info->tree_mod_log;
|
tm_root = &fs_info->tree_mod_log;
|
||||||
node = tm_root->rb_node;
|
node = tm_root->rb_node;
|
||||||
while (node) {
|
while (node) {
|
||||||
cur = container_of(node, struct tree_mod_elem, node);
|
cur = container_of(node, struct tree_mod_elem, node);
|
||||||
if (cur->index < index) {
|
if (cur->logical < start) {
|
||||||
node = node->rb_left;
|
node = node->rb_left;
|
||||||
} else if (cur->index > index) {
|
} else if (cur->logical > start) {
|
||||||
node = node->rb_right;
|
node = node->rb_right;
|
||||||
} else if (cur->seq < min_seq) {
|
} else if (cur->seq < min_seq) {
|
||||||
node = node->rb_left;
|
node = node->rb_left;
|
||||||
@ -1230,9 +1229,10 @@ __tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info,
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the very last operation that's logged for a root is the replacement
|
* the very last operation that's logged for a root is the
|
||||||
* operation (if it is replaced at all). this has the index of the *new*
|
* replacement operation (if it is replaced at all). this has
|
||||||
* root, making it the very first operation that's logged for this root.
|
* the logical address of the *new* root, making it the very
|
||||||
|
* first operation that's logged for this root.
|
||||||
*/
|
*/
|
||||||
while (1) {
|
while (1) {
|
||||||
tm = tree_mod_log_search_oldest(fs_info, root_logical,
|
tm = tree_mod_log_search_oldest(fs_info, root_logical,
|
||||||
@ -1336,7 +1336,7 @@ __tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
|
|||||||
if (!next)
|
if (!next)
|
||||||
break;
|
break;
|
||||||
tm = container_of(next, struct tree_mod_elem, node);
|
tm = container_of(next, struct tree_mod_elem, node);
|
||||||
if (tm->index != first_tm->index)
|
if (tm->logical != first_tm->logical)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
tree_mod_log_read_unlock(fs_info);
|
tree_mod_log_read_unlock(fs_info);
|
||||||
|
@ -2353,6 +2353,9 @@ struct btrfs_map_token {
|
|||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BTRFS_BYTES_TO_BLKS(fs_info, bytes) \
|
||||||
|
((bytes) >> (fs_info)->sb->s_blocksize_bits)
|
||||||
|
|
||||||
static inline void btrfs_init_map_token (struct btrfs_map_token *token)
|
static inline void btrfs_init_map_token (struct btrfs_map_token *token)
|
||||||
{
|
{
|
||||||
token->kaddr = NULL;
|
token->kaddr = NULL;
|
||||||
@ -4027,7 +4030,7 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
|
|||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
struct inode *dir, u64 objectid,
|
struct inode *dir, u64 objectid,
|
||||||
const char *name, int name_len);
|
const char *name, int name_len);
|
||||||
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);
|
int front);
|
||||||
int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
|
int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root,
|
struct btrfs_root *root,
|
||||||
|
@ -3186,7 +3186,8 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
lock_extent(tree, start, end);
|
lock_extent(tree, start, end);
|
||||||
ordered = btrfs_lookup_ordered_extent(inode, start);
|
ordered = btrfs_lookup_ordered_range(inode, start,
|
||||||
|
PAGE_CACHE_SIZE);
|
||||||
if (!ordered)
|
if (!ordered)
|
||||||
break;
|
break;
|
||||||
unlock_extent(tree, start, end);
|
unlock_extent(tree, start, end);
|
||||||
|
@ -172,6 +172,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
|
|||||||
u64 item_start_offset = 0;
|
u64 item_start_offset = 0;
|
||||||
u64 item_last_offset = 0;
|
u64 item_last_offset = 0;
|
||||||
u64 disk_bytenr;
|
u64 disk_bytenr;
|
||||||
|
u64 page_bytes_left;
|
||||||
u32 diff;
|
u32 diff;
|
||||||
int nblocks;
|
int nblocks;
|
||||||
int bio_index = 0;
|
int bio_index = 0;
|
||||||
@ -220,6 +221,8 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
|
|||||||
disk_bytenr = (u64)bio->bi_iter.bi_sector << 9;
|
disk_bytenr = (u64)bio->bi_iter.bi_sector << 9;
|
||||||
if (dio)
|
if (dio)
|
||||||
offset = logical_offset;
|
offset = logical_offset;
|
||||||
|
|
||||||
|
page_bytes_left = bvec->bv_len;
|
||||||
while (bio_index < bio->bi_vcnt) {
|
while (bio_index < bio->bi_vcnt) {
|
||||||
if (!dio)
|
if (!dio)
|
||||||
offset = page_offset(bvec->bv_page) + bvec->bv_offset;
|
offset = page_offset(bvec->bv_page) + bvec->bv_offset;
|
||||||
@ -243,7 +246,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
|
|||||||
if (BTRFS_I(inode)->root->root_key.objectid ==
|
if (BTRFS_I(inode)->root->root_key.objectid ==
|
||||||
BTRFS_DATA_RELOC_TREE_OBJECTID) {
|
BTRFS_DATA_RELOC_TREE_OBJECTID) {
|
||||||
set_extent_bits(io_tree, offset,
|
set_extent_bits(io_tree, offset,
|
||||||
offset + bvec->bv_len - 1,
|
offset + root->sectorsize - 1,
|
||||||
EXTENT_NODATASUM, GFP_NOFS);
|
EXTENT_NODATASUM, GFP_NOFS);
|
||||||
} else {
|
} else {
|
||||||
btrfs_info(BTRFS_I(inode)->root->fs_info,
|
btrfs_info(BTRFS_I(inode)->root->fs_info,
|
||||||
@ -281,11 +284,17 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
|
|||||||
found:
|
found:
|
||||||
csum += count * csum_size;
|
csum += count * csum_size;
|
||||||
nblocks -= count;
|
nblocks -= count;
|
||||||
bio_index += count;
|
|
||||||
while (count--) {
|
while (count--) {
|
||||||
disk_bytenr += bvec->bv_len;
|
disk_bytenr += root->sectorsize;
|
||||||
offset += bvec->bv_len;
|
offset += root->sectorsize;
|
||||||
bvec++;
|
page_bytes_left -= root->sectorsize;
|
||||||
|
if (!page_bytes_left) {
|
||||||
|
bio_index++;
|
||||||
|
bvec++;
|
||||||
|
page_bytes_left = bvec->bv_len;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
@ -432,6 +441,8 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
|
|||||||
struct bio_vec *bvec = bio->bi_io_vec;
|
struct bio_vec *bvec = bio->bi_io_vec;
|
||||||
int bio_index = 0;
|
int bio_index = 0;
|
||||||
int index;
|
int index;
|
||||||
|
int nr_sectors;
|
||||||
|
int i;
|
||||||
unsigned long total_bytes = 0;
|
unsigned long total_bytes = 0;
|
||||||
unsigned long this_sum_bytes = 0;
|
unsigned long this_sum_bytes = 0;
|
||||||
u64 offset;
|
u64 offset;
|
||||||
@ -459,41 +470,56 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
|
|||||||
if (!contig)
|
if (!contig)
|
||||||
offset = page_offset(bvec->bv_page) + bvec->bv_offset;
|
offset = page_offset(bvec->bv_page) + bvec->bv_offset;
|
||||||
|
|
||||||
if (offset >= ordered->file_offset + ordered->len ||
|
data = kmap_atomic(bvec->bv_page);
|
||||||
offset < ordered->file_offset) {
|
|
||||||
unsigned long bytes_left;
|
|
||||||
sums->len = this_sum_bytes;
|
|
||||||
this_sum_bytes = 0;
|
|
||||||
btrfs_add_ordered_sum(inode, ordered, sums);
|
|
||||||
btrfs_put_ordered_extent(ordered);
|
|
||||||
|
|
||||||
bytes_left = bio->bi_iter.bi_size - total_bytes;
|
nr_sectors = BTRFS_BYTES_TO_BLKS(root->fs_info,
|
||||||
|
bvec->bv_len + root->sectorsize
|
||||||
|
- 1);
|
||||||
|
|
||||||
sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
|
for (i = 0; i < nr_sectors; i++) {
|
||||||
GFP_NOFS);
|
if (offset >= ordered->file_offset + ordered->len ||
|
||||||
BUG_ON(!sums); /* -ENOMEM */
|
offset < ordered->file_offset) {
|
||||||
sums->len = bytes_left;
|
unsigned long bytes_left;
|
||||||
ordered = btrfs_lookup_ordered_extent(inode, offset);
|
|
||||||
BUG_ON(!ordered); /* Logic error */
|
kunmap_atomic(data);
|
||||||
sums->bytenr = ((u64)bio->bi_iter.bi_sector << 9) +
|
sums->len = this_sum_bytes;
|
||||||
total_bytes;
|
this_sum_bytes = 0;
|
||||||
index = 0;
|
btrfs_add_ordered_sum(inode, ordered, sums);
|
||||||
|
btrfs_put_ordered_extent(ordered);
|
||||||
|
|
||||||
|
bytes_left = bio->bi_iter.bi_size - total_bytes;
|
||||||
|
|
||||||
|
sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
|
||||||
|
GFP_NOFS);
|
||||||
|
BUG_ON(!sums); /* -ENOMEM */
|
||||||
|
sums->len = bytes_left;
|
||||||
|
ordered = btrfs_lookup_ordered_extent(inode,
|
||||||
|
offset);
|
||||||
|
ASSERT(ordered); /* Logic error */
|
||||||
|
sums->bytenr = ((u64)bio->bi_iter.bi_sector << 9)
|
||||||
|
+ total_bytes;
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
data = kmap_atomic(bvec->bv_page);
|
||||||
|
}
|
||||||
|
|
||||||
|
sums->sums[index] = ~(u32)0;
|
||||||
|
sums->sums[index]
|
||||||
|
= btrfs_csum_data(data + bvec->bv_offset
|
||||||
|
+ (i * root->sectorsize),
|
||||||
|
sums->sums[index],
|
||||||
|
root->sectorsize);
|
||||||
|
btrfs_csum_final(sums->sums[index],
|
||||||
|
(char *)(sums->sums + index));
|
||||||
|
index++;
|
||||||
|
offset += root->sectorsize;
|
||||||
|
this_sum_bytes += root->sectorsize;
|
||||||
|
total_bytes += root->sectorsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = kmap_atomic(bvec->bv_page);
|
|
||||||
sums->sums[index] = ~(u32)0;
|
|
||||||
sums->sums[index] = btrfs_csum_data(data + bvec->bv_offset,
|
|
||||||
sums->sums[index],
|
|
||||||
bvec->bv_len);
|
|
||||||
kunmap_atomic(data);
|
kunmap_atomic(data);
|
||||||
btrfs_csum_final(sums->sums[index],
|
|
||||||
(char *)(sums->sums + index));
|
|
||||||
|
|
||||||
bio_index++;
|
bio_index++;
|
||||||
index++;
|
|
||||||
total_bytes += bvec->bv_len;
|
|
||||||
this_sum_bytes += bvec->bv_len;
|
|
||||||
offset += bvec->bv_len;
|
|
||||||
bvec++;
|
bvec++;
|
||||||
}
|
}
|
||||||
this_sum_bytes = 0;
|
this_sum_bytes = 0;
|
||||||
|
@ -498,7 +498,7 @@ int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode,
|
|||||||
loff_t isize = i_size_read(inode);
|
loff_t isize = i_size_read(inode);
|
||||||
|
|
||||||
start_pos = pos & ~((u64)root->sectorsize - 1);
|
start_pos = pos & ~((u64)root->sectorsize - 1);
|
||||||
num_bytes = ALIGN(write_bytes + pos - start_pos, root->sectorsize);
|
num_bytes = round_up(write_bytes + pos - start_pos, root->sectorsize);
|
||||||
|
|
||||||
end_of_last_block = start_pos + num_bytes - 1;
|
end_of_last_block = start_pos + num_bytes - 1;
|
||||||
err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
|
err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block,
|
||||||
@ -1379,16 +1379,19 @@ static noinline int prepare_pages(struct inode *inode, struct page **pages,
|
|||||||
static noinline int
|
static noinline int
|
||||||
lock_and_cleanup_extent_if_need(struct inode *inode, struct page **pages,
|
lock_and_cleanup_extent_if_need(struct inode *inode, struct page **pages,
|
||||||
size_t num_pages, loff_t pos,
|
size_t num_pages, loff_t pos,
|
||||||
|
size_t write_bytes,
|
||||||
u64 *lockstart, u64 *lockend,
|
u64 *lockstart, u64 *lockend,
|
||||||
struct extent_state **cached_state)
|
struct extent_state **cached_state)
|
||||||
{
|
{
|
||||||
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
u64 start_pos;
|
u64 start_pos;
|
||||||
u64 last_pos;
|
u64 last_pos;
|
||||||
int i;
|
int i;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
start_pos = pos & ~((u64)PAGE_CACHE_SIZE - 1);
|
start_pos = round_down(pos, root->sectorsize);
|
||||||
last_pos = start_pos + ((u64)num_pages << PAGE_CACHE_SHIFT) - 1;
|
last_pos = start_pos
|
||||||
|
+ round_up(pos + write_bytes - start_pos, root->sectorsize) - 1;
|
||||||
|
|
||||||
if (start_pos < inode->i_size) {
|
if (start_pos < inode->i_size) {
|
||||||
struct btrfs_ordered_extent *ordered;
|
struct btrfs_ordered_extent *ordered;
|
||||||
@ -1503,6 +1506,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
|
|||||||
|
|
||||||
while (iov_iter_count(i) > 0) {
|
while (iov_iter_count(i) > 0) {
|
||||||
size_t offset = pos & (PAGE_CACHE_SIZE - 1);
|
size_t offset = pos & (PAGE_CACHE_SIZE - 1);
|
||||||
|
size_t sector_offset;
|
||||||
size_t write_bytes = min(iov_iter_count(i),
|
size_t write_bytes = min(iov_iter_count(i),
|
||||||
nrptrs * (size_t)PAGE_CACHE_SIZE -
|
nrptrs * (size_t)PAGE_CACHE_SIZE -
|
||||||
offset);
|
offset);
|
||||||
@ -1511,6 +1515,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
|
|||||||
size_t reserve_bytes;
|
size_t reserve_bytes;
|
||||||
size_t dirty_pages;
|
size_t dirty_pages;
|
||||||
size_t copied;
|
size_t copied;
|
||||||
|
size_t dirty_sectors;
|
||||||
|
size_t num_sectors;
|
||||||
|
|
||||||
WARN_ON(num_pages > nrptrs);
|
WARN_ON(num_pages > nrptrs);
|
||||||
|
|
||||||
@ -1523,7 +1529,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
|
sector_offset = pos & (root->sectorsize - 1);
|
||||||
|
reserve_bytes = round_up(write_bytes + sector_offset,
|
||||||
|
root->sectorsize);
|
||||||
|
|
||||||
if (BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
|
if (BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW |
|
||||||
BTRFS_INODE_PREALLOC)) {
|
BTRFS_INODE_PREALLOC)) {
|
||||||
@ -1542,7 +1550,9 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
|
|||||||
*/
|
*/
|
||||||
num_pages = DIV_ROUND_UP(write_bytes + offset,
|
num_pages = DIV_ROUND_UP(write_bytes + offset,
|
||||||
PAGE_CACHE_SIZE);
|
PAGE_CACHE_SIZE);
|
||||||
reserve_bytes = num_pages << PAGE_CACHE_SHIFT;
|
reserve_bytes = round_up(write_bytes
|
||||||
|
+ sector_offset,
|
||||||
|
root->sectorsize);
|
||||||
goto reserve_metadata;
|
goto reserve_metadata;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1576,8 +1586,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
ret = lock_and_cleanup_extent_if_need(inode, pages, num_pages,
|
ret = lock_and_cleanup_extent_if_need(inode, pages, num_pages,
|
||||||
pos, &lockstart, &lockend,
|
pos, write_bytes, &lockstart,
|
||||||
&cached_state);
|
&lockend, &cached_state);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (ret == -EAGAIN)
|
if (ret == -EAGAIN)
|
||||||
goto again;
|
goto again;
|
||||||
@ -1612,9 +1622,16 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
|
|||||||
* we still have an outstanding extent for the chunk we actually
|
* we still have an outstanding extent for the chunk we actually
|
||||||
* managed to copy.
|
* managed to copy.
|
||||||
*/
|
*/
|
||||||
if (num_pages > dirty_pages) {
|
num_sectors = BTRFS_BYTES_TO_BLKS(root->fs_info,
|
||||||
release_bytes = (num_pages - dirty_pages) <<
|
reserve_bytes);
|
||||||
PAGE_CACHE_SHIFT;
|
dirty_sectors = round_up(copied + sector_offset,
|
||||||
|
root->sectorsize);
|
||||||
|
dirty_sectors = BTRFS_BYTES_TO_BLKS(root->fs_info,
|
||||||
|
dirty_sectors);
|
||||||
|
|
||||||
|
if (num_sectors > dirty_sectors) {
|
||||||
|
release_bytes = (write_bytes - copied)
|
||||||
|
& ~((u64)root->sectorsize - 1);
|
||||||
if (copied > 0) {
|
if (copied > 0) {
|
||||||
spin_lock(&BTRFS_I(inode)->lock);
|
spin_lock(&BTRFS_I(inode)->lock);
|
||||||
BTRFS_I(inode)->outstanding_extents++;
|
BTRFS_I(inode)->outstanding_extents++;
|
||||||
@ -1633,7 +1650,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
release_bytes = dirty_pages << PAGE_CACHE_SHIFT;
|
release_bytes = round_up(copied + sector_offset,
|
||||||
|
root->sectorsize);
|
||||||
|
|
||||||
if (copied > 0)
|
if (copied > 0)
|
||||||
ret = btrfs_dirty_pages(root, inode, pages,
|
ret = btrfs_dirty_pages(root, inode, pages,
|
||||||
@ -1654,8 +1672,7 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
|
|||||||
|
|
||||||
if (only_release_metadata && copied > 0) {
|
if (only_release_metadata && copied > 0) {
|
||||||
lockstart = round_down(pos, root->sectorsize);
|
lockstart = round_down(pos, root->sectorsize);
|
||||||
lockend = lockstart +
|
lockend = round_up(pos + copied, root->sectorsize) - 1;
|
||||||
(dirty_pages << PAGE_CACHE_SHIFT) - 1;
|
|
||||||
|
|
||||||
set_extent_bit(&BTRFS_I(inode)->io_tree, lockstart,
|
set_extent_bit(&BTRFS_I(inode)->io_tree, lockstart,
|
||||||
lockend, EXTENT_NORESERVE, NULL,
|
lockend, EXTENT_NORESERVE, NULL,
|
||||||
@ -1761,6 +1778,8 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
|
|||||||
ssize_t err;
|
ssize_t err;
|
||||||
loff_t pos;
|
loff_t pos;
|
||||||
size_t count;
|
size_t count;
|
||||||
|
loff_t oldsize;
|
||||||
|
int clean_page = 0;
|
||||||
|
|
||||||
inode_lock(inode);
|
inode_lock(inode);
|
||||||
err = generic_write_checks(iocb, from);
|
err = generic_write_checks(iocb, from);
|
||||||
@ -1799,14 +1818,17 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
|
|||||||
pos = iocb->ki_pos;
|
pos = iocb->ki_pos;
|
||||||
count = iov_iter_count(from);
|
count = iov_iter_count(from);
|
||||||
start_pos = round_down(pos, root->sectorsize);
|
start_pos = round_down(pos, root->sectorsize);
|
||||||
if (start_pos > i_size_read(inode)) {
|
oldsize = i_size_read(inode);
|
||||||
|
if (start_pos > oldsize) {
|
||||||
/* Expand hole size to cover write data, preventing empty gap */
|
/* Expand hole size to cover write data, preventing empty gap */
|
||||||
end_pos = round_up(pos + count, root->sectorsize);
|
end_pos = round_up(pos + count, root->sectorsize);
|
||||||
err = btrfs_cont_expand(inode, i_size_read(inode), end_pos);
|
err = btrfs_cont_expand(inode, oldsize, end_pos);
|
||||||
if (err) {
|
if (err) {
|
||||||
inode_unlock(inode);
|
inode_unlock(inode);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if (start_pos > round_up(oldsize, root->sectorsize))
|
||||||
|
clean_page = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sync)
|
if (sync)
|
||||||
@ -1818,6 +1840,9 @@ static ssize_t btrfs_file_write_iter(struct kiocb *iocb,
|
|||||||
num_written = __btrfs_buffered_write(file, from, pos);
|
num_written = __btrfs_buffered_write(file, from, pos);
|
||||||
if (num_written > 0)
|
if (num_written > 0)
|
||||||
iocb->ki_pos = pos + num_written;
|
iocb->ki_pos = pos + num_written;
|
||||||
|
if (clean_page)
|
||||||
|
pagecache_isize_extended(inode, oldsize,
|
||||||
|
i_size_read(inode));
|
||||||
}
|
}
|
||||||
|
|
||||||
inode_unlock(inode);
|
inode_unlock(inode);
|
||||||
@ -2293,10 +2318,10 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
|
|||||||
int ret = 0;
|
int ret = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
unsigned int rsv_count;
|
unsigned int rsv_count;
|
||||||
bool same_page;
|
bool same_block;
|
||||||
bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES);
|
bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES);
|
||||||
u64 ino_size;
|
u64 ino_size;
|
||||||
bool truncated_page = false;
|
bool truncated_block = false;
|
||||||
bool updated_inode = false;
|
bool updated_inode = false;
|
||||||
|
|
||||||
ret = btrfs_wait_ordered_range(inode, offset, len);
|
ret = btrfs_wait_ordered_range(inode, offset, len);
|
||||||
@ -2304,7 +2329,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
inode_lock(inode);
|
inode_lock(inode);
|
||||||
ino_size = round_up(inode->i_size, PAGE_CACHE_SIZE);
|
ino_size = round_up(inode->i_size, root->sectorsize);
|
||||||
ret = find_first_non_hole(inode, &offset, &len);
|
ret = find_first_non_hole(inode, &offset, &len);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_only_mutex;
|
goto out_only_mutex;
|
||||||
@ -2317,31 +2342,30 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
|
|||||||
lockstart = round_up(offset, BTRFS_I(inode)->root->sectorsize);
|
lockstart = round_up(offset, BTRFS_I(inode)->root->sectorsize);
|
||||||
lockend = round_down(offset + len,
|
lockend = round_down(offset + len,
|
||||||
BTRFS_I(inode)->root->sectorsize) - 1;
|
BTRFS_I(inode)->root->sectorsize) - 1;
|
||||||
same_page = ((offset >> PAGE_CACHE_SHIFT) ==
|
same_block = (BTRFS_BYTES_TO_BLKS(root->fs_info, offset))
|
||||||
((offset + len - 1) >> PAGE_CACHE_SHIFT));
|
== (BTRFS_BYTES_TO_BLKS(root->fs_info, offset + len - 1));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We needn't truncate any page which is beyond the end of the file
|
* We needn't truncate any block which is beyond the end of the file
|
||||||
* because we are sure there is no data there.
|
* because we are sure there is no data there.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Only do this if we are in the same page and we aren't doing the
|
* Only do this if we are in the same block and we aren't doing the
|
||||||
* entire page.
|
* entire block.
|
||||||
*/
|
*/
|
||||||
if (same_page && len < PAGE_CACHE_SIZE) {
|
if (same_block && len < root->sectorsize) {
|
||||||
if (offset < ino_size) {
|
if (offset < ino_size) {
|
||||||
truncated_page = true;
|
truncated_block = true;
|
||||||
ret = btrfs_truncate_page(inode, offset, len, 0);
|
ret = btrfs_truncate_block(inode, offset, len, 0);
|
||||||
} else {
|
} else {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
goto out_only_mutex;
|
goto out_only_mutex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* zero back part of the first page */
|
/* zero back part of the first block */
|
||||||
if (offset < ino_size) {
|
if (offset < ino_size) {
|
||||||
truncated_page = true;
|
truncated_block = true;
|
||||||
ret = btrfs_truncate_page(inode, offset, 0, 0);
|
ret = btrfs_truncate_block(inode, offset, 0, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
inode_unlock(inode);
|
inode_unlock(inode);
|
||||||
return ret;
|
return ret;
|
||||||
@ -2376,9 +2400,10 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
|
|||||||
if (!ret) {
|
if (!ret) {
|
||||||
/* zero the front end of the last page */
|
/* zero the front end of the last page */
|
||||||
if (tail_start + tail_len < ino_size) {
|
if (tail_start + tail_len < ino_size) {
|
||||||
truncated_page = true;
|
truncated_block = true;
|
||||||
ret = btrfs_truncate_page(inode,
|
ret = btrfs_truncate_block(inode,
|
||||||
tail_start + tail_len, 0, 1);
|
tail_start + tail_len,
|
||||||
|
0, 1);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_only_mutex;
|
goto out_only_mutex;
|
||||||
}
|
}
|
||||||
@ -2558,7 +2583,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
|
|||||||
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
|
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
|
||||||
&cached_state, GFP_NOFS);
|
&cached_state, GFP_NOFS);
|
||||||
out_only_mutex:
|
out_only_mutex:
|
||||||
if (!updated_inode && truncated_page && !ret && !err) {
|
if (!updated_inode && truncated_block && !ret && !err) {
|
||||||
/*
|
/*
|
||||||
* If we only end up zeroing part of a page, we still need to
|
* If we only end up zeroing part of a page, we still need to
|
||||||
* update the inode item, so that all the time fields are
|
* update the inode item, so that all the time fields are
|
||||||
@ -2678,10 +2703,10 @@ static long btrfs_fallocate(struct file *file, int mode,
|
|||||||
} else if (offset + len > inode->i_size) {
|
} else if (offset + len > inode->i_size) {
|
||||||
/*
|
/*
|
||||||
* If we are fallocating from the end of the file onward we
|
* If we are fallocating from the end of the file onward we
|
||||||
* need to zero out the end of the page if i_size lands in the
|
* need to zero out the end of the block if i_size lands in the
|
||||||
* middle of a page.
|
* middle of a block.
|
||||||
*/
|
*/
|
||||||
ret = btrfs_truncate_page(inode, inode->i_size, 0, 0);
|
ret = btrfs_truncate_block(inode, inode->i_size, 0, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
248
fs/btrfs/inode.c
248
fs/btrfs/inode.c
@ -263,7 +263,7 @@ static noinline int cow_file_range_inline(struct btrfs_root *root,
|
|||||||
data_len = compressed_size;
|
data_len = compressed_size;
|
||||||
|
|
||||||
if (start > 0 ||
|
if (start > 0 ||
|
||||||
actual_end > PAGE_CACHE_SIZE ||
|
actual_end > root->sectorsize ||
|
||||||
data_len > BTRFS_MAX_INLINE_DATA_SIZE(root) ||
|
data_len > BTRFS_MAX_INLINE_DATA_SIZE(root) ||
|
||||||
(!compressed_size &&
|
(!compressed_size &&
|
||||||
(actual_end & (root->sectorsize - 1)) == 0) ||
|
(actual_end & (root->sectorsize - 1)) == 0) ||
|
||||||
@ -2002,7 +2002,8 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
|
|||||||
if (PagePrivate2(page))
|
if (PagePrivate2(page))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ordered = btrfs_lookup_ordered_extent(inode, page_start);
|
ordered = btrfs_lookup_ordered_range(inode, page_start,
|
||||||
|
PAGE_CACHE_SIZE);
|
||||||
if (ordered) {
|
if (ordered) {
|
||||||
unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start,
|
unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start,
|
||||||
page_end, &cached_state, GFP_NOFS);
|
page_end, &cached_state, GFP_NOFS);
|
||||||
@ -4248,7 +4249,8 @@ static int truncate_inline_extent(struct inode *inode,
|
|||||||
* read the extent item from disk (data not in the page cache).
|
* read the extent item from disk (data not in the page cache).
|
||||||
*/
|
*/
|
||||||
btrfs_release_path(path);
|
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);
|
btrfs_set_file_extent_ram_bytes(leaf, fi, size);
|
||||||
@ -4601,17 +4603,17 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
* @inode - inode that we're zeroing
|
||||||
* @from - the offset to start zeroing
|
* @from - the offset to start zeroing
|
||||||
* @len - the length to zero, 0 to zero the entire range respective to the
|
* @len - the length to zero, 0 to zero the entire range respective to the
|
||||||
* offset
|
* offset
|
||||||
* @front - zero up to the offset instead of from the offset on
|
* @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.
|
* 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)
|
int front)
|
||||||
{
|
{
|
||||||
struct address_space *mapping = inode->i_mapping;
|
struct address_space *mapping = inode->i_mapping;
|
||||||
@ -4622,18 +4624,19 @@ int btrfs_truncate_page(struct inode *inode, loff_t from, loff_t len,
|
|||||||
char *kaddr;
|
char *kaddr;
|
||||||
u32 blocksize = root->sectorsize;
|
u32 blocksize = root->sectorsize;
|
||||||
pgoff_t index = from >> PAGE_CACHE_SHIFT;
|
pgoff_t index = from >> PAGE_CACHE_SHIFT;
|
||||||
unsigned offset = from & (PAGE_CACHE_SIZE-1);
|
unsigned offset = from & (blocksize - 1);
|
||||||
struct page *page;
|
struct page *page;
|
||||||
gfp_t mask = btrfs_alloc_write_mask(mapping);
|
gfp_t mask = btrfs_alloc_write_mask(mapping);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u64 page_start;
|
u64 block_start;
|
||||||
u64 page_end;
|
u64 block_end;
|
||||||
|
|
||||||
if ((offset & (blocksize - 1)) == 0 &&
|
if ((offset & (blocksize - 1)) == 0 &&
|
||||||
(!len || ((len & (blocksize - 1)) == 0)))
|
(!len || ((len & (blocksize - 1)) == 0)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = btrfs_delalloc_reserve_space(inode,
|
ret = btrfs_delalloc_reserve_space(inode,
|
||||||
round_down(from, PAGE_CACHE_SIZE), PAGE_CACHE_SIZE);
|
round_down(from, blocksize), blocksize);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -4641,14 +4644,14 @@ int btrfs_truncate_page(struct inode *inode, loff_t from, loff_t len,
|
|||||||
page = find_or_create_page(mapping, index, mask);
|
page = find_or_create_page(mapping, index, mask);
|
||||||
if (!page) {
|
if (!page) {
|
||||||
btrfs_delalloc_release_space(inode,
|
btrfs_delalloc_release_space(inode,
|
||||||
round_down(from, PAGE_CACHE_SIZE),
|
round_down(from, blocksize),
|
||||||
PAGE_CACHE_SIZE);
|
blocksize);
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
page_start = page_offset(page);
|
block_start = round_down(from, blocksize);
|
||||||
page_end = page_start + PAGE_CACHE_SIZE - 1;
|
block_end = block_start + blocksize - 1;
|
||||||
|
|
||||||
if (!PageUptodate(page)) {
|
if (!PageUptodate(page)) {
|
||||||
ret = btrfs_readpage(NULL, page);
|
ret = btrfs_readpage(NULL, page);
|
||||||
@ -4665,12 +4668,12 @@ int btrfs_truncate_page(struct inode *inode, loff_t from, loff_t len,
|
|||||||
}
|
}
|
||||||
wait_on_page_writeback(page);
|
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);
|
set_page_extent_mapped(page);
|
||||||
|
|
||||||
ordered = btrfs_lookup_ordered_extent(inode, page_start);
|
ordered = btrfs_lookup_ordered_extent(inode, block_start);
|
||||||
if (ordered) {
|
if (ordered) {
|
||||||
unlock_extent_cached(io_tree, page_start, page_end,
|
unlock_extent_cached(io_tree, block_start, block_end,
|
||||||
&cached_state, GFP_NOFS);
|
&cached_state, GFP_NOFS);
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
page_cache_release(page);
|
page_cache_release(page);
|
||||||
@ -4679,39 +4682,41 @@ int btrfs_truncate_page(struct inode *inode, loff_t from, loff_t len,
|
|||||||
goto 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_DIRTY | EXTENT_DELALLOC |
|
||||||
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, page_end,
|
ret = btrfs_set_extent_delalloc(inode, block_start, block_end,
|
||||||
&cached_state);
|
&cached_state);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
unlock_extent_cached(io_tree, page_start, page_end,
|
unlock_extent_cached(io_tree, block_start, block_end,
|
||||||
&cached_state, GFP_NOFS);
|
&cached_state, GFP_NOFS);
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset != PAGE_CACHE_SIZE) {
|
if (offset != blocksize) {
|
||||||
if (!len)
|
if (!len)
|
||||||
len = PAGE_CACHE_SIZE - offset;
|
len = blocksize - offset;
|
||||||
kaddr = kmap(page);
|
kaddr = kmap(page);
|
||||||
if (front)
|
if (front)
|
||||||
memset(kaddr, 0, offset);
|
memset(kaddr + (block_start - page_offset(page)),
|
||||||
|
0, offset);
|
||||||
else
|
else
|
||||||
memset(kaddr + offset, 0, len);
|
memset(kaddr + (block_start - page_offset(page)) + offset,
|
||||||
|
0, len);
|
||||||
flush_dcache_page(page);
|
flush_dcache_page(page);
|
||||||
kunmap(page);
|
kunmap(page);
|
||||||
}
|
}
|
||||||
ClearPageChecked(page);
|
ClearPageChecked(page);
|
||||||
set_page_dirty(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);
|
GFP_NOFS);
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
if (ret)
|
if (ret)
|
||||||
btrfs_delalloc_release_space(inode, page_start,
|
btrfs_delalloc_release_space(inode, block_start,
|
||||||
PAGE_CACHE_SIZE);
|
blocksize);
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
page_cache_release(page);
|
page_cache_release(page);
|
||||||
out:
|
out:
|
||||||
@ -4782,11 +4787,11 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
|
|||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If our size started in the middle of a page we need to zero out the
|
* If our size started in the middle of a block we need to zero out the
|
||||||
* rest of the page before we expand the i_size, otherwise we could
|
* rest of the block before we expand the i_size, otherwise we could
|
||||||
* expose stale data.
|
* expose stale data.
|
||||||
*/
|
*/
|
||||||
err = btrfs_truncate_page(inode, oldsize, 0, 0);
|
err = btrfs_truncate_block(inode, oldsize, 0, 0);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -4895,7 +4900,6 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (newsize > oldsize) {
|
if (newsize > oldsize) {
|
||||||
truncate_pagecache(inode, newsize);
|
|
||||||
/*
|
/*
|
||||||
* Don't do an expanding truncate while snapshoting is ongoing.
|
* Don't do an expanding truncate while snapshoting is ongoing.
|
||||||
* This is to ensure the snapshot captures a fully consistent
|
* This is to ensure the snapshot captures a fully consistent
|
||||||
@ -4918,6 +4922,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
|
|||||||
|
|
||||||
i_size_write(inode, newsize);
|
i_size_write(inode, newsize);
|
||||||
btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL);
|
btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL);
|
||||||
|
pagecache_isize_extended(inode, oldsize, newsize);
|
||||||
ret = btrfs_update_inode(trans, root, inode);
|
ret = btrfs_update_inode(trans, root, inode);
|
||||||
btrfs_end_write_no_snapshoting(root);
|
btrfs_end_write_no_snapshoting(root);
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
@ -7752,9 +7757,9 @@ static int btrfs_check_dio_repairable(struct inode *inode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int dio_read_error(struct inode *inode, struct bio *failed_bio,
|
static int dio_read_error(struct inode *inode, struct bio *failed_bio,
|
||||||
struct page *page, u64 start, u64 end,
|
struct page *page, unsigned int pgoff,
|
||||||
int failed_mirror, bio_end_io_t *repair_endio,
|
u64 start, u64 end, int failed_mirror,
|
||||||
void *repair_arg)
|
bio_end_io_t *repair_endio, void *repair_arg)
|
||||||
{
|
{
|
||||||
struct io_failure_record *failrec;
|
struct io_failure_record *failrec;
|
||||||
struct bio *bio;
|
struct bio *bio;
|
||||||
@ -7775,7 +7780,9 @@ static int dio_read_error(struct inode *inode, struct bio *failed_bio,
|
|||||||
return -EIO;
|
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;
|
read_mode = READ_SYNC | REQ_FAILFAST_DEV;
|
||||||
else
|
else
|
||||||
read_mode = READ_SYNC;
|
read_mode = READ_SYNC;
|
||||||
@ -7783,7 +7790,7 @@ static int dio_read_error(struct inode *inode, struct bio *failed_bio,
|
|||||||
isector = start - btrfs_io_bio(failed_bio)->logical;
|
isector = start - btrfs_io_bio(failed_bio)->logical;
|
||||||
isector >>= inode->i_sb->s_blocksize_bits;
|
isector >>= inode->i_sb->s_blocksize_bits;
|
||||||
bio = btrfs_create_repair_bio(inode, failed_bio, failrec, page,
|
bio = btrfs_create_repair_bio(inode, failed_bio, failrec, page,
|
||||||
0, isector, repair_endio, repair_arg);
|
pgoff, isector, repair_endio, repair_arg);
|
||||||
if (!bio) {
|
if (!bio) {
|
||||||
free_io_failure(inode, failrec);
|
free_io_failure(inode, failrec);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
@ -7813,12 +7820,17 @@ struct btrfs_retry_complete {
|
|||||||
static void btrfs_retry_endio_nocsum(struct bio *bio)
|
static void btrfs_retry_endio_nocsum(struct bio *bio)
|
||||||
{
|
{
|
||||||
struct btrfs_retry_complete *done = bio->bi_private;
|
struct btrfs_retry_complete *done = bio->bi_private;
|
||||||
|
struct inode *inode;
|
||||||
struct bio_vec *bvec;
|
struct bio_vec *bvec;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (bio->bi_error)
|
if (bio->bi_error)
|
||||||
goto end;
|
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;
|
done->uptodate = 1;
|
||||||
bio_for_each_segment_all(bvec, bio, i)
|
bio_for_each_segment_all(bvec, bio, i)
|
||||||
clean_io_failure(done->inode, done->start, bvec->bv_page, 0);
|
clean_io_failure(done->inode, done->start, bvec->bv_page, 0);
|
||||||
@ -7830,25 +7842,35 @@ static void btrfs_retry_endio_nocsum(struct bio *bio)
|
|||||||
static int __btrfs_correct_data_nocsum(struct inode *inode,
|
static int __btrfs_correct_data_nocsum(struct inode *inode,
|
||||||
struct btrfs_io_bio *io_bio)
|
struct btrfs_io_bio *io_bio)
|
||||||
{
|
{
|
||||||
|
struct btrfs_fs_info *fs_info;
|
||||||
struct bio_vec *bvec;
|
struct bio_vec *bvec;
|
||||||
struct btrfs_retry_complete done;
|
struct btrfs_retry_complete done;
|
||||||
u64 start;
|
u64 start;
|
||||||
|
unsigned int pgoff;
|
||||||
|
u32 sectorsize;
|
||||||
|
int nr_sectors;
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
fs_info = BTRFS_I(inode)->root->fs_info;
|
||||||
|
sectorsize = BTRFS_I(inode)->root->sectorsize;
|
||||||
|
|
||||||
start = io_bio->logical;
|
start = io_bio->logical;
|
||||||
done.inode = inode;
|
done.inode = inode;
|
||||||
|
|
||||||
bio_for_each_segment_all(bvec, &io_bio->bio, i) {
|
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.uptodate = 0;
|
||||||
done.start = start;
|
done.start = start;
|
||||||
init_completion(&done.done);
|
init_completion(&done.done);
|
||||||
|
|
||||||
ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page, start,
|
ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page,
|
||||||
start + bvec->bv_len - 1,
|
pgoff, start, start + sectorsize - 1,
|
||||||
io_bio->mirror_num,
|
io_bio->mirror_num,
|
||||||
btrfs_retry_endio_nocsum, &done);
|
btrfs_retry_endio_nocsum, &done);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -7856,10 +7878,15 @@ static int __btrfs_correct_data_nocsum(struct inode *inode,
|
|||||||
|
|
||||||
if (!done.uptodate) {
|
if (!done.uptodate) {
|
||||||
/* We might have another mirror, so try again */
|
/* 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;
|
return 0;
|
||||||
@ -7869,7 +7896,9 @@ static void btrfs_retry_endio(struct bio *bio)
|
|||||||
{
|
{
|
||||||
struct btrfs_retry_complete *done = bio->bi_private;
|
struct btrfs_retry_complete *done = bio->bi_private;
|
||||||
struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
|
struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
|
||||||
|
struct inode *inode;
|
||||||
struct bio_vec *bvec;
|
struct bio_vec *bvec;
|
||||||
|
u64 start;
|
||||||
int uptodate;
|
int uptodate;
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
@ -7878,13 +7907,20 @@ static void btrfs_retry_endio(struct bio *bio)
|
|||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
uptodate = 1;
|
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) {
|
bio_for_each_segment_all(bvec, bio, i) {
|
||||||
ret = __readpage_endio_check(done->inode, io_bio, i,
|
ret = __readpage_endio_check(done->inode, io_bio, i,
|
||||||
bvec->bv_page, 0,
|
bvec->bv_page, bvec->bv_offset,
|
||||||
done->start, bvec->bv_len);
|
done->start, bvec->bv_len);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
clean_io_failure(done->inode, done->start,
|
clean_io_failure(done->inode, done->start,
|
||||||
bvec->bv_page, 0);
|
bvec->bv_page, bvec->bv_offset);
|
||||||
else
|
else
|
||||||
uptodate = 0;
|
uptodate = 0;
|
||||||
}
|
}
|
||||||
@ -7898,20 +7934,34 @@ static void btrfs_retry_endio(struct bio *bio)
|
|||||||
static int __btrfs_subio_endio_read(struct inode *inode,
|
static int __btrfs_subio_endio_read(struct inode *inode,
|
||||||
struct btrfs_io_bio *io_bio, int err)
|
struct btrfs_io_bio *io_bio, int err)
|
||||||
{
|
{
|
||||||
|
struct btrfs_fs_info *fs_info;
|
||||||
struct bio_vec *bvec;
|
struct bio_vec *bvec;
|
||||||
struct btrfs_retry_complete done;
|
struct btrfs_retry_complete done;
|
||||||
u64 start;
|
u64 start;
|
||||||
u64 offset = 0;
|
u64 offset = 0;
|
||||||
|
u32 sectorsize;
|
||||||
|
int nr_sectors;
|
||||||
|
unsigned int pgoff;
|
||||||
|
int csum_pos;
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
fs_info = BTRFS_I(inode)->root->fs_info;
|
||||||
|
sectorsize = BTRFS_I(inode)->root->sectorsize;
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
start = io_bio->logical;
|
start = io_bio->logical;
|
||||||
done.inode = inode;
|
done.inode = inode;
|
||||||
|
|
||||||
bio_for_each_segment_all(bvec, &io_bio->bio, i) {
|
bio_for_each_segment_all(bvec, &io_bio->bio, i) {
|
||||||
ret = __readpage_endio_check(inode, io_bio, i, bvec->bv_page,
|
nr_sectors = BTRFS_BYTES_TO_BLKS(fs_info, bvec->bv_len);
|
||||||
0, start, 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))
|
if (likely(!ret))
|
||||||
goto next;
|
goto next;
|
||||||
try_again:
|
try_again:
|
||||||
@ -7919,10 +7969,10 @@ static int __btrfs_subio_endio_read(struct inode *inode,
|
|||||||
done.start = start;
|
done.start = start;
|
||||||
init_completion(&done.done);
|
init_completion(&done.done);
|
||||||
|
|
||||||
ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page, start,
|
ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page,
|
||||||
start + bvec->bv_len - 1,
|
pgoff, start, start + sectorsize - 1,
|
||||||
io_bio->mirror_num,
|
io_bio->mirror_num,
|
||||||
btrfs_retry_endio, &done);
|
btrfs_retry_endio, &done);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
err = ret;
|
err = ret;
|
||||||
goto next;
|
goto next;
|
||||||
@ -7935,8 +7985,15 @@ static int __btrfs_subio_endio_read(struct inode *inode,
|
|||||||
goto try_again;
|
goto try_again;
|
||||||
}
|
}
|
||||||
next:
|
next:
|
||||||
offset += bvec->bv_len;
|
offset += sectorsize;
|
||||||
start += bvec->bv_len;
|
start += sectorsize;
|
||||||
|
|
||||||
|
ASSERT(nr_sectors);
|
||||||
|
|
||||||
|
if (--nr_sectors) {
|
||||||
|
pgoff += sectorsize;
|
||||||
|
goto next_block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@ -8188,9 +8245,11 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
|||||||
u64 file_offset = dip->logical_offset;
|
u64 file_offset = dip->logical_offset;
|
||||||
u64 submit_len = 0;
|
u64 submit_len = 0;
|
||||||
u64 map_length;
|
u64 map_length;
|
||||||
int nr_pages = 0;
|
u32 blocksize = root->sectorsize;
|
||||||
int ret;
|
|
||||||
int async_submit = 0;
|
int async_submit = 0;
|
||||||
|
int nr_sectors;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
map_length = orig_bio->bi_iter.bi_size;
|
map_length = orig_bio->bi_iter.bi_size;
|
||||||
ret = btrfs_map_block(root->fs_info, rw, start_sector << 9,
|
ret = btrfs_map_block(root->fs_info, rw, start_sector << 9,
|
||||||
@ -8220,9 +8279,12 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
|||||||
atomic_inc(&dip->pending_bios);
|
atomic_inc(&dip->pending_bios);
|
||||||
|
|
||||||
while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) {
|
while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) {
|
||||||
if (map_length < submit_len + bvec->bv_len ||
|
nr_sectors = BTRFS_BYTES_TO_BLKS(root->fs_info, bvec->bv_len);
|
||||||
bio_add_page(bio, bvec->bv_page, bvec->bv_len,
|
i = 0;
|
||||||
bvec->bv_offset) < bvec->bv_len) {
|
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
|
* inc the count before we submit the bio so
|
||||||
* we know the end IO handler won't happen before
|
* we know the end IO handler won't happen before
|
||||||
@ -8243,7 +8305,6 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
|||||||
file_offset += submit_len;
|
file_offset += submit_len;
|
||||||
|
|
||||||
submit_len = 0;
|
submit_len = 0;
|
||||||
nr_pages = 0;
|
|
||||||
|
|
||||||
bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev,
|
bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev,
|
||||||
start_sector, GFP_NOFS);
|
start_sector, GFP_NOFS);
|
||||||
@ -8261,9 +8322,14 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
|
|||||||
bio_put(bio);
|
bio_put(bio);
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goto next_block;
|
||||||
} else {
|
} else {
|
||||||
submit_len += bvec->bv_len;
|
submit_len += blocksize;
|
||||||
nr_pages++;
|
if (--nr_sectors) {
|
||||||
|
i++;
|
||||||
|
goto next_block;
|
||||||
|
}
|
||||||
bvec++;
|
bvec++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8628,6 +8694,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
|
|||||||
struct extent_state *cached_state = NULL;
|
struct extent_state *cached_state = NULL;
|
||||||
u64 page_start = page_offset(page);
|
u64 page_start = page_offset(page);
|
||||||
u64 page_end = page_start + PAGE_CACHE_SIZE - 1;
|
u64 page_end = page_start + PAGE_CACHE_SIZE - 1;
|
||||||
|
u64 start;
|
||||||
|
u64 end;
|
||||||
int inode_evicting = inode->i_state & I_FREEING;
|
int inode_evicting = inode->i_state & I_FREEING;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -8647,14 +8715,18 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
|
|||||||
|
|
||||||
if (!inode_evicting)
|
if (!inode_evicting)
|
||||||
lock_extent_bits(tree, page_start, page_end, &cached_state);
|
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) {
|
if (ordered) {
|
||||||
|
end = min(page_end, ordered->file_offset + ordered->len - 1);
|
||||||
/*
|
/*
|
||||||
* IO on this page will never be started, so we need
|
* IO on this page will never be started, so we need
|
||||||
* to account for any ordered extents now
|
* to account for any ordered extents now
|
||||||
*/
|
*/
|
||||||
if (!inode_evicting)
|
if (!inode_evicting)
|
||||||
clear_extent_bit(tree, page_start, page_end,
|
clear_extent_bit(tree, start, end,
|
||||||
EXTENT_DIRTY | EXTENT_DELALLOC |
|
EXTENT_DIRTY | EXTENT_DELALLOC |
|
||||||
EXTENT_LOCKED | EXTENT_DO_ACCOUNTING |
|
EXTENT_LOCKED | EXTENT_DO_ACCOUNTING |
|
||||||
EXTENT_DEFRAG, 1, 0, &cached_state,
|
EXTENT_DEFRAG, 1, 0, &cached_state,
|
||||||
@ -8671,22 +8743,26 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
|
|||||||
|
|
||||||
spin_lock_irq(&tree->lock);
|
spin_lock_irq(&tree->lock);
|
||||||
set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags);
|
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)
|
if (new_len < ordered->truncated_len)
|
||||||
ordered->truncated_len = new_len;
|
ordered->truncated_len = new_len;
|
||||||
spin_unlock_irq(&tree->lock);
|
spin_unlock_irq(&tree->lock);
|
||||||
|
|
||||||
if (btrfs_dec_test_ordered_pending(inode, &ordered,
|
if (btrfs_dec_test_ordered_pending(inode, &ordered,
|
||||||
page_start,
|
start,
|
||||||
PAGE_CACHE_SIZE, 1))
|
end - start + 1, 1))
|
||||||
btrfs_finish_ordered_io(ordered);
|
btrfs_finish_ordered_io(ordered);
|
||||||
}
|
}
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
if (!inode_evicting) {
|
if (!inode_evicting) {
|
||||||
cached_state = NULL;
|
cached_state = NULL;
|
||||||
lock_extent_bits(tree, page_start, page_end,
|
lock_extent_bits(tree, start, end,
|
||||||
&cached_state);
|
&cached_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
start = end + 1;
|
||||||
|
if (start < page_end)
|
||||||
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -8747,15 +8823,28 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||||||
loff_t size;
|
loff_t size;
|
||||||
int ret;
|
int ret;
|
||||||
int reserved = 0;
|
int reserved = 0;
|
||||||
|
u64 reserved_space;
|
||||||
u64 page_start;
|
u64 page_start;
|
||||||
u64 page_end;
|
u64 page_end;
|
||||||
|
u64 end;
|
||||||
|
|
||||||
|
reserved_space = PAGE_CACHE_SIZE;
|
||||||
|
|
||||||
sb_start_pagefault(inode->i_sb);
|
sb_start_pagefault(inode->i_sb);
|
||||||
page_start = page_offset(page);
|
page_start = page_offset(page);
|
||||||
page_end = page_start + PAGE_CACHE_SIZE - 1;
|
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,
|
ret = btrfs_delalloc_reserve_space(inode, page_start,
|
||||||
PAGE_CACHE_SIZE);
|
reserved_space);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
ret = file_update_time(vma->vm_file);
|
ret = file_update_time(vma->vm_file);
|
||||||
reserved = 1;
|
reserved = 1;
|
||||||
@ -8789,7 +8878,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||||||
* we can't set the delalloc bits if there are pending ordered
|
* we can't set the delalloc bits if there are pending ordered
|
||||||
* extents. Drop our locks and wait for them to finish
|
* 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) {
|
if (ordered) {
|
||||||
unlock_extent_cached(io_tree, page_start, page_end,
|
unlock_extent_cached(io_tree, page_start, page_end,
|
||||||
&cached_state, GFP_NOFS);
|
&cached_state, GFP_NOFS);
|
||||||
@ -8799,6 +8888,18 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||||||
goto 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
|
* 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
|
* if it was already dirty, so for space accounting reasons we need to
|
||||||
@ -8806,12 +8907,12 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||||||
* is probably a better way to do this, but for now keep consistent with
|
* is probably a better way to do this, but for now keep consistent with
|
||||||
* prepare_pages in the normal write path.
|
* 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_DIRTY | EXTENT_DELALLOC |
|
||||||
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, page_end,
|
ret = btrfs_set_extent_delalloc(inode, page_start, end,
|
||||||
&cached_state);
|
&cached_state);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
unlock_extent_cached(io_tree, page_start, page_end,
|
unlock_extent_cached(io_tree, page_start, page_end,
|
||||||
@ -8850,7 +8951,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||||||
}
|
}
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
out:
|
out:
|
||||||
btrfs_delalloc_release_space(inode, page_start, PAGE_CACHE_SIZE);
|
btrfs_delalloc_release_space(inode, page_start, reserved_space);
|
||||||
out_noreserve:
|
out_noreserve:
|
||||||
sb_end_pagefault(inode->i_sb);
|
sb_end_pagefault(inode->i_sb);
|
||||||
return ret;
|
return ret;
|
||||||
@ -9236,7 +9337,6 @@ static int btrfs_getattr(struct vfsmount *mnt,
|
|||||||
|
|
||||||
generic_fillattr(inode, stat);
|
generic_fillattr(inode, stat);
|
||||||
stat->dev = BTRFS_I(inode)->root->anon_dev;
|
stat->dev = BTRFS_I(inode)->root->anon_dev;
|
||||||
stat->blksize = PAGE_CACHE_SIZE;
|
|
||||||
|
|
||||||
spin_lock(&BTRFS_I(inode)->lock);
|
spin_lock(&BTRFS_I(inode)->lock);
|
||||||
delalloc_bytes = BTRFS_I(inode)->delalloc_bytes;
|
delalloc_bytes = BTRFS_I(inode)->delalloc_bytes;
|
||||||
|
@ -3814,8 +3814,9 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
|
|||||||
* Truncate page cache pages so that future reads will see the cloned
|
* Truncate page cache pages so that future reads will see the cloned
|
||||||
* data immediately and not the previous data.
|
* data immediately and not the previous data.
|
||||||
*/
|
*/
|
||||||
truncate_inode_pages_range(&inode->i_data, destoff,
|
truncate_inode_pages_range(&inode->i_data,
|
||||||
PAGE_CACHE_ALIGN(destoff + len) - 1);
|
round_down(destoff, PAGE_CACHE_SIZE),
|
||||||
|
round_up(destoff + len, PAGE_CACHE_SIZE) - 1);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
if (!same_inode)
|
if (!same_inode)
|
||||||
btrfs_double_inode_unlock(src, inode);
|
btrfs_double_inode_unlock(src, inode);
|
||||||
|
Loading…
Reference in New Issue
Block a user