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