From ea8c281947950fac5f78818b767821d696c9512a Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Mon, 4 Aug 2008 23:17:27 -0400 Subject: [PATCH] Btrfs: Maintain a list of inodes that are delalloc and a way to wait on them Signed-off-by: Chris Mason --- fs/btrfs/btrfs_inode.h | 2 ++ fs/btrfs/ctree.h | 4 ++++ fs/btrfs/disk-io.c | 1 + fs/btrfs/extent-tree.c | 12 ++++++++--- fs/btrfs/file.c | 3 +-- fs/btrfs/inode.c | 47 ++++++++++++++++++++++++++++++++++++------ fs/btrfs/ioctl.c | 4 ++-- 7 files changed, 60 insertions(+), 13 deletions(-) diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h index df624fd735c1..534ac4153ddd 100644 --- a/fs/btrfs/btrfs_inode.h +++ b/fs/btrfs/btrfs_inode.h @@ -42,6 +42,8 @@ struct btrfs_inode { /* for keeping track of orphaned inodes */ struct list_head i_orphan; + struct list_head delalloc_inodes; + /* * transid of the trans_handle that last modified this inode */ diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 62499dd761b7..116aee21bf77 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -551,6 +551,7 @@ struct btrfs_fs_info { */ spinlock_t ordered_extent_lock; struct list_head ordered_extents; + struct list_head delalloc_inodes; /* * there is a pool of worker threads for checksumming during writes @@ -637,6 +638,7 @@ struct btrfs_root { struct kobject root_kobj; struct completion kobj_unregister; struct mutex objectid_mutex; + u64 objectid; u64 last_trans; @@ -1651,6 +1653,8 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans, #define PageChecked PageFsMisc #endif +int btrfs_start_delalloc_inodes(struct btrfs_root *root); +int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end); int btrfs_writepages(struct address_space *mapping, struct writeback_control *wbc); int btrfs_create_subvol_root(struct btrfs_root *new_root, diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index da9dda4338a3..76543683f3b9 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -1234,6 +1234,7 @@ struct btrfs_root *open_ctree(struct super_block *sb, INIT_LIST_HEAD(&fs_info->trans_list); INIT_LIST_HEAD(&fs_info->dead_roots); INIT_LIST_HEAD(&fs_info->hashers); + INIT_LIST_HEAD(&fs_info->delalloc_inodes); spin_lock_init(&fs_info->hash_lock); spin_lock_init(&fs_info->delalloc_lock); spin_lock_init(&fs_info->new_trans_lock); diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index dbde12881244..33cb2ac4cb28 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c @@ -1230,7 +1230,6 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, found->total_bytes += total_bytes; found->bytes_used += bytes_used; found->full = 0; - WARN_ON(found->total_bytes < found->bytes_used); *space_info = found; return 0; } @@ -2841,8 +2840,7 @@ again: */ clear_page_dirty_for_io(page); - set_extent_delalloc(io_tree, page_start, - page_end, GFP_NOFS); + btrfs_set_extent_delalloc(inode, page_start, page_end); set_page_dirty(page); unlock_extent(io_tree, page_start, page_end, GFP_NOFS); @@ -3319,6 +3317,13 @@ again: key.type = 0; cur_byte = key.objectid; + mutex_unlock(&root->fs_info->alloc_mutex); + + btrfs_start_delalloc_inodes(root); + btrfs_wait_ordered_extents(tree_root); + + mutex_lock(&root->fs_info->alloc_mutex); + ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) goto out; @@ -3401,6 +3406,7 @@ next: btrfs_clean_old_snapshots(tree_root); + btrfs_start_delalloc_inodes(root); btrfs_wait_ordered_extents(tree_root); trans = btrfs_start_transaction(tree_root, 1); diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 8915f2dc1bce..eb8e4556fa71 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -312,8 +312,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, * to reset the delalloc bit on things that already have * extents reserved. */ - set_extent_delalloc(io_tree, start_pos, - end_of_last_block, GFP_NOFS); + btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block); for (i = 0; i < num_pages; i++) { struct page *p = pages[i]; SetPageUptodate(p); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 640648c66b22..8a405a5fa6a3 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -303,6 +303,10 @@ int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end, spin_lock_irqsave(&root->fs_info->delalloc_lock, flags); BTRFS_I(inode)->delalloc_bytes += end - start + 1; root->fs_info->delalloc_bytes += end - start + 1; + if (list_empty(&BTRFS_I(inode)->delalloc_inodes)) { + list_add_tail(&BTRFS_I(inode)->delalloc_inodes, + &root->fs_info->delalloc_inodes); + } spin_unlock_irqrestore(&root->fs_info->delalloc_lock, flags); } return 0; @@ -325,6 +329,10 @@ int btrfs_clear_bit_hook(struct inode *inode, u64 start, u64 end, root->fs_info->delalloc_bytes -= end - start + 1; BTRFS_I(inode)->delalloc_bytes -= end - start + 1; } + if (BTRFS_I(inode)->delalloc_bytes == 0 && + !list_empty(&BTRFS_I(inode)->delalloc_inodes)) { + list_del_init(&BTRFS_I(inode)->delalloc_inodes); + } spin_unlock_irqrestore(&root->fs_info->delalloc_lock, flags); } return 0; @@ -408,6 +416,12 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans, return 0; } +int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end) +{ + return set_extent_delalloc(&BTRFS_I(inode)->io_tree, start, end, + GFP_NOFS); +} + struct btrfs_writepage_fixup { struct page *page; struct btrfs_work work; @@ -453,8 +467,7 @@ again: goto again; } - set_extent_delalloc(&BTRFS_I(inode)->io_tree, page_start, page_end, - GFP_NOFS); + btrfs_set_extent_delalloc(inode, page_start, page_end); ClearPageChecked(page); out: unlock_extent(&BTRFS_I(inode)->io_tree, page_start, page_end, GFP_NOFS); @@ -1530,8 +1543,7 @@ again: goto again; } - set_extent_delalloc(&BTRFS_I(inode)->io_tree, page_start, - page_end, GFP_NOFS); + btrfs_set_extent_delalloc(inode, page_start, page_end); ret = 0; if (offset != PAGE_CACHE_SIZE) { kaddr = kmap(page); @@ -1766,6 +1778,7 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p) inode->i_mapping, GFP_NOFS); extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree, inode->i_mapping, GFP_NOFS); + INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes); btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree); mutex_init(&BTRFS_I(inode)->csum_mutex); mutex_init(&BTRFS_I(inode)->extent_mutex); @@ -2158,6 +2171,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree, inode->i_mapping, GFP_NOFS); btrfs_ordered_inode_tree_init(&BTRFS_I(inode)->ordered_tree); + INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes); mutex_init(&BTRFS_I(inode)->csum_mutex); mutex_init(&BTRFS_I(inode)->extent_mutex); BTRFS_I(inode)->delalloc_bytes = 0; @@ -2400,6 +2414,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, inode->i_mapping, GFP_NOFS); extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree, inode->i_mapping, GFP_NOFS); + INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes); mutex_init(&BTRFS_I(inode)->csum_mutex); mutex_init(&BTRFS_I(inode)->extent_mutex); BTRFS_I(inode)->delalloc_bytes = 0; @@ -3049,8 +3064,7 @@ again: goto again; } - set_extent_delalloc(&BTRFS_I(inode)->io_tree, page_start, - page_end, GFP_NOFS); + btrfs_set_extent_delalloc(inode, page_start, page_end); ret = 0; /* page is wholly or partially inside EOF */ @@ -3373,6 +3387,26 @@ out_unlock: return ret; } +int btrfs_start_delalloc_inodes(struct btrfs_root *root) +{ + struct list_head *head = &root->fs_info->delalloc_inodes; + struct btrfs_inode *binode; + unsigned long flags; + + spin_lock_irqsave(&root->fs_info->delalloc_lock, flags); + while(!list_empty(head)) { + binode = list_entry(head->next, struct btrfs_inode, + delalloc_inodes); + atomic_inc(&binode->vfs_inode.i_count); + spin_unlock_irqrestore(&root->fs_info->delalloc_lock, flags); + filemap_write_and_wait(binode->vfs_inode.i_mapping); + iput(&binode->vfs_inode); + spin_lock_irqsave(&root->fs_info->delalloc_lock, flags); + } + spin_unlock_irqrestore(&root->fs_info->delalloc_lock, flags); + return 0; +} + static int btrfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { @@ -3436,6 +3470,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, inode->i_mapping, GFP_NOFS); extent_io_tree_init(&BTRFS_I(inode)->io_failure_tree, inode->i_mapping, GFP_NOFS); + INIT_LIST_HEAD(&BTRFS_I(inode)->delalloc_inodes); mutex_init(&BTRFS_I(inode)->csum_mutex); mutex_init(&BTRFS_I(inode)->extent_mutex); BTRFS_I(inode)->delalloc_bytes = 0; diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 0b63c3c77cfd..e1046a54b1c5 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -274,8 +274,7 @@ again: */ clear_page_dirty_for_io(page); - set_extent_delalloc(io_tree, page_start, - page_end, GFP_NOFS); + btrfs_set_extent_delalloc(inode, page_start, page_end); unlock_extent(io_tree, page_start, page_end, GFP_NOFS); set_page_dirty(page); @@ -784,6 +783,7 @@ long btrfs_ioctl(struct file *file, unsigned int case BTRFS_IOC_TRANS_END: return btrfs_ioctl_trans_end(file); case BTRFS_IOC_SYNC: + btrfs_start_delalloc_inodes(root); btrfs_sync_fs(file->f_dentry->d_sb, 1); return 0; } -- 2.20.1