@@ -1515,12 +1515,14 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
1515
1515
struct btrfs_tree_parent_check check = { 0 };
1516
1516
u64 blocknr ;
1517
1517
u64 gen ;
1518
- struct extent_buffer * tmp ;
1519
- int ret ;
1518
+ struct extent_buffer * tmp = NULL ;
1519
+ int ret = 0 ;
1520
1520
int parent_level ;
1521
- bool unlock_up ;
1521
+ int err ;
1522
+ bool read_tmp = false;
1523
+ bool tmp_locked = false;
1524
+ bool path_released = false;
1522
1525
1523
- unlock_up = ((level + 1 < BTRFS_MAX_LEVEL ) && p -> locks [level + 1 ]);
1524
1526
blocknr = btrfs_node_blockptr (* eb_ret , slot );
1525
1527
gen = btrfs_node_ptr_generation (* eb_ret , slot );
1526
1528
parent_level = btrfs_header_level (* eb_ret );
@@ -1551,68 +1553,105 @@ read_block_for_search(struct btrfs_root *root, struct btrfs_path *p,
1551
1553
*/
1552
1554
if (btrfs_verify_level_key (tmp ,
1553
1555
parent_level - 1 , & check .first_key , gen )) {
1554
- free_extent_buffer ( tmp ) ;
1555
- return - EUCLEAN ;
1556
+ ret = - EUCLEAN ;
1557
+ goto out ;
1556
1558
}
1557
1559
* eb_ret = tmp ;
1558
- return 0 ;
1560
+ tmp = NULL ;
1561
+ ret = 0 ;
1562
+ goto out ;
1559
1563
}
1560
1564
1561
1565
if (p -> nowait ) {
1562
- free_extent_buffer ( tmp ) ;
1563
- return - EAGAIN ;
1566
+ ret = - EAGAIN ;
1567
+ goto out ;
1564
1568
}
1565
1569
1566
- if (unlock_up )
1570
+ if (! p -> skip_locking ) {
1567
1571
btrfs_unlock_up_safe (p , level + 1 );
1568
-
1569
- /* now we're allowed to do a blocking uptodate check */
1570
- ret = btrfs_read_extent_buffer (tmp , & check );
1571
- if (ret ) {
1572
- free_extent_buffer (tmp );
1572
+ tmp_locked = true;
1573
+ btrfs_tree_read_lock (tmp );
1573
1574
btrfs_release_path (p );
1574
- return ret ;
1575
+ ret = - EAGAIN ;
1576
+ path_released = true;
1575
1577
}
1576
1578
1577
- if (unlock_up )
1578
- ret = - EAGAIN ;
1579
+ /* Now we're allowed to do a blocking uptodate check. */
1580
+ err = btrfs_read_extent_buffer (tmp , & check );
1581
+ if (err ) {
1582
+ ret = err ;
1583
+ goto out ;
1584
+ }
1579
1585
1586
+ if (ret == 0 ) {
1587
+ ASSERT (!tmp_locked );
1588
+ * eb_ret = tmp ;
1589
+ tmp = NULL ;
1590
+ }
1580
1591
goto out ;
1581
1592
} else if (p -> nowait ) {
1582
- return - EAGAIN ;
1593
+ ret = - EAGAIN ;
1594
+ goto out ;
1583
1595
}
1584
1596
1585
- if (unlock_up ) {
1597
+ if (! p -> skip_locking ) {
1586
1598
btrfs_unlock_up_safe (p , level + 1 );
1587
1599
ret = - EAGAIN ;
1588
- } else {
1589
- ret = 0 ;
1590
1600
}
1591
1601
1592
1602
if (p -> reada != READA_NONE )
1593
1603
reada_for_search (fs_info , p , level , slot , key -> objectid );
1594
1604
1595
- tmp = read_tree_block (fs_info , blocknr , & check );
1605
+ tmp = btrfs_find_create_tree_block (fs_info , blocknr , check . owner_root , check . level );
1596
1606
if (IS_ERR (tmp )) {
1607
+ ret = PTR_ERR (tmp );
1608
+ tmp = NULL ;
1609
+ goto out ;
1610
+ }
1611
+ read_tmp = true;
1612
+
1613
+ if (!p -> skip_locking ) {
1614
+ ASSERT (ret == - EAGAIN );
1615
+ tmp_locked = true;
1616
+ btrfs_tree_read_lock (tmp );
1597
1617
btrfs_release_path (p );
1598
- return PTR_ERR (tmp );
1618
+ path_released = true;
1619
+ }
1620
+
1621
+ /* Now we're allowed to do a blocking uptodate check. */
1622
+ err = btrfs_read_extent_buffer (tmp , & check );
1623
+ if (err ) {
1624
+ ret = err ;
1625
+ goto out ;
1599
1626
}
1627
+
1600
1628
/*
1601
1629
* If the read above didn't mark this buffer up to date,
1602
1630
* it will never end up being up to date. Set ret to EIO now
1603
1631
* and give up so that our caller doesn't loop forever
1604
1632
* on our EAGAINs.
1605
1633
*/
1606
- if (!extent_buffer_uptodate (tmp ))
1634
+ if (!extent_buffer_uptodate (tmp )) {
1607
1635
ret = - EIO ;
1636
+ goto out ;
1637
+ }
1608
1638
1609
- out :
1610
1639
if (ret == 0 ) {
1640
+ ASSERT (!tmp_locked );
1611
1641
* eb_ret = tmp ;
1612
- } else {
1613
- free_extent_buffer (tmp );
1614
- btrfs_release_path (p );
1642
+ tmp = NULL ;
1643
+ }
1644
+ out :
1645
+ if (tmp ) {
1646
+ if (tmp_locked )
1647
+ btrfs_tree_read_unlock (tmp );
1648
+ if (read_tmp && ret && ret != - EAGAIN )
1649
+ free_extent_buffer_stale (tmp );
1650
+ else
1651
+ free_extent_buffer (tmp );
1615
1652
}
1653
+ if (ret && !path_released )
1654
+ btrfs_release_path (p );
1616
1655
1617
1656
return ret ;
1618
1657
}
@@ -2198,7 +2237,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root *root,
2198
2237
}
2199
2238
2200
2239
err = read_block_for_search (root , p , & b , level , slot , key );
2201
- if (err == - EAGAIN )
2240
+ if (err == - EAGAIN && ! p -> nowait )
2202
2241
goto again ;
2203
2242
if (err ) {
2204
2243
ret = err ;
@@ -2325,7 +2364,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, const struct btrfs_key *key,
2325
2364
}
2326
2365
2327
2366
err = read_block_for_search (root , p , & b , level , slot , key );
2328
- if (err == - EAGAIN )
2367
+ if (err == - EAGAIN && ! p -> nowait )
2329
2368
goto again ;
2330
2369
if (err ) {
2331
2370
ret = err ;
0 commit comments