diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-12-21 16:27:24 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:58 -0400 |
commit | edbd8d4efe4ddaf29a175ae504e2c9a05a96ebee (patch) | |
tree | c5156fe3a75e97972186c9a933a631b258490a7e /fs/btrfs | |
parent | 5d4fb734b4cb89a3902d6de309af0f6f3e63fe73 (diff) |
Btrfs: Support for online FS resize (grow and shrink)
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/ctree.h | 10 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 32 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 2 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 480 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 105 | ||||
-rw-r--r-- | fs/btrfs/ioctl.h | 2 | ||||
-rw-r--r-- | fs/btrfs/root-tree.c | 5 | ||||
-rw-r--r-- | fs/btrfs/super.c | 7 |
8 files changed, 629 insertions, 14 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 10129cc6656f..b83a1bec346f 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -508,6 +508,8 @@ BTRFS_SETGET_STACK_FUNCS(block_group_used, struct btrfs_block_group_item, | |||
508 | used, 64); | 508 | used, 64); |
509 | BTRFS_SETGET_FUNCS(disk_block_group_used, struct btrfs_block_group_item, | 509 | BTRFS_SETGET_FUNCS(disk_block_group_used, struct btrfs_block_group_item, |
510 | used, 64); | 510 | used, 64); |
511 | BTRFS_SETGET_FUNCS(disk_block_group_flags, struct btrfs_block_group_item, | ||
512 | flags, 8); | ||
511 | 513 | ||
512 | /* struct btrfs_inode_ref */ | 514 | /* struct btrfs_inode_ref */ |
513 | BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16); | 515 | BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16); |
@@ -960,6 +962,9 @@ struct extent_buffer *__btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
960 | int level, | 962 | int level, |
961 | u64 hint, | 963 | u64 hint, |
962 | u64 empty_size); | 964 | u64 empty_size); |
965 | int btrfs_grow_extent_tree(struct btrfs_trans_handle *trans, | ||
966 | struct btrfs_root *root, u64 new_size); | ||
967 | int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size); | ||
963 | int btrfs_insert_extent_backref(struct btrfs_trans_handle *trans, | 968 | int btrfs_insert_extent_backref(struct btrfs_trans_handle *trans, |
964 | struct btrfs_root *root, | 969 | struct btrfs_root *root, |
965 | struct btrfs_path *path, u64 bytenr, | 970 | struct btrfs_path *path, u64 bytenr, |
@@ -1117,6 +1122,9 @@ int btrfs_csum_truncate(struct btrfs_trans_handle *trans, | |||
1117 | struct btrfs_root *root, struct btrfs_path *path, | 1122 | struct btrfs_root *root, struct btrfs_path *path, |
1118 | u64 isize); | 1123 | u64 isize); |
1119 | /* inode.c */ | 1124 | /* inode.c */ |
1125 | unsigned long btrfs_force_ra(struct address_space *mapping, | ||
1126 | struct file_ra_state *ra, struct file *file, | ||
1127 | pgoff_t offset, pgoff_t last_index); | ||
1120 | int btrfs_check_free_space(struct btrfs_root *root, u64 num_required, | 1128 | int btrfs_check_free_space(struct btrfs_root *root, u64 num_required, |
1121 | int for_del); | 1129 | int for_del); |
1122 | int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page); | 1130 | int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page); |
@@ -1162,4 +1170,6 @@ void btrfs_sysfs_del_super(struct btrfs_fs_info *root); | |||
1162 | ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size); | 1170 | ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size); |
1163 | int btrfs_delete_xattrs(struct btrfs_trans_handle *trans, | 1171 | int btrfs_delete_xattrs(struct btrfs_trans_handle *trans, |
1164 | struct btrfs_root *root, struct inode *inode); | 1172 | struct btrfs_root *root, struct inode *inode); |
1173 | /* super.c */ | ||
1174 | u64 btrfs_parse_size(char *str); | ||
1165 | #endif | 1175 | #endif |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index eebb4fb65c61..de026d9d9b2b 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -471,13 +471,17 @@ insert: | |||
471 | return root; | 471 | return root; |
472 | } | 472 | } |
473 | 473 | ||
474 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | 474 | struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, |
475 | struct btrfs_key *location, | 475 | struct btrfs_key *location) |
476 | const char *name, int namelen) | ||
477 | { | 476 | { |
478 | struct btrfs_root *root; | 477 | struct btrfs_root *root; |
479 | int ret; | 478 | int ret; |
480 | 479 | ||
480 | if (location->objectid == BTRFS_ROOT_TREE_OBJECTID) | ||
481 | return fs_info->tree_root; | ||
482 | if (location->objectid == BTRFS_EXTENT_TREE_OBJECTID) | ||
483 | return fs_info->extent_root; | ||
484 | |||
481 | root = radix_tree_lookup(&fs_info->fs_roots_radix, | 485 | root = radix_tree_lookup(&fs_info->fs_roots_radix, |
482 | (unsigned long)location->objectid); | 486 | (unsigned long)location->objectid); |
483 | if (root) | 487 | if (root) |
@@ -494,6 +498,23 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | |||
494 | kfree(root); | 498 | kfree(root); |
495 | return ERR_PTR(ret); | 499 | return ERR_PTR(ret); |
496 | } | 500 | } |
501 | ret = btrfs_find_dead_roots(fs_info->tree_root, | ||
502 | root->root_key.objectid, root); | ||
503 | BUG_ON(ret); | ||
504 | |||
505 | return root; | ||
506 | } | ||
507 | |||
508 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | ||
509 | struct btrfs_key *location, | ||
510 | const char *name, int namelen) | ||
511 | { | ||
512 | struct btrfs_root *root; | ||
513 | int ret; | ||
514 | |||
515 | root = btrfs_read_fs_root_no_name(fs_info, location); | ||
516 | if (!root) | ||
517 | return NULL; | ||
497 | 518 | ||
498 | ret = btrfs_set_root_name(root, name, namelen); | 519 | ret = btrfs_set_root_name(root, name, namelen); |
499 | if (ret) { | 520 | if (ret) { |
@@ -509,11 +530,6 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | |||
509 | kfree(root); | 530 | kfree(root); |
510 | return ERR_PTR(ret); | 531 | return ERR_PTR(ret); |
511 | } | 532 | } |
512 | |||
513 | ret = btrfs_find_dead_roots(fs_info->tree_root, | ||
514 | root->root_key.objectid, root); | ||
515 | BUG_ON(ret); | ||
516 | |||
517 | return root; | 533 | return root; |
518 | } | 534 | } |
519 | #if 0 | 535 | #if 0 |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 33d2ccfd74d8..8c3cfd02901f 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -39,6 +39,8 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | |||
39 | const char *name, int namelen); | 39 | const char *name, int namelen); |
40 | struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, | 40 | struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, |
41 | struct btrfs_key *location); | 41 | struct btrfs_key *location); |
42 | struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, | ||
43 | struct btrfs_key *location); | ||
42 | int btrfs_insert_dev_radix(struct btrfs_root *root, | 44 | int btrfs_insert_dev_radix(struct btrfs_root *root, |
43 | struct block_device *bdev, | 45 | struct block_device *bdev, |
44 | u64 device_id, | 46 | u64 device_id, |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 1412d556313f..de0fb0743cf9 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include <linux/crc32c.h> | 20 | #include <linux/crc32c.h> |
21 | #include <linux/pagemap.h> | ||
21 | #include "hash.h" | 22 | #include "hash.h" |
22 | #include "ctree.h" | 23 | #include "ctree.h" |
23 | #include "disk-io.h" | 24 | #include "disk-io.h" |
@@ -1622,6 +1623,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1622 | int pending_ret; | 1623 | int pending_ret; |
1623 | u64 super_used, root_used; | 1624 | u64 super_used, root_used; |
1624 | u64 search_start = 0; | 1625 | u64 search_start = 0; |
1626 | u64 new_hint; | ||
1625 | struct btrfs_fs_info *info = root->fs_info; | 1627 | struct btrfs_fs_info *info = root->fs_info; |
1626 | struct btrfs_root *extent_root = info->extent_root; | 1628 | struct btrfs_root *extent_root = info->extent_root; |
1627 | struct btrfs_extent_item extent_item; | 1629 | struct btrfs_extent_item extent_item; |
@@ -1629,6 +1631,10 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1629 | 1631 | ||
1630 | btrfs_set_stack_extent_refs(&extent_item, 1); | 1632 | btrfs_set_stack_extent_refs(&extent_item, 1); |
1631 | 1633 | ||
1634 | new_hint = max(hint_byte, 16ULL * 1024 * 1024 * 1024); | ||
1635 | if (new_hint < btrfs_super_total_bytes(&info->super_copy)) | ||
1636 | hint_byte = new_hint; | ||
1637 | |||
1632 | WARN_ON(num_bytes < root->sectorsize); | 1638 | WARN_ON(num_bytes < root->sectorsize); |
1633 | ret = find_free_extent(trans, root, num_bytes, empty_size, | 1639 | ret = find_free_extent(trans, root, num_bytes, empty_size, |
1634 | search_start, search_end, hint_byte, ins, | 1640 | search_start, search_end, hint_byte, ins, |
@@ -2100,6 +2106,480 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info) | |||
2100 | return 0; | 2106 | return 0; |
2101 | } | 2107 | } |
2102 | 2108 | ||
2109 | static int relocate_inode_pages(struct inode *inode, u64 start, u64 len) | ||
2110 | { | ||
2111 | u64 page_start; | ||
2112 | u64 page_end; | ||
2113 | u64 delalloc_start; | ||
2114 | u64 existing_delalloc; | ||
2115 | unsigned long last_index; | ||
2116 | unsigned long first_index; | ||
2117 | unsigned long i; | ||
2118 | struct page *page; | ||
2119 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
2120 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | ||
2121 | struct file_ra_state ra; | ||
2122 | |||
2123 | mutex_lock(&inode->i_mutex); | ||
2124 | first_index = start >> PAGE_CACHE_SHIFT; | ||
2125 | last_index = (start + len - 1) >> PAGE_CACHE_SHIFT; | ||
2126 | |||
2127 | memset(&ra, 0, sizeof(ra)); | ||
2128 | file_ra_state_init(&ra, inode->i_mapping); | ||
2129 | btrfs_force_ra(inode->i_mapping, &ra, NULL, first_index, last_index); | ||
2130 | |||
2131 | for (i = first_index; i <= last_index; i++) { | ||
2132 | page = grab_cache_page(inode->i_mapping, i); | ||
2133 | if (!page) | ||
2134 | goto out_unlock; | ||
2135 | if (!PageUptodate(page)) { | ||
2136 | btrfs_readpage(NULL, page); | ||
2137 | lock_page(page); | ||
2138 | if (!PageUptodate(page)) { | ||
2139 | unlock_page(page); | ||
2140 | page_cache_release(page); | ||
2141 | goto out_unlock; | ||
2142 | } | ||
2143 | } | ||
2144 | page_start = (u64)page->index << PAGE_CACHE_SHIFT; | ||
2145 | page_end = page_start + PAGE_CACHE_SIZE - 1; | ||
2146 | |||
2147 | lock_extent(em_tree, page_start, page_end, GFP_NOFS); | ||
2148 | |||
2149 | delalloc_start = page_start; | ||
2150 | existing_delalloc = | ||
2151 | count_range_bits(&BTRFS_I(inode)->extent_tree, | ||
2152 | &delalloc_start, page_end, | ||
2153 | PAGE_CACHE_SIZE, EXTENT_DELALLOC); | ||
2154 | |||
2155 | set_extent_delalloc(em_tree, page_start, | ||
2156 | page_end, GFP_NOFS); | ||
2157 | |||
2158 | spin_lock(&root->fs_info->delalloc_lock); | ||
2159 | root->fs_info->delalloc_bytes += PAGE_CACHE_SIZE - | ||
2160 | existing_delalloc; | ||
2161 | spin_unlock(&root->fs_info->delalloc_lock); | ||
2162 | |||
2163 | unlock_extent(em_tree, page_start, page_end, GFP_NOFS); | ||
2164 | set_page_dirty(page); | ||
2165 | unlock_page(page); | ||
2166 | page_cache_release(page); | ||
2167 | } | ||
2168 | |||
2169 | out_unlock: | ||
2170 | mutex_unlock(&inode->i_mutex); | ||
2171 | return 0; | ||
2172 | } | ||
2173 | |||
2174 | static int relocate_one_reference(struct btrfs_root *extent_root, | ||
2175 | struct btrfs_path *path, | ||
2176 | struct btrfs_key *extent_key, | ||
2177 | u64 ref_root, u64 ref_gen, u64 ref_objectid, | ||
2178 | u64 ref_offset) | ||
2179 | { | ||
2180 | struct inode *inode; | ||
2181 | struct btrfs_root *found_root; | ||
2182 | struct btrfs_key root_location; | ||
2183 | int ret; | ||
2184 | |||
2185 | root_location.objectid = ref_root; | ||
2186 | if (ref_gen == 0) | ||
2187 | root_location.offset = 0; | ||
2188 | else | ||
2189 | root_location.offset = (u64)-1; | ||
2190 | root_location.type = BTRFS_ROOT_ITEM_KEY; | ||
2191 | |||
2192 | found_root = btrfs_read_fs_root_no_name(extent_root->fs_info, | ||
2193 | &root_location); | ||
2194 | BUG_ON(!found_root); | ||
2195 | |||
2196 | if (ref_objectid >= BTRFS_FIRST_FREE_OBJECTID) { | ||
2197 | mutex_unlock(&extent_root->fs_info->fs_mutex); | ||
2198 | inode = btrfs_iget_locked(extent_root->fs_info->sb, | ||
2199 | ref_objectid, found_root); | ||
2200 | if (inode->i_state & I_NEW) { | ||
2201 | /* the inode and parent dir are two different roots */ | ||
2202 | BTRFS_I(inode)->root = found_root; | ||
2203 | BTRFS_I(inode)->location.objectid = ref_objectid; | ||
2204 | BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY; | ||
2205 | BTRFS_I(inode)->location.offset = 0; | ||
2206 | btrfs_read_locked_inode(inode); | ||
2207 | unlock_new_inode(inode); | ||
2208 | |||
2209 | } | ||
2210 | /* this can happen if the reference is not against | ||
2211 | * the latest version of the tree root | ||
2212 | */ | ||
2213 | if (is_bad_inode(inode)) { | ||
2214 | mutex_lock(&extent_root->fs_info->fs_mutex); | ||
2215 | goto out; | ||
2216 | } | ||
2217 | relocate_inode_pages(inode, ref_offset, extent_key->offset); | ||
2218 | /* FIXME, data=ordered will help get rid of this */ | ||
2219 | filemap_fdatawrite(inode->i_mapping); | ||
2220 | iput(inode); | ||
2221 | mutex_lock(&extent_root->fs_info->fs_mutex); | ||
2222 | } else { | ||
2223 | struct btrfs_trans_handle *trans; | ||
2224 | struct btrfs_key found_key; | ||
2225 | struct extent_buffer *eb; | ||
2226 | int level; | ||
2227 | int i; | ||
2228 | |||
2229 | trans = btrfs_start_transaction(found_root, 1); | ||
2230 | eb = read_tree_block(found_root, extent_key->objectid, | ||
2231 | extent_key->offset); | ||
2232 | level = btrfs_header_level(eb); | ||
2233 | |||
2234 | if (level == 0) | ||
2235 | btrfs_item_key_to_cpu(eb, &found_key, 0); | ||
2236 | else | ||
2237 | btrfs_node_key_to_cpu(eb, &found_key, 0); | ||
2238 | |||
2239 | free_extent_buffer(eb); | ||
2240 | |||
2241 | path->lowest_level = level; | ||
2242 | path->reada = 0; | ||
2243 | ret = btrfs_search_slot(trans, found_root, &found_key, path, | ||
2244 | 0, 1); | ||
2245 | path->lowest_level = 0; | ||
2246 | for (i = level; i < BTRFS_MAX_LEVEL; i++) { | ||
2247 | if (!path->nodes[i]) | ||
2248 | break; | ||
2249 | free_extent_buffer(path->nodes[i]); | ||
2250 | path->nodes[i] = NULL; | ||
2251 | } | ||
2252 | btrfs_release_path(found_root, path); | ||
2253 | btrfs_end_transaction(trans, found_root); | ||
2254 | } | ||
2255 | |||
2256 | out: | ||
2257 | return 0; | ||
2258 | } | ||
2259 | |||
2260 | static int relocate_one_extent(struct btrfs_root *extent_root, | ||
2261 | struct btrfs_path *path, | ||
2262 | struct btrfs_key *extent_key) | ||
2263 | { | ||
2264 | struct btrfs_key key; | ||
2265 | struct btrfs_key found_key; | ||
2266 | struct btrfs_extent_ref *ref; | ||
2267 | struct extent_buffer *leaf; | ||
2268 | u64 ref_root; | ||
2269 | u64 ref_gen; | ||
2270 | u64 ref_objectid; | ||
2271 | u64 ref_offset; | ||
2272 | u32 nritems; | ||
2273 | u32 item_size; | ||
2274 | int ret = 0; | ||
2275 | |||
2276 | key.objectid = extent_key->objectid; | ||
2277 | key.type = BTRFS_EXTENT_REF_KEY; | ||
2278 | key.offset = 0; | ||
2279 | |||
2280 | while(1) { | ||
2281 | ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0); | ||
2282 | |||
2283 | BUG_ON(ret == 0); | ||
2284 | |||
2285 | if (ret < 0) | ||
2286 | goto out; | ||
2287 | |||
2288 | ret = 0; | ||
2289 | leaf = path->nodes[0]; | ||
2290 | nritems = btrfs_header_nritems(leaf); | ||
2291 | if (path->slots[0] == nritems) | ||
2292 | goto out; | ||
2293 | |||
2294 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | ||
2295 | if (found_key.objectid != extent_key->objectid) | ||
2296 | break; | ||
2297 | |||
2298 | if (found_key.type != BTRFS_EXTENT_REF_KEY) | ||
2299 | break; | ||
2300 | |||
2301 | key.offset = found_key.offset + 1; | ||
2302 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); | ||
2303 | |||
2304 | ref = btrfs_item_ptr(leaf, path->slots[0], | ||
2305 | struct btrfs_extent_ref); | ||
2306 | ref_root = btrfs_ref_root(leaf, ref); | ||
2307 | ref_gen = btrfs_ref_generation(leaf, ref); | ||
2308 | ref_objectid = btrfs_ref_objectid(leaf, ref); | ||
2309 | ref_offset = btrfs_ref_offset(leaf, ref); | ||
2310 | btrfs_release_path(extent_root, path); | ||
2311 | |||
2312 | ret = relocate_one_reference(extent_root, path, | ||
2313 | extent_key, ref_root, ref_gen, | ||
2314 | ref_objectid, ref_offset); | ||
2315 | if (ret) | ||
2316 | goto out; | ||
2317 | } | ||
2318 | ret = 0; | ||
2319 | out: | ||
2320 | btrfs_release_path(extent_root, path); | ||
2321 | return ret; | ||
2322 | } | ||
2323 | |||
2324 | static int find_overlapping_extent(struct btrfs_root *root, | ||
2325 | struct btrfs_path *path, u64 new_size) | ||
2326 | { | ||
2327 | struct btrfs_key found_key; | ||
2328 | struct extent_buffer *leaf; | ||
2329 | int ret; | ||
2330 | |||
2331 | while(1) { | ||
2332 | if (path->slots[0] == 0) { | ||
2333 | ret = btrfs_prev_leaf(root, path); | ||
2334 | if (ret == 1) { | ||
2335 | return 1; | ||
2336 | } | ||
2337 | if (ret < 0) | ||
2338 | return ret; | ||
2339 | } else { | ||
2340 | path->slots[0]--; | ||
2341 | } | ||
2342 | leaf = path->nodes[0]; | ||
2343 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | ||
2344 | if (found_key.type == BTRFS_EXTENT_ITEM_KEY) { | ||
2345 | if (found_key.objectid + found_key.offset > new_size) | ||
2346 | return 0; | ||
2347 | else | ||
2348 | return 1; | ||
2349 | } | ||
2350 | } | ||
2351 | return 1; | ||
2352 | } | ||
2353 | |||
2354 | int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 new_size) | ||
2355 | { | ||
2356 | struct btrfs_trans_handle *trans; | ||
2357 | struct btrfs_root *tree_root = root->fs_info->tree_root; | ||
2358 | struct btrfs_path *path; | ||
2359 | u64 cur_byte; | ||
2360 | u64 total_found; | ||
2361 | u64 ptr; | ||
2362 | struct btrfs_fs_info *info = root->fs_info; | ||
2363 | struct extent_map_tree *block_group_cache; | ||
2364 | struct btrfs_key key; | ||
2365 | struct btrfs_key found_key = { 0, 0, 0 }; | ||
2366 | struct extent_buffer *leaf; | ||
2367 | u32 nritems; | ||
2368 | int ret; | ||
2369 | int slot; | ||
2370 | |||
2371 | btrfs_set_super_total_bytes(&info->super_copy, new_size); | ||
2372 | block_group_cache = &info->block_group_cache; | ||
2373 | path = btrfs_alloc_path(); | ||
2374 | root = root->fs_info->extent_root; | ||
2375 | |||
2376 | again: | ||
2377 | total_found = 0; | ||
2378 | key.objectid = new_size; | ||
2379 | cur_byte = key.objectid; | ||
2380 | key.offset = 0; | ||
2381 | key.type = 0; | ||
2382 | while(1) { | ||
2383 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
2384 | if (ret < 0) | ||
2385 | goto out; | ||
2386 | next: | ||
2387 | leaf = path->nodes[0]; | ||
2388 | if (key.objectid == new_size - 1) { | ||
2389 | ret = find_overlapping_extent(root, path, new_size); | ||
2390 | if (ret != 0) { | ||
2391 | btrfs_release_path(root, path); | ||
2392 | ret = btrfs_search_slot(NULL, root, &key, | ||
2393 | path, 0, 0); | ||
2394 | if (ret < 0) | ||
2395 | goto out; | ||
2396 | } | ||
2397 | } | ||
2398 | nritems = btrfs_header_nritems(leaf); | ||
2399 | ret = 0; | ||
2400 | slot = path->slots[0]; | ||
2401 | if (slot < nritems) | ||
2402 | btrfs_item_key_to_cpu(leaf, &found_key, slot); | ||
2403 | if (slot == nritems || | ||
2404 | btrfs_key_type(&found_key) != BTRFS_EXTENT_ITEM_KEY) { | ||
2405 | path->slots[0]++; | ||
2406 | if (path->slots[0] >= nritems) { | ||
2407 | ret = btrfs_next_leaf(root, path); | ||
2408 | if (ret < 0) | ||
2409 | goto out; | ||
2410 | if (ret == 1) { | ||
2411 | ret = 0; | ||
2412 | break; | ||
2413 | } | ||
2414 | } | ||
2415 | goto next; | ||
2416 | } | ||
2417 | btrfs_item_key_to_cpu(leaf, &found_key, slot); | ||
2418 | if (found_key.objectid + found_key.offset <= cur_byte) | ||
2419 | continue; | ||
2420 | total_found++; | ||
2421 | cur_byte = found_key.objectid + found_key.offset; | ||
2422 | key.objectid = cur_byte; | ||
2423 | btrfs_release_path(root, path); | ||
2424 | ret = relocate_one_extent(root, path, &found_key); | ||
2425 | } | ||
2426 | |||
2427 | btrfs_release_path(root, path); | ||
2428 | |||
2429 | if (total_found > 0) { | ||
2430 | trans = btrfs_start_transaction(tree_root, 1); | ||
2431 | btrfs_commit_transaction(trans, tree_root); | ||
2432 | |||
2433 | mutex_unlock(&root->fs_info->fs_mutex); | ||
2434 | btrfs_clean_old_snapshots(tree_root); | ||
2435 | mutex_lock(&root->fs_info->fs_mutex); | ||
2436 | |||
2437 | trans = btrfs_start_transaction(tree_root, 1); | ||
2438 | btrfs_commit_transaction(trans, tree_root); | ||
2439 | goto again; | ||
2440 | } | ||
2441 | |||
2442 | trans = btrfs_start_transaction(root, 1); | ||
2443 | key.objectid = new_size; | ||
2444 | key.offset = 0; | ||
2445 | key.type = 0; | ||
2446 | while(1) { | ||
2447 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | ||
2448 | if (ret < 0) | ||
2449 | goto out; | ||
2450 | bg_next: | ||
2451 | leaf = path->nodes[0]; | ||
2452 | nritems = btrfs_header_nritems(leaf); | ||
2453 | ret = 0; | ||
2454 | slot = path->slots[0]; | ||
2455 | if (slot < nritems) | ||
2456 | btrfs_item_key_to_cpu(leaf, &found_key, slot); | ||
2457 | if (slot == nritems || | ||
2458 | btrfs_key_type(&found_key) != BTRFS_BLOCK_GROUP_ITEM_KEY) { | ||
2459 | if (slot < nritems) { | ||
2460 | printk("shrinker found key %Lu %u %Lu\n", | ||
2461 | found_key.objectid, found_key.type, | ||
2462 | found_key.offset); | ||
2463 | path->slots[0]++; | ||
2464 | } | ||
2465 | if (path->slots[0] >= nritems) { | ||
2466 | ret = btrfs_next_leaf(root, path); | ||
2467 | if (ret < 0) | ||
2468 | break; | ||
2469 | if (ret == 1) { | ||
2470 | ret = 0; | ||
2471 | break; | ||
2472 | } | ||
2473 | } | ||
2474 | goto bg_next; | ||
2475 | } | ||
2476 | btrfs_item_key_to_cpu(leaf, &found_key, slot); | ||
2477 | ret = get_state_private(&info->block_group_cache, | ||
2478 | found_key.objectid, &ptr); | ||
2479 | if (!ret) | ||
2480 | kfree((void *)(unsigned long)ptr); | ||
2481 | |||
2482 | clear_extent_bits(&info->block_group_cache, found_key.objectid, | ||
2483 | found_key.objectid + found_key.offset - 1, | ||
2484 | (unsigned int)-1, GFP_NOFS); | ||
2485 | |||
2486 | key.objectid = found_key.objectid + 1; | ||
2487 | btrfs_del_item(trans, root, path); | ||
2488 | btrfs_release_path(root, path); | ||
2489 | } | ||
2490 | clear_extent_dirty(&info->free_space_cache, new_size, (u64)-1, | ||
2491 | GFP_NOFS); | ||
2492 | btrfs_commit_transaction(trans, root); | ||
2493 | out: | ||
2494 | btrfs_free_path(path); | ||
2495 | return ret; | ||
2496 | } | ||
2497 | |||
2498 | int btrfs_grow_extent_tree(struct btrfs_trans_handle *trans, | ||
2499 | struct btrfs_root *root, u64 new_size) | ||
2500 | { | ||
2501 | struct btrfs_path *path; | ||
2502 | u64 nr = 0; | ||
2503 | u64 cur_byte; | ||
2504 | u64 old_size; | ||
2505 | struct btrfs_block_group_cache *cache; | ||
2506 | struct btrfs_block_group_item *item; | ||
2507 | struct btrfs_fs_info *info = root->fs_info; | ||
2508 | struct extent_map_tree *block_group_cache; | ||
2509 | struct btrfs_key key; | ||
2510 | struct extent_buffer *leaf; | ||
2511 | int ret; | ||
2512 | int bit; | ||
2513 | |||
2514 | old_size = btrfs_super_total_bytes(&info->super_copy); | ||
2515 | block_group_cache = &info->block_group_cache; | ||
2516 | |||
2517 | root = info->extent_root; | ||
2518 | |||
2519 | cache = btrfs_lookup_block_group(root->fs_info, old_size - 1); | ||
2520 | |||
2521 | cur_byte = cache->key.objectid + cache->key.offset; | ||
2522 | if (cur_byte >= new_size) | ||
2523 | goto set_size; | ||
2524 | |||
2525 | key.offset = BTRFS_BLOCK_GROUP_SIZE; | ||
2526 | btrfs_set_key_type(&key, BTRFS_BLOCK_GROUP_ITEM_KEY); | ||
2527 | |||
2528 | path = btrfs_alloc_path(); | ||
2529 | if (!path) | ||
2530 | return -ENOMEM; | ||
2531 | |||
2532 | while(cur_byte < new_size) { | ||
2533 | key.objectid = cur_byte; | ||
2534 | ret = btrfs_insert_empty_item(trans, root, path, &key, | ||
2535 | sizeof(struct btrfs_block_group_item)); | ||
2536 | BUG_ON(ret); | ||
2537 | leaf = path->nodes[0]; | ||
2538 | item = btrfs_item_ptr(leaf, path->slots[0], | ||
2539 | struct btrfs_block_group_item); | ||
2540 | |||
2541 | btrfs_set_disk_block_group_used(leaf, item, 0); | ||
2542 | if (nr % 3) { | ||
2543 | btrfs_set_disk_block_group_flags(leaf, item, | ||
2544 | BTRFS_BLOCK_GROUP_DATA); | ||
2545 | } else { | ||
2546 | btrfs_set_disk_block_group_flags(leaf, item, 0); | ||
2547 | } | ||
2548 | nr++; | ||
2549 | |||
2550 | cache = kmalloc(sizeof(*cache), GFP_NOFS); | ||
2551 | BUG_ON(!cache); | ||
2552 | |||
2553 | read_extent_buffer(leaf, &cache->item, (unsigned long)item, | ||
2554 | sizeof(cache->item)); | ||
2555 | |||
2556 | memcpy(&cache->key, &key, sizeof(key)); | ||
2557 | cache->cached = 0; | ||
2558 | cache->pinned = 0; | ||
2559 | cur_byte = key.objectid + key.offset; | ||
2560 | btrfs_release_path(root, path); | ||
2561 | |||
2562 | if (cache->item.flags & BTRFS_BLOCK_GROUP_DATA) { | ||
2563 | bit = BLOCK_GROUP_DATA; | ||
2564 | cache->data = BTRFS_BLOCK_GROUP_DATA; | ||
2565 | } else { | ||
2566 | bit = BLOCK_GROUP_METADATA; | ||
2567 | cache->data = 0; | ||
2568 | } | ||
2569 | |||
2570 | /* use EXTENT_LOCKED to prevent merging */ | ||
2571 | set_extent_bits(block_group_cache, key.objectid, | ||
2572 | key.objectid + key.offset - 1, | ||
2573 | bit | EXTENT_LOCKED, GFP_NOFS); | ||
2574 | set_state_private(block_group_cache, key.objectid, | ||
2575 | (unsigned long)cache); | ||
2576 | } | ||
2577 | btrfs_free_path(path); | ||
2578 | set_size: | ||
2579 | btrfs_set_super_total_bytes(&info->super_copy, new_size); | ||
2580 | return 0; | ||
2581 | } | ||
2582 | |||
2103 | int btrfs_read_block_groups(struct btrfs_root *root) | 2583 | int btrfs_read_block_groups(struct btrfs_root *root) |
2104 | { | 2584 | { |
2105 | struct btrfs_path *path; | 2585 | struct btrfs_path *path; |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5f5b7b89b144..f6a20112d9e7 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2346,7 +2346,7 @@ fail_unlock: | |||
2346 | return ret; | 2346 | return ret; |
2347 | } | 2347 | } |
2348 | 2348 | ||
2349 | static unsigned long force_ra(struct address_space *mapping, | 2349 | unsigned long btrfs_force_ra(struct address_space *mapping, |
2350 | struct file_ra_state *ra, struct file *file, | 2350 | struct file_ra_state *ra, struct file *file, |
2351 | pgoff_t offset, pgoff_t last_index) | 2351 | pgoff_t offset, pgoff_t last_index) |
2352 | { | 2352 | { |
@@ -2372,6 +2372,8 @@ int btrfs_defrag_file(struct file *file) { | |||
2372 | unsigned long ra_index = 0; | 2372 | unsigned long ra_index = 0; |
2373 | u64 page_start; | 2373 | u64 page_start; |
2374 | u64 page_end; | 2374 | u64 page_end; |
2375 | u64 delalloc_start; | ||
2376 | u64 existing_delalloc; | ||
2375 | unsigned long i; | 2377 | unsigned long i; |
2376 | int ret; | 2378 | int ret; |
2377 | 2379 | ||
@@ -2385,8 +2387,9 @@ int btrfs_defrag_file(struct file *file) { | |||
2385 | last_index = inode->i_size >> PAGE_CACHE_SHIFT; | 2387 | last_index = inode->i_size >> PAGE_CACHE_SHIFT; |
2386 | for (i = 0; i <= last_index; i++) { | 2388 | for (i = 0; i <= last_index; i++) { |
2387 | if (i == ra_index) { | 2389 | if (i == ra_index) { |
2388 | ra_index = force_ra(inode->i_mapping, &file->f_ra, | 2390 | ra_index = btrfs_force_ra(inode->i_mapping, |
2389 | file, ra_index, last_index); | 2391 | &file->f_ra, |
2392 | file, ra_index, last_index); | ||
2390 | } | 2393 | } |
2391 | page = grab_cache_page(inode->i_mapping, i); | 2394 | page = grab_cache_page(inode->i_mapping, i); |
2392 | if (!page) | 2395 | if (!page) |
@@ -2404,8 +2407,19 @@ int btrfs_defrag_file(struct file *file) { | |||
2404 | page_end = page_start + PAGE_CACHE_SIZE - 1; | 2407 | page_end = page_start + PAGE_CACHE_SIZE - 1; |
2405 | 2408 | ||
2406 | lock_extent(em_tree, page_start, page_end, GFP_NOFS); | 2409 | lock_extent(em_tree, page_start, page_end, GFP_NOFS); |
2410 | delalloc_start = page_start; | ||
2411 | existing_delalloc = | ||
2412 | count_range_bits(&BTRFS_I(inode)->extent_tree, | ||
2413 | &delalloc_start, page_end, | ||
2414 | PAGE_CACHE_SIZE, EXTENT_DELALLOC); | ||
2407 | set_extent_delalloc(em_tree, page_start, | 2415 | set_extent_delalloc(em_tree, page_start, |
2408 | page_end, GFP_NOFS); | 2416 | page_end, GFP_NOFS); |
2417 | |||
2418 | spin_lock(&root->fs_info->delalloc_lock); | ||
2419 | root->fs_info->delalloc_bytes += PAGE_CACHE_SIZE - | ||
2420 | existing_delalloc; | ||
2421 | spin_unlock(&root->fs_info->delalloc_lock); | ||
2422 | |||
2409 | unlock_extent(em_tree, page_start, page_end, GFP_NOFS); | 2423 | unlock_extent(em_tree, page_start, page_end, GFP_NOFS); |
2410 | set_page_dirty(page); | 2424 | set_page_dirty(page); |
2411 | unlock_page(page); | 2425 | unlock_page(page); |
@@ -2418,6 +2432,89 @@ out_unlock: | |||
2418 | return 0; | 2432 | return 0; |
2419 | } | 2433 | } |
2420 | 2434 | ||
2435 | static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg) | ||
2436 | { | ||
2437 | u64 new_size; | ||
2438 | u64 old_size; | ||
2439 | struct btrfs_ioctl_vol_args *vol_args; | ||
2440 | struct btrfs_trans_handle *trans; | ||
2441 | char *sizestr; | ||
2442 | int ret = 0; | ||
2443 | int namelen; | ||
2444 | int mod = 0; | ||
2445 | |||
2446 | vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS); | ||
2447 | |||
2448 | if (!vol_args) | ||
2449 | return -ENOMEM; | ||
2450 | |||
2451 | if (copy_from_user(vol_args, arg, sizeof(*vol_args))) { | ||
2452 | ret = -EFAULT; | ||
2453 | goto out; | ||
2454 | } | ||
2455 | namelen = strlen(vol_args->name); | ||
2456 | if (namelen > BTRFS_VOL_NAME_MAX) { | ||
2457 | ret = -EINVAL; | ||
2458 | goto out; | ||
2459 | } | ||
2460 | |||
2461 | sizestr = vol_args->name; | ||
2462 | if (!strcmp(sizestr, "max")) | ||
2463 | new_size = root->fs_info->sb->s_bdev->bd_inode->i_size; | ||
2464 | else { | ||
2465 | if (sizestr[0] == '-') { | ||
2466 | mod = -1; | ||
2467 | sizestr++; | ||
2468 | } else if (sizestr[0] == '+') { | ||
2469 | mod = 1; | ||
2470 | sizestr++; | ||
2471 | } | ||
2472 | new_size = btrfs_parse_size(sizestr); | ||
2473 | if (new_size == 0) { | ||
2474 | ret = -EINVAL; | ||
2475 | goto out; | ||
2476 | } | ||
2477 | } | ||
2478 | |||
2479 | mutex_lock(&root->fs_info->fs_mutex); | ||
2480 | old_size = btrfs_super_total_bytes(&root->fs_info->super_copy); | ||
2481 | |||
2482 | if (mod < 0) { | ||
2483 | if (new_size > old_size) { | ||
2484 | ret = -EINVAL; | ||
2485 | goto out_unlock; | ||
2486 | } | ||
2487 | new_size = old_size - new_size; | ||
2488 | } else if (mod > 0) { | ||
2489 | new_size = old_size + new_size; | ||
2490 | } | ||
2491 | |||
2492 | if (new_size < 256 * 1024 * 1024) { | ||
2493 | ret = -EINVAL; | ||
2494 | goto out_unlock; | ||
2495 | } | ||
2496 | if (new_size > root->fs_info->sb->s_bdev->bd_inode->i_size) { | ||
2497 | ret = -EFBIG; | ||
2498 | goto out_unlock; | ||
2499 | } | ||
2500 | new_size = (new_size / root->sectorsize) * root->sectorsize; | ||
2501 | |||
2502 | printk("new size is %Lu\n", new_size); | ||
2503 | if (new_size > old_size) { | ||
2504 | trans = btrfs_start_transaction(root, 1); | ||
2505 | ret = btrfs_grow_extent_tree(trans, root, new_size); | ||
2506 | btrfs_commit_transaction(trans, root); | ||
2507 | } else { | ||
2508 | ret = btrfs_shrink_extent_tree(root, new_size); | ||
2509 | } | ||
2510 | |||
2511 | out_unlock: | ||
2512 | mutex_unlock(&root->fs_info->fs_mutex); | ||
2513 | out: | ||
2514 | kfree(vol_args); | ||
2515 | return ret; | ||
2516 | } | ||
2517 | |||
2421 | static int btrfs_ioctl_snap_create(struct btrfs_root *root, void __user *arg) | 2518 | static int btrfs_ioctl_snap_create(struct btrfs_root *root, void __user *arg) |
2422 | { | 2519 | { |
2423 | struct btrfs_ioctl_vol_args *vol_args; | 2520 | struct btrfs_ioctl_vol_args *vol_args; |
@@ -2510,6 +2607,8 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
2510 | return btrfs_ioctl_snap_create(root, (void __user *)arg); | 2607 | return btrfs_ioctl_snap_create(root, (void __user *)arg); |
2511 | case BTRFS_IOC_DEFRAG: | 2608 | case BTRFS_IOC_DEFRAG: |
2512 | return btrfs_ioctl_defrag(file); | 2609 | return btrfs_ioctl_defrag(file); |
2610 | case BTRFS_IOC_RESIZE: | ||
2611 | return btrfs_ioctl_resize(root, (void __user *)arg); | ||
2513 | } | 2612 | } |
2514 | 2613 | ||
2515 | return -ENOTTY; | 2614 | return -ENOTTY; |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 8bc47dec2865..8c6290665d49 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
@@ -30,4 +30,6 @@ struct btrfs_ioctl_vol_args { | |||
30 | struct btrfs_ioctl_vol_args) | 30 | struct btrfs_ioctl_vol_args) |
31 | #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ | 31 | #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ |
32 | struct btrfs_ioctl_vol_args) | 32 | struct btrfs_ioctl_vol_args) |
33 | #define BTRFS_IOC_RESIZE _IOW(BTRFS_IOCTL_MAGIC, 3, \ | ||
34 | struct btrfs_ioctl_vol_args) | ||
33 | #endif | 35 | #endif |
diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c index 88bcdd33f56e..e2b9b86af696 100644 --- a/fs/btrfs/root-tree.c +++ b/fs/btrfs/root-tree.c | |||
@@ -179,6 +179,11 @@ int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, | |||
179 | ret = btrfs_search_slot(trans, root, key, path, -1, 1); | 179 | ret = btrfs_search_slot(trans, root, key, path, -1, 1); |
180 | if (ret < 0) | 180 | if (ret < 0) |
181 | goto out; | 181 | goto out; |
182 | if (ret) { | ||
183 | btrfs_print_leaf(root, path->nodes[0]); | ||
184 | printk("failed to del %Lu %u %Lu\n", key->objectid, key->type, key->offset); | ||
185 | |||
186 | } | ||
182 | BUG_ON(ret != 0); | 187 | BUG_ON(ret != 0); |
183 | leaf = path->nodes[0]; | 188 | leaf = path->nodes[0]; |
184 | ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item); | 189 | ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item); |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 7cab680418a1..3bbd7f665694 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -74,9 +74,9 @@ static match_table_t tokens = { | |||
74 | {Opt_err, NULL} | 74 | {Opt_err, NULL} |
75 | }; | 75 | }; |
76 | 76 | ||
77 | static unsigned long parse_size(char *str) | 77 | u64 btrfs_parse_size(char *str) |
78 | { | 78 | { |
79 | unsigned long res; | 79 | u64 res; |
80 | int mult = 1; | 80 | int mult = 1; |
81 | char *end; | 81 | char *end; |
82 | char last; | 82 | char last; |
@@ -150,7 +150,8 @@ static int parse_options (char * options, | |||
150 | if (info) { | 150 | if (info) { |
151 | char *num = match_strdup(&args[0]); | 151 | char *num = match_strdup(&args[0]); |
152 | if (num) { | 152 | if (num) { |
153 | info->max_extent = parse_size(num); | 153 | info->max_extent = |
154 | btrfs_parse_size(num); | ||
154 | kfree(num); | 155 | kfree(num); |
155 | 156 | ||
156 | info->max_extent = max_t(u64, | 157 | info->max_extent = max_t(u64, |