diff options
Diffstat (limited to 'fs/ext4/indirect.c')
| -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 6b9878a24182..45fe924f82bc 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c | |||
| @@ -1401,10 +1401,7 @@ end_range: | |||
| 1401 | * to free. Everything was covered by the start | 1401 | * to free. Everything was covered by the start |
| 1402 | * of the range. | 1402 | * of the range. |
| 1403 | */ | 1403 | */ |
| 1404 | return 0; | 1404 | goto do_indirects; |
| 1405 | } else { | ||
| 1406 | /* Shared branch grows from an indirect block */ | ||
| 1407 | partial2--; | ||
| 1408 | } | 1405 | } |
| 1409 | } else { | 1406 | } else { |
| 1410 | /* | 1407 | /* |
| @@ -1435,56 +1432,96 @@ end_range: | |||
| 1435 | /* Punch happened within the same level (n == n2) */ | 1432 | /* Punch happened within the same level (n == n2) */ |
| 1436 | partial = ext4_find_shared(inode, n, offsets, chain, &nr); | 1433 | partial = ext4_find_shared(inode, n, offsets, chain, &nr); |
| 1437 | partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2); | 1434 | partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2); |
| 1438 | /* | 1435 | |
| 1439 | * ext4_find_shared returns Indirect structure which | 1436 | /* Free top, but only if partial2 isn't its subtree. */ |
| 1440 | * points to the last element which should not be | 1437 | if (nr) { |
| 1441 | * removed by truncate. But this is end of the range | 1438 | int level = min(partial - chain, partial2 - chain2); |
| 1442 | * in punch_hole so we need to point to the next element | 1439 | int i; |
| 1443 | */ | 1440 | int subtree = 1; |
| 1444 | partial2->p++; | 1441 | |
| 1445 | while ((partial > chain) || (partial2 > chain2)) { | 1442 | for (i = 0; i <= level; i++) { |
| 1446 | /* We're at the same block, so we're almost finished */ | 1443 | if (offsets[i] != offsets2[i]) { |
| 1447 | if ((partial->bh && partial2->bh) && | 1444 | subtree = 0; |
| 1448 | (partial->bh->b_blocknr == partial2->bh->b_blocknr)) { | 1445 | break; |
| 1449 | if ((partial > chain) && (partial2 > chain2)) { | 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 | ext4_free_branches(handle, inode, partial->bh, | 1459 | ext4_free_branches(handle, inode, partial->bh, |
| 1451 | partial->p + 1, | 1460 | partial->p, |
| 1452 | partial2->p, | 1461 | partial->p+1, |
| 1453 | (chain+n-1) - partial); | 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 | 1469 | * ext4_find_shared returns Indirect structure which |
| 1463 | * at the start of the range | 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 | ext4_free_branches(handle, inode, partial->bh, | 1487 | ext4_free_branches(handle, inode, partial->bh, |
| 1467 | partial->p + 1, | 1488 | partial->p + 1, |
| 1468 | (__le32 *)partial->bh->b_data+addr_per_block, | 1489 | partial2->p, |
| 1469 | (chain+n-1) - partial); | 1490 | (chain+n-1) - partial); |
| 1470 | BUFFER_TRACE(partial->bh, "call brelse"); | 1491 | BUFFER_TRACE(partial->bh, "call brelse"); |
| 1471 | brelse(partial->bh); | 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 | 1499 | * The start and end partial branches may not be at the same |
| 1476 | * at the end of the range | 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 | ext4_free_branches(handle, inode, partial2->bh, | 1515 | ext4_free_branches(handle, inode, partial2->bh, |
| 1480 | (__le32 *)partial2->bh->b_data, | 1516 | (__le32 *)partial2->bh->b_data, |
| 1481 | partial2->p, | 1517 | partial2->p, |
| 1482 | (chain2+n-1) - partial2); | 1518 | (chain2+n2-1) - partial2); |
| 1483 | BUFFER_TRACE(partial2->bh, "call brelse"); | 1519 | BUFFER_TRACE(partial2->bh, "call brelse"); |
| 1484 | brelse(partial2->bh); | 1520 | brelse(partial2->bh); |
| 1485 | partial2--; | 1521 | partial2--; |
| 1486 | } | 1522 | } |
| 1487 | } | 1523 | } |
| 1524 | return 0; | ||
| 1488 | 1525 | ||
| 1489 | do_indirects: | 1526 | do_indirects: |
| 1490 | /* Kill the remaining (whole) subtrees */ | 1527 | /* Kill the remaining (whole) subtrees */ |
