diff options
Diffstat (limited to 'fs/xfs/xfs_file.c')
-rw-r--r-- | fs/xfs/xfs_file.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 2e7989e3a2d6..52f96e16694c 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)) | ||
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)) { |
@@ -859,7 +874,7 @@ xfs_file_fallocate( | |||
859 | if (ip->i_d.di_mode & S_IXGRP) | 874 | if (ip->i_d.di_mode & S_IXGRP) |
860 | ip->i_d.di_mode &= ~S_ISGID; | 875 | ip->i_d.di_mode &= ~S_ISGID; |
861 | 876 | ||
862 | if (!(mode & FALLOC_FL_PUNCH_HOLE)) | 877 | if (!(mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_COLLAPSE_RANGE))) |
863 | ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; | 878 | ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; |
864 | 879 | ||
865 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); | 880 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); |