Btrfs: Fix i_blocks accounting
authorChris Mason <chris.mason@oracle.com>
Fri, 8 Feb 2008 18:49:28 +0000 (13:49 -0500)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:04:00 +0000 (11:04 -0400)
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>
fs/btrfs/btrfs_inode.h
fs/btrfs/ctree.h
fs/btrfs/file.c
fs/btrfs/inode.c

index 9a0647dc5a0b0ace76f89e68b1728b7a4ccc8d62..9b9db9cbc019ad0703137885020968cb1d494aab 100644 (file)
@@ -36,6 +36,7 @@ struct btrfs_inode {
         * transid of the trans_handle that last modified this inode
         */
        u64 last_trans;
+       u64 delalloc_bytes;
        u32 flags;
 };
 static inline struct btrfs_inode *BTRFS_I(struct inode *inode)
index dfb700efcd6bb7e021df039a8066c8779bee7223..52144b04f1af100ee2ad2f927a38da18c6a21fe4 100644 (file)
@@ -1161,6 +1161,15 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans,
                        struct btrfs_root *root, struct btrfs_path *path,
                        u64 isize);
 /* 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,
                              struct file_ra_state *ra, struct file *file,
                              pgoff_t offset, pgoff_t last_index);
index bfa4149c053dcaa101018cd93386ddb47db1d128..f893960825440256a6faef215e996d30a11e5741 100644 (file)
@@ -175,6 +175,7 @@ static int noinline insert_inline_extent(struct btrfs_trans_handle *trans,
                        leaf = path->nodes[0];
                        ei = btrfs_item_ptr(leaf, path->slots[0],
                                            struct btrfs_file_extent_item);
+                       inode->i_blocks += (offset + size - found_end) >> 9;
                }
                if (found_end < offset) {
                        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:
                btrfs_release_path(root, path);
                datasize = offset + size - key.offset;
+               inode->i_blocks += datasize >> 9;
                datasize = btrfs_file_extent_calc_inline_size(datasize);
                ret = btrfs_insert_empty_item(trans, root, path, &key,
                                              datasize);
@@ -256,7 +258,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
                goto out_unlock;
        }
        btrfs_set_trans_block_group(trans, inode);
-       inode->i_blocks += num_bytes >> 9;
        hint_byte = 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)
                        goto out;
 
-               if (found_key.offset != last_offset) {
+               if (found_key.offset < last_offset) {
                        WARN_ON(1);
                        btrfs_print_leaf(root, leaf);
                        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;
                path->slots[0]++;
        }
-       if (last_offset < inode->i_size) {
+       if (0 && last_offset < inode->i_size) {
                WARN_ON(1);
                btrfs_print_leaf(root, leaf);
                printk("inode %lu found offset %Lu size %Lu\n", inode->i_ino,
@@ -608,8 +609,7 @@ next_slot:
                                                                      extent);
                                if (btrfs_file_extent_disk_bytenr(leaf,
                                                                  extent)) {
-                                       inode->i_blocks -=
-                                               (old_num - new_num) >> 9;
+                                       dec_i_blocks(inode, old_num - new_num);
                                }
                                btrfs_set_file_extent_num_bytes(leaf, extent,
                                                                new_num);
@@ -620,6 +620,8 @@ next_slot:
                                u32 new_size;
                                new_size = btrfs_file_extent_calc_inline_size(
                                                   inline_limit - key.offset);
+                               dec_i_blocks(inode, (extent_end - key.offset) -
+                                       (inline_limit - key.offset));
                                btrfs_truncate_item(trans, root, path,
                                                    new_size, 1);
                        }
@@ -653,7 +655,7 @@ next_slot:
                        btrfs_release_path(root, path);
                        extent = NULL;
                        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,
                                                disk_bytenr,
                                                disk_num_bytes,
@@ -674,6 +676,8 @@ next_slot:
                        u32 new_size;
                        new_size = btrfs_file_extent_calc_inline_size(
                                                   extent_end - end);
+                       dec_i_blocks(inode, (extent_end - key.offset) -
+                                       (extent_end - end));
                        btrfs_truncate_item(trans, root, path, new_size, 0);
                }
                /* create bookend, splitting the extent in two */
@@ -718,6 +722,7 @@ next_slot:
        }
 out:
        btrfs_free_path(path);
+       btrfs_check_file(root, inode);
        return ret;
 }
 
index 44fc94fee2c4ca3e2b5738ddef355c460c796e19..913ab128eee1b6039e9a9ba8f0e548d968af8e5f 100644 (file)
@@ -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,
                                               start, ins.objectid, ins.offset,
                                               ins.offset);
+               inode->i_blocks += ins.offset >> 9;
                btrfs_check_file(root, inode);
                num_bytes -= cur_alloc_size;
                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,
                                orig_start + orig_num_bytes - 1);
        btrfs_add_ordered_inode(inode);
+       btrfs_update_inode(trans, root, inode);
 out:
        btrfs_end_transaction(trans, root);
        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)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
                spin_lock(&root->fs_info->delalloc_lock);
+               BTRFS_I(inode)->delalloc_bytes += end - start + 1;
                root->fs_info->delalloc_bytes += end - start + 1;
                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",
                               end - start + 1, root->fs_info->delalloc_bytes);
                        root->fs_info->delalloc_bytes = 0;
+                       BTRFS_I(inode)->delalloc_bytes = 0;
                } else {
                        root->fs_info->delalloc_bytes -= end - start + 1;
+                       BTRFS_I(inode)->delalloc_bytes -= end - start + 1;
                }
                spin_unlock(&root->fs_info->delalloc_lock);
        }
@@ -833,32 +838,37 @@ search_again:
                                btrfs_set_file_extent_num_bytes(leaf, fi,
                                                         extent_num_bytes);
                                num_dec = (orig_num_bytes -
-                                          extent_num_bytes) >> 9;
-                               if (extent_start != 0) {
-                                       inode->i_blocks -= num_dec;
-                               }
+                                          extent_num_bytes);
+                               if (extent_start != 0)
+                                       dec_i_blocks(inode, num_dec);
                                btrfs_mark_buffer_dirty(leaf);
                        } else {
                                extent_num_bytes =
                                        btrfs_file_extent_disk_num_bytes(leaf,
                                                                         fi);
                                /* FIXME blocksize != 4096 */
-                               num_dec = btrfs_file_extent_num_bytes(leaf,
-                                                                      fi) >> 9;
+                               num_dec = btrfs_file_extent_num_bytes(leaf, fi);
                                if (extent_start != 0) {
                                        found_extent = 1;
-                                       inode->i_blocks -= num_dec;
+                                       dec_i_blocks(inode, num_dec);
                                }
                                root_gen = btrfs_header_generation(leaf);
                                root_owner = btrfs_header_owner(leaf);
                        }
-               } else if (extent_type == BTRFS_FILE_EXTENT_INLINE &&
-                          !del_item) {
-                       u32 newsize = inode->i_size - found_key.offset;
-                       newsize = btrfs_file_extent_calc_inline_size(newsize);
-                       ret = btrfs_truncate_item(trans, root, path,
-                                                 newsize, 1);
-                       BUG_ON(ret);
+               } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
+                       if (!del_item) {
+                               u32 newsize = inode->i_size - found_key.offset;
+                               dec_i_blocks(inode, item_end + 1 -
+                                           found_key.offset - newsize);
+                               newsize =
+                                   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:
                if (del_item) {
@@ -1222,6 +1232,7 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
        struct btrfs_iget_args *args = p;
        inode->i_ino = args->ino;
        BTRFS_I(inode)->root = args->root;
+       BTRFS_I(inode)->delalloc_bytes = 0;
        extent_map_tree_init(&BTRFS_I(inode)->extent_tree, GFP_NOFS);
        extent_io_tree_init(&BTRFS_I(inode)->io_tree,
                             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_io_tree_init(&BTRFS_I(inode)->io_tree,
                             inode->i_mapping, GFP_NOFS);
+       BTRFS_I(inode)->delalloc_bytes = 0;
        BTRFS_I(inode)->root = root;
 
        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_io_tree_init(&BTRFS_I(inode)->io_tree,
                                     inode->i_mapping, GFP_NOFS);
+               BTRFS_I(inode)->delalloc_bytes = 0;
                BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
        }
        dir->i_sb->s_dirt = 1;
@@ -2797,6 +2810,7 @@ static int btrfs_getattr(struct vfsmount *mnt,
        struct inode *inode = dentry->d_inode;
        generic_fillattr(inode, stat);
        stat->blksize = PAGE_CACHE_SIZE;
+       stat->blocks = inode->i_blocks + (BTRFS_I(inode)->delalloc_bytes >> 9);
        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_io_tree_init(&BTRFS_I(inode)->io_tree,
                                     inode->i_mapping, GFP_NOFS);
+               BTRFS_I(inode)->delalloc_bytes = 0;
                BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops;
        }
        dir->i_sb->s_dirt = 1;