Message ID | 20230214055114.4141947-3-david@fromorbit.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | xfs, iomap: fix writeback failure handling | expand |
On Tue, Feb 14, 2023 at 04:51:13PM +1100, Dave Chinner wrote: > index 958e4bb2e51e..fb718a5825d5 100644 > --- a/fs/xfs/libxfs/xfs_bmap.c > +++ b/fs/xfs/libxfs/xfs_bmap.c > @@ -4553,8 +4553,12 @@ xfs_bmapi_convert_delalloc( > * should only happen for the COW fork, where another thread > * might have moved the extent to the data fork in the meantime. > */ > - WARN_ON_ONCE(whichfork != XFS_COW_FORK); > - error = -EAGAIN; > + if (whichfork != XFS_COW_FORK) { > + xfs_bmap_mark_sick(ip, whichfork); > + error = -EFSCORRUPTED; > + } else { > + error = -EAGAIN; > + } The comment above should probably be expanded a bit on what this means for a non-cow fork extent and how we'll handle it later. > + if (error) { > + if ((error == -EFSCORRUPTED) || (error == -EFSBADCRC)) Nit: no need for the inner braces. > > + /* > + * If the inode is sick, then it might have delalloc extents > + * within EOF that we were unable to convert. We have to punch > + * them out here to release the reservation as there is no > + * longer any data to write back into the delalloc range now. > + */ > + if (!xfs_inode_is_healthy(ip)) > + xfs_bmap_punch_delalloc_range(ip, 0, > + i_size_read(VFS_I(ip))); Is i_size_read the right check here? The delalloc extent could extend past i_size if i_size is not block aligned. Can't we just simply pass (xfs_off_t)-1 here?
On Tue, Feb 14, 2023 at 12:13:19AM -0800, Christoph Hellwig wrote: > On Tue, Feb 14, 2023 at 04:51:13PM +1100, Dave Chinner wrote: > > index 958e4bb2e51e..fb718a5825d5 100644 > > --- a/fs/xfs/libxfs/xfs_bmap.c > > +++ b/fs/xfs/libxfs/xfs_bmap.c > > @@ -4553,8 +4553,12 @@ xfs_bmapi_convert_delalloc( > > * should only happen for the COW fork, where another thread > > * might have moved the extent to the data fork in the meantime. > > */ > > - WARN_ON_ONCE(whichfork != XFS_COW_FORK); > > - error = -EAGAIN; > > + if (whichfork != XFS_COW_FORK) { > > + xfs_bmap_mark_sick(ip, whichfork); > > + error = -EFSCORRUPTED; > > + } else { > > + error = -EAGAIN; > > + } > > The comment above should probably be expanded a bit on what this means > for a non-cow fork extent and how we'll handle it later. > > > + if (error) { > > + if ((error == -EFSCORRUPTED) || (error == -EFSBADCRC)) > > Nit: no need for the inner braces. > > > > > + /* > > + * If the inode is sick, then it might have delalloc extents > > + * within EOF that we were unable to convert. We have to punch > > + * them out here to release the reservation as there is no > > + * longer any data to write back into the delalloc range now. > > + */ > > + if (!xfs_inode_is_healthy(ip)) > > + xfs_bmap_punch_delalloc_range(ip, 0, > > + i_size_read(VFS_I(ip))); > > Is i_size_read the right check here? The delalloc extent could extend > past i_size if i_size is not block aligned. Can't we just simply pass > (xfs_off_t)-1 here? Probably, we just killed all the delalloc blocks beyond eof via xfs_free_eofblocks() in the line above this, so I didn't seem necessary to try to punch blocks beyond EOF for this case. Easy enough to do to be safe, just need a comment update to go with it.... Cheers, Dave. > >
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 958e4bb2e51e..fb718a5825d5 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -4553,8 +4553,12 @@ xfs_bmapi_convert_delalloc( * should only happen for the COW fork, where another thread * might have moved the extent to the data fork in the meantime. */ - WARN_ON_ONCE(whichfork != XFS_COW_FORK); - error = -EAGAIN; + if (whichfork != XFS_COW_FORK) { + xfs_bmap_mark_sick(ip, whichfork); + error = -EFSCORRUPTED; + } else { + error = -EAGAIN; + } goto out_trans_cancel; } @@ -4598,8 +4602,11 @@ xfs_bmapi_convert_delalloc( bma.prev.br_startoff = NULLFILEOFF; error = xfs_bmapi_allocate(&bma); - if (error) + if (error) { + if ((error == -EFSCORRUPTED) || (error == -EFSBADCRC)) + xfs_bmap_mark_sick(ip, whichfork); goto out_finish; + } error = -ENOSPC; if (WARN_ON_ONCE(bma.blkno == NULLFSBLOCK)) diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index ddeaccc04aec..4354b6639dec 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -24,6 +24,7 @@ #include "xfs_ialloc.h" #include "xfs_ag.h" #include "xfs_log_priv.h" +#include "xfs_health.h" #include <linux/iversion.h> @@ -1810,7 +1811,8 @@ xfs_inodegc_set_reclaimable( struct xfs_mount *mp = ip->i_mount; struct xfs_perag *pag; - if (!xfs_is_shutdown(mp) && ip->i_delayed_blks) { + if (ip->i_delayed_blks && xfs_inode_is_healthy(ip) && + !xfs_is_shutdown(mp)) { xfs_check_delalloc(ip, XFS_DATA_FORK); xfs_check_delalloc(ip, XFS_COW_FORK); ASSERT(0); diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index d354ea2b74f9..06f1229ef628 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -37,6 +37,7 @@ #include "xfs_reflink.h" #include "xfs_ag.h" #include "xfs_log_priv.h" +#include "xfs_health.h" struct kmem_cache *xfs_inode_cache; @@ -1738,6 +1739,15 @@ xfs_inactive( if (xfs_can_free_eofblocks(ip, true)) xfs_free_eofblocks(ip); + /* + * If the inode is sick, then it might have delalloc extents + * within EOF that we were unable to convert. We have to punch + * them out here to release the reservation as there is no + * longer any data to write back into the delalloc range now. + */ + if (!xfs_inode_is_healthy(ip)) + xfs_bmap_punch_delalloc_range(ip, 0, + i_size_read(VFS_I(ip))); goto out; }