diff options
author | Theodore Ts'o <tytso@mit.edu> | 2013-04-03 12:45:17 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-04-03 12:45:17 -0400 |
commit | 26a4c0c6ccecf6814cf44f951c97222bd795bc1a (patch) | |
tree | 9b3a2fa02c61464ead1456499cad46e41644878b /fs | |
parent | 781f143ea0fd7981ebe2e8cd96114997c8cf6c07 (diff) |
ext4: refactor punch hole code
Move common code in ext4_ind_punch_hole() and ext4_ext_punch_hole()
into ext4_punch_hole(). This saves over 150 lines of code.
This also fixes a potential bug when the punch_hole() code is racing
against indirect-to-extents or extents-to-indirect migation. We are
currently using i_mutex to protect against changes to the inode flag;
specifically, the append-only, immutable, and extents inode flags. So
we need to take i_mutex before deciding whether to use the
extents-specific or indirect-specific punch_hole code.
Also, there was a missing call to ext4_inode_block_unlocked_dio() in
the indirect punch codepath. This was added in commit 02d262dffcf4c
to block DIO readers racing against the punch operation in the
codepath for extent-mapped inodes, but it was missing for
indirect-block mapped inodes. One of the advantages of refactoring
the code is that it makes such oversights much less likely.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/ext4.h | 7 | ||||
-rw-r--r-- | fs/ext4/extents.c | 185 | ||||
-rw-r--r-- | fs/ext4/indirect.c | 158 | ||||
-rw-r--r-- | fs/ext4/inode.c | 180 |
4 files changed, 183 insertions, 347 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index f91e11bd9753..0649253804c4 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -2110,7 +2110,8 @@ extern ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, | |||
2110 | extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock); | 2110 | extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock); |
2111 | extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk); | 2111 | extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk); |
2112 | extern void ext4_ind_truncate(struct inode *inode); | 2112 | extern void ext4_ind_truncate(struct inode *inode); |
2113 | extern int ext4_ind_punch_hole(struct file *file, loff_t offset, loff_t length); | 2113 | extern int ext4_free_hole_blocks(handle_t *handle, struct inode *inode, |
2114 | ext4_lblk_t first, ext4_lblk_t stop); | ||
2114 | 2115 | ||
2115 | /* ioctl.c */ | 2116 | /* ioctl.c */ |
2116 | extern long ext4_ioctl(struct file *, unsigned int, unsigned long); | 2117 | extern long ext4_ioctl(struct file *, unsigned int, unsigned long); |
@@ -2575,8 +2576,8 @@ extern int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks, | |||
2575 | extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, | 2576 | extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, |
2576 | struct ext4_map_blocks *map, int flags); | 2577 | struct ext4_map_blocks *map, int flags); |
2577 | extern void ext4_ext_truncate(struct inode *); | 2578 | extern void ext4_ext_truncate(struct inode *); |
2578 | extern int ext4_ext_punch_hole(struct file *file, loff_t offset, | 2579 | extern int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, |
2579 | loff_t length); | 2580 | ext4_lblk_t end); |
2580 | extern void ext4_ext_init(struct super_block *); | 2581 | extern void ext4_ext_init(struct super_block *); |
2581 | extern void ext4_ext_release(struct super_block *); | 2582 | extern void ext4_ext_release(struct super_block *); |
2582 | extern long ext4_fallocate(struct file *file, int mode, loff_t offset, | 2583 | extern long ext4_fallocate(struct file *file, int mode, loff_t offset, |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 9c6d06dcef8b..d58365e40df7 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -2599,8 +2599,8 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path) | |||
2599 | return 1; | 2599 | return 1; |
2600 | } | 2600 | } |
2601 | 2601 | ||
2602 | static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, | 2602 | int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, |
2603 | ext4_lblk_t end) | 2603 | ext4_lblk_t end) |
2604 | { | 2604 | { |
2605 | struct super_block *sb = inode->i_sb; | 2605 | struct super_block *sb = inode->i_sb; |
2606 | int depth = ext_depth(inode); | 2606 | int depth = ext_depth(inode); |
@@ -4623,187 +4623,6 @@ static int ext4_xattr_fiemap(struct inode *inode, | |||
4623 | return (error < 0 ? error : 0); | 4623 | return (error < 0 ? error : 0); |
4624 | } | 4624 | } |
4625 | 4625 | ||
4626 | /* | ||
4627 | * ext4_ext_punch_hole | ||
4628 | * | ||
4629 | * Punches a hole of "length" bytes in a file starting | ||
4630 | * at byte "offset" | ||
4631 | * | ||
4632 | * @inode: The inode of the file to punch a hole in | ||
4633 | * @offset: The starting byte offset of the hole | ||
4634 | * @length: The length of the hole | ||
4635 | * | ||
4636 | * Returns the number of blocks removed or negative on err | ||
4637 | */ | ||
4638 | int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length) | ||
4639 | { | ||
4640 | struct inode *inode = file_inode(file); | ||
4641 | struct super_block *sb = inode->i_sb; | ||
4642 | ext4_lblk_t first_block, stop_block; | ||
4643 | struct address_space *mapping = inode->i_mapping; | ||
4644 | handle_t *handle; | ||
4645 | loff_t first_page, last_page, page_len; | ||
4646 | loff_t first_page_offset, last_page_offset; | ||
4647 | int credits, err = 0; | ||
4648 | |||
4649 | /* | ||
4650 | * Write out all dirty pages to avoid race conditions | ||
4651 | * Then release them. | ||
4652 | */ | ||
4653 | if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { | ||
4654 | err = filemap_write_and_wait_range(mapping, | ||
4655 | offset, offset + length - 1); | ||
4656 | |||
4657 | if (err) | ||
4658 | return err; | ||
4659 | } | ||
4660 | |||
4661 | mutex_lock(&inode->i_mutex); | ||
4662 | /* It's not possible punch hole on append only file */ | ||
4663 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) { | ||
4664 | err = -EPERM; | ||
4665 | goto out_mutex; | ||
4666 | } | ||
4667 | if (IS_SWAPFILE(inode)) { | ||
4668 | err = -ETXTBSY; | ||
4669 | goto out_mutex; | ||
4670 | } | ||
4671 | |||
4672 | /* No need to punch hole beyond i_size */ | ||
4673 | if (offset >= inode->i_size) | ||
4674 | goto out_mutex; | ||
4675 | |||
4676 | /* | ||
4677 | * If the hole extends beyond i_size, set the hole | ||
4678 | * to end after the page that contains i_size | ||
4679 | */ | ||
4680 | if (offset + length > inode->i_size) { | ||
4681 | length = inode->i_size + | ||
4682 | PAGE_CACHE_SIZE - (inode->i_size & (PAGE_CACHE_SIZE - 1)) - | ||
4683 | offset; | ||
4684 | } | ||
4685 | |||
4686 | first_page = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
4687 | last_page = (offset + length) >> PAGE_CACHE_SHIFT; | ||
4688 | |||
4689 | first_page_offset = first_page << PAGE_CACHE_SHIFT; | ||
4690 | last_page_offset = last_page << PAGE_CACHE_SHIFT; | ||
4691 | |||
4692 | /* Now release the pages */ | ||
4693 | if (last_page_offset > first_page_offset) { | ||
4694 | truncate_pagecache_range(inode, first_page_offset, | ||
4695 | last_page_offset - 1); | ||
4696 | } | ||
4697 | |||
4698 | /* Wait all existing dio workers, newcomers will block on i_mutex */ | ||
4699 | ext4_inode_block_unlocked_dio(inode); | ||
4700 | err = ext4_flush_unwritten_io(inode); | ||
4701 | if (err) | ||
4702 | goto out_dio; | ||
4703 | inode_dio_wait(inode); | ||
4704 | |||
4705 | credits = ext4_writepage_trans_blocks(inode); | ||
4706 | handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits); | ||
4707 | if (IS_ERR(handle)) { | ||
4708 | err = PTR_ERR(handle); | ||
4709 | goto out_dio; | ||
4710 | } | ||
4711 | |||
4712 | |||
4713 | /* | ||
4714 | * Now we need to zero out the non-page-aligned data in the | ||
4715 | * pages at the start and tail of the hole, and unmap the buffer | ||
4716 | * heads for the block aligned regions of the page that were | ||
4717 | * completely zeroed. | ||
4718 | */ | ||
4719 | if (first_page > last_page) { | ||
4720 | /* | ||
4721 | * If the file space being truncated is contained within a page | ||
4722 | * just zero out and unmap the middle of that page | ||
4723 | */ | ||
4724 | err = ext4_discard_partial_page_buffers(handle, | ||
4725 | mapping, offset, length, 0); | ||
4726 | |||
4727 | if (err) | ||
4728 | goto out; | ||
4729 | } else { | ||
4730 | /* | ||
4731 | * zero out and unmap the partial page that contains | ||
4732 | * the start of the hole | ||
4733 | */ | ||
4734 | page_len = first_page_offset - offset; | ||
4735 | if (page_len > 0) { | ||
4736 | err = ext4_discard_partial_page_buffers(handle, mapping, | ||
4737 | offset, page_len, 0); | ||
4738 | if (err) | ||
4739 | goto out; | ||
4740 | } | ||
4741 | |||
4742 | /* | ||
4743 | * zero out and unmap the partial page that contains | ||
4744 | * the end of the hole | ||
4745 | */ | ||
4746 | page_len = offset + length - last_page_offset; | ||
4747 | if (page_len > 0) { | ||
4748 | err = ext4_discard_partial_page_buffers(handle, mapping, | ||
4749 | last_page_offset, page_len, 0); | ||
4750 | if (err) | ||
4751 | goto out; | ||
4752 | } | ||
4753 | } | ||
4754 | |||
4755 | /* | ||
4756 | * If i_size is contained in the last page, we need to | ||
4757 | * unmap and zero the partial page after i_size | ||
4758 | */ | ||
4759 | if (inode->i_size >> PAGE_CACHE_SHIFT == last_page && | ||
4760 | inode->i_size % PAGE_CACHE_SIZE != 0) { | ||
4761 | |||
4762 | page_len = PAGE_CACHE_SIZE - | ||
4763 | (inode->i_size & (PAGE_CACHE_SIZE - 1)); | ||
4764 | |||
4765 | if (page_len > 0) { | ||
4766 | err = ext4_discard_partial_page_buffers(handle, | ||
4767 | mapping, inode->i_size, page_len, 0); | ||
4768 | |||
4769 | if (err) | ||
4770 | goto out; | ||
4771 | } | ||
4772 | } | ||
4773 | |||
4774 | first_block = (offset + sb->s_blocksize - 1) >> | ||
4775 | EXT4_BLOCK_SIZE_BITS(sb); | ||
4776 | stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb); | ||
4777 | |||
4778 | /* If there are no blocks to remove, return now */ | ||
4779 | if (first_block >= stop_block) | ||
4780 | goto out; | ||
4781 | |||
4782 | down_write(&EXT4_I(inode)->i_data_sem); | ||
4783 | ext4_discard_preallocations(inode); | ||
4784 | |||
4785 | err = ext4_es_remove_extent(inode, first_block, | ||
4786 | stop_block - first_block); | ||
4787 | err = ext4_ext_remove_space(inode, first_block, stop_block - 1); | ||
4788 | |||
4789 | ext4_discard_preallocations(inode); | ||
4790 | |||
4791 | if (IS_SYNC(inode)) | ||
4792 | ext4_handle_sync(handle); | ||
4793 | |||
4794 | up_write(&EXT4_I(inode)->i_data_sem); | ||
4795 | |||
4796 | out: | ||
4797 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); | ||
4798 | ext4_mark_inode_dirty(handle, inode); | ||
4799 | ext4_journal_stop(handle); | ||
4800 | out_dio: | ||
4801 | ext4_inode_resume_unlocked_dio(inode); | ||
4802 | out_mutex: | ||
4803 | mutex_unlock(&inode->i_mutex); | ||
4804 | return err; | ||
4805 | } | ||
4806 | |||
4807 | int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 4626 | int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
4808 | __u64 start, __u64 len) | 4627 | __u64 start, __u64 len) |
4809 | { | 4628 | { |
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index c0f9e4699f0b..d8846779f4ea 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c | |||
@@ -1434,8 +1434,8 @@ err: | |||
1434 | return ret; | 1434 | return ret; |
1435 | } | 1435 | } |
1436 | 1436 | ||
1437 | static int ext4_free_hole_blocks(handle_t *handle, struct inode *inode, | 1437 | int ext4_free_hole_blocks(handle_t *handle, struct inode *inode, |
1438 | ext4_lblk_t first, ext4_lblk_t stop) | 1438 | ext4_lblk_t first, ext4_lblk_t stop) |
1439 | { | 1439 | { |
1440 | int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb); | 1440 | int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb); |
1441 | int level, ret = 0; | 1441 | int level, ret = 0; |
@@ -1469,157 +1469,3 @@ err: | |||
1469 | return ret; | 1469 | return ret; |
1470 | } | 1470 | } |
1471 | 1471 | ||
1472 | int ext4_ind_punch_hole(struct file *file, loff_t offset, loff_t length) | ||
1473 | { | ||
1474 | struct inode *inode = file_inode(file); | ||
1475 | struct super_block *sb = inode->i_sb; | ||
1476 | ext4_lblk_t first_block, stop_block; | ||
1477 | struct address_space *mapping = inode->i_mapping; | ||
1478 | handle_t *handle = NULL; | ||
1479 | loff_t first_page, last_page, page_len; | ||
1480 | loff_t first_page_offset, last_page_offset; | ||
1481 | int err = 0; | ||
1482 | |||
1483 | /* | ||
1484 | * Write out all dirty pages to avoid race conditions | ||
1485 | * Then release them. | ||
1486 | */ | ||
1487 | if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { | ||
1488 | err = filemap_write_and_wait_range(mapping, | ||
1489 | offset, offset + length - 1); | ||
1490 | if (err) | ||
1491 | return err; | ||
1492 | } | ||
1493 | |||
1494 | mutex_lock(&inode->i_mutex); | ||
1495 | /* It's not possible punch hole on append only file */ | ||
1496 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) { | ||
1497 | err = -EPERM; | ||
1498 | goto out_mutex; | ||
1499 | } | ||
1500 | if (IS_SWAPFILE(inode)) { | ||
1501 | err = -ETXTBSY; | ||
1502 | goto out_mutex; | ||
1503 | } | ||
1504 | |||
1505 | /* No need to punch hole beyond i_size */ | ||
1506 | if (offset >= inode->i_size) | ||
1507 | goto out_mutex; | ||
1508 | |||
1509 | /* | ||
1510 | * If the hole extents beyond i_size, set the hole | ||
1511 | * to end after the page that contains i_size | ||
1512 | */ | ||
1513 | if (offset + length > inode->i_size) { | ||
1514 | length = inode->i_size + | ||
1515 | PAGE_CACHE_SIZE - (inode->i_size & (PAGE_CACHE_SIZE - 1)) - | ||
1516 | offset; | ||
1517 | } | ||
1518 | |||
1519 | first_page = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
1520 | last_page = (offset + length) >> PAGE_CACHE_SHIFT; | ||
1521 | |||
1522 | first_page_offset = first_page << PAGE_CACHE_SHIFT; | ||
1523 | last_page_offset = last_page << PAGE_CACHE_SHIFT; | ||
1524 | |||
1525 | /* Now release the pages */ | ||
1526 | if (last_page_offset > first_page_offset) { | ||
1527 | truncate_pagecache_range(inode, first_page_offset, | ||
1528 | last_page_offset - 1); | ||
1529 | } | ||
1530 | |||
1531 | /* Wait all existing dio works, newcomers will block on i_mutex */ | ||
1532 | inode_dio_wait(inode); | ||
1533 | |||
1534 | handle = start_transaction(inode); | ||
1535 | if (IS_ERR(handle)) | ||
1536 | goto out_mutex; | ||
1537 | |||
1538 | /* | ||
1539 | * Now we need to zero out the non-page-aligned data in the | ||
1540 | * pages at the start and tail of the hole, and unmap the buffer | ||
1541 | * heads for the block aligned regions of the page that were | ||
1542 | * completely zerod. | ||
1543 | */ | ||
1544 | if (first_page > last_page) { | ||
1545 | /* | ||
1546 | * If the file space being truncated is contained within a page | ||
1547 | * just zero out and unmap the middle of that page | ||
1548 | */ | ||
1549 | err = ext4_discard_partial_page_buffers(handle, | ||
1550 | mapping, offset, length, 0); | ||
1551 | if (err) | ||
1552 | goto out; | ||
1553 | } else { | ||
1554 | /* | ||
1555 | * Zero out and unmap the paritial page that contains | ||
1556 | * the start of the hole | ||
1557 | */ | ||
1558 | page_len = first_page_offset - offset; | ||
1559 | if (page_len > 0) { | ||
1560 | err = ext4_discard_partial_page_buffers(handle, mapping, | ||
1561 | offset, page_len, 0); | ||
1562 | if (err) | ||
1563 | goto out; | ||
1564 | } | ||
1565 | |||
1566 | /* | ||
1567 | * Zero out and unmap the partial page that contains | ||
1568 | * the end of the hole | ||
1569 | */ | ||
1570 | page_len = offset + length - last_page_offset; | ||
1571 | if (page_len > 0) { | ||
1572 | err = ext4_discard_partial_page_buffers(handle, mapping, | ||
1573 | last_page_offset, page_len, 0); | ||
1574 | if (err) | ||
1575 | goto out; | ||
1576 | } | ||
1577 | } | ||
1578 | |||
1579 | /* | ||
1580 | * If i_size contained in the last page, we need to | ||
1581 | * unmap and zero the paritial page after i_size | ||
1582 | */ | ||
1583 | if (inode->i_size >> PAGE_CACHE_SHIFT == last_page && | ||
1584 | inode->i_size % PAGE_CACHE_SIZE != 0) { | ||
1585 | page_len = PAGE_CACHE_SIZE - | ||
1586 | (inode->i_size & (PAGE_CACHE_SIZE - 1)); | ||
1587 | if (page_len > 0) { | ||
1588 | err = ext4_discard_partial_page_buffers(handle, | ||
1589 | mapping, inode->i_size, page_len, 0); | ||
1590 | if (err) | ||
1591 | goto out; | ||
1592 | } | ||
1593 | } | ||
1594 | |||
1595 | first_block = (offset + sb->s_blocksize - 1) >> | ||
1596 | EXT4_BLOCK_SIZE_BITS(sb); | ||
1597 | stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb); | ||
1598 | |||
1599 | if (first_block >= stop_block) | ||
1600 | goto out; | ||
1601 | |||
1602 | down_write(&EXT4_I(inode)->i_data_sem); | ||
1603 | ext4_discard_preallocations(inode); | ||
1604 | |||
1605 | err = ext4_es_remove_extent(inode, first_block, | ||
1606 | stop_block - first_block); | ||
1607 | err = ext4_free_hole_blocks(handle, inode, first_block, stop_block); | ||
1608 | |||
1609 | ext4_discard_preallocations(inode); | ||
1610 | |||
1611 | if (IS_SYNC(inode)) | ||
1612 | ext4_handle_sync(handle); | ||
1613 | |||
1614 | up_write(&EXT4_I(inode)->i_data_sem); | ||
1615 | |||
1616 | out: | ||
1617 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); | ||
1618 | ext4_mark_inode_dirty(handle, inode); | ||
1619 | ext4_journal_stop(handle); | ||
1620 | |||
1621 | out_mutex: | ||
1622 | mutex_unlock(&inode->i_mutex); | ||
1623 | |||
1624 | return err; | ||
1625 | } | ||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index a4ffb470fbf3..9bda50aa34e2 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -3566,20 +3566,190 @@ int ext4_can_truncate(struct inode *inode) | |||
3566 | int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) | 3566 | int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) |
3567 | { | 3567 | { |
3568 | struct inode *inode = file_inode(file); | 3568 | struct inode *inode = file_inode(file); |
3569 | struct super_block *sb = inode->i_sb; | ||
3570 | ext4_lblk_t first_block, stop_block; | ||
3571 | struct address_space *mapping = inode->i_mapping; | ||
3572 | loff_t first_page, last_page, page_len; | ||
3573 | loff_t first_page_offset, last_page_offset; | ||
3574 | handle_t *handle; | ||
3575 | unsigned int credits; | ||
3576 | int ret = 0; | ||
3577 | |||
3569 | if (!S_ISREG(inode->i_mode)) | 3578 | if (!S_ISREG(inode->i_mode)) |
3570 | return -EOPNOTSUPP; | 3579 | return -EOPNOTSUPP; |
3571 | 3580 | ||
3572 | if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) | 3581 | if (EXT4_SB(sb)->s_cluster_ratio > 1) { |
3573 | return ext4_ind_punch_hole(file, offset, length); | ||
3574 | |||
3575 | if (EXT4_SB(inode->i_sb)->s_cluster_ratio > 1) { | ||
3576 | /* TODO: Add support for bigalloc file systems */ | 3582 | /* TODO: Add support for bigalloc file systems */ |
3577 | return -EOPNOTSUPP; | 3583 | return -EOPNOTSUPP; |
3578 | } | 3584 | } |
3579 | 3585 | ||
3580 | trace_ext4_punch_hole(inode, offset, length); | 3586 | trace_ext4_punch_hole(inode, offset, length); |
3581 | 3587 | ||
3582 | return ext4_ext_punch_hole(file, offset, length); | 3588 | /* |
3589 | * Write out all dirty pages to avoid race conditions | ||
3590 | * Then release them. | ||
3591 | */ | ||
3592 | if (mapping->nrpages && mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { | ||
3593 | ret = filemap_write_and_wait_range(mapping, offset, | ||
3594 | offset + length - 1); | ||
3595 | if (ret) | ||
3596 | return ret; | ||
3597 | } | ||
3598 | |||
3599 | mutex_lock(&inode->i_mutex); | ||
3600 | /* It's not possible punch hole on append only file */ | ||
3601 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) { | ||
3602 | ret = -EPERM; | ||
3603 | goto out_mutex; | ||
3604 | } | ||
3605 | if (IS_SWAPFILE(inode)) { | ||
3606 | ret = -ETXTBSY; | ||
3607 | goto out_mutex; | ||
3608 | } | ||
3609 | |||
3610 | /* No need to punch hole beyond i_size */ | ||
3611 | if (offset >= inode->i_size) | ||
3612 | goto out_mutex; | ||
3613 | |||
3614 | /* | ||
3615 | * If the hole extends beyond i_size, set the hole | ||
3616 | * to end after the page that contains i_size | ||
3617 | */ | ||
3618 | if (offset + length > inode->i_size) { | ||
3619 | length = inode->i_size + | ||
3620 | PAGE_CACHE_SIZE - (inode->i_size & (PAGE_CACHE_SIZE - 1)) - | ||
3621 | offset; | ||
3622 | } | ||
3623 | |||
3624 | first_page = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
3625 | last_page = (offset + length) >> PAGE_CACHE_SHIFT; | ||
3626 | |||
3627 | first_page_offset = first_page << PAGE_CACHE_SHIFT; | ||
3628 | last_page_offset = last_page << PAGE_CACHE_SHIFT; | ||
3629 | |||
3630 | /* Now release the pages */ | ||
3631 | if (last_page_offset > first_page_offset) { | ||
3632 | truncate_pagecache_range(inode, first_page_offset, | ||
3633 | last_page_offset - 1); | ||
3634 | } | ||
3635 | |||
3636 | /* Wait all existing dio workers, newcomers will block on i_mutex */ | ||
3637 | ext4_inode_block_unlocked_dio(inode); | ||
3638 | ret = ext4_flush_unwritten_io(inode); | ||
3639 | if (ret) | ||
3640 | goto out_dio; | ||
3641 | inode_dio_wait(inode); | ||
3642 | |||
3643 | if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) | ||
3644 | credits = ext4_writepage_trans_blocks(inode); | ||
3645 | else | ||
3646 | credits = ext4_blocks_for_truncate(inode); | ||
3647 | handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits); | ||
3648 | if (IS_ERR(handle)) { | ||
3649 | ret = PTR_ERR(handle); | ||
3650 | ext4_std_error(sb, ret); | ||
3651 | goto out_dio; | ||
3652 | } | ||
3653 | |||
3654 | /* | ||
3655 | * Now we need to zero out the non-page-aligned data in the | ||
3656 | * pages at the start and tail of the hole, and unmap the | ||
3657 | * buffer heads for the block aligned regions of the page that | ||
3658 | * were completely zeroed. | ||
3659 | */ | ||
3660 | if (first_page > last_page) { | ||
3661 | /* | ||
3662 | * If the file space being truncated is contained | ||
3663 | * within a page just zero out and unmap the middle of | ||
3664 | * that page | ||
3665 | */ | ||
3666 | ret = ext4_discard_partial_page_buffers(handle, | ||
3667 | mapping, offset, length, 0); | ||
3668 | |||
3669 | if (ret) | ||
3670 | goto out_stop; | ||
3671 | } else { | ||
3672 | /* | ||
3673 | * zero out and unmap the partial page that contains | ||
3674 | * the start of the hole | ||
3675 | */ | ||
3676 | page_len = first_page_offset - offset; | ||
3677 | if (page_len > 0) { | ||
3678 | ret = ext4_discard_partial_page_buffers(handle, mapping, | ||
3679 | offset, page_len, 0); | ||
3680 | if (ret) | ||
3681 | goto out_stop; | ||
3682 | } | ||
3683 | |||
3684 | /* | ||
3685 | * zero out and unmap the partial page that contains | ||
3686 | * the end of the hole | ||
3687 | */ | ||
3688 | page_len = offset + length - last_page_offset; | ||
3689 | if (page_len > 0) { | ||
3690 | ret = ext4_discard_partial_page_buffers(handle, mapping, | ||
3691 | last_page_offset, page_len, 0); | ||
3692 | if (ret) | ||
3693 | goto out_stop; | ||
3694 | } | ||
3695 | } | ||
3696 | |||
3697 | /* | ||
3698 | * If i_size is contained in the last page, we need to | ||
3699 | * unmap and zero the partial page after i_size | ||
3700 | */ | ||
3701 | if (inode->i_size >> PAGE_CACHE_SHIFT == last_page && | ||
3702 | inode->i_size % PAGE_CACHE_SIZE != 0) { | ||
3703 | page_len = PAGE_CACHE_SIZE - | ||
3704 | (inode->i_size & (PAGE_CACHE_SIZE - 1)); | ||
3705 | |||
3706 | if (page_len > 0) { | ||
3707 | ret = ext4_discard_partial_page_buffers(handle, | ||
3708 | mapping, inode->i_size, page_len, 0); | ||
3709 | |||
3710 | if (ret) | ||
3711 | goto out_stop; | ||
3712 | } | ||
3713 | } | ||
3714 | |||
3715 | first_block = (offset + sb->s_blocksize - 1) >> | ||
3716 | EXT4_BLOCK_SIZE_BITS(sb); | ||
3717 | stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb); | ||
3718 | |||
3719 | /* If there are no blocks to remove, return now */ | ||
3720 | if (first_block >= stop_block) | ||
3721 | goto out_stop; | ||
3722 | |||
3723 | down_write(&EXT4_I(inode)->i_data_sem); | ||
3724 | ext4_discard_preallocations(inode); | ||
3725 | |||
3726 | ret = ext4_es_remove_extent(inode, first_block, | ||
3727 | stop_block - first_block); | ||
3728 | if (ret) { | ||
3729 | up_write(&EXT4_I(inode)->i_data_sem); | ||
3730 | goto out_stop; | ||
3731 | } | ||
3732 | |||
3733 | if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) | ||
3734 | ret = ext4_ext_remove_space(inode, first_block, | ||
3735 | stop_block - 1); | ||
3736 | else | ||
3737 | ret = ext4_free_hole_blocks(handle, inode, first_block, | ||
3738 | stop_block); | ||
3739 | |||
3740 | ext4_discard_preallocations(inode); | ||
3741 | if (IS_SYNC(inode)) | ||
3742 | ext4_handle_sync(handle); | ||
3743 | up_write(&EXT4_I(inode)->i_data_sem); | ||
3744 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); | ||
3745 | ext4_mark_inode_dirty(handle, inode); | ||
3746 | out_stop: | ||
3747 | ext4_journal_stop(handle); | ||
3748 | out_dio: | ||
3749 | ext4_inode_resume_unlocked_dio(inode); | ||
3750 | out_mutex: | ||
3751 | mutex_unlock(&inode->i_mutex); | ||
3752 | return ret; | ||
3583 | } | 3753 | } |
3584 | 3754 | ||
3585 | /* | 3755 | /* |