xfs: release new dquot buffer on defer_finish error
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 4 May 2018 22:30:19 +0000 (15:30 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Thu, 10 May 2018 15:56:47 +0000 (08:56 -0700)
commit7b6b50f55c1064e619f2da0696ed99f9db10b960
tree141b3a966adcb0249c9f81d7c217a6c53fdf932e
parent84ca484ecf2f8e1dc3afddc895cb9b62c531db49
xfs: release new dquot buffer on defer_finish error

In commit efa092f3d4c6 "[XFS] Fixes a bug in the quota code when
allocating a new dquot record", we allocate a new dquot block, grab a
buffer to initialize it, and return the locked initialized dquot buffer
to the caller for further in-core dquot initialization.  Unfortunately,
if the _bmap_finish errored out, _qm_dqalloc would also error out
without bothering to free the (locked) buffer.  Leaking a locked buffer
caused hangs in generic/388 when quotas are enabled.

Furthermore, the _bmap_finish -> _defer_finish conversion in
310a75a3c6c747 ("xfs: change xfs_bmap_{finish,cancel,init,free} ->
xfs_defer_*") failed to observe that the buffer was held going into
_defer_finish and therefore failed to notice that the buffer lock is
/not/ maintained afterwards.  Now that we can bjoin a buffer to a
defer_ops, use this mechanism to ensure that the buffer stays locked
across the _defer_finish.  Release the holds and locks on the buffer as
appropriate if we have to error out.

There is a subtlety here for the caller in that the buffer emerges
locked and held to the transaction, so if the _trans_commit fails we
have to release the buffer explicitly.  This fixes the unmount hang
in generic/388 when quotas are enabled.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
fs/xfs/xfs_dquot.c