Btrfs: Fix i_blocks accounting
Now that delayed allocation accounting works, i_blocks accounting is changed to only modify i_blocks when extents inserted or removed. The fillattr call is changed to include the delayed allocation byte count in the i_blocks result. Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
parent
a86c12c73d
commit
9069218d44
|
@ -36,6 +36,7 @@ struct btrfs_inode {
|
||||||
* transid of the trans_handle that last modified this inode
|
* transid of the trans_handle that last modified this inode
|
||||||
*/
|
*/
|
||||||
u64 last_trans;
|
u64 last_trans;
|
||||||
|
u64 delalloc_bytes;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
};
|
};
|
||||||
static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
|
static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
|
||||||
|
|
|
@ -1161,6 +1161,15 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
|
||||||
struct btrfs_root *root, struct btrfs_path *path,
|
struct btrfs_root *root, struct btrfs_path *path,
|
||||||
u64 isize);
|
u64 isize);
|
||||||
/* inode.c */
|
/* inode.c */
|
||||||
|
static inline void dec_i_blocks(struct inode *inode, u64 dec)
|
||||||
|
{
|
||||||
|
dec = dec >> 9;
|
||||||
|
if (dec <= inode->i_blocks)
|
||||||
|
inode->i_blocks -= dec;
|
||||||
|
else
|
||||||
|
inode->i_blocks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long btrfs_force_ra(struct address_space *mapping,
|
unsigned long btrfs_force_ra(struct address_space *mapping,
|
||||||
struct file_ra_state *ra, struct file *file,
|
struct file_ra_state *ra, struct file *file,
|
||||||
pgoff_t offset, pgoff_t last_index);
|
pgoff_t offset, pgoff_t last_index);
|
||||||
|
|
|
@ -175,6 +175,7 @@ static int noinline insert_inline_extent(struct btrfs_trans_handle *trans,
|
||||||
leaf = path->nodes[0];
|
leaf = path->nodes[0];
|
||||||
ei = btrfs_item_ptr(leaf, path->slots[0],
|
ei = btrfs_item_ptr(leaf, path->slots[0],
|
||||||
struct btrfs_file_extent_item);
|
struct btrfs_file_extent_item);
|
||||||
|
inode->i_blocks += (offset + size - found_end) >> 9;
|
||||||
}
|
}
|
||||||
if (found_end < offset) {
|
if (found_end < offset) {
|
||||||
ptr = btrfs_file_extent_inline_start(ei) + found_size;
|
ptr = btrfs_file_extent_inline_start(ei) + found_size;
|
||||||
|
@ -184,6 +185,7 @@ static int noinline insert_inline_extent(struct btrfs_trans_handle *trans,
|
||||||
insert:
|
insert:
|
||||||
btrfs_release_path(root, path);
|
btrfs_release_path(root, path);
|
||||||
datasize = offset + size - key.offset;
|
datasize = offset + size - key.offset;
|
||||||
|
inode->i_blocks += datasize >> 9;
|
||||||
datasize = btrfs_file_extent_calc_inline_size(datasize);
|
datasize = btrfs_file_extent_calc_inline_size(datasize);
|
||||||
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
ret = btrfs_insert_empty_item(trans, root, path, &key,
|
||||||
datasize);
|
datasize);
|
||||||
|
@ -256,7 +258,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
btrfs_set_trans_block_group(trans, inode);
|
btrfs_set_trans_block_group(trans, inode);
|
||||||
inode->i_blocks += num_bytes >> 9;
|
|
||||||
hint_byte = 0;
|
hint_byte = 0;
|
||||||
|
|
||||||
if ((end_of_last_block & 4095) == 0) {
|
if ((end_of_last_block & 4095) == 0) {
|
||||||
|
@ -410,7 +411,7 @@ int btrfs_check_file(struct btrfs_root *root, struct inode *inode)
|
||||||
if (found_key.type != BTRFS_EXTENT_DATA_KEY)
|
if (found_key.type != BTRFS_EXTENT_DATA_KEY)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (found_key.offset != last_offset) {
|
if (found_key.offset < last_offset) {
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
btrfs_print_leaf(root, leaf);
|
btrfs_print_leaf(root, leaf);
|
||||||
printk("inode %lu found offset %Lu expected %Lu\n",
|
printk("inode %lu found offset %Lu expected %Lu\n",
|
||||||
|
@ -435,7 +436,7 @@ int btrfs_check_file(struct btrfs_root *root, struct inode *inode)
|
||||||
last_offset = extent_end;
|
last_offset = extent_end;
|
||||||
path->slots[0]++;
|
path->slots[0]++;
|
||||||
}
|
}
|
||||||
if (last_offset < inode->i_size) {
|
if (0 && last_offset < inode->i_size) {
|
||||||
WARN_ON(1);
|
WARN_ON(1);
|
||||||
btrfs_print_leaf(root, leaf);
|
btrfs_print_leaf(root, leaf);
|
||||||
printk("inode %lu found offset %Lu size %Lu\n", inode->i_ino,
|
printk("inode %lu found offset %Lu size %Lu\n", inode->i_ino,
|
||||||
|
@ -608,8 +609,7 @@ next_slot:
|
||||||
extent);
|
extent);
|
||||||
if (btrfs_file_extent_disk_bytenr(leaf,
|
if (btrfs_file_extent_disk_bytenr(leaf,
|
||||||
extent)) {
|
extent)) {
|
||||||
inode->i_blocks -=
|
dec_i_blocks(inode, old_num - new_num);
|
||||||
(old_num - new_num) >> 9;
|
|
||||||
}
|
}
|
||||||
btrfs_set_file_extent_num_bytes(leaf, extent,
|
btrfs_set_file_extent_num_bytes(leaf, extent,
|
||||||
new_num);
|
new_num);
|
||||||
|
@ -620,6 +620,8 @@ next_slot:
|
||||||
u32 new_size;
|
u32 new_size;
|
||||||
new_size = btrfs_file_extent_calc_inline_size(
|
new_size = btrfs_file_extent_calc_inline_size(
|
||||||
inline_limit - key.offset);
|
inline_limit - key.offset);
|
||||||
|
dec_i_blocks(inode, (extent_end - key.offset) -
|
||||||
|
(inline_limit - key.offset));
|
||||||
btrfs_truncate_item(trans, root, path,
|
btrfs_truncate_item(trans, root, path,
|
||||||
new_size, 1);
|
new_size, 1);
|
||||||
}
|
}
|
||||||
|
@ -653,7 +655,7 @@ next_slot:
|
||||||
btrfs_release_path(root, path);
|
btrfs_release_path(root, path);
|
||||||
extent = NULL;
|
extent = NULL;
|
||||||
if (found_extent && disk_bytenr != 0) {
|
if (found_extent && disk_bytenr != 0) {
|
||||||
inode->i_blocks -= extent_num_bytes >> 9;
|
dec_i_blocks(inode, extent_num_bytes);
|
||||||
ret = btrfs_free_extent(trans, root,
|
ret = btrfs_free_extent(trans, root,
|
||||||
disk_bytenr,
|
disk_bytenr,
|
||||||
disk_num_bytes,
|
disk_num_bytes,
|
||||||
|
@ -674,6 +676,8 @@ next_slot:
|
||||||
u32 new_size;
|
u32 new_size;
|
||||||
new_size = btrfs_file_extent_calc_inline_size(
|
new_size = btrfs_file_extent_calc_inline_size(
|
||||||
extent_end - end);
|
extent_end - end);
|
||||||
|
dec_i_blocks(inode, (extent_end - key.offset) -
|
||||||
|
(extent_end - end));
|
||||||
btrfs_truncate_item(trans, root, path, new_size, 0);
|
btrfs_truncate_item(trans, root, path, new_size, 0);
|
||||||
}
|
}
|
||||||
/* create bookend, splitting the extent in two */
|
/* create bookend, splitting the extent in two */
|
||||||
|
@ -718,6 +722,7 @@ next_slot:
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
btrfs_free_path(path);
|
btrfs_free_path(path);
|
||||||
|
btrfs_check_file(root, inode);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
|
||||||
ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
|
ret = btrfs_insert_file_extent(trans, root, inode->i_ino,
|
||||||
start, ins.objectid, ins.offset,
|
start, ins.objectid, ins.offset,
|
||||||
ins.offset);
|
ins.offset);
|
||||||
|
inode->i_blocks += ins.offset >> 9;
|
||||||
btrfs_check_file(root, inode);
|
btrfs_check_file(root, inode);
|
||||||
num_bytes -= cur_alloc_size;
|
num_bytes -= cur_alloc_size;
|
||||||
alloc_hint = ins.objectid + ins.offset;
|
alloc_hint = ins.objectid + ins.offset;
|
||||||
|
@ -142,6 +143,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end)
|
||||||
btrfs_drop_extent_cache(inode, orig_start,
|
btrfs_drop_extent_cache(inode, orig_start,
|
||||||
orig_start + orig_num_bytes - 1);
|
orig_start + orig_num_bytes - 1);
|
||||||
btrfs_add_ordered_inode(inode);
|
btrfs_add_ordered_inode(inode);
|
||||||
|
btrfs_update_inode(trans, root, inode);
|
||||||
out:
|
out:
|
||||||
btrfs_end_transaction(trans, root);
|
btrfs_end_transaction(trans, root);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -265,6 +267,7 @@ int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end,
|
||||||
if (!(old & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
|
if (!(old & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
|
||||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||||
spin_lock(&root->fs_info->delalloc_lock);
|
spin_lock(&root->fs_info->delalloc_lock);
|
||||||
|
BTRFS_I(inode)->delalloc_bytes += end - start + 1;
|
||||||
root->fs_info->delalloc_bytes += end - start + 1;
|
root->fs_info->delalloc_bytes += end - start + 1;
|
||||||
spin_unlock(&root->fs_info->delalloc_lock);
|
spin_unlock(&root->fs_info->delalloc_lock);
|
||||||
}
|
}
|
||||||
|
@ -281,8 +284,10 @@ int btrfs_clear_bit_hook(struct inode *inode, u64 start, u64 end,
|
||||||
printk("warning: delalloc account %Lu %Lu\n",
|
printk("warning: delalloc account %Lu %Lu\n",
|
||||||
end - start + 1, root->fs_info->delalloc_bytes);
|
end - start + 1, root->fs_info->delalloc_bytes);
|
||||||
root->fs_info->delalloc_bytes = 0;
|
root->fs_info->delalloc_bytes = 0;
|
||||||
|
BTRFS_I(inode)->delalloc_bytes = 0;
|
||||||
} else {
|
} else {
|
||||||
root->fs_info->delalloc_bytes -= end - start + 1;
|
root->fs_info->delalloc_bytes -= end - start + 1;
|
||||||
|
BTRFS_I(inode)->delalloc_bytes -= end - start + 1;
|
||||||
}
|
}
|
||||||
spin_unlock(&root->fs_info->delalloc_lock);
|
spin_unlock(&root->fs_info->delalloc_lock);
|
||||||
}
|
}
|
||||||
|
@ -833,32 +838,37 @@ search_again:
|
||||||
btrfs_set_file_extent_num_bytes(leaf, fi,
|
btrfs_set_file_extent_num_bytes(leaf, fi,
|
||||||
extent_num_bytes);
|
extent_num_bytes);
|
||||||
num_dec = (orig_num_bytes -
|
num_dec = (orig_num_bytes -
|
||||||
extent_num_bytes) >> 9;
|
extent_num_bytes);
|
||||||
if (extent_start != 0) {
|
if (extent_start != 0)
|
||||||
inode->i_blocks -= num_dec;
|
dec_i_blocks(inode, num_dec);
|
||||||
}
|
|
||||||
btrfs_mark_buffer_dirty(leaf);
|
btrfs_mark_buffer_dirty(leaf);
|
||||||
} else {
|
} else {
|
||||||
extent_num_bytes =
|
extent_num_bytes =
|
||||||
btrfs_file_extent_disk_num_bytes(leaf,
|
btrfs_file_extent_disk_num_bytes(leaf,
|
||||||
fi);
|
fi);
|
||||||
/* FIXME blocksize != 4096 */
|
/* FIXME blocksize != 4096 */
|
||||||
num_dec = btrfs_file_extent_num_bytes(leaf,
|
num_dec = btrfs_file_extent_num_bytes(leaf, fi);
|
||||||
fi) >> 9;
|
|
||||||
if (extent_start != 0) {
|
if (extent_start != 0) {
|
||||||
found_extent = 1;
|
found_extent = 1;
|
||||||
inode->i_blocks -= num_dec;
|
dec_i_blocks(inode, num_dec);
|
||||||
}
|
}
|
||||||
root_gen = btrfs_header_generation(leaf);
|
root_gen = btrfs_header_generation(leaf);
|
||||||
root_owner = btrfs_header_owner(leaf);
|
root_owner = btrfs_header_owner(leaf);
|
||||||
}
|
}
|
||||||
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE &&
|
} else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
|
||||||
!del_item) {
|
if (!del_item) {
|
||||||
u32 newsize = inode->i_size - found_key.offset;
|
u32 newsize = inode->i_size - found_key.offset;
|
||||||
newsize = btrfs_file_extent_calc_inline_size(newsize);
|
dec_i_blocks(inode, item_end + 1 -
|
||||||
ret = btrfs_truncate_item(trans, root, path,
|
found_key.offset - newsize);
|
||||||
newsize, 1);
|
newsize =
|
||||||
BUG_ON(ret);
|
btrfs_file_extent_calc_inline_size(newsize);
|
||||||
|
ret = btrfs_truncate_item(trans, root, path,
|
||||||
|
newsize, 1);
|
||||||
|
BUG_ON(ret);
|
||||||
|
} else {
|
||||||
|
dec_i_blocks(inode, item_end + 1 -
|
||||||
|
found_key.offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delete:
|
delete:
|
||||||
if (del_item) {
|
if (del_item) {
|
||||||
|
@ -1222,6 +1232,7 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
|
||||||
struct btrfs_iget_args *args = p;
|
struct btrfs_iget_args *args = p;
|
||||||
inode->i_ino = args->ino;
|
inode->i_ino = args->ino;
|
||||||
BTRFS_I(inode)->root = args->root;
|
BTRFS_I(inode)->root = args->root;
|
||||||
|
BTRFS_I(inode)->delalloc_bytes = 0;
|
||||||
extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
|
extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
|
||||||
extent_io_tree_init(&BTRFS_I(inode)->io_tree,
|
extent_io_tree_init(&BTRFS_I(inode)->io_tree,
|
||||||
inode->i_mapping, GFP_NOFS);
|
inode->i_mapping, GFP_NOFS);
|
||||||
|
@ -1528,6 +1539,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
|
||||||
extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
|
extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
|
||||||
extent_io_tree_init(&BTRFS_I(inode)->io_tree,
|
extent_io_tree_init(&BTRFS_I(inode)->io_tree,
|
||||||
inode->i_mapping, GFP_NOFS);
|
inode->i_mapping, GFP_NOFS);
|
||||||
|
BTRFS_I(inode)->delalloc_bytes = 0;
|
||||||
BTRFS_I(inode)->root = root;
|
BTRFS_I(inode)->root = root;
|
||||||
|
|
||||||
if (mode & S_IFDIR)
|
if (mode & S_IFDIR)
|
||||||
|
@ -1746,6 +1758,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
|
||||||
extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
|
extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
|
||||||
extent_io_tree_init(&BTRFS_I(inode)->io_tree,
|
extent_io_tree_init(&BTRFS_I(inode)->io_tree,
|
||||||
inode->i_mapping, GFP_NOFS);
|
inode->i_mapping, GFP_NOFS);
|
||||||
|
BTRFS_I(inode)->delalloc_bytes = 0;
|
||||||
BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
|
BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
|
||||||
}
|
}
|
||||||
dir->i_sb->s_dirt = 1;
|
dir->i_sb->s_dirt = 1;
|
||||||
|
@ -2797,6 +2810,7 @@ static int btrfs_getattr(struct vfsmount *mnt,
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
generic_fillattr(inode, stat);
|
generic_fillattr(inode, stat);
|
||||||
stat->blksize = PAGE_CACHE_SIZE;
|
stat->blksize = PAGE_CACHE_SIZE;
|
||||||
|
stat->blocks = inode->i_blocks + (BTRFS_I(inode)->delalloc_bytes >> 9);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2912,6 +2926,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
|
||||||
extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
|
extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
|
||||||
extent_io_tree_init(&BTRFS_I(inode)->io_tree,
|
extent_io_tree_init(&BTRFS_I(inode)->io_tree,
|
||||||
inode->i_mapping, GFP_NOFS);
|
inode->i_mapping, GFP_NOFS);
|
||||||
|
BTRFS_I(inode)->delalloc_bytes = 0;
|
||||||
BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
|
BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
|
||||||
}
|
}
|
||||||
dir->i_sb->s_dirt = 1;
|
dir->i_sb->s_dirt = 1;
|
||||||
|
|
Loading…
Reference in a new issue