Loading fs/btrfs/ctree.c +4 −0 Original line number Diff line number Diff line Loading @@ -217,6 +217,9 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, root->fs_info->generation); WARN_ON(1); } if (buffer_defrag_done(parent)) return 0; parent_node = btrfs_buffer_node(parent); parent_nritems = btrfs_header_nritems(&parent_node->header); parent_level = btrfs_header_level(&parent_node->header); Loading Loading @@ -274,6 +277,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, *last_ret = search_start; if (parent_level == 1) clear_buffer_defrag(tmp_bh); set_buffer_defrag_done(tmp_bh); brelse(tmp_bh); } return err; Loading fs/btrfs/disk-io.h +2 −0 Original line number Diff line number Diff line Loading @@ -26,9 +26,11 @@ enum btrfs_bh_state_bits { BH_Checked = BH_PrivateStart, BH_Defrag, BH_DefragDone, }; BUFFER_FNS(Checked, checked); BUFFER_FNS(Defrag, defrag); BUFFER_FNS(DefragDone, defrag_done); static inline struct btrfs_node *btrfs_buffer_node(struct buffer_head *bh) { Loading fs/btrfs/extent_map.c +10 −6 Original line number Diff line number Diff line Loading @@ -10,6 +10,12 @@ #include <linux/blkdev.h> #include "extent_map.h" /* temporary define until extent_map moves out of btrfs */ struct kmem_cache *btrfs_cache_create(const char *name, size_t size, unsigned long extra_flags, void (*ctor)(void *, struct kmem_cache *, unsigned long)); static struct kmem_cache *extent_map_cache; static struct kmem_cache *extent_state_cache; Loading @@ -32,14 +38,12 @@ struct tree_entry { void __init extent_map_init(void) { extent_map_cache = kmem_cache_create("extent_map", sizeof(struct extent_map), 0, SLAB_RECLAIM_ACCOUNT | extent_map_cache = btrfs_cache_create("extent_map", sizeof(struct extent_map), SLAB_DESTROY_BY_RCU, NULL); extent_state_cache = kmem_cache_create("extent_state", sizeof(struct extent_state), 0, SLAB_RECLAIM_ACCOUNT | extent_state_cache = btrfs_cache_create("extent_state", sizeof(struct extent_state), SLAB_DESTROY_BY_RCU, NULL); } Loading fs/btrfs/inode.c +81 −12 Original line number Diff line number Diff line Loading @@ -1904,6 +1904,70 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) return ret; } static unsigned long force_ra(struct address_space *mapping, struct file_ra_state *ra, struct file *file, pgoff_t offset, pgoff_t last_index) { pgoff_t req_size; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) req_size = last_index - offset + 1; offset = page_cache_readahead(mapping, ra, file, offset, req_size); return offset; #else req_size = min(last_index - offset + 1, (pgoff_t)128); page_cache_sync_readahead(mapping, ra, file, offset, req_size); return offset + req_size; #endif } int btrfs_defrag_file(struct file *file) { struct inode *inode = file->f_path.dentry->d_inode; struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; struct page *page; unsigned long last_index; unsigned long ra_index = 0; u64 page_start; u64 page_end; unsigned long i; mutex_lock(&inode->i_mutex); last_index = inode->i_size >> PAGE_CACHE_SHIFT; for (i = 0; i <= last_index; i++) { if (i == ra_index) { ra_index = force_ra(inode->i_mapping, &file->f_ra, file, ra_index, last_index); } page = grab_cache_page(inode->i_mapping, i); if (!page) goto out_unlock; if (!PageUptodate(page)) { btrfs_readpage(NULL, page); lock_page(page); if (!PageUptodate(page)) { unlock_page(page); page_cache_release(page); goto out_unlock; } } page_start = page->index << PAGE_CACHE_SHIFT; page_end = page_start + PAGE_CACHE_SIZE - 1; lock_extent(em_tree, page_start, page_end, GFP_NOFS); set_extent_delalloc(em_tree, page_start, page_end, GFP_NOFS); unlock_extent(em_tree, page_start, page_end, GFP_NOFS); set_page_dirty(page); unlock_page(page); page_cache_release(page); balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1); } out_unlock: mutex_unlock(&inode->i_mutex); return 0; } int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { Loading Loading @@ -1948,10 +2012,14 @@ int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int break; case BTRFS_IOC_DEFRAG: if (S_ISDIR(inode->i_mode)) { mutex_lock(&root->fs_info->fs_mutex); btrfs_defrag_root(root, 0); btrfs_defrag_root(root->fs_info->extent_root, 0); mutex_unlock(&root->fs_info->fs_mutex); } else if (S_ISREG(inode->i_mode)) { btrfs_defrag_file(filp); } ret = 0; break; default: Loading Loading @@ -2018,7 +2086,7 @@ void btrfs_destroy_cachep(void) kmem_cache_destroy(btrfs_path_cachep); } static struct kmem_cache *cache_create(const char *name, size_t size, struct kmem_cache *btrfs_cache_create(const char *name, size_t size, unsigned long extra_flags, void (*ctor)(void *, struct kmem_cache *, unsigned long)) Loading @@ -2033,27 +2101,28 @@ static struct kmem_cache *cache_create(const char *name, size_t size, int btrfs_init_cachep(void) { btrfs_inode_cachep = cache_create("btrfs_inode_cache", btrfs_inode_cachep = btrfs_cache_create("btrfs_inode_cache", sizeof(struct btrfs_inode), 0, init_once); if (!btrfs_inode_cachep) goto fail; btrfs_trans_handle_cachep = cache_create("btrfs_trans_handle_cache", btrfs_trans_handle_cachep = btrfs_cache_create("btrfs_trans_handle_cache", sizeof(struct btrfs_trans_handle), 0, NULL); if (!btrfs_trans_handle_cachep) goto fail; btrfs_transaction_cachep = cache_create("btrfs_transaction_cache", btrfs_transaction_cachep = btrfs_cache_create("btrfs_transaction_cache", sizeof(struct btrfs_transaction), 0, NULL); if (!btrfs_transaction_cachep) goto fail; btrfs_path_cachep = cache_create("btrfs_path_cache", btrfs_path_cachep = btrfs_cache_create("btrfs_path_cache", sizeof(struct btrfs_transaction), 0, NULL); if (!btrfs_path_cachep) goto fail; btrfs_bit_radix_cachep = cache_create("btrfs_radix", 256, btrfs_bit_radix_cachep = btrfs_cache_create("btrfs_radix", 256, SLAB_DESTROY_BY_RCU, NULL); if (!btrfs_bit_radix_cachep) goto fail; Loading fs/btrfs/tree-defrag.c +3 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,8 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans, } WARN_ON(*level < 0); WARN_ON(*level >= BTRFS_MAX_LEVEL); clear_buffer_defrag(path->nodes[*level]); clear_buffer_defrag_done(path->nodes[*level]); btrfs_block_release(root, path->nodes[*level]); path->nodes[*level] = NULL; *level += 1; Loading Loading @@ -143,6 +145,7 @@ static int defrag_walk_up(struct btrfs_trans_handle *trans, return 0; } else { clear_buffer_defrag(path->nodes[*level]); clear_buffer_defrag_done(path->nodes[*level]); btrfs_block_release(root, path->nodes[*level]); path->nodes[*level] = NULL; *level = i + 1; Loading Loading
fs/btrfs/ctree.c +4 −0 Original line number Diff line number Diff line Loading @@ -217,6 +217,9 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, root->fs_info->generation); WARN_ON(1); } if (buffer_defrag_done(parent)) return 0; parent_node = btrfs_buffer_node(parent); parent_nritems = btrfs_header_nritems(&parent_node->header); parent_level = btrfs_header_level(&parent_node->header); Loading Loading @@ -274,6 +277,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans, *last_ret = search_start; if (parent_level == 1) clear_buffer_defrag(tmp_bh); set_buffer_defrag_done(tmp_bh); brelse(tmp_bh); } return err; Loading
fs/btrfs/disk-io.h +2 −0 Original line number Diff line number Diff line Loading @@ -26,9 +26,11 @@ enum btrfs_bh_state_bits { BH_Checked = BH_PrivateStart, BH_Defrag, BH_DefragDone, }; BUFFER_FNS(Checked, checked); BUFFER_FNS(Defrag, defrag); BUFFER_FNS(DefragDone, defrag_done); static inline struct btrfs_node *btrfs_buffer_node(struct buffer_head *bh) { Loading
fs/btrfs/extent_map.c +10 −6 Original line number Diff line number Diff line Loading @@ -10,6 +10,12 @@ #include <linux/blkdev.h> #include "extent_map.h" /* temporary define until extent_map moves out of btrfs */ struct kmem_cache *btrfs_cache_create(const char *name, size_t size, unsigned long extra_flags, void (*ctor)(void *, struct kmem_cache *, unsigned long)); static struct kmem_cache *extent_map_cache; static struct kmem_cache *extent_state_cache; Loading @@ -32,14 +38,12 @@ struct tree_entry { void __init extent_map_init(void) { extent_map_cache = kmem_cache_create("extent_map", sizeof(struct extent_map), 0, SLAB_RECLAIM_ACCOUNT | extent_map_cache = btrfs_cache_create("extent_map", sizeof(struct extent_map), SLAB_DESTROY_BY_RCU, NULL); extent_state_cache = kmem_cache_create("extent_state", sizeof(struct extent_state), 0, SLAB_RECLAIM_ACCOUNT | extent_state_cache = btrfs_cache_create("extent_state", sizeof(struct extent_state), SLAB_DESTROY_BY_RCU, NULL); } Loading
fs/btrfs/inode.c +81 −12 Original line number Diff line number Diff line Loading @@ -1904,6 +1904,70 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) return ret; } static unsigned long force_ra(struct address_space *mapping, struct file_ra_state *ra, struct file *file, pgoff_t offset, pgoff_t last_index) { pgoff_t req_size; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) req_size = last_index - offset + 1; offset = page_cache_readahead(mapping, ra, file, offset, req_size); return offset; #else req_size = min(last_index - offset + 1, (pgoff_t)128); page_cache_sync_readahead(mapping, ra, file, offset, req_size); return offset + req_size; #endif } int btrfs_defrag_file(struct file *file) { struct inode *inode = file->f_path.dentry->d_inode; struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; struct page *page; unsigned long last_index; unsigned long ra_index = 0; u64 page_start; u64 page_end; unsigned long i; mutex_lock(&inode->i_mutex); last_index = inode->i_size >> PAGE_CACHE_SHIFT; for (i = 0; i <= last_index; i++) { if (i == ra_index) { ra_index = force_ra(inode->i_mapping, &file->f_ra, file, ra_index, last_index); } page = grab_cache_page(inode->i_mapping, i); if (!page) goto out_unlock; if (!PageUptodate(page)) { btrfs_readpage(NULL, page); lock_page(page); if (!PageUptodate(page)) { unlock_page(page); page_cache_release(page); goto out_unlock; } } page_start = page->index << PAGE_CACHE_SHIFT; page_end = page_start + PAGE_CACHE_SIZE - 1; lock_extent(em_tree, page_start, page_end, GFP_NOFS); set_extent_delalloc(em_tree, page_start, page_end, GFP_NOFS); unlock_extent(em_tree, page_start, page_end, GFP_NOFS); set_page_dirty(page); unlock_page(page); page_cache_release(page); balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1); } out_unlock: mutex_unlock(&inode->i_mutex); return 0; } int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { Loading Loading @@ -1948,10 +2012,14 @@ int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int break; case BTRFS_IOC_DEFRAG: if (S_ISDIR(inode->i_mode)) { mutex_lock(&root->fs_info->fs_mutex); btrfs_defrag_root(root, 0); btrfs_defrag_root(root->fs_info->extent_root, 0); mutex_unlock(&root->fs_info->fs_mutex); } else if (S_ISREG(inode->i_mode)) { btrfs_defrag_file(filp); } ret = 0; break; default: Loading Loading @@ -2018,7 +2086,7 @@ void btrfs_destroy_cachep(void) kmem_cache_destroy(btrfs_path_cachep); } static struct kmem_cache *cache_create(const char *name, size_t size, struct kmem_cache *btrfs_cache_create(const char *name, size_t size, unsigned long extra_flags, void (*ctor)(void *, struct kmem_cache *, unsigned long)) Loading @@ -2033,27 +2101,28 @@ static struct kmem_cache *cache_create(const char *name, size_t size, int btrfs_init_cachep(void) { btrfs_inode_cachep = cache_create("btrfs_inode_cache", btrfs_inode_cachep = btrfs_cache_create("btrfs_inode_cache", sizeof(struct btrfs_inode), 0, init_once); if (!btrfs_inode_cachep) goto fail; btrfs_trans_handle_cachep = cache_create("btrfs_trans_handle_cache", btrfs_trans_handle_cachep = btrfs_cache_create("btrfs_trans_handle_cache", sizeof(struct btrfs_trans_handle), 0, NULL); if (!btrfs_trans_handle_cachep) goto fail; btrfs_transaction_cachep = cache_create("btrfs_transaction_cache", btrfs_transaction_cachep = btrfs_cache_create("btrfs_transaction_cache", sizeof(struct btrfs_transaction), 0, NULL); if (!btrfs_transaction_cachep) goto fail; btrfs_path_cachep = cache_create("btrfs_path_cache", btrfs_path_cachep = btrfs_cache_create("btrfs_path_cache", sizeof(struct btrfs_transaction), 0, NULL); if (!btrfs_path_cachep) goto fail; btrfs_bit_radix_cachep = cache_create("btrfs_radix", 256, btrfs_bit_radix_cachep = btrfs_cache_create("btrfs_radix", 256, SLAB_DESTROY_BY_RCU, NULL); if (!btrfs_bit_radix_cachep) goto fail; Loading
fs/btrfs/tree-defrag.c +3 −0 Original line number Diff line number Diff line Loading @@ -113,6 +113,8 @@ static int defrag_walk_down(struct btrfs_trans_handle *trans, } WARN_ON(*level < 0); WARN_ON(*level >= BTRFS_MAX_LEVEL); clear_buffer_defrag(path->nodes[*level]); clear_buffer_defrag_done(path->nodes[*level]); btrfs_block_release(root, path->nodes[*level]); path->nodes[*level] = NULL; *level += 1; Loading Loading @@ -143,6 +145,7 @@ static int defrag_walk_up(struct btrfs_trans_handle *trans, return 0; } else { clear_buffer_defrag(path->nodes[*level]); clear_buffer_defrag_done(path->nodes[*level]); btrfs_block_release(root, path->nodes[*level]); path->nodes[*level] = NULL; *level = i + 1; Loading