aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2013-04-03 12:45:17 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-04-03 12:45:17 -0400
commit26a4c0c6ccecf6814cf44f951c97222bd795bc1a (patch)
tree9b3a2fa02c61464ead1456499cad46e41644878b /fs
parent781f143ea0fd7981ebe2e8cd96114997c8cf6c07 (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.h7
-rw-r--r--fs/ext4/extents.c185
-rw-r--r--fs/ext4/indirect.c158
-rw-r--r--fs/ext4/inode.c180
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,
2110extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock); 2110extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock);
2111extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk); 2111extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks, int chunk);
2112extern void ext4_ind_truncate(struct inode *inode); 2112extern void ext4_ind_truncate(struct inode *inode);
2113extern int ext4_ind_punch_hole(struct file *file, loff_t offset, loff_t length); 2113extern 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 */
2116extern long ext4_ioctl(struct file *, unsigned int, unsigned long); 2117extern 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,
2575extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, 2576extern 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);
2577extern void ext4_ext_truncate(struct inode *); 2578extern void ext4_ext_truncate(struct inode *);
2578extern int ext4_ext_punch_hole(struct file *file, loff_t offset, 2579extern int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
2579 loff_t length); 2580 ext4_lblk_t end);
2580extern void ext4_ext_init(struct super_block *); 2581extern void ext4_ext_init(struct super_block *);
2581extern void ext4_ext_release(struct super_block *); 2582extern void ext4_ext_release(struct super_block *);
2582extern long ext4_fallocate(struct file *file, int mode, loff_t offset, 2583extern 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
2602static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, 2602int 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 */
4638int 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
4796out:
4797 inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
4798 ext4_mark_inode_dirty(handle, inode);
4799 ext4_journal_stop(handle);
4800out_dio:
4801 ext4_inode_resume_unlocked_dio(inode);
4802out_mutex:
4803 mutex_unlock(&inode->i_mutex);
4804 return err;
4805}
4806
4807int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, 4626int 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
1437static int ext4_free_hole_blocks(handle_t *handle, struct inode *inode, 1437int 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
1472int 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
1616out:
1617 inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
1618 ext4_mark_inode_dirty(handle, inode);
1619 ext4_journal_stop(handle);
1620
1621out_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)
3566int ext4_punch_hole(struct file *file, loff_t offset, loff_t length) 3566int 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);
3746out_stop:
3747 ext4_journal_stop(handle);
3748out_dio:
3749 ext4_inode_resume_unlocked_dio(inode);
3750out_mutex:
3751 mutex_unlock(&inode->i_mutex);
3752 return ret;
3583} 3753}
3584 3754
3585/* 3755/*