diff options
author | Christoph Hellwig <hch@lst.de> | 2011-01-14 07:07:43 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-01-17 02:25:31 -0500 |
commit | 2fe17c1075836b66678ed2a305fd09b6773883aa (patch) | |
tree | eb5287be8138686682eef9622872cfc7657e0664 /fs/xfs | |
parent | 64c23e86873ee410554d6d1c76b60da47025e96f (diff) |
fallocate should be a file operation
Currently all filesystems except XFS implement fallocate asynchronously,
while XFS forced a commit. Both of these are suboptimal - in case of O_SYNC
I/O we really want our allocation on disk, especially for the !KEEP_SIZE
case where we actually grow the file with user-visible zeroes. On the
other hand always commiting the transaction is a bad idea for fast-path
uses of fallocate like for example in recent Samba versions. Given
that block allocation is a data plane operation anyway change it from
an inode operation to a file operation so that we have the file structure
available that lets us check for O_SYNC.
This also includes moving the code around for a few of the filesystems,
and remove the already unnedded S_ISDIR checks given that we only wire
up fallocate for regular files.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/xfs')
-rw-r--r-- | fs/xfs/linux-2.6/xfs_file.c | 56 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_iops.c | 60 |
2 files changed, 56 insertions, 60 deletions
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index ef51eb43e137..a55c1b46b219 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 | ||
@@ -882,6 +883,60 @@ 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 | |||
900 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) | ||
901 | return -EOPNOTSUPP; | ||
902 | |||
903 | bf.l_whence = 0; | ||
904 | bf.l_start = offset; | ||
905 | bf.l_len = len; | ||
906 | |||
907 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | ||
908 | |||
909 | if (mode & FALLOC_FL_PUNCH_HOLE) | ||
910 | cmd = XFS_IOC_UNRESVSP; | ||
911 | |||
912 | /* check the new inode size is valid before allocating */ | ||
913 | if (!(mode & FALLOC_FL_KEEP_SIZE) && | ||
914 | offset + len > i_size_read(inode)) { | ||
915 | new_size = offset + len; | ||
916 | error = inode_newsize_ok(inode, new_size); | ||
917 | if (error) | ||
918 | goto out_unlock; | ||
919 | } | ||
920 | |||
921 | error = -xfs_change_file_space(ip, cmd, &bf, 0, XFS_ATTR_NOLOCK); | ||
922 | if (error) | ||
923 | goto out_unlock; | ||
924 | |||
925 | /* Change file size if needed */ | ||
926 | if (new_size) { | ||
927 | struct iattr iattr; | ||
928 | |||
929 | iattr.ia_valid = ATTR_SIZE; | ||
930 | iattr.ia_size = new_size; | ||
931 | error = -xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK); | ||
932 | } | ||
933 | |||
934 | out_unlock: | ||
935 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | ||
936 | return error; | ||
937 | } | ||
938 | |||
939 | |||
885 | STATIC int | 940 | STATIC int |
886 | xfs_file_open( | 941 | xfs_file_open( |
887 | struct inode *inode, | 942 | struct inode *inode, |
@@ -1000,6 +1055,7 @@ const struct file_operations xfs_file_operations = { | |||
1000 | .open = xfs_file_open, | 1055 | .open = xfs_file_open, |
1001 | .release = xfs_file_release, | 1056 | .release = xfs_file_release, |
1002 | .fsync = xfs_file_fsync, | 1057 | .fsync = xfs_file_fsync, |
1058 | .fallocate = xfs_file_fallocate, | ||
1003 | }; | 1059 | }; |
1004 | 1060 | ||
1005 | const struct file_operations xfs_dir_file_operations = { | 1061 | const struct file_operations xfs_dir_file_operations = { |
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index a4ecc2188a09..bd5727852fd6 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c | |||
@@ -46,7 +46,6 @@ | |||
46 | #include <linux/namei.h> | 46 | #include <linux/namei.h> |
47 | #include <linux/posix_acl.h> | 47 | #include <linux/posix_acl.h> |
48 | #include <linux/security.h> | 48 | #include <linux/security.h> |
49 | #include <linux/falloc.h> | ||
50 | #include <linux/fiemap.h> | 49 | #include <linux/fiemap.h> |
51 | #include <linux/slab.h> | 50 | #include <linux/slab.h> |
52 | 51 | ||
@@ -505,64 +504,6 @@ xfs_vn_setattr( | |||
505 | return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0); | 504 | return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0); |
506 | } | 505 | } |
507 | 506 | ||
508 | STATIC long | ||
509 | xfs_vn_fallocate( | ||
510 | struct inode *inode, | ||
511 | int mode, | ||
512 | loff_t offset, | ||
513 | loff_t len) | ||
514 | { | ||
515 | long error; | ||
516 | loff_t new_size = 0; | ||
517 | xfs_flock64_t bf; | ||
518 | xfs_inode_t *ip = XFS_I(inode); | ||
519 | int cmd = XFS_IOC_RESVSP; | ||
520 | |||
521 | if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) | ||
522 | return -EOPNOTSUPP; | ||
523 | |||
524 | /* preallocation on directories not yet supported */ | ||
525 | error = -ENODEV; | ||
526 | if (S_ISDIR(inode->i_mode)) | ||
527 | goto out_error; | ||
528 | |||
529 | bf.l_whence = 0; | ||
530 | bf.l_start = offset; | ||
531 | bf.l_len = len; | ||
532 | |||
533 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | ||
534 | |||
535 | if (mode & FALLOC_FL_PUNCH_HOLE) | ||
536 | cmd = XFS_IOC_UNRESVSP; | ||
537 | |||
538 | /* check the new inode size is valid before allocating */ | ||
539 | if (!(mode & FALLOC_FL_KEEP_SIZE) && | ||
540 | offset + len > i_size_read(inode)) { | ||
541 | new_size = offset + len; | ||
542 | error = inode_newsize_ok(inode, new_size); | ||
543 | if (error) | ||
544 | goto out_unlock; | ||
545 | } | ||
546 | |||
547 | error = -xfs_change_file_space(ip, cmd, &bf, 0, XFS_ATTR_NOLOCK); | ||
548 | if (error) | ||
549 | goto out_unlock; | ||
550 | |||
551 | /* Change file size if needed */ | ||
552 | if (new_size) { | ||
553 | struct iattr iattr; | ||
554 | |||
555 | iattr.ia_valid = ATTR_SIZE; | ||
556 | iattr.ia_size = new_size; | ||
557 | error = -xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK); | ||
558 | } | ||
559 | |||
560 | out_unlock: | ||
561 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | ||
562 | out_error: | ||
563 | return error; | ||
564 | } | ||
565 | |||
566 | #define XFS_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR) | 507 | #define XFS_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR) |
567 | 508 | ||
568 | /* | 509 | /* |
@@ -656,7 +597,6 @@ static const struct inode_operations xfs_inode_operations = { | |||
656 | .getxattr = generic_getxattr, | 597 | .getxattr = generic_getxattr, |
657 | .removexattr = generic_removexattr, | 598 | .removexattr = generic_removexattr, |
658 | .listxattr = xfs_vn_listxattr, | 599 | .listxattr = xfs_vn_listxattr, |
659 | .fallocate = xfs_vn_fallocate, | ||
660 | .fiemap = xfs_vn_fiemap, | 600 | .fiemap = xfs_vn_fiemap, |
661 | }; | 601 | }; |
662 | 602 | ||