diff options
author | Eric Sandeen <sandeen@sandeen.net> | 2014-09-08 21:56:48 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2014-09-08 21:56:48 -0400 |
commit | 49c69591c80648c14ff87525e97ee6ebe3a343cb (patch) | |
tree | 55d217ff0eb9ec2f152ba5a980fbf92d93fff091 | |
parent | 2e2271787419a12496bf5da5c3028a9c73c9697f (diff) |
xfs: combine xfs_seek_hole & xfs_seek_data
xfs_seek_hole & xfs_seek_data are remarkably similar;
so much so that they can be combined, saving a fair
bit of semi-complex code duplication.
The following patch passes generic/285 and generic/286,
which specifically test seek behavior.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Jie Liu <jeff.liu@oracle.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r-- | fs/xfs/xfs_file.c | 172 |
1 files changed, 50 insertions, 122 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 076b1708d134..1da3b7db5bf7 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -964,7 +964,7 @@ xfs_vm_page_mkwrite( | |||
964 | 964 | ||
965 | /* | 965 | /* |
966 | * This type is designed to indicate the type of offset we would like | 966 | * This type is designed to indicate the type of offset we would like |
967 | * to search from page cache for either xfs_seek_data() or xfs_seek_hole(). | 967 | * to search from page cache for xfs_seek_hole_data(). |
968 | */ | 968 | */ |
969 | enum { | 969 | enum { |
970 | HOLE_OFF = 0, | 970 | HOLE_OFF = 0, |
@@ -1021,7 +1021,7 @@ xfs_lookup_buffer_offset( | |||
1021 | /* | 1021 | /* |
1022 | * This routine is called to find out and return a data or hole offset | 1022 | * This routine is called to find out and return a data or hole offset |
1023 | * from the page cache for unwritten extents according to the desired | 1023 | * from the page cache for unwritten extents according to the desired |
1024 | * type for xfs_seek_data() or xfs_seek_hole(). | 1024 | * type for xfs_seek_hole_data(). |
1025 | * | 1025 | * |
1026 | * The argument offset is used to tell where we start to search from the | 1026 | * The argument offset is used to tell where we start to search from the |
1027 | * page cache. Map is used to figure out the end points of the range to | 1027 | * page cache. Map is used to figure out the end points of the range to |
@@ -1181,9 +1181,10 @@ out: | |||
1181 | } | 1181 | } |
1182 | 1182 | ||
1183 | STATIC loff_t | 1183 | STATIC loff_t |
1184 | xfs_seek_data( | 1184 | xfs_seek_hole_data( |
1185 | struct file *file, | 1185 | struct file *file, |
1186 | loff_t start) | 1186 | loff_t start, |
1187 | int whence) | ||
1187 | { | 1188 | { |
1188 | struct inode *inode = file->f_mapping->host; | 1189 | struct inode *inode = file->f_mapping->host; |
1189 | struct xfs_inode *ip = XFS_I(inode); | 1190 | struct xfs_inode *ip = XFS_I(inode); |
@@ -1195,6 +1196,9 @@ xfs_seek_data( | |||
1195 | uint lock; | 1196 | uint lock; |
1196 | int error; | 1197 | int error; |
1197 | 1198 | ||
1199 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
1200 | return -EIO; | ||
1201 | |||
1198 | lock = xfs_ilock_data_map_shared(ip); | 1202 | lock = xfs_ilock_data_map_shared(ip); |
1199 | 1203 | ||
1200 | isize = i_size_read(inode); | 1204 | isize = i_size_read(inode); |
@@ -1209,6 +1213,7 @@ xfs_seek_data( | |||
1209 | */ | 1213 | */ |
1210 | fsbno = XFS_B_TO_FSBT(mp, start); | 1214 | fsbno = XFS_B_TO_FSBT(mp, start); |
1211 | end = XFS_B_TO_FSB(mp, isize); | 1215 | end = XFS_B_TO_FSB(mp, isize); |
1216 | |||
1212 | for (;;) { | 1217 | for (;;) { |
1213 | struct xfs_bmbt_irec map[2]; | 1218 | struct xfs_bmbt_irec map[2]; |
1214 | int nmap = 2; | 1219 | int nmap = 2; |
@@ -1229,29 +1234,48 @@ xfs_seek_data( | |||
1229 | offset = max_t(loff_t, start, | 1234 | offset = max_t(loff_t, start, |
1230 | XFS_FSB_TO_B(mp, map[i].br_startoff)); | 1235 | XFS_FSB_TO_B(mp, map[i].br_startoff)); |
1231 | 1236 | ||
1232 | /* Landed in a data extent */ | 1237 | /* Landed in the hole we wanted? */ |
1233 | if (map[i].br_startblock == DELAYSTARTBLOCK || | 1238 | if (whence == SEEK_HOLE && |
1234 | (map[i].br_state == XFS_EXT_NORM && | 1239 | map[i].br_startblock == HOLESTARTBLOCK) |
1235 | !isnullstartblock(map[i].br_startblock))) | 1240 | goto out; |
1241 | |||
1242 | /* Landed in the data extent we wanted? */ | ||
1243 | if (whence == SEEK_DATA && | ||
1244 | (map[i].br_startblock == DELAYSTARTBLOCK || | ||
1245 | (map[i].br_state == XFS_EXT_NORM && | ||
1246 | !isnullstartblock(map[i].br_startblock)))) | ||
1236 | goto out; | 1247 | goto out; |
1237 | 1248 | ||
1238 | /* | 1249 | /* |
1239 | * Landed in an unwritten extent, try to search data | 1250 | * Landed in an unwritten extent, try to search |
1240 | * from page cache. | 1251 | * for hole or data from page cache. |
1241 | */ | 1252 | */ |
1242 | if (map[i].br_state == XFS_EXT_UNWRITTEN) { | 1253 | if (map[i].br_state == XFS_EXT_UNWRITTEN) { |
1243 | if (xfs_find_get_desired_pgoff(inode, &map[i], | 1254 | if (xfs_find_get_desired_pgoff(inode, &map[i], |
1244 | DATA_OFF, &offset)) | 1255 | whence == SEEK_HOLE ? HOLE_OFF : DATA_OFF, |
1256 | &offset)) | ||
1245 | goto out; | 1257 | goto out; |
1246 | } | 1258 | } |
1247 | } | 1259 | } |
1248 | 1260 | ||
1249 | /* | 1261 | /* |
1250 | * map[0] is hole or its an unwritten extent but | 1262 | * We only received one extent out of the two requested. This |
1251 | * without data in page cache. Probably means that | 1263 | * means we've hit EOF and didn't find what we are looking for. |
1252 | * we are reading after EOF if nothing in map[1]. | ||
1253 | */ | 1264 | */ |
1254 | if (nmap == 1) { | 1265 | if (nmap == 1) { |
1266 | /* | ||
1267 | * If we were looking for a hole, set offset to | ||
1268 | * the end of the file (i.e., there is an implicit | ||
1269 | * hole at the end of any file). | ||
1270 | */ | ||
1271 | if (whence == SEEK_HOLE) { | ||
1272 | offset = isize; | ||
1273 | break; | ||
1274 | } | ||
1275 | /* | ||
1276 | * If we were looking for data, it's nowhere to be found | ||
1277 | */ | ||
1278 | ASSERT(whence == SEEK_DATA); | ||
1255 | error = -ENXIO; | 1279 | error = -ENXIO; |
1256 | goto out_unlock; | 1280 | goto out_unlock; |
1257 | } | 1281 | } |
@@ -1260,125 +1284,30 @@ xfs_seek_data( | |||
1260 | 1284 | ||
1261 | /* | 1285 | /* |
1262 | * Nothing was found, proceed to the next round of search | 1286 | * Nothing was found, proceed to the next round of search |
1263 | * if reading offset not beyond or hit EOF. | 1287 | * if the next reading offset is not at or beyond EOF. |
1264 | */ | 1288 | */ |
1265 | fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; | 1289 | fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; |
1266 | start = XFS_FSB_TO_B(mp, fsbno); | 1290 | start = XFS_FSB_TO_B(mp, fsbno); |
1267 | if (start >= isize) { | 1291 | if (start >= isize) { |
1292 | if (whence == SEEK_HOLE) { | ||
1293 | offset = isize; | ||
1294 | break; | ||
1295 | } | ||
1296 | ASSERT(whence == SEEK_DATA); | ||
1268 | error = -ENXIO; | 1297 | error = -ENXIO; |
1269 | goto out_unlock; | 1298 | goto out_unlock; |
1270 | } | 1299 | } |
1271 | } | 1300 | } |
1272 | 1301 | ||
1273 | out: | 1302 | out: |
1274 | offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); | ||
1275 | |||
1276 | out_unlock: | ||
1277 | xfs_iunlock(ip, lock); | ||
1278 | |||
1279 | if (error) | ||
1280 | return error; | ||
1281 | return offset; | ||
1282 | } | ||
1283 | |||
1284 | STATIC loff_t | ||
1285 | xfs_seek_hole( | ||
1286 | struct file *file, | ||
1287 | loff_t start) | ||
1288 | { | ||
1289 | struct inode *inode = file->f_mapping->host; | ||
1290 | struct xfs_inode *ip = XFS_I(inode); | ||
1291 | struct xfs_mount *mp = ip->i_mount; | ||
1292 | loff_t uninitialized_var(offset); | ||
1293 | xfs_fsize_t isize; | ||
1294 | xfs_fileoff_t fsbno; | ||
1295 | xfs_filblks_t end; | ||
1296 | uint lock; | ||
1297 | int error; | ||
1298 | |||
1299 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
1300 | return -EIO; | ||
1301 | |||
1302 | lock = xfs_ilock_data_map_shared(ip); | ||
1303 | |||
1304 | isize = i_size_read(inode); | ||
1305 | if (start >= isize) { | ||
1306 | error = -ENXIO; | ||
1307 | goto out_unlock; | ||
1308 | } | ||
1309 | |||
1310 | fsbno = XFS_B_TO_FSBT(mp, start); | ||
1311 | end = XFS_B_TO_FSB(mp, isize); | ||
1312 | |||
1313 | for (;;) { | ||
1314 | struct xfs_bmbt_irec map[2]; | ||
1315 | int nmap = 2; | ||
1316 | unsigned int i; | ||
1317 | |||
1318 | error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap, | ||
1319 | XFS_BMAPI_ENTIRE); | ||
1320 | if (error) | ||
1321 | goto out_unlock; | ||
1322 | |||
1323 | /* No extents at given offset, must be beyond EOF */ | ||
1324 | if (nmap == 0) { | ||
1325 | error = -ENXIO; | ||
1326 | goto out_unlock; | ||
1327 | } | ||
1328 | |||
1329 | for (i = 0; i < nmap; i++) { | ||
1330 | offset = max_t(loff_t, start, | ||
1331 | XFS_FSB_TO_B(mp, map[i].br_startoff)); | ||
1332 | |||
1333 | /* Landed in a hole */ | ||
1334 | if (map[i].br_startblock == HOLESTARTBLOCK) | ||
1335 | goto out; | ||
1336 | |||
1337 | /* | ||
1338 | * Landed in an unwritten extent, try to search hole | ||
1339 | * from page cache. | ||
1340 | */ | ||
1341 | if (map[i].br_state == XFS_EXT_UNWRITTEN) { | ||
1342 | if (xfs_find_get_desired_pgoff(inode, &map[i], | ||
1343 | HOLE_OFF, &offset)) | ||
1344 | goto out; | ||
1345 | } | ||
1346 | } | ||
1347 | |||
1348 | /* | ||
1349 | * map[0] contains data or its unwritten but contains | ||
1350 | * data in page cache, probably means that we are | ||
1351 | * reading after EOF. We should fix offset to point | ||
1352 | * to the end of the file(i.e., there is an implicit | ||
1353 | * hole at the end of any file). | ||
1354 | */ | ||
1355 | if (nmap == 1) { | ||
1356 | offset = isize; | ||
1357 | break; | ||
1358 | } | ||
1359 | |||
1360 | ASSERT(i > 1); | ||
1361 | |||
1362 | /* | ||
1363 | * Both mappings contains data, proceed to the next round of | ||
1364 | * search if the current reading offset not beyond or hit EOF. | ||
1365 | */ | ||
1366 | fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; | ||
1367 | start = XFS_FSB_TO_B(mp, fsbno); | ||
1368 | if (start >= isize) { | ||
1369 | offset = isize; | ||
1370 | break; | ||
1371 | } | ||
1372 | } | ||
1373 | |||
1374 | out: | ||
1375 | /* | 1303 | /* |
1376 | * At this point, we must have found a hole. However, the returned | 1304 | * If at this point we have found the hole we wanted, the returned |
1377 | * offset may be bigger than the file size as it may be aligned to | 1305 | * offset may be bigger than the file size as it may be aligned to |
1378 | * page boundary for unwritten extents, we need to deal with this | 1306 | * page boundary for unwritten extents. We need to deal with this |
1379 | * situation in particular. | 1307 | * situation in particular. |
1380 | */ | 1308 | */ |
1381 | offset = min_t(loff_t, offset, isize); | 1309 | if (whence == SEEK_HOLE) |
1310 | offset = min_t(loff_t, offset, isize); | ||
1382 | offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); | 1311 | offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); |
1383 | 1312 | ||
1384 | out_unlock: | 1313 | out_unlock: |
@@ -1400,10 +1329,9 @@ xfs_file_llseek( | |||
1400 | case SEEK_CUR: | 1329 | case SEEK_CUR: |
1401 | case SEEK_SET: | 1330 | case SEEK_SET: |
1402 | return generic_file_llseek(file, offset, origin); | 1331 | return generic_file_llseek(file, offset, origin); |
1403 | case SEEK_DATA: | ||
1404 | return xfs_seek_data(file, offset); | ||
1405 | case SEEK_HOLE: | 1332 | case SEEK_HOLE: |
1406 | return xfs_seek_hole(file, offset); | 1333 | case SEEK_DATA: |
1334 | return xfs_seek_hole_data(file, offset, origin); | ||
1407 | default: | 1335 | default: |
1408 | return -EINVAL; | 1336 | return -EINVAL; |
1409 | } | 1337 | } |