diff options
Diffstat (limited to 'fs/xfs/xfs_file.c')
-rw-r--r-- | fs/xfs/xfs_file.c | 381 |
1 files changed, 345 insertions, 36 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 56afcdb2377d..aa473fa640a2 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -36,6 +36,7 @@ | |||
36 | 36 | ||
37 | #include <linux/dcache.h> | 37 | #include <linux/dcache.h> |
38 | #include <linux/falloc.h> | 38 | #include <linux/falloc.h> |
39 | #include <linux/pagevec.h> | ||
39 | 40 | ||
40 | static const struct vm_operations_struct xfs_file_vm_ops; | 41 | static const struct vm_operations_struct xfs_file_vm_ops; |
41 | 42 | ||
@@ -939,7 +940,6 @@ xfs_file_mmap( | |||
939 | struct vm_area_struct *vma) | 940 | struct vm_area_struct *vma) |
940 | { | 941 | { |
941 | vma->vm_ops = &xfs_file_vm_ops; | 942 | vma->vm_ops = &xfs_file_vm_ops; |
942 | vma->vm_flags |= VM_CAN_NONLINEAR; | ||
943 | 943 | ||
944 | file_accessed(filp); | 944 | file_accessed(filp); |
945 | return 0; | 945 | return 0; |
@@ -959,17 +959,232 @@ xfs_vm_page_mkwrite( | |||
959 | return block_page_mkwrite(vma, vmf, xfs_get_blocks); | 959 | return block_page_mkwrite(vma, vmf, xfs_get_blocks); |
960 | } | 960 | } |
961 | 961 | ||
962 | /* | ||
963 | * This type is designed to indicate the type of offset we would like | ||
964 | * to search from page cache for either xfs_seek_data() or xfs_seek_hole(). | ||
965 | */ | ||
966 | enum { | ||
967 | HOLE_OFF = 0, | ||
968 | DATA_OFF, | ||
969 | }; | ||
970 | |||
971 | /* | ||
972 | * Lookup the desired type of offset from the given page. | ||
973 | * | ||
974 | * On success, return true and the offset argument will point to the | ||
975 | * start of the region that was found. Otherwise this function will | ||
976 | * return false and keep the offset argument unchanged. | ||
977 | */ | ||
978 | STATIC bool | ||
979 | xfs_lookup_buffer_offset( | ||
980 | struct page *page, | ||
981 | loff_t *offset, | ||
982 | unsigned int type) | ||
983 | { | ||
984 | loff_t lastoff = page_offset(page); | ||
985 | bool found = false; | ||
986 | struct buffer_head *bh, *head; | ||
987 | |||
988 | bh = head = page_buffers(page); | ||
989 | do { | ||
990 | /* | ||
991 | * Unwritten extents that have data in the page | ||
992 | * cache covering them can be identified by the | ||
993 | * BH_Unwritten state flag. Pages with multiple | ||
994 | * buffers might have a mix of holes, data and | ||
995 | * unwritten extents - any buffer with valid | ||
996 | * data in it should have BH_Uptodate flag set | ||
997 | * on it. | ||
998 | */ | ||
999 | if (buffer_unwritten(bh) || | ||
1000 | buffer_uptodate(bh)) { | ||
1001 | if (type == DATA_OFF) | ||
1002 | found = true; | ||
1003 | } else { | ||
1004 | if (type == HOLE_OFF) | ||
1005 | found = true; | ||
1006 | } | ||
1007 | |||
1008 | if (found) { | ||
1009 | *offset = lastoff; | ||
1010 | break; | ||
1011 | } | ||
1012 | lastoff += bh->b_size; | ||
1013 | } while ((bh = bh->b_this_page) != head); | ||
1014 | |||
1015 | return found; | ||
1016 | } | ||
1017 | |||
1018 | /* | ||
1019 | * This routine is called to find out and return a data or hole offset | ||
1020 | * from the page cache for unwritten extents according to the desired | ||
1021 | * type for xfs_seek_data() or xfs_seek_hole(). | ||
1022 | * | ||
1023 | * The argument offset is used to tell where we start to search from the | ||
1024 | * page cache. Map is used to figure out the end points of the range to | ||
1025 | * lookup pages. | ||
1026 | * | ||
1027 | * Return true if the desired type of offset was found, and the argument | ||
1028 | * offset is filled with that address. Otherwise, return false and keep | ||
1029 | * offset unchanged. | ||
1030 | */ | ||
1031 | STATIC bool | ||
1032 | xfs_find_get_desired_pgoff( | ||
1033 | struct inode *inode, | ||
1034 | struct xfs_bmbt_irec *map, | ||
1035 | unsigned int type, | ||
1036 | loff_t *offset) | ||
1037 | { | ||
1038 | struct xfs_inode *ip = XFS_I(inode); | ||
1039 | struct xfs_mount *mp = ip->i_mount; | ||
1040 | struct pagevec pvec; | ||
1041 | pgoff_t index; | ||
1042 | pgoff_t end; | ||
1043 | loff_t endoff; | ||
1044 | loff_t startoff = *offset; | ||
1045 | loff_t lastoff = startoff; | ||
1046 | bool found = false; | ||
1047 | |||
1048 | pagevec_init(&pvec, 0); | ||
1049 | |||
1050 | index = startoff >> PAGE_CACHE_SHIFT; | ||
1051 | endoff = XFS_FSB_TO_B(mp, map->br_startoff + map->br_blockcount); | ||
1052 | end = endoff >> PAGE_CACHE_SHIFT; | ||
1053 | do { | ||
1054 | int want; | ||
1055 | unsigned nr_pages; | ||
1056 | unsigned int i; | ||
1057 | |||
1058 | want = min_t(pgoff_t, end - index, PAGEVEC_SIZE); | ||
1059 | nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index, | ||
1060 | want); | ||
1061 | /* | ||
1062 | * No page mapped into given range. If we are searching holes | ||
1063 | * and if this is the first time we got into the loop, it means | ||
1064 | * that the given offset is landed in a hole, return it. | ||
1065 | * | ||
1066 | * If we have already stepped through some block buffers to find | ||
1067 | * holes but they all contains data. In this case, the last | ||
1068 | * offset is already updated and pointed to the end of the last | ||
1069 | * mapped page, if it does not reach the endpoint to search, | ||
1070 | * that means there should be a hole between them. | ||
1071 | */ | ||
1072 | if (nr_pages == 0) { | ||
1073 | /* Data search found nothing */ | ||
1074 | if (type == DATA_OFF) | ||
1075 | break; | ||
1076 | |||
1077 | ASSERT(type == HOLE_OFF); | ||
1078 | if (lastoff == startoff || lastoff < endoff) { | ||
1079 | found = true; | ||
1080 | *offset = lastoff; | ||
1081 | } | ||
1082 | break; | ||
1083 | } | ||
1084 | |||
1085 | /* | ||
1086 | * At lease we found one page. If this is the first time we | ||
1087 | * step into the loop, and if the first page index offset is | ||
1088 | * greater than the given search offset, a hole was found. | ||
1089 | */ | ||
1090 | if (type == HOLE_OFF && lastoff == startoff && | ||
1091 | lastoff < page_offset(pvec.pages[0])) { | ||
1092 | found = true; | ||
1093 | break; | ||
1094 | } | ||
1095 | |||
1096 | for (i = 0; i < nr_pages; i++) { | ||
1097 | struct page *page = pvec.pages[i]; | ||
1098 | loff_t b_offset; | ||
1099 | |||
1100 | /* | ||
1101 | * At this point, the page may be truncated or | ||
1102 | * invalidated (changing page->mapping to NULL), | ||
1103 | * or even swizzled back from swapper_space to tmpfs | ||
1104 | * file mapping. However, page->index will not change | ||
1105 | * because we have a reference on the page. | ||
1106 | * | ||
1107 | * Searching done if the page index is out of range. | ||
1108 | * If the current offset is not reaches the end of | ||
1109 | * the specified search range, there should be a hole | ||
1110 | * between them. | ||
1111 | */ | ||
1112 | if (page->index > end) { | ||
1113 | if (type == HOLE_OFF && lastoff < endoff) { | ||
1114 | *offset = lastoff; | ||
1115 | found = true; | ||
1116 | } | ||
1117 | goto out; | ||
1118 | } | ||
1119 | |||
1120 | lock_page(page); | ||
1121 | /* | ||
1122 | * Page truncated or invalidated(page->mapping == NULL). | ||
1123 | * We can freely skip it and proceed to check the next | ||
1124 | * page. | ||
1125 | */ | ||
1126 | if (unlikely(page->mapping != inode->i_mapping)) { | ||
1127 | unlock_page(page); | ||
1128 | continue; | ||
1129 | } | ||
1130 | |||
1131 | if (!page_has_buffers(page)) { | ||
1132 | unlock_page(page); | ||
1133 | continue; | ||
1134 | } | ||
1135 | |||
1136 | found = xfs_lookup_buffer_offset(page, &b_offset, type); | ||
1137 | if (found) { | ||
1138 | /* | ||
1139 | * The found offset may be less than the start | ||
1140 | * point to search if this is the first time to | ||
1141 | * come here. | ||
1142 | */ | ||
1143 | *offset = max_t(loff_t, startoff, b_offset); | ||
1144 | unlock_page(page); | ||
1145 | goto out; | ||
1146 | } | ||
1147 | |||
1148 | /* | ||
1149 | * We either searching data but nothing was found, or | ||
1150 | * searching hole but found a data buffer. In either | ||
1151 | * case, probably the next page contains the desired | ||
1152 | * things, update the last offset to it so. | ||
1153 | */ | ||
1154 | lastoff = page_offset(page) + PAGE_SIZE; | ||
1155 | unlock_page(page); | ||
1156 | } | ||
1157 | |||
1158 | /* | ||
1159 | * The number of returned pages less than our desired, search | ||
1160 | * done. In this case, nothing was found for searching data, | ||
1161 | * but we found a hole behind the last offset. | ||
1162 | */ | ||
1163 | if (nr_pages < want) { | ||
1164 | if (type == HOLE_OFF) { | ||
1165 | *offset = lastoff; | ||
1166 | found = true; | ||
1167 | } | ||
1168 | break; | ||
1169 | } | ||
1170 | |||
1171 | index = pvec.pages[i - 1]->index + 1; | ||
1172 | pagevec_release(&pvec); | ||
1173 | } while (index <= end); | ||
1174 | |||
1175 | out: | ||
1176 | pagevec_release(&pvec); | ||
1177 | return found; | ||
1178 | } | ||
1179 | |||
962 | STATIC loff_t | 1180 | STATIC loff_t |
963 | xfs_seek_data( | 1181 | xfs_seek_data( |
964 | struct file *file, | 1182 | struct file *file, |
965 | loff_t start, | 1183 | loff_t start) |
966 | u32 type) | ||
967 | { | 1184 | { |
968 | struct inode *inode = file->f_mapping->host; | 1185 | struct inode *inode = file->f_mapping->host; |
969 | struct xfs_inode *ip = XFS_I(inode); | 1186 | struct xfs_inode *ip = XFS_I(inode); |
970 | struct xfs_mount *mp = ip->i_mount; | 1187 | struct xfs_mount *mp = ip->i_mount; |
971 | struct xfs_bmbt_irec map[2]; | ||
972 | int nmap = 2; | ||
973 | loff_t uninitialized_var(offset); | 1188 | loff_t uninitialized_var(offset); |
974 | xfs_fsize_t isize; | 1189 | xfs_fsize_t isize; |
975 | xfs_fileoff_t fsbno; | 1190 | xfs_fileoff_t fsbno; |
@@ -985,36 +1200,74 @@ xfs_seek_data( | |||
985 | goto out_unlock; | 1200 | goto out_unlock; |
986 | } | 1201 | } |
987 | 1202 | ||
988 | fsbno = XFS_B_TO_FSBT(mp, start); | ||
989 | |||
990 | /* | 1203 | /* |
991 | * Try to read extents from the first block indicated | 1204 | * Try to read extents from the first block indicated |
992 | * by fsbno to the end block of the file. | 1205 | * by fsbno to the end block of the file. |
993 | */ | 1206 | */ |
1207 | fsbno = XFS_B_TO_FSBT(mp, start); | ||
994 | end = XFS_B_TO_FSB(mp, isize); | 1208 | end = XFS_B_TO_FSB(mp, isize); |
1209 | for (;;) { | ||
1210 | struct xfs_bmbt_irec map[2]; | ||
1211 | int nmap = 2; | ||
1212 | unsigned int i; | ||
995 | 1213 | ||
996 | error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap, | 1214 | error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap, |
997 | XFS_BMAPI_ENTIRE); | 1215 | XFS_BMAPI_ENTIRE); |
998 | if (error) | 1216 | if (error) |
999 | goto out_unlock; | 1217 | goto out_unlock; |
1000 | 1218 | ||
1001 | /* | 1219 | /* No extents at given offset, must be beyond EOF */ |
1002 | * Treat unwritten extent as data extent since it might | 1220 | if (nmap == 0) { |
1003 | * contains dirty data in page cache. | 1221 | error = ENXIO; |
1004 | */ | 1222 | goto out_unlock; |
1005 | if (map[0].br_startblock != HOLESTARTBLOCK) { | 1223 | } |
1006 | offset = max_t(loff_t, start, | 1224 | |
1007 | XFS_FSB_TO_B(mp, map[0].br_startoff)); | 1225 | for (i = 0; i < nmap; i++) { |
1008 | } else { | 1226 | offset = max_t(loff_t, start, |
1227 | XFS_FSB_TO_B(mp, map[i].br_startoff)); | ||
1228 | |||
1229 | /* Landed in a data extent */ | ||
1230 | if (map[i].br_startblock == DELAYSTARTBLOCK || | ||
1231 | (map[i].br_state == XFS_EXT_NORM && | ||
1232 | !isnullstartblock(map[i].br_startblock))) | ||
1233 | goto out; | ||
1234 | |||
1235 | /* | ||
1236 | * Landed in an unwritten extent, try to search data | ||
1237 | * from page cache. | ||
1238 | */ | ||
1239 | if (map[i].br_state == XFS_EXT_UNWRITTEN) { | ||
1240 | if (xfs_find_get_desired_pgoff(inode, &map[i], | ||
1241 | DATA_OFF, &offset)) | ||
1242 | goto out; | ||
1243 | } | ||
1244 | } | ||
1245 | |||
1246 | /* | ||
1247 | * map[0] is hole or its an unwritten extent but | ||
1248 | * without data in page cache. Probably means that | ||
1249 | * we are reading after EOF if nothing in map[1]. | ||
1250 | */ | ||
1009 | if (nmap == 1) { | 1251 | if (nmap == 1) { |
1010 | error = ENXIO; | 1252 | error = ENXIO; |
1011 | goto out_unlock; | 1253 | goto out_unlock; |
1012 | } | 1254 | } |
1013 | 1255 | ||
1014 | offset = max_t(loff_t, start, | 1256 | ASSERT(i > 1); |
1015 | XFS_FSB_TO_B(mp, map[1].br_startoff)); | 1257 | |
1258 | /* | ||
1259 | * Nothing was found, proceed to the next round of search | ||
1260 | * if reading offset not beyond or hit EOF. | ||
1261 | */ | ||
1262 | fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; | ||
1263 | start = XFS_FSB_TO_B(mp, fsbno); | ||
1264 | if (start >= isize) { | ||
1265 | error = ENXIO; | ||
1266 | goto out_unlock; | ||
1267 | } | ||
1016 | } | 1268 | } |
1017 | 1269 | ||
1270 | out: | ||
1018 | if (offset != file->f_pos) | 1271 | if (offset != file->f_pos) |
1019 | file->f_pos = offset; | 1272 | file->f_pos = offset; |
1020 | 1273 | ||
@@ -1029,16 +1282,15 @@ out_unlock: | |||
1029 | STATIC loff_t | 1282 | STATIC loff_t |
1030 | xfs_seek_hole( | 1283 | xfs_seek_hole( |
1031 | struct file *file, | 1284 | struct file *file, |
1032 | loff_t start, | 1285 | loff_t start) |
1033 | u32 type) | ||
1034 | { | 1286 | { |
1035 | struct inode *inode = file->f_mapping->host; | 1287 | struct inode *inode = file->f_mapping->host; |
1036 | struct xfs_inode *ip = XFS_I(inode); | 1288 | struct xfs_inode *ip = XFS_I(inode); |
1037 | struct xfs_mount *mp = ip->i_mount; | 1289 | struct xfs_mount *mp = ip->i_mount; |
1038 | loff_t uninitialized_var(offset); | 1290 | loff_t uninitialized_var(offset); |
1039 | loff_t holeoff; | ||
1040 | xfs_fsize_t isize; | 1291 | xfs_fsize_t isize; |
1041 | xfs_fileoff_t fsbno; | 1292 | xfs_fileoff_t fsbno; |
1293 | xfs_filblks_t end; | ||
1042 | uint lock; | 1294 | uint lock; |
1043 | int error; | 1295 | int error; |
1044 | 1296 | ||
@@ -1054,21 +1306,77 @@ xfs_seek_hole( | |||
1054 | } | 1306 | } |
1055 | 1307 | ||
1056 | fsbno = XFS_B_TO_FSBT(mp, start); | 1308 | fsbno = XFS_B_TO_FSBT(mp, start); |
1057 | error = xfs_bmap_first_unused(NULL, ip, 1, &fsbno, XFS_DATA_FORK); | 1309 | end = XFS_B_TO_FSB(mp, isize); |
1058 | if (error) | 1310 | |
1059 | goto out_unlock; | 1311 | for (;;) { |
1312 | struct xfs_bmbt_irec map[2]; | ||
1313 | int nmap = 2; | ||
1314 | unsigned int i; | ||
1315 | |||
1316 | error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap, | ||
1317 | XFS_BMAPI_ENTIRE); | ||
1318 | if (error) | ||
1319 | goto out_unlock; | ||
1320 | |||
1321 | /* No extents at given offset, must be beyond EOF */ | ||
1322 | if (nmap == 0) { | ||
1323 | error = ENXIO; | ||
1324 | goto out_unlock; | ||
1325 | } | ||
1326 | |||
1327 | for (i = 0; i < nmap; i++) { | ||
1328 | offset = max_t(loff_t, start, | ||
1329 | XFS_FSB_TO_B(mp, map[i].br_startoff)); | ||
1330 | |||
1331 | /* Landed in a hole */ | ||
1332 | if (map[i].br_startblock == HOLESTARTBLOCK) | ||
1333 | goto out; | ||
1334 | |||
1335 | /* | ||
1336 | * Landed in an unwritten extent, try to search hole | ||
1337 | * from page cache. | ||
1338 | */ | ||
1339 | if (map[i].br_state == XFS_EXT_UNWRITTEN) { | ||
1340 | if (xfs_find_get_desired_pgoff(inode, &map[i], | ||
1341 | HOLE_OFF, &offset)) | ||
1342 | goto out; | ||
1343 | } | ||
1344 | } | ||
1345 | |||
1346 | /* | ||
1347 | * map[0] contains data or its unwritten but contains | ||
1348 | * data in page cache, probably means that we are | ||
1349 | * reading after EOF. We should fix offset to point | ||
1350 | * to the end of the file(i.e., there is an implicit | ||
1351 | * hole at the end of any file). | ||
1352 | */ | ||
1353 | if (nmap == 1) { | ||
1354 | offset = isize; | ||
1355 | break; | ||
1356 | } | ||
1357 | |||
1358 | ASSERT(i > 1); | ||
1060 | 1359 | ||
1061 | holeoff = XFS_FSB_TO_B(mp, fsbno); | ||
1062 | if (holeoff <= start) | ||
1063 | offset = start; | ||
1064 | else { | ||
1065 | /* | 1360 | /* |
1066 | * xfs_bmap_first_unused() could return a value bigger than | 1361 | * Both mappings contains data, proceed to the next round of |
1067 | * isize if there are no more holes past the supplied offset. | 1362 | * search if the current reading offset not beyond or hit EOF. |
1068 | */ | 1363 | */ |
1069 | offset = min_t(loff_t, holeoff, isize); | 1364 | fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; |
1365 | start = XFS_FSB_TO_B(mp, fsbno); | ||
1366 | if (start >= isize) { | ||
1367 | offset = isize; | ||
1368 | break; | ||
1369 | } | ||
1070 | } | 1370 | } |
1071 | 1371 | ||
1372 | out: | ||
1373 | /* | ||
1374 | * At this point, we must have found a hole. However, the returned | ||
1375 | * offset may be bigger than the file size as it may be aligned to | ||
1376 | * page boundary for unwritten extents, we need to deal with this | ||
1377 | * situation in particular. | ||
1378 | */ | ||
1379 | offset = min_t(loff_t, offset, isize); | ||
1072 | if (offset != file->f_pos) | 1380 | if (offset != file->f_pos) |
1073 | file->f_pos = offset; | 1381 | file->f_pos = offset; |
1074 | 1382 | ||
@@ -1092,9 +1400,9 @@ xfs_file_llseek( | |||
1092 | case SEEK_SET: | 1400 | case SEEK_SET: |
1093 | return generic_file_llseek(file, offset, origin); | 1401 | return generic_file_llseek(file, offset, origin); |
1094 | case SEEK_DATA: | 1402 | case SEEK_DATA: |
1095 | return xfs_seek_data(file, offset, origin); | 1403 | return xfs_seek_data(file, offset); |
1096 | case SEEK_HOLE: | 1404 | case SEEK_HOLE: |
1097 | return xfs_seek_hole(file, offset, origin); | 1405 | return xfs_seek_hole(file, offset); |
1098 | default: | 1406 | default: |
1099 | return -EINVAL; | 1407 | return -EINVAL; |
1100 | } | 1408 | } |
@@ -1134,4 +1442,5 @@ const struct file_operations xfs_dir_file_operations = { | |||
1134 | static const struct vm_operations_struct xfs_file_vm_ops = { | 1442 | static const struct vm_operations_struct xfs_file_vm_ops = { |
1135 | .fault = filemap_fault, | 1443 | .fault = filemap_fault, |
1136 | .page_mkwrite = xfs_vm_page_mkwrite, | 1444 | .page_mkwrite = xfs_vm_page_mkwrite, |
1445 | .remap_pages = generic_file_remap_pages, | ||
1137 | }; | 1446 | }; |