STATIC loff_t xfs_seek_data( struct file *file, loff_t start) { struct inode *inode = file->f_mapping->host; struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; loff_t uninitialized_var(offset); xfs_fsize_t isize; xfs_fileoff_t fsbno; xfs_filblks_t end; uint lock; int error; lock = xfs_ilock_data_map_shared(ip); isize = i_size_read(inode); if (start >= isize) { error = ENXIO; goto out_unlock; } /* * Try to read extents from the first block indicated * by fsbno to the end block of the file. */ fsbno = XFS_B_TO_FSBT(mp, start); end = XFS_B_TO_FSB(mp, isize); for (;;) { struct xfs_bmbt_irec map[2]; int nmap = 2; unsigned int i; error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap, XFS_BMAPI_ENTIRE); if (error) goto out_unlock; /* No extents at given offset, must be beyond EOF */ if (nmap == 0) { error = ENXIO; goto out_unlock; } for (i = 0; i < nmap; i++) { offset = max_t(loff_t, start, XFS_FSB_TO_B(mp, map[i].br_startoff)); /* Landed in a data extent */ if (map[i].br_startblock == DELAYSTARTBLOCK || (map[i].br_state == XFS_EXT_NORM && !isnullstartblock(map[i].br_startblock))) goto out; /* * Landed in an unwritten extent, try to search data * from page cache. */ if (map[i].br_state == XFS_EXT_UNWRITTEN) { if (xfs_find_get_desired_pgoff(inode, &map[i], DATA_OFF, &offset)) goto out; } } /* * map[0] is hole or its an unwritten extent but * without data in page cache. Probably means that * we are reading after EOF if nothing in map[1]. */ if (nmap == 1) { error = ENXIO; goto out_unlock; } ASSERT(i > 1); /* * Nothing was found, proceed to the next round of search * if reading offset not beyond or hit EOF. */ fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; start = XFS_FSB_TO_B(mp, fsbno); if (start >= isize) { error = ENXIO; goto out_unlock; } } out: offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); out_unlock: xfs_iunlock(ip, lock); if (error) return -error; return offset; }
STATIC loff_t xfs_seek_hole( struct file *file, loff_t start) { struct inode *inode = file->f_mapping->host; struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; loff_t uninitialized_var(offset); xfs_fsize_t isize; xfs_fileoff_t fsbno; xfs_filblks_t end; uint lock; int error; if (XFS_FORCED_SHUTDOWN(mp)) return -XFS_ERROR(EIO); lock = xfs_ilock_data_map_shared(ip); isize = i_size_read(inode); if (start >= isize) { error = ENXIO; goto out_unlock; } fsbno = XFS_B_TO_FSBT(mp, start); end = XFS_B_TO_FSB(mp, isize); for (;;) { struct xfs_bmbt_irec map[2]; int nmap = 2; unsigned int i; error = xfs_bmapi_read(ip, fsbno, end - fsbno, map, &nmap, XFS_BMAPI_ENTIRE); if (error) goto out_unlock; /* No extents at given offset, must be beyond EOF */ if (nmap == 0) { error = ENXIO; goto out_unlock; } for (i = 0; i < nmap; i++) { offset = max_t(loff_t, start, XFS_FSB_TO_B(mp, map[i].br_startoff)); /* Landed in a hole */ if (map[i].br_startblock == HOLESTARTBLOCK) goto out; /* * Landed in an unwritten extent, try to search hole * from page cache. */ if (map[i].br_state == XFS_EXT_UNWRITTEN) { if (xfs_find_get_desired_pgoff(inode, &map[i], HOLE_OFF, &offset)) goto out; } } /* * map[0] contains data or its unwritten but contains * data in page cache, probably means that we are * reading after EOF. We should fix offset to point * to the end of the file(i.e., there is an implicit * hole at the end of any file). */ if (nmap == 1) { offset = isize; break; } ASSERT(i > 1); /* * Both mappings contains data, proceed to the next round of * search if the current reading offset not beyond or hit EOF. */ fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; start = XFS_FSB_TO_B(mp, fsbno); if (start >= isize) { offset = isize; break; } } out: /* * At this point, we must have found a hole. However, the returned * offset may be bigger than the file size as it may be aligned to * page boundary for unwritten extents, we need to deal with this * situation in particular. */ offset = min_t(loff_t, offset, isize); offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); out_unlock: xfs_iunlock(ip, lock); if (error) return -error; return offset; }
/* * caller must lock inode with xfs_ilock_data_map_shared, * can we craft an appropriate ASSERT? * * end is because the VFS-level lseek interface is defined such that any * offset past i_size shall return -ENXIO, but we use this for quota code * which does not maintain i_size, and we want to SEEK_DATA past i_size. */ loff_t __xfs_seek_hole_data( struct inode *inode, loff_t start, loff_t end, int whence) { struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; loff_t uninitialized_var(offset); xfs_fileoff_t fsbno; xfs_filblks_t lastbno; int error; if (start >= end) { error = -ENXIO; goto out_error; } /* * Try to read extents from the first block indicated * by fsbno to the end block of the file. */ fsbno = XFS_B_TO_FSBT(mp, start); lastbno = XFS_B_TO_FSB(mp, end); for (;;) { struct xfs_bmbt_irec map[2]; int nmap = 2; unsigned int i; error = xfs_bmapi_read(ip, fsbno, lastbno - fsbno, map, &nmap, XFS_BMAPI_ENTIRE); if (error) goto out_error; /* No extents at given offset, must be beyond EOF */ if (nmap == 0) { error = -ENXIO; goto out_error; } for (i = 0; i < nmap; i++) { offset = max_t(loff_t, start, XFS_FSB_TO_B(mp, map[i].br_startoff)); /* Landed in the hole we wanted? */ if (whence == SEEK_HOLE && map[i].br_startblock == HOLESTARTBLOCK) goto out; /* Landed in the data extent we wanted? */ if (whence == SEEK_DATA && (map[i].br_startblock == DELAYSTARTBLOCK || (map[i].br_state == XFS_EXT_NORM && !isnullstartblock(map[i].br_startblock)))) goto out; /* * Landed in an unwritten extent, try to search * for hole or data from page cache. */ if (map[i].br_state == XFS_EXT_UNWRITTEN) { if (xfs_find_get_desired_pgoff(inode, &map[i], whence == SEEK_HOLE ? HOLE_OFF : DATA_OFF, &offset)) goto out; } } /* * We only received one extent out of the two requested. This * means we've hit EOF and didn't find what we are looking for. */ if (nmap == 1) { /* * If we were looking for a hole, set offset to * the end of the file (i.e., there is an implicit * hole at the end of any file). */ if (whence == SEEK_HOLE) { offset = end; break; } /* * If we were looking for data, it's nowhere to be found */ ASSERT(whence == SEEK_DATA); error = -ENXIO; goto out_error; } ASSERT(i > 1); /* * Nothing was found, proceed to the next round of search * if the next reading offset is not at or beyond EOF. */ fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; start = XFS_FSB_TO_B(mp, fsbno); if (start >= end) { if (whence == SEEK_HOLE) { offset = end; break; } ASSERT(whence == SEEK_DATA); error = -ENXIO; goto out_error; } } out: /* * If at this point we have found the hole we wanted, the returned * offset may be bigger than the file size as it may be aligned to * page boundary for unwritten extents. We need to deal with this * situation in particular. */ if (whence == SEEK_HOLE) offset = min_t(loff_t, offset, end); return offset; out_error: return error; }