aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Liu <jeff.liu@oracle.com>2012-05-10 09:29:17 -0400
committerBen Myers <bpm@sgi.com>2012-05-14 17:21:05 -0400
commit3fe3e6b18216c1247497dfd51c35484338856e1b (patch)
tree4ebbec83f37d2b7bd7d2aaab3800ed5b335b42b9
parente700a06c71dbbc0879a5d15881cca7b772282484 (diff)
xfs: introduce SEEK_DATA/SEEK_HOLE support
This patch adds lseek(2) SEEK_DATA/SEEK_HOLE functionality to xfs. Signed-off-by: Jie Liu <jeff.liu@oracle.com> Reviewed-by: Mark Tinguely <tinguely@sgi.com> Signed-off-by: Ben Myers <bpm@sgi.com>
-rw-r--r--fs/xfs/xfs_file.c143
1 files changed, 142 insertions, 1 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 51fc2cf07d5e..8d214b87f6bb 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -963,8 +963,149 @@ xfs_vm_page_mkwrite(
963 return block_page_mkwrite(vma, vmf, xfs_get_blocks); 963 return block_page_mkwrite(vma, vmf, xfs_get_blocks);
964} 964}
965 965
966STATIC loff_t
967xfs_seek_data(
968 struct file *file,
969 loff_t start,
970 u32 type)
971{
972 struct inode *inode = file->f_mapping->host;
973 struct xfs_inode *ip = XFS_I(inode);
974 struct xfs_mount *mp = ip->i_mount;
975 struct xfs_bmbt_irec map[2];
976 int nmap = 2;
977 loff_t uninitialized_var(offset);
978 xfs_fsize_t isize;
979 xfs_fileoff_t fsbno;
980 xfs_filblks_t end;
981 uint lock;
982 int error;
983
984 lock = xfs_ilock_map_shared(ip);
985
986 isize = i_size_read(inode);
987 if (start >= isize) {
988 error = ENXIO;
989 goto out_unlock;
990 }
991
992 fsbno = XFS_B_TO_FSBT(mp, start);
993
994 /*
995 * Try to read extents from the first block indicated
996 * by fsbno to the end block of the file.
997 */
998 end = XFS_B_TO_FSB(mp, isize);
999
1000 error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap,
1001 XFS_BMAPI_ENTIRE);
1002 if (error)
1003 goto out_unlock;
1004
1005 /*
1006 * Treat unwritten extent as data extent since it might
1007 * contains dirty data in page cache.
1008 */
1009 if (map[0].br_startblock != HOLESTARTBLOCK) {
1010 offset = max_t(loff_t, start,
1011 XFS_FSB_TO_B(mp, map[0].br_startoff));
1012 } else {
1013 if (nmap == 1) {
1014 error = ENXIO;
1015 goto out_unlock;
1016 }
1017
1018 offset = max_t(loff_t, start,
1019 XFS_FSB_TO_B(mp, map[1].br_startoff));
1020 }
1021
1022 if (offset != file->f_pos)
1023 file->f_pos = offset;
1024
1025out_unlock:
1026 xfs_iunlock_map_shared(ip, lock);
1027
1028 if (error)
1029 return -error;
1030 return offset;
1031}
1032
1033STATIC loff_t
1034xfs_seek_hole(
1035 struct file *file,
1036 loff_t start,
1037 u32 type)
1038{
1039 struct inode *inode = file->f_mapping->host;
1040 struct xfs_inode *ip = XFS_I(inode);
1041 struct xfs_mount *mp = ip->i_mount;
1042 loff_t uninitialized_var(offset);
1043 loff_t holeoff;
1044 xfs_fsize_t isize;
1045 xfs_fileoff_t fsbno;
1046 uint lock;
1047 int error;
1048
1049 if (XFS_FORCED_SHUTDOWN(mp))
1050 return -XFS_ERROR(EIO);
1051
1052 lock = xfs_ilock_map_shared(ip);
1053
1054 isize = i_size_read(inode);
1055 if (start >= isize) {
1056 error = ENXIO;
1057 goto out_unlock;
1058 }
1059
1060 fsbno = XFS_B_TO_FSBT(mp, start);
1061 error = xfs_bmap_first_unused(NULL, ip, 1, &fsbno, XFS_DATA_FORK);
1062 if (error)
1063 goto out_unlock;
1064
1065 holeoff = XFS_FSB_TO_B(mp, fsbno);
1066 if (holeoff <= start)
1067 offset = start;
1068 else {
1069 /*
1070 * xfs_bmap_first_unused() could return a value bigger than
1071 * isize if there are no more holes past the supplied offset.
1072 */
1073 offset = min_t(loff_t, holeoff, isize);
1074 }
1075
1076 if (offset != file->f_pos)
1077 file->f_pos = offset;
1078
1079out_unlock:
1080 xfs_iunlock_map_shared(ip, lock);
1081
1082 if (error)
1083 return -error;
1084 return offset;
1085}
1086
1087STATIC loff_t
1088xfs_file_llseek(
1089 struct file *file,
1090 loff_t offset,
1091 int origin)
1092{
1093 switch (origin) {
1094 case SEEK_END:
1095 case SEEK_CUR:
1096 case SEEK_SET:
1097 return generic_file_llseek(file, offset, origin);
1098 case SEEK_DATA:
1099 return xfs_seek_data(file, offset, origin);
1100 case SEEK_HOLE:
1101 return xfs_seek_hole(file, offset, origin);
1102 default:
1103 return -EINVAL;
1104 }
1105}
1106
966const struct file_operations xfs_file_operations = { 1107const struct file_operations xfs_file_operations = {
967 .llseek = generic_file_llseek, 1108 .llseek = xfs_file_llseek,
968 .read = do_sync_read, 1109 .read = do_sync_read,
969 .write = do_sync_write, 1110 .write = do_sync_write,
970 .aio_read = xfs_file_aio_read, 1111 .aio_read = xfs_file_aio_read,