Re: Introduce SEEK_DATA/SEEK_HOLE to XFS V5

Jeff Liu
2012-01-12T13:29:46Z

Hi Mark,

Thanks for your comments!

On 01/12/2012 05:07 AM, Mark Tinguely wrote:

>
> xfs_bmapi_read() returns the br_state == XFS_EXT_NORM for a hole.

Yes, this is key point I have missed before.

> There are a couple places that a hole can trigger a data test.
> BTW, I could not generate a large enough hole that xfs_bmapi_read()
> would return as more than one hole entry, so I will ignore those
> situations and just list the couple places that a hole may be match
> a data rule:
>
> in xfs_seek_data():
> + /*
> + * Landed in an unwritten extent, try to find out the data
> + * buffer offset from page cache firstly. If nothing was
> + * found, treat it as a hole, and skip to check the next
> + * extent, something just like above.
> + */
> + if (map[0].br_state == XFS_EXT_UNWRITTEN) {
> + if (xfs_has_unwritten_buffer(inode, &map[0],
> + PAGECACHE_TAG_DIRTY,
> + &offset) ||
> + xfs_has_unwritten_buffer(inode, &map[0],
> + PAGECACHE_TAG_WRITEBACK,
> + &offset)) {
> + offset = max_t(loff_t, seekoff, offset);
> + break;
> + }
> +
> + /* No data extent at the given offset */
> + if (nmap == 1) {
> + error = ENXIO;
> + break;
> + }
> +
> + if (map[1].br_state == XFS_EXT_NORM ||
> ^^^ could be a hole and not data^^^
>
> I think you need to add back the br_startblock test:
>
> + if ((map[1].br_state == XFS_EXT_NORM &&
> + map[1].br_startblock != HOLESTARTBLOCK) ||

Ok, I'll add !isnullstartblock() test for normal extents test.

>
>
> in xfs_seek_hole():
> + /*
> + * Landed in a delay allocated extent or a real data extent,
> + * if the next extent is landed in a hole or in an unwritten
> + * extent but without data committed in the page cache, return
> + * its offset. If the next extent has dirty data in page cache,
> + * but its offset starts past both the start block of the map
> + * and the seek offset, it still be a hole.
> + */
> + if (map[0].br_startblock == DELAYSTARTBLOCK ||
> + map[0].br_state == XFS_EXT_NORM) {
> ^^^ could be a hole ^^^
>
> and this only matters because this test is checked before the next test:
>
> +
> + /* Landed in a hole, its fine to return */
> + if (map[0].br_startblock == HOLESTARTBLOCK) {
> + offset = max_t(loff_t, seekoff,
> + XFS_FSB_TO_B(mp, map[0].br_startoff));
> + break;
> + }
>
>
>
> Switching the order of these two tests would return the immediate offset
> starting a hole seek at the offset of a hole.

looks this issue is caused by missing hole test for extents at
XFS_EXT_NORM state. I'll fix them later.

Thanks,
-Jeff

>
>
> None of these conditions will result in data corruption, only earlier
> detection of a hole.