aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Sandeen <sandeen@sandeen.net>2014-09-08 21:56:48 -0400
committerDave Chinner <david@fromorbit.com>2014-09-08 21:56:48 -0400
commit49c69591c80648c14ff87525e97ee6ebe3a343cb (patch)
tree55d217ff0eb9ec2f152ba5a980fbf92d93fff091
parent2e2271787419a12496bf5da5c3028a9c73c9697f (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.c172
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 */
969enum { 969enum {
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
1183STATIC loff_t 1183STATIC loff_t
1184xfs_seek_data( 1184xfs_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
1273out: 1302out:
1274 offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
1275
1276out_unlock:
1277 xfs_iunlock(ip, lock);
1278
1279 if (error)
1280 return error;
1281 return offset;
1282}
1283
1284STATIC loff_t
1285xfs_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
1374out:
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
1384out_unlock: 1313out_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 }