diff options
Diffstat (limited to 'fs/xfs/xfs_file.c')
-rw-r--r-- | fs/xfs/xfs_file.c | 178 |
1 files changed, 53 insertions, 125 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index de5368c803f9..eb596b419942 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -983,7 +983,7 @@ xfs_vm_page_mkwrite( | |||
983 | 983 | ||
984 | /* | 984 | /* |
985 | * This type is designed to indicate the type of offset we would like | 985 | * This type is designed to indicate the type of offset we would like |
986 | * to search from page cache for either xfs_seek_data() or xfs_seek_hole(). | 986 | * to search from page cache for xfs_seek_hole_data(). |
987 | */ | 987 | */ |
988 | enum { | 988 | enum { |
989 | HOLE_OFF = 0, | 989 | HOLE_OFF = 0, |
@@ -1040,7 +1040,7 @@ xfs_lookup_buffer_offset( | |||
1040 | /* | 1040 | /* |
1041 | * This routine is called to find out and return a data or hole offset | 1041 | * This routine is called to find out and return a data or hole offset |
1042 | * from the page cache for unwritten extents according to the desired | 1042 | * from the page cache for unwritten extents according to the desired |
1043 | * type for xfs_seek_data() or xfs_seek_hole(). | 1043 | * type for xfs_seek_hole_data(). |
1044 | * | 1044 | * |
1045 | * The argument offset is used to tell where we start to search from the | 1045 | * The argument offset is used to tell where we start to search from the |
1046 | * page cache. Map is used to figure out the end points of the range to | 1046 | * page cache. Map is used to figure out the end points of the range to |
@@ -1200,9 +1200,10 @@ out: | |||
1200 | } | 1200 | } |
1201 | 1201 | ||
1202 | STATIC loff_t | 1202 | STATIC loff_t |
1203 | xfs_seek_data( | 1203 | xfs_seek_hole_data( |
1204 | struct file *file, | 1204 | struct file *file, |
1205 | loff_t start) | 1205 | loff_t start, |
1206 | int whence) | ||
1206 | { | 1207 | { |
1207 | struct inode *inode = file->f_mapping->host; | 1208 | struct inode *inode = file->f_mapping->host; |
1208 | struct xfs_inode *ip = XFS_I(inode); | 1209 | struct xfs_inode *ip = XFS_I(inode); |
@@ -1214,6 +1215,9 @@ xfs_seek_data( | |||
1214 | uint lock; | 1215 | uint lock; |
1215 | int error; | 1216 | int error; |
1216 | 1217 | ||
1218 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
1219 | return -EIO; | ||
1220 | |||
1217 | lock = xfs_ilock_data_map_shared(ip); | 1221 | lock = xfs_ilock_data_map_shared(ip); |
1218 | 1222 | ||
1219 | isize = i_size_read(inode); | 1223 | isize = i_size_read(inode); |
@@ -1228,6 +1232,7 @@ xfs_seek_data( | |||
1228 | */ | 1232 | */ |
1229 | fsbno = XFS_B_TO_FSBT(mp, start); | 1233 | fsbno = XFS_B_TO_FSBT(mp, start); |
1230 | end = XFS_B_TO_FSB(mp, isize); | 1234 | end = XFS_B_TO_FSB(mp, isize); |
1235 | |||
1231 | for (;;) { | 1236 | for (;;) { |
1232 | struct xfs_bmbt_irec map[2]; | 1237 | struct xfs_bmbt_irec map[2]; |
1233 | int nmap = 2; | 1238 | int nmap = 2; |
@@ -1248,29 +1253,48 @@ xfs_seek_data( | |||
1248 | offset = max_t(loff_t, start, | 1253 | offset = max_t(loff_t, start, |
1249 | XFS_FSB_TO_B(mp, map[i].br_startoff)); | 1254 | XFS_FSB_TO_B(mp, map[i].br_startoff)); |
1250 | 1255 | ||
1251 | /* Landed in a data extent */ | 1256 | /* Landed in the hole we wanted? */ |
1252 | if (map[i].br_startblock == DELAYSTARTBLOCK || | 1257 | if (whence == SEEK_HOLE && |
1253 | (map[i].br_state == XFS_EXT_NORM && | 1258 | map[i].br_startblock == HOLESTARTBLOCK) |
1254 | !isnullstartblock(map[i].br_startblock))) | 1259 | goto out; |
1260 | |||
1261 | /* Landed in the data extent we wanted? */ | ||
1262 | if (whence == SEEK_DATA && | ||
1263 | (map[i].br_startblock == DELAYSTARTBLOCK || | ||
1264 | (map[i].br_state == XFS_EXT_NORM && | ||
1265 | !isnullstartblock(map[i].br_startblock)))) | ||
1255 | goto out; | 1266 | goto out; |
1256 | 1267 | ||
1257 | /* | 1268 | /* |
1258 | * Landed in an unwritten extent, try to search data | 1269 | * Landed in an unwritten extent, try to search |
1259 | * from page cache. | 1270 | * for hole or data from page cache. |
1260 | */ | 1271 | */ |
1261 | if (map[i].br_state == XFS_EXT_UNWRITTEN) { | 1272 | if (map[i].br_state == XFS_EXT_UNWRITTEN) { |
1262 | if (xfs_find_get_desired_pgoff(inode, &map[i], | 1273 | if (xfs_find_get_desired_pgoff(inode, &map[i], |
1263 | DATA_OFF, &offset)) | 1274 | whence == SEEK_HOLE ? HOLE_OFF : DATA_OFF, |
1275 | &offset)) | ||
1264 | goto out; | 1276 | goto out; |
1265 | } | 1277 | } |
1266 | } | 1278 | } |
1267 | 1279 | ||
1268 | /* | 1280 | /* |
1269 | * map[0] is hole or its an unwritten extent but | 1281 | * We only received one extent out of the two requested. This |
1270 | * without data in page cache. Probably means that | 1282 | * means we've hit EOF and didn't find what we are looking for. |
1271 | * we are reading after EOF if nothing in map[1]. | ||
1272 | */ | 1283 | */ |
1273 | if (nmap == 1) { | 1284 | if (nmap == 1) { |
1285 | /* | ||
1286 | * If we were looking for a hole, set offset to | ||
1287 | * the end of the file (i.e., there is an implicit | ||
1288 | * hole at the end of any file). | ||
1289 | */ | ||
1290 | if (whence == SEEK_HOLE) { | ||
1291 | offset = isize; | ||
1292 | break; | ||
1293 | } | ||
1294 | /* | ||
1295 | * If we were looking for data, it's nowhere to be found | ||
1296 | */ | ||
1297 | ASSERT(whence == SEEK_DATA); | ||
1274 | error = -ENXIO; | 1298 | error = -ENXIO; |
1275 | goto out_unlock; | 1299 | goto out_unlock; |
1276 | } | 1300 | } |
@@ -1279,125 +1303,30 @@ xfs_seek_data( | |||
1279 | 1303 | ||
1280 | /* | 1304 | /* |
1281 | * Nothing was found, proceed to the next round of search | 1305 | * Nothing was found, proceed to the next round of search |
1282 | * if reading offset not beyond or hit EOF. | 1306 | * if the next reading offset is not at or beyond EOF. |
1283 | */ | 1307 | */ |
1284 | fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; | 1308 | fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; |
1285 | start = XFS_FSB_TO_B(mp, fsbno); | 1309 | start = XFS_FSB_TO_B(mp, fsbno); |
1286 | if (start >= isize) { | 1310 | if (start >= isize) { |
1311 | if (whence == SEEK_HOLE) { | ||
1312 | offset = isize; | ||
1313 | break; | ||
1314 | } | ||
1315 | ASSERT(whence == SEEK_DATA); | ||
1287 | error = -ENXIO; | 1316 | error = -ENXIO; |
1288 | goto out_unlock; | 1317 | goto out_unlock; |
1289 | } | 1318 | } |
1290 | } | 1319 | } |
1291 | 1320 | ||
1292 | out: | 1321 | out: |
1293 | offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); | ||
1294 | |||
1295 | out_unlock: | ||
1296 | xfs_iunlock(ip, lock); | ||
1297 | |||
1298 | if (error) | ||
1299 | return error; | ||
1300 | return offset; | ||
1301 | } | ||
1302 | |||
1303 | STATIC loff_t | ||
1304 | xfs_seek_hole( | ||
1305 | struct file *file, | ||
1306 | loff_t start) | ||
1307 | { | ||
1308 | struct inode *inode = file->f_mapping->host; | ||
1309 | struct xfs_inode *ip = XFS_I(inode); | ||
1310 | struct xfs_mount *mp = ip->i_mount; | ||
1311 | loff_t uninitialized_var(offset); | ||
1312 | xfs_fsize_t isize; | ||
1313 | xfs_fileoff_t fsbno; | ||
1314 | xfs_filblks_t end; | ||
1315 | uint lock; | ||
1316 | int error; | ||
1317 | |||
1318 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
1319 | return -EIO; | ||
1320 | |||
1321 | lock = xfs_ilock_data_map_shared(ip); | ||
1322 | |||
1323 | isize = i_size_read(inode); | ||
1324 | if (start >= isize) { | ||
1325 | error = -ENXIO; | ||
1326 | goto out_unlock; | ||
1327 | } | ||
1328 | |||
1329 | fsbno = XFS_B_TO_FSBT(mp, start); | ||
1330 | end = XFS_B_TO_FSB(mp, isize); | ||
1331 | |||
1332 | for (;;) { | ||
1333 | struct xfs_bmbt_irec map[2]; | ||
1334 | int nmap = 2; | ||
1335 | unsigned int i; | ||
1336 | |||
1337 | error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap, | ||
1338 | XFS_BMAPI_ENTIRE); | ||
1339 | if (error) | ||
1340 | goto out_unlock; | ||
1341 | |||
1342 | /* No extents at given offset, must be beyond EOF */ | ||
1343 | if (nmap == 0) { | ||
1344 | error = -ENXIO; | ||
1345 | goto out_unlock; | ||
1346 | } | ||
1347 | |||
1348 | for (i = 0; i < nmap; i++) { | ||
1349 | offset = max_t(loff_t, start, | ||
1350 | XFS_FSB_TO_B(mp, map[i].br_startoff)); | ||
1351 | |||
1352 | /* Landed in a hole */ | ||
1353 | if (map[i].br_startblock == HOLESTARTBLOCK) | ||
1354 | goto out; | ||
1355 | |||
1356 | /* | ||
1357 | * Landed in an unwritten extent, try to search hole | ||
1358 | * from page cache. | ||
1359 | */ | ||
1360 | if (map[i].br_state == XFS_EXT_UNWRITTEN) { | ||
1361 | if (xfs_find_get_desired_pgoff(inode, &map[i], | ||
1362 | HOLE_OFF, &offset)) | ||
1363 | goto out; | ||
1364 | } | ||
1365 | } | ||
1366 | |||
1367 | /* | ||
1368 | * map[0] contains data or its unwritten but contains | ||
1369 | * data in page cache, probably means that we are | ||
1370 | * reading after EOF. We should fix offset to point | ||
1371 | * to the end of the file(i.e., there is an implicit | ||
1372 | * hole at the end of any file). | ||
1373 | */ | ||
1374 | if (nmap == 1) { | ||
1375 | offset = isize; | ||
1376 | break; | ||
1377 | } | ||
1378 | |||
1379 | ASSERT(i > 1); | ||
1380 | |||
1381 | /* | ||
1382 | * Both mappings contains data, proceed to the next round of | ||
1383 | * search if the current reading offset not beyond or hit EOF. | ||
1384 | */ | ||
1385 | fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; | ||
1386 | start = XFS_FSB_TO_B(mp, fsbno); | ||
1387 | if (start >= isize) { | ||
1388 | offset = isize; | ||
1389 | break; | ||
1390 | } | ||
1391 | } | ||
1392 | |||
1393 | out: | ||
1394 | /* | 1322 | /* |
1395 | * At this point, we must have found a hole. However, the returned | 1323 | * If at this point we have found the hole we wanted, the returned |
1396 | * offset may be bigger than the file size as it may be aligned to | 1324 | * offset may be bigger than the file size as it may be aligned to |
1397 | * page boundary for unwritten extents, we need to deal with this | 1325 | * page boundary for unwritten extents. We need to deal with this |
1398 | * situation in particular. | 1326 | * situation in particular. |
1399 | */ | 1327 | */ |
1400 | offset = min_t(loff_t, offset, isize); | 1328 | if (whence == SEEK_HOLE) |
1329 | offset = min_t(loff_t, offset, isize); | ||
1401 | offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); | 1330 | offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); |
1402 | 1331 | ||
1403 | out_unlock: | 1332 | out_unlock: |
@@ -1412,17 +1341,16 @@ STATIC loff_t | |||
1412 | xfs_file_llseek( | 1341 | xfs_file_llseek( |
1413 | struct file *file, | 1342 | struct file *file, |
1414 | loff_t offset, | 1343 | loff_t offset, |
1415 | int origin) | 1344 | int whence) |
1416 | { | 1345 | { |
1417 | switch (origin) { | 1346 | switch (whence) { |
1418 | case SEEK_END: | 1347 | case SEEK_END: |
1419 | case SEEK_CUR: | 1348 | case SEEK_CUR: |
1420 | case SEEK_SET: | 1349 | case SEEK_SET: |
1421 | return generic_file_llseek(file, offset, origin); | 1350 | return generic_file_llseek(file, offset, whence); |
1422 | case SEEK_DATA: | ||
1423 | return xfs_seek_data(file, offset); | ||
1424 | case SEEK_HOLE: | 1351 | case SEEK_HOLE: |
1425 | return xfs_seek_hole(file, offset); | 1352 | case SEEK_DATA: |
1353 | return xfs_seek_hole_data(file, offset, whence); | ||
1426 | default: | 1354 | default: |
1427 | return -EINVAL; | 1355 | return -EINVAL; |
1428 | } | 1356 | } |