diff options
Diffstat (limited to 'fs/xfs/xfs_file.c')
-rw-r--r-- | fs/xfs/xfs_file.c | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 64b48eade91d..f7abff8c16ca 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -823,7 +823,8 @@ xfs_file_fallocate( | |||
823 | 823 | ||
824 | if (!S_ISREG(inode->i_mode)) | 824 | if (!S_ISREG(inode->i_mode)) |
825 | return -EINVAL; | 825 | return -EINVAL; |
826 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) | 826 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | |
827 | FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE)) | ||
827 | return -EOPNOTSUPP; | 828 | return -EOPNOTSUPP; |
828 | 829 | ||
829 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 830 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
@@ -831,6 +832,20 @@ xfs_file_fallocate( | |||
831 | error = xfs_free_file_space(ip, offset, len); | 832 | error = xfs_free_file_space(ip, offset, len); |
832 | if (error) | 833 | if (error) |
833 | goto out_unlock; | 834 | goto out_unlock; |
835 | } else if (mode & FALLOC_FL_COLLAPSE_RANGE) { | ||
836 | unsigned blksize_mask = (1 << inode->i_blkbits) - 1; | ||
837 | |||
838 | if (offset & blksize_mask || len & blksize_mask) { | ||
839 | error = -EINVAL; | ||
840 | goto out_unlock; | ||
841 | } | ||
842 | |||
843 | ASSERT(offset + len < i_size_read(inode)); | ||
844 | new_size = i_size_read(inode) - len; | ||
845 | |||
846 | error = xfs_collapse_file_space(ip, offset, len); | ||
847 | if (error) | ||
848 | goto out_unlock; | ||
834 | } else { | 849 | } else { |
835 | if (!(mode & FALLOC_FL_KEEP_SIZE) && | 850 | if (!(mode & FALLOC_FL_KEEP_SIZE) && |
836 | offset + len > i_size_read(inode)) { | 851 | offset + len > i_size_read(inode)) { |
@@ -840,8 +855,11 @@ xfs_file_fallocate( | |||
840 | goto out_unlock; | 855 | goto out_unlock; |
841 | } | 856 | } |
842 | 857 | ||
843 | error = xfs_alloc_file_space(ip, offset, len, | 858 | if (mode & FALLOC_FL_ZERO_RANGE) |
844 | XFS_BMAPI_PREALLOC); | 859 | error = xfs_zero_file_space(ip, offset, len); |
860 | else | ||
861 | error = xfs_alloc_file_space(ip, offset, len, | ||
862 | XFS_BMAPI_PREALLOC); | ||
845 | if (error) | 863 | if (error) |
846 | goto out_unlock; | 864 | goto out_unlock; |
847 | } | 865 | } |
@@ -859,7 +877,7 @@ xfs_file_fallocate( | |||
859 | if (ip->i_d.di_mode & S_IXGRP) | 877 | if (ip->i_d.di_mode & S_IXGRP) |
860 | ip->i_d.di_mode &= ~S_ISGID; | 878 | ip->i_d.di_mode &= ~S_ISGID; |
861 | 879 | ||
862 | if (!(mode & FALLOC_FL_PUNCH_HOLE)) | 880 | if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE))) |
863 | ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; | 881 | ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; |
864 | 882 | ||
865 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 883 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |