Re: [PATCH 11/11] xfs: flush speculative space allocations when we run out of space

Brian Foster
2021-01-25T23:51:14Z

On Mon, Jan 25, 2021 at 12:02:16PM -0800, Darrick J. Wong wrote:
> On Sun, Jan 24, 2021 at 09:48:16AM +0000, Christoph Hellwig wrote:
> > > +retry:
> > > /*
> > > * Allocate the handle before we do our freeze accounting and setting up
> > > * GFP_NOFS allocation context so that we avoid lockdep false positives
> > > @@ -285,6 +289,22 @@ xfs_trans_alloc(
> > > tp->t_firstblock = NULLFSBLOCK;
> > >
> > > error = xfs_trans_reserve(tp, resp, blocks, rtextents);
> > > + if (error == -ENOSPC && tries > 0) {
> > > + xfs_trans_cancel(tp);
> > > +
> > > + /*
> > > + * We weren't able to reserve enough space for the transaction.
> > > + * Flush the other speculative space allocations to free space.
> > > + * Do not perform a synchronous scan because callers can hold
> > > + * other locks.
> > > + */
> > > + error = xfs_blockgc_free_space(mp, NULL);
> > > + if (error)
> > > + return error;
> > > +
> > > + tries--;
> > > + goto retry;
> > > + }
> > > if (error) {
> > > xfs_trans_cancel(tp);
> > > return error;
> >
> > Why do we need to restart the whole function? A failing
> > xfs_trans_reserve should restore tp to its initial state, and keeping
> > the SB_FREEZE_FS counter increased also doesn't look harmful as far as
> > I can tell. So why not:
> >
> > error = xfs_trans_reserve(tp, resp, blocks, rtextents);
> > if (error == -ENOSPC) {
> > /*
> > * We weren't able to reserve enough space for the transaction.
> > * Flush the other speculative space allocations to free space.
> > * Do not perform a synchronous scan because callers can hold
> > * other locks.
> > */
> > error = xfs_blockgc_free_space(mp, NULL);
>
> xfs_blockgc_free_space runs the blockgc scan directly, which means that
> it creates transactions to free blocks. Since we can't have nested
> transactions, we have to drop tp here.
>

Technically, I don't think it's a problem to hold a transaction memory
allocation (and superblock write access?) while diving into the scanning
mechanism. BTW, this also looks like a landmine passing a NULL eofb into
the xfs_blockgc_free_space() tracepoint.

Brian

> --D
>
> > if (error)
> > return error;
> > error = xfs_trans_reserve(tp, resp, blocks, rtextents);
> > }
> > if (error) {
> > xfs_trans_cancel(tp);
> > return error;
> >
> > ?
>