@@ -169,17 +169,17 @@ static int finish_current_insert(struct btrfs_trans_handle *trans, struct
169
169
btrfs_set_key_type (& ins , BTRFS_EXTENT_ITEM_KEY );
170
170
btrfs_set_extent_owner (& extent_item , extent_root -> root_key .objectid );
171
171
172
- for (i = 0 ; i < extent_root -> fs_info -> current_insert .flags ; i ++ ) {
173
- ins .objectid = extent_root -> fs_info -> current_insert .objectid +
174
- i ;
172
+ for (i = 0 ; i < extent_root -> fs_info -> extent_tree_insert_nr ; i ++ ) {
173
+ ins .objectid = extent_root -> fs_info -> extent_tree_insert [i ];
175
174
super_blocks_used = btrfs_super_blocks_used (info -> disk_super );
176
175
btrfs_set_super_blocks_used (info -> disk_super ,
177
176
super_blocks_used + 1 );
178
177
ret = btrfs_insert_item (trans , extent_root , & ins , & extent_item ,
179
178
sizeof (extent_item ));
180
179
BUG_ON (ret );
181
180
}
182
- extent_root -> fs_info -> current_insert .offset = 0 ;
181
+ extent_root -> fs_info -> extent_tree_insert_nr = 0 ;
182
+ extent_root -> fs_info -> extent_tree_prealloc_nr = 0 ;
183
183
return 0 ;
184
184
}
185
185
@@ -349,16 +349,23 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
349
349
int start_found ;
350
350
struct btrfs_leaf * l ;
351
351
struct btrfs_root * root = orig_root -> fs_info -> extent_root ;
352
+ struct btrfs_fs_info * info = root -> fs_info ;
352
353
int total_needed = num_blocks ;
354
+ int total_found = 0 ;
355
+ int fill_prealloc = 0 ;
353
356
int level ;
354
357
355
358
path = btrfs_alloc_path ();
356
359
ins -> flags = 0 ;
357
360
btrfs_set_key_type (ins , BTRFS_EXTENT_ITEM_KEY );
358
361
359
362
level = btrfs_header_level (btrfs_buffer_header (root -> node ));
360
- total_needed += (level + 2 ) * 3 ;
361
- if (root -> fs_info -> last_insert .objectid == 0 && search_end == (u64 )- 1 ) {
363
+ if (num_blocks == 0 ) {
364
+ fill_prealloc = 1 ;
365
+ num_blocks = 1 ;
366
+ total_needed = min (level + 2 , BTRFS_MAX_LEVEL ) * 3 ;
367
+ }
368
+ if (info -> last_insert .objectid == 0 && search_end == (u64 )- 1 ) {
362
369
struct btrfs_disk_key * last_key ;
363
370
btrfs_init_path (path );
364
371
ins -> objectid = (u64 )- 1 ;
@@ -373,8 +380,8 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
373
380
last_key = & l -> items [path -> slots [0 ]].key ;
374
381
search_start = btrfs_disk_key_objectid (last_key );
375
382
}
376
- if (root -> fs_info -> last_insert .objectid > search_start )
377
- search_start = root -> fs_info -> last_insert .objectid ;
383
+ if (info -> last_insert .objectid > search_start )
384
+ search_start = info -> last_insert .objectid ;
378
385
379
386
check_failed :
380
387
btrfs_init_path (path );
@@ -392,20 +399,24 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
392
399
l = btrfs_buffer_leaf (path -> nodes [0 ]);
393
400
slot = path -> slots [0 ];
394
401
if (slot >= btrfs_header_nritems (& l -> header )) {
402
+ if (fill_prealloc ) {
403
+ info -> extent_tree_prealloc_nr = 0 ;
404
+ total_found = 0 ;
405
+ }
395
406
ret = btrfs_next_leaf (root , path );
396
407
if (ret == 0 )
397
408
continue ;
398
409
if (ret < 0 )
399
410
goto error ;
400
411
if (!start_found ) {
401
412
ins -> objectid = search_start ;
402
- ins -> offset = (u64 )- 1 ;
413
+ ins -> offset = (u64 )- 1 - search_start ;
403
414
start_found = 1 ;
404
415
goto check_pending ;
405
416
}
406
417
ins -> objectid = last_block > search_start ?
407
418
last_block : search_start ;
408
- ins -> offset = (u64 )- 1 ;
419
+ ins -> offset = (u64 )- 1 - ins -> objectid ;
409
420
goto check_pending ;
410
421
}
411
422
btrfs_disk_key_to_cpu (& key , & l -> items [slot ].key );
@@ -414,7 +425,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
414
425
if (last_block < search_start )
415
426
last_block = search_start ;
416
427
hole_size = key .objectid - last_block ;
417
- if (hole_size > total_needed ) {
428
+ if (hole_size > num_blocks ) {
418
429
ins -> objectid = last_block ;
419
430
ins -> offset = hole_size ;
420
431
goto check_pending ;
@@ -433,17 +444,51 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
433
444
btrfs_release_path (root , path );
434
445
BUG_ON (ins -> objectid < search_start );
435
446
for (test_block = ins -> objectid ;
436
- test_block < ins -> objectid + total_needed ; test_block ++ ) {
437
- if (test_radix_bit (& root -> fs_info -> pinned_radix ,
438
- test_block )) {
447
+ test_block < ins -> objectid + num_blocks ; test_block ++ ) {
448
+ if (test_radix_bit (& info -> pinned_radix , test_block )) {
439
449
search_start = test_block + 1 ;
440
450
goto check_failed ;
441
451
}
442
452
}
443
- BUG_ON (root -> fs_info -> current_insert .offset );
444
- root -> fs_info -> current_insert .offset = total_needed - num_blocks ;
445
- root -> fs_info -> current_insert .objectid = ins -> objectid + num_blocks ;
446
- root -> fs_info -> current_insert .flags = 0 ;
453
+ if (!fill_prealloc && info -> extent_tree_insert_nr ) {
454
+ u64 last =
455
+ info -> extent_tree_insert [info -> extent_tree_insert_nr - 1 ];
456
+ if (ins -> objectid + num_blocks >
457
+ info -> extent_tree_insert [0 ] &&
458
+ ins -> objectid <= last ) {
459
+ search_start = last + 1 ;
460
+ WARN_ON (1 );
461
+ goto check_failed ;
462
+ }
463
+ }
464
+ if (!fill_prealloc && info -> extent_tree_prealloc_nr ) {
465
+ u64 first =
466
+ info -> extent_tree_prealloc [info -> extent_tree_prealloc_nr - 1 ];
467
+ if (ins -> objectid + num_blocks > first &&
468
+ ins -> objectid <= info -> extent_tree_prealloc [0 ]) {
469
+ search_start = info -> extent_tree_prealloc [0 ] + 1 ;
470
+ WARN_ON (1 );
471
+ goto check_failed ;
472
+ }
473
+ }
474
+ if (fill_prealloc ) {
475
+ int nr ;
476
+ test_block = ins -> objectid ;
477
+ while (test_block < ins -> objectid + ins -> offset &&
478
+ total_found < total_needed ) {
479
+ nr = total_needed - total_found - 1 ;
480
+ BUG_ON (nr < 0 );
481
+ root -> fs_info -> extent_tree_prealloc [nr ] =
482
+ test_block ;
483
+ total_found ++ ;
484
+ test_block ++ ;
485
+ }
486
+ if (total_found < total_needed ) {
487
+ search_start = test_block ;
488
+ goto check_failed ;
489
+ }
490
+ root -> fs_info -> extent_tree_prealloc_nr = total_found ;
491
+ }
447
492
root -> fs_info -> last_insert .objectid = ins -> objectid ;
448
493
ins -> offset = num_blocks ;
449
494
btrfs_free_path (path );
@@ -472,25 +517,35 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
472
517
struct btrfs_fs_info * info = root -> fs_info ;
473
518
struct btrfs_root * extent_root = info -> extent_root ;
474
519
struct btrfs_extent_item extent_item ;
520
+ struct btrfs_key prealloc_key ;
475
521
476
522
btrfs_set_extent_refs (& extent_item , 1 );
477
523
btrfs_set_extent_owner (& extent_item , owner );
478
524
479
525
if (root == extent_root ) {
480
- BUG_ON (extent_root -> fs_info -> current_insert .offset == 0 );
526
+ int nr ;
527
+ BUG_ON (info -> extent_tree_prealloc_nr == 0 );
481
528
BUG_ON (num_blocks != 1 );
482
- BUG_ON (extent_root -> fs_info -> current_insert .flags ==
483
- extent_root -> fs_info -> current_insert .offset );
484
529
ins -> offset = 1 ;
485
- ins -> objectid = extent_root -> fs_info -> current_insert .objectid +
486
- extent_root -> fs_info -> current_insert .flags ++ ;
530
+ info -> extent_tree_prealloc_nr -- ;
531
+ nr = info -> extent_tree_prealloc_nr ;
532
+ ins -> objectid = info -> extent_tree_prealloc [nr ];
533
+ info -> extent_tree_insert [info -> extent_tree_insert_nr ++ ] =
534
+ ins -> objectid ;
487
535
return 0 ;
488
536
}
537
+ /* do the real allocation */
489
538
ret = find_free_extent (trans , root , num_blocks , search_start ,
490
539
search_end , ins );
491
540
if (ret )
492
541
return ret ;
493
542
543
+ /* then do prealloc for the extent tree */
544
+ ret = find_free_extent (trans , root , 0 , ins -> objectid + ins -> offset ,
545
+ search_end , & prealloc_key );
546
+ if (ret )
547
+ return ret ;
548
+
494
549
super_blocks_used = btrfs_super_blocks_used (info -> disk_super );
495
550
btrfs_set_super_blocks_used (info -> disk_super , super_blocks_used +
496
551
num_blocks );
0 commit comments