diff options
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_file.c')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_file.c | 62 |
1 files changed, 61 insertions, 1 deletions
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index ef51eb43e137..f4213ba1ff85 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include "xfs_trace.h" | 37 | #include "xfs_trace.h" |
38 | 38 | ||
39 | #include <linux/dcache.h> | 39 | #include <linux/dcache.h> |
40 | #include <linux/falloc.h> | ||
40 | 41 | ||
41 | static const struct vm_operations_struct xfs_file_vm_ops; | 42 | static const struct vm_operations_struct xfs_file_vm_ops; |
42 | 43 | ||
@@ -380,7 +381,7 @@ xfs_aio_write_isize_update( | |||
380 | 381 | ||
381 | /* | 382 | /* |
382 | * If this was a direct or synchronous I/O that failed (such as ENOSPC) then | 383 | * If this was a direct or synchronous I/O that failed (such as ENOSPC) then |
383 | * part of the I/O may have been written to disk before the error occured. In | 384 | * part of the I/O may have been written to disk before the error occurred. In |
384 | * this case the on-disk file size may have been adjusted beyond the in-memory | 385 | * this case the on-disk file size may have been adjusted beyond the in-memory |
385 | * file size and now needs to be truncated back. | 386 | * file size and now needs to be truncated back. |
386 | */ | 387 | */ |
@@ -882,6 +883,64 @@ out_unlock: | |||
882 | return ret; | 883 | return ret; |
883 | } | 884 | } |
884 | 885 | ||
886 | STATIC long | ||
887 | xfs_file_fallocate( | ||
888 | struct file *file, | ||
889 | int mode, | ||
890 | loff_t offset, | ||
891 | loff_t len) | ||
892 | { | ||
893 | struct inode *inode = file->f_path.dentry->d_inode; | ||
894 | long error; | ||
895 | loff_t new_size = 0; | ||
896 | xfs_flock64_t bf; | ||
897 | xfs_inode_t *ip = XFS_I(inode); | ||
898 | int cmd = XFS_IOC_RESVSP; | ||
899 | int attr_flags = XFS_ATTR_NOLOCK; | ||
900 | |||
901 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) | ||
902 | return -EOPNOTSUPP; | ||
903 | |||
904 | bf.l_whence = 0; | ||
905 | bf.l_start = offset; | ||
906 | bf.l_len = len; | ||
907 | |||
908 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | ||
909 | |||
910 | if (mode & FALLOC_FL_PUNCH_HOLE) | ||
911 | cmd = XFS_IOC_UNRESVSP; | ||
912 | |||
913 | /* check the new inode size is valid before allocating */ | ||
914 | if (!(mode & FALLOC_FL_KEEP_SIZE) && | ||
915 | offset + len > i_size_read(inode)) { | ||
916 | new_size = offset + len; | ||
917 | error = inode_newsize_ok(inode, new_size); | ||
918 | if (error) | ||
919 | goto out_unlock; | ||
920 | } | ||
921 | |||
922 | if (file->f_flags & O_DSYNC) | ||
923 | attr_flags |= XFS_ATTR_SYNC; | ||
924 | |||
925 | error = -xfs_change_file_space(ip, cmd, &bf, 0, attr_flags); | ||
926 | if (error) | ||
927 | goto out_unlock; | ||
928 | |||
929 | /* Change file size if needed */ | ||
930 | if (new_size) { | ||
931 | struct iattr iattr; | ||
932 | |||
933 | iattr.ia_valid = ATTR_SIZE; | ||
934 | iattr.ia_size = new_size; | ||
935 | error = -xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK); | ||
936 | } | ||
937 | |||
938 | out_unlock: | ||
939 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | ||
940 | return error; | ||
941 | } | ||
942 | |||
943 | |||
885 | STATIC int | 944 | STATIC int |
886 | xfs_file_open( | 945 | xfs_file_open( |
887 | struct inode *inode, | 946 | struct inode *inode, |
@@ -1000,6 +1059,7 @@ const struct file_operations xfs_file_operations = { | |||
1000 | .open = xfs_file_open, | 1059 | .open = xfs_file_open, |
1001 | .release = xfs_file_release, | 1060 | .release = xfs_file_release, |
1002 | .fsync = xfs_file_fsync, | 1061 | .fsync = xfs_file_fsync, |
1062 | .fallocate = xfs_file_fallocate, | ||
1003 | }; | 1063 | }; |
1004 | 1064 | ||
1005 | const struct file_operations xfs_dir_file_operations = { | 1065 | const struct file_operations xfs_dir_file_operations = { |