diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-09-10 19:58:16 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-09-10 19:58:16 -0400 |
commit | 86479a04eef8f304a13aeb8b64bcc8e506a68268 (patch) | |
tree | cda7e66d469bcdc2f41144ea91405aeb96d1f777 /fs/btrfs/inode.c | |
parent | 8e21528f87854314792aaef4d279bc9e5a9be997 (diff) |
Add support for defragging files via btrfsctl -d. Avoid OOM on extent tree
defrag.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 93 |
1 files changed, 81 insertions, 12 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 64710fa77d01..6b3e4404dc6a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -1904,6 +1904,70 @@ fail: | |||
1904 | return ret; | 1904 | return ret; |
1905 | } | 1905 | } |
1906 | 1906 | ||
1907 | static unsigned long force_ra(struct address_space *mapping, | ||
1908 | struct file_ra_state *ra, struct file *file, | ||
1909 | pgoff_t offset, pgoff_t last_index) | ||
1910 | { | ||
1911 | pgoff_t req_size; | ||
1912 | |||
1913 | #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) | ||
1914 | req_size = last_index - offset + 1; | ||
1915 | offset = page_cache_readahead(mapping, ra, file, offset, req_size); | ||
1916 | return offset; | ||
1917 | #else | ||
1918 | req_size = min(last_index - offset + 1, (pgoff_t)128); | ||
1919 | page_cache_sync_readahead(mapping, ra, file, offset, req_size); | ||
1920 | return offset + req_size; | ||
1921 | #endif | ||
1922 | } | ||
1923 | |||
1924 | int btrfs_defrag_file(struct file *file) { | ||
1925 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1926 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | ||
1927 | struct page *page; | ||
1928 | unsigned long last_index; | ||
1929 | unsigned long ra_index = 0; | ||
1930 | u64 page_start; | ||
1931 | u64 page_end; | ||
1932 | unsigned long i; | ||
1933 | |||
1934 | mutex_lock(&inode->i_mutex); | ||
1935 | last_index = inode->i_size >> PAGE_CACHE_SHIFT; | ||
1936 | for (i = 0; i <= last_index; i++) { | ||
1937 | if (i == ra_index) { | ||
1938 | ra_index = force_ra(inode->i_mapping, &file->f_ra, | ||
1939 | file, ra_index, last_index); | ||
1940 | } | ||
1941 | page = grab_cache_page(inode->i_mapping, i); | ||
1942 | if (!page) | ||
1943 | goto out_unlock; | ||
1944 | if (!PageUptodate(page)) { | ||
1945 | btrfs_readpage(NULL, page); | ||
1946 | lock_page(page); | ||
1947 | if (!PageUptodate(page)) { | ||
1948 | unlock_page(page); | ||
1949 | page_cache_release(page); | ||
1950 | goto out_unlock; | ||
1951 | } | ||
1952 | } | ||
1953 | page_start = page->index << PAGE_CACHE_SHIFT; | ||
1954 | page_end = page_start + PAGE_CACHE_SIZE - 1; | ||
1955 | |||
1956 | lock_extent(em_tree, page_start, page_end, GFP_NOFS); | ||
1957 | set_extent_delalloc(em_tree, page_start, | ||
1958 | page_end, GFP_NOFS); | ||
1959 | unlock_extent(em_tree, page_start, page_end, GFP_NOFS); | ||
1960 | set_page_dirty(page); | ||
1961 | unlock_page(page); | ||
1962 | page_cache_release(page); | ||
1963 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, 1); | ||
1964 | } | ||
1965 | |||
1966 | out_unlock: | ||
1967 | mutex_unlock(&inode->i_mutex); | ||
1968 | return 0; | ||
1969 | } | ||
1970 | |||
1907 | int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int | 1971 | int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int |
1908 | cmd, unsigned long arg) | 1972 | cmd, unsigned long arg) |
1909 | { | 1973 | { |
@@ -1948,10 +2012,14 @@ int btrfs_ioctl(struct inode *inode, struct file *filp, unsigned int | |||
1948 | break; | 2012 | break; |
1949 | 2013 | ||
1950 | case BTRFS_IOC_DEFRAG: | 2014 | case BTRFS_IOC_DEFRAG: |
1951 | mutex_lock(&root->fs_info->fs_mutex); | 2015 | if (S_ISDIR(inode->i_mode)) { |
1952 | btrfs_defrag_root(root, 0); | 2016 | mutex_lock(&root->fs_info->fs_mutex); |
1953 | btrfs_defrag_root(root->fs_info->extent_root, 0); | 2017 | btrfs_defrag_root(root, 0); |
1954 | mutex_unlock(&root->fs_info->fs_mutex); | 2018 | btrfs_defrag_root(root->fs_info->extent_root, 0); |
2019 | mutex_unlock(&root->fs_info->fs_mutex); | ||
2020 | } else if (S_ISREG(inode->i_mode)) { | ||
2021 | btrfs_defrag_file(filp); | ||
2022 | } | ||
1955 | ret = 0; | 2023 | ret = 0; |
1956 | break; | 2024 | break; |
1957 | default: | 2025 | default: |
@@ -2018,7 +2086,7 @@ void btrfs_destroy_cachep(void) | |||
2018 | kmem_cache_destroy(btrfs_path_cachep); | 2086 | kmem_cache_destroy(btrfs_path_cachep); |
2019 | } | 2087 | } |
2020 | 2088 | ||
2021 | static struct kmem_cache *cache_create(const char *name, size_t size, | 2089 | struct kmem_cache *btrfs_cache_create(const char *name, size_t size, |
2022 | unsigned long extra_flags, | 2090 | unsigned long extra_flags, |
2023 | void (*ctor)(void *, struct kmem_cache *, | 2091 | void (*ctor)(void *, struct kmem_cache *, |
2024 | unsigned long)) | 2092 | unsigned long)) |
@@ -2033,27 +2101,28 @@ static struct kmem_cache *cache_create(const char *name, size_t size, | |||
2033 | 2101 | ||
2034 | int btrfs_init_cachep(void) | 2102 | int btrfs_init_cachep(void) |
2035 | { | 2103 | { |
2036 | btrfs_inode_cachep = cache_create("btrfs_inode_cache", | 2104 | btrfs_inode_cachep = btrfs_cache_create("btrfs_inode_cache", |
2037 | sizeof(struct btrfs_inode), | 2105 | sizeof(struct btrfs_inode), |
2038 | 0, init_once); | 2106 | 0, init_once); |
2039 | if (!btrfs_inode_cachep) | 2107 | if (!btrfs_inode_cachep) |
2040 | goto fail; | 2108 | goto fail; |
2041 | btrfs_trans_handle_cachep = cache_create("btrfs_trans_handle_cache", | 2109 | btrfs_trans_handle_cachep = |
2042 | sizeof(struct btrfs_trans_handle), | 2110 | btrfs_cache_create("btrfs_trans_handle_cache", |
2043 | 0, NULL); | 2111 | sizeof(struct btrfs_trans_handle), |
2112 | 0, NULL); | ||
2044 | if (!btrfs_trans_handle_cachep) | 2113 | if (!btrfs_trans_handle_cachep) |
2045 | goto fail; | 2114 | goto fail; |
2046 | btrfs_transaction_cachep = cache_create("btrfs_transaction_cache", | 2115 | btrfs_transaction_cachep = btrfs_cache_create("btrfs_transaction_cache", |
2047 | sizeof(struct btrfs_transaction), | 2116 | sizeof(struct btrfs_transaction), |
2048 | 0, NULL); | 2117 | 0, NULL); |
2049 | if (!btrfs_transaction_cachep) | 2118 | if (!btrfs_transaction_cachep) |
2050 | goto fail; | 2119 | goto fail; |
2051 | btrfs_path_cachep = cache_create("btrfs_path_cache", | 2120 | btrfs_path_cachep = btrfs_cache_create("btrfs_path_cache", |
2052 | sizeof(struct btrfs_transaction), | 2121 | sizeof(struct btrfs_transaction), |
2053 | 0, NULL); | 2122 | 0, NULL); |
2054 | if (!btrfs_path_cachep) | 2123 | if (!btrfs_path_cachep) |
2055 | goto fail; | 2124 | goto fail; |
2056 | btrfs_bit_radix_cachep = cache_create("btrfs_radix", 256, | 2125 | btrfs_bit_radix_cachep = btrfs_cache_create("btrfs_radix", 256, |
2057 | SLAB_DESTROY_BY_RCU, NULL); | 2126 | SLAB_DESTROY_BY_RCU, NULL); |
2058 | if (!btrfs_bit_radix_cachep) | 2127 | if (!btrfs_bit_radix_cachep) |
2059 | goto fail; | 2128 | goto fail; |