@@ -1401,10 +1401,7 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
1401
1401
* to free. Everything was covered by the start
1402
1402
* of the range.
1403
1403
*/
1404
- return 0 ;
1405
- } else {
1406
- /* Shared branch grows from an indirect block */
1407
- partial2 -- ;
1404
+ goto do_indirects ;
1408
1405
}
1409
1406
} else {
1410
1407
/*
@@ -1435,56 +1432,96 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
1435
1432
/* Punch happened within the same level (n == n2) */
1436
1433
partial = ext4_find_shared (inode , n , offsets , chain , & nr );
1437
1434
partial2 = ext4_find_shared (inode , n2 , offsets2 , chain2 , & nr2 );
1438
- /*
1439
- * ext4_find_shared returns Indirect structure which
1440
- * points to the last element which should not be
1441
- * removed by truncate. But this is end of the range
1442
- * in punch_hole so we need to point to the next element
1443
- */
1444
- partial2 -> p ++ ;
1445
- while ((partial > chain ) || (partial2 > chain2 )) {
1446
- /* We're at the same block, so we're almost finished */
1447
- if ((partial -> bh && partial2 -> bh ) &&
1448
- (partial -> bh -> b_blocknr == partial2 -> bh -> b_blocknr )) {
1449
- if ((partial > chain ) && (partial2 > chain2 )) {
1435
+
1436
+ /* Free top, but only if partial2 isn't its subtree. */
1437
+ if (nr ) {
1438
+ int level = min (partial - chain , partial2 - chain2 );
1439
+ int i ;
1440
+ int subtree = 1 ;
1441
+
1442
+ for (i = 0 ; i <= level ; i ++ ) {
1443
+ if (offsets [i ] != offsets2 [i ]) {
1444
+ subtree = 0 ;
1445
+ break ;
1446
+ }
1447
+ }
1448
+
1449
+ if (!subtree ) {
1450
+ if (partial == chain ) {
1451
+ /* Shared branch grows from the inode */
1452
+ ext4_free_branches (handle , inode , NULL ,
1453
+ & nr , & nr + 1 ,
1454
+ (chain + n - 1 ) - partial );
1455
+ * partial -> p = 0 ;
1456
+ } else {
1457
+ /* Shared branch grows from an indirect block */
1458
+ BUFFER_TRACE (partial -> bh , "get_write_access" );
1450
1459
ext4_free_branches (handle , inode , partial -> bh ,
1451
- partial -> p + 1 ,
1452
- partial2 -> p ,
1460
+ partial -> p ,
1461
+ partial -> p + 1 ,
1453
1462
(chain + n - 1 ) - partial );
1454
- BUFFER_TRACE (partial -> bh , "call brelse" );
1455
- brelse (partial -> bh );
1456
- BUFFER_TRACE (partial2 -> bh , "call brelse" );
1457
- brelse (partial2 -> bh );
1458
1463
}
1459
- return 0 ;
1460
1464
}
1465
+ }
1466
+
1467
+ if (!nr2 ) {
1461
1468
/*
1462
- * Clear the ends of indirect blocks on the shared branch
1463
- * at the start of the range
1469
+ * ext4_find_shared returns Indirect structure which
1470
+ * points to the last element which should not be
1471
+ * removed by truncate. But this is end of the range
1472
+ * in punch_hole so we need to point to the next element
1464
1473
*/
1465
- if (partial > chain ) {
1474
+ partial2 -> p ++ ;
1475
+ }
1476
+
1477
+ while (partial > chain || partial2 > chain2 ) {
1478
+ int depth = (chain + n - 1 ) - partial ;
1479
+ int depth2 = (chain2 + n2 - 1 ) - partial2 ;
1480
+
1481
+ if (partial > chain && partial2 > chain2 &&
1482
+ partial -> bh -> b_blocknr == partial2 -> bh -> b_blocknr ) {
1483
+ /*
1484
+ * We've converged on the same block. Clear the range,
1485
+ * then we're done.
1486
+ */
1466
1487
ext4_free_branches (handle , inode , partial -> bh ,
1467
- partial -> p + 1 ,
1468
- ( __le32 * ) partial -> bh -> b_data + addr_per_block ,
1469
- (chain + n - 1 ) - partial );
1488
+ partial -> p + 1 ,
1489
+ partial2 -> p ,
1490
+ (chain + n - 1 ) - partial );
1470
1491
BUFFER_TRACE (partial -> bh , "call brelse" );
1471
1492
brelse (partial -> bh );
1472
- partial -- ;
1493
+ BUFFER_TRACE (partial2 -> bh , "call brelse" );
1494
+ brelse (partial2 -> bh );
1495
+ return 0 ;
1473
1496
}
1497
+
1474
1498
/*
1475
- * Clear the ends of indirect blocks on the shared branch
1476
- * at the end of the range
1499
+ * The start and end partial branches may not be at the same
1500
+ * level even though the punch happened within one level. So, we
1501
+ * give them a chance to arrive at the same level, then walk
1502
+ * them in step with each other until we converge on the same
1503
+ * block.
1477
1504
*/
1478
- if (partial2 > chain2 ) {
1505
+ if (partial > chain && depth <= depth2 ) {
1506
+ ext4_free_branches (handle , inode , partial -> bh ,
1507
+ partial -> p + 1 ,
1508
+ (__le32 * )partial -> bh -> b_data + addr_per_block ,
1509
+ (chain + n - 1 ) - partial );
1510
+ BUFFER_TRACE (partial -> bh , "call brelse" );
1511
+ brelse (partial -> bh );
1512
+ partial -- ;
1513
+ }
1514
+ if (partial2 > chain2 && depth2 <= depth ) {
1479
1515
ext4_free_branches (handle , inode , partial2 -> bh ,
1480
1516
(__le32 * )partial2 -> bh -> b_data ,
1481
1517
partial2 -> p ,
1482
- (chain2 + n - 1 ) - partial2 );
1518
+ (chain2 + n2 - 1 ) - partial2 );
1483
1519
BUFFER_TRACE (partial2 -> bh , "call brelse" );
1484
1520
brelse (partial2 -> bh );
1485
1521
partial2 -- ;
1486
1522
}
1487
1523
}
1524
+ return 0 ;
1488
1525
1489
1526
do_indirects :
1490
1527
/* Kill the remaining (whole) subtrees */
0 commit comments