diff options
author | Christoph Hellwig <hch@infradead.org> | 2011-12-18 15:00:04 -0500 |
---|---|---|
committer | Ben Myers <bpm@sgi.com> | 2012-01-13 13:11:45 -0500 |
commit | 673e8e597c06eb81954bf21a10f5cce74a1de8f1 (patch) | |
tree | a6d47b0c44dfe24119de8d4c944f7c5c6e2c30dc /fs/xfs/xfs_iops.c | |
parent | 099469502f62fbe0d7e4f0b83a2f22538367f734 (diff) |
xfs: remove xfs_itruncate_data
This wrapper isn't overly useful, not to say rather confusing.
Around the call to xfs_itruncate_extents it does:
- add tracing
- add a few asserts in debug builds
- conditionally update the inode size in two places
- log the inode
Both the tracing and the inode logging can be moved to xfs_itruncate_extents
as they are useful for the attribute fork as well - in fact the attr code
already does an equivalent xfs_trans_log_inode call just after calling
xfs_itruncate_extents. The conditional size updates are a mess, and there
was no reason to do them in two places anyway, as the first one was
conditional on the inode having extents - but without extents we
xfs_itruncate_extents would be a no-op and the placement wouldn't matter
anyway. Instead move the size assignments and the asserts that make sense
to the callers that want it.
As a side effect of this clean up xfs_setattr_size by introducing variables
for the old and new inode size, and moving the size updates into a common
place.
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ben Myers <bpm@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_iops.c')
-rw-r--r-- | fs/xfs/xfs_iops.c | 47 |
1 files changed, 30 insertions, 17 deletions
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index f9babd179223..f02eaa298d3c 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c | |||
@@ -750,6 +750,7 @@ xfs_setattr_size( | |||
750 | struct xfs_mount *mp = ip->i_mount; | 750 | struct xfs_mount *mp = ip->i_mount; |
751 | struct inode *inode = VFS_I(ip); | 751 | struct inode *inode = VFS_I(ip); |
752 | int mask = iattr->ia_valid; | 752 | int mask = iattr->ia_valid; |
753 | xfs_off_t oldsize, newsize; | ||
753 | struct xfs_trans *tp; | 754 | struct xfs_trans *tp; |
754 | int error; | 755 | int error; |
755 | uint lock_flags; | 756 | uint lock_flags; |
@@ -777,11 +778,13 @@ xfs_setattr_size( | |||
777 | lock_flags |= XFS_IOLOCK_EXCL; | 778 | lock_flags |= XFS_IOLOCK_EXCL; |
778 | xfs_ilock(ip, lock_flags); | 779 | xfs_ilock(ip, lock_flags); |
779 | 780 | ||
781 | oldsize = ip->i_size; | ||
782 | newsize = iattr->ia_size; | ||
783 | |||
780 | /* | 784 | /* |
781 | * Short circuit the truncate case for zero length files. | 785 | * Short circuit the truncate case for zero length files. |
782 | */ | 786 | */ |
783 | if (iattr->ia_size == 0 && | 787 | if (newsize == 0 && oldsize == 0 && ip->i_d.di_nextents == 0) { |
784 | ip->i_size == 0 && ip->i_d.di_nextents == 0) { | ||
785 | if (!(mask & (ATTR_CTIME|ATTR_MTIME))) | 788 | if (!(mask & (ATTR_CTIME|ATTR_MTIME))) |
786 | goto out_unlock; | 789 | goto out_unlock; |
787 | 790 | ||
@@ -807,14 +810,14 @@ xfs_setattr_size( | |||
807 | * the inode to the transaction, because the inode cannot be unlocked | 810 | * the inode to the transaction, because the inode cannot be unlocked |
808 | * once it is a part of the transaction. | 811 | * once it is a part of the transaction. |
809 | */ | 812 | */ |
810 | if (iattr->ia_size > ip->i_size) { | 813 | if (newsize > oldsize) { |
811 | /* | 814 | /* |
812 | * Do the first part of growing a file: zero any data in the | 815 | * Do the first part of growing a file: zero any data in the |
813 | * last block that is beyond the old EOF. We need to do this | 816 | * last block that is beyond the old EOF. We need to do this |
814 | * before the inode is joined to the transaction to modify | 817 | * before the inode is joined to the transaction to modify |
815 | * i_size. | 818 | * i_size. |
816 | */ | 819 | */ |
817 | error = xfs_zero_eof(ip, iattr->ia_size, ip->i_size); | 820 | error = xfs_zero_eof(ip, newsize, oldsize); |
818 | if (error) | 821 | if (error) |
819 | goto out_unlock; | 822 | goto out_unlock; |
820 | } | 823 | } |
@@ -833,8 +836,8 @@ xfs_setattr_size( | |||
833 | * here and prevents waiting for other data not within the range we | 836 | * here and prevents waiting for other data not within the range we |
834 | * care about here. | 837 | * care about here. |
835 | */ | 838 | */ |
836 | if (ip->i_size != ip->i_d.di_size && iattr->ia_size > ip->i_d.di_size) { | 839 | if (oldsize != ip->i_d.di_size && newsize > ip->i_d.di_size) { |
837 | error = xfs_flush_pages(ip, ip->i_d.di_size, iattr->ia_size, 0, | 840 | error = xfs_flush_pages(ip, ip->i_d.di_size, newsize, 0, |
838 | FI_NONE); | 841 | FI_NONE); |
839 | if (error) | 842 | if (error) |
840 | goto out_unlock; | 843 | goto out_unlock; |
@@ -845,8 +848,7 @@ xfs_setattr_size( | |||
845 | */ | 848 | */ |
846 | inode_dio_wait(inode); | 849 | inode_dio_wait(inode); |
847 | 850 | ||
848 | error = -block_truncate_page(inode->i_mapping, iattr->ia_size, | 851 | error = -block_truncate_page(inode->i_mapping, newsize, xfs_get_blocks); |
849 | xfs_get_blocks); | ||
850 | if (error) | 852 | if (error) |
851 | goto out_unlock; | 853 | goto out_unlock; |
852 | 854 | ||
@@ -857,7 +859,7 @@ xfs_setattr_size( | |||
857 | if (error) | 859 | if (error) |
858 | goto out_trans_cancel; | 860 | goto out_trans_cancel; |
859 | 861 | ||
860 | truncate_setsize(inode, iattr->ia_size); | 862 | truncate_setsize(inode, newsize); |
861 | 863 | ||
862 | commit_flags = XFS_TRANS_RELEASE_LOG_RES; | 864 | commit_flags = XFS_TRANS_RELEASE_LOG_RES; |
863 | lock_flags |= XFS_ILOCK_EXCL; | 865 | lock_flags |= XFS_ILOCK_EXCL; |
@@ -876,19 +878,30 @@ xfs_setattr_size( | |||
876 | * these flags set. For all other operations the VFS set these flags | 878 | * these flags set. For all other operations the VFS set these flags |
877 | * explicitly if it wants a timestamp update. | 879 | * explicitly if it wants a timestamp update. |
878 | */ | 880 | */ |
879 | if (iattr->ia_size != ip->i_size && | 881 | if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME)))) { |
880 | (!(mask & (ATTR_CTIME | ATTR_MTIME)))) { | ||
881 | iattr->ia_ctime = iattr->ia_mtime = | 882 | iattr->ia_ctime = iattr->ia_mtime = |
882 | current_fs_time(inode->i_sb); | 883 | current_fs_time(inode->i_sb); |
883 | mask |= ATTR_CTIME | ATTR_MTIME; | 884 | mask |= ATTR_CTIME | ATTR_MTIME; |
884 | } | 885 | } |
885 | 886 | ||
886 | if (iattr->ia_size > ip->i_size) { | 887 | /* |
887 | ip->i_d.di_size = iattr->ia_size; | 888 | * The first thing we do is set the size to new_size permanently on |
888 | ip->i_size = iattr->ia_size; | 889 | * disk. This way we don't have to worry about anyone ever being able |
889 | } else if (iattr->ia_size <= ip->i_size || | 890 | * to look at the data being freed even in the face of a crash. |
890 | (iattr->ia_size == 0 && ip->i_d.di_nextents)) { | 891 | * What we're getting around here is the case where we free a block, it |
891 | error = xfs_itruncate_data(&tp, ip, iattr->ia_size); | 892 | * is allocated to another file, it is written to, and then we crash. |
893 | * If the new data gets written to the file but the log buffers | ||
894 | * containing the free and reallocation don't, then we'd end up with | ||
895 | * garbage in the blocks being freed. As long as we make the new size | ||
896 | * permanent before actually freeing any blocks it doesn't matter if | ||
897 | * they get written to. | ||
898 | */ | ||
899 | ip->i_d.di_size = newsize; | ||
900 | ip->i_size = newsize; | ||
901 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | ||
902 | |||
903 | if (newsize <= oldsize) { | ||
904 | error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, newsize); | ||
892 | if (error) | 905 | if (error) |
893 | goto out_trans_abort; | 906 | goto out_trans_abort; |
894 | 907 | ||