@@ -1401,10 +1401,7 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
14011401 * to free. Everything was covered by the start
14021402 * of the range.
14031403 */
1404- return 0 ;
1405- } else {
1406- /* Shared branch grows from an indirect block */
1407- partial2 -- ;
1404+ goto do_indirects ;
14081405 }
14091406 } else {
14101407 /*
@@ -1435,56 +1432,96 @@ int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
14351432 /* Punch happened within the same level (n == n2) */
14361433 partial = ext4_find_shared (inode , n , offsets , chain , & nr );
14371434 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" );
14501459 ext4_free_branches (handle , inode , partial -> bh ,
1451- partial -> p + 1 ,
1452- partial2 -> p ,
1460+ partial -> p ,
1461+ partial -> p + 1 ,
14531462 (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 );
14581463 }
1459- return 0 ;
14601464 }
1465+ }
1466+
1467+ if (!nr2 ) {
14611468 /*
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
14641473 */
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+ */
14661487 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 );
14701491 BUFFER_TRACE (partial -> bh , "call brelse" );
14711492 brelse (partial -> bh );
1472- partial -- ;
1493+ BUFFER_TRACE (partial2 -> bh , "call brelse" );
1494+ brelse (partial2 -> bh );
1495+ return 0 ;
14731496 }
1497+
14741498 /*
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.
14771504 */
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 ) {
14791515 ext4_free_branches (handle , inode , partial2 -> bh ,
14801516 (__le32 * )partial2 -> bh -> b_data ,
14811517 partial2 -> p ,
1482- (chain2 + n - 1 ) - partial2 );
1518+ (chain2 + n2 - 1 ) - partial2 );
14831519 BUFFER_TRACE (partial2 -> bh , "call brelse" );
14841520 brelse (partial2 -> bh );
14851521 partial2 -- ;
14861522 }
14871523 }
1524+ return 0 ;
14881525
14891526do_indirects :
14901527 /* Kill the remaining (whole) subtrees */
0 commit comments