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/extent-tree.c | |
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/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 480 |
1 files changed, 480 insertions, 0 deletions
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; |