On Mon, Feb 13, 2012 at 12:48:06PM -0500, Christoph Hellwig wrote:
> On Thu, Feb 09, 2012 at 05:09:20PM +1100, Dave Chinner wrote:
> > if (create) {
> > - lockmode = XFS_ILOCK_EXCL;
> > + /*
> > + * For direct IO, we lock in shared mode so that write
> > + * operations that don't require allocation can occur
> > + * concurrently. The ilock has to be dropped over the allocation
> > + * transaction reservation, so the only thing the ilock is
> > + * providing here is modification exclusion. i.e. there is no
> > + * need to hold the lock exclusive.
> > + *
> > + * For buffered IO, if we need to do delayed allocation then
> > + * hold the ilock exclusive so that the lookup and delalloc
> > + * reservation is atomic.
> > + */
> > + if (direct)
> > + lockmode = XFS_ILOCK_SHARED;
> > + else
> > + lockmode = XFS_ILOCK_EXCL;
> > xfs_ilock(ip, lockmode);
> > } else {
> > lockmode = xfs_ilock_map_shared(ip);
>
> We'll actually need to use xfs_ilock_map_shared for the the direct
> create case too, to make sure we have the exclusive lock when we first
> read the extent list in.
Good point.
> Also xfs_qm_dqattach_locked really wants the inode locked exclusively,
> which your current code doesn't handle.
I didn't consider quotas. Looking at the code, it seems that it
wants an exclusive lock purely for ensuring there are no races
attaching the dquots to the inode. The xfs_dqget() code can actually
drop and regain the ilock, so I can't see that it is for any other
specific purpose.
I think that we could probably attach the dquot after dropping the
shared lock but before starting the transaction via a call to
xfs_qm_dqattach() which handles the locking internally. It does mean
an extra lock traversal for the quota case, but it still allows the
initial mapping to be done with a shared lock....
Cheers,
Dave.
--
Dave Chinner
david@xxxxxxxxxxxxx
|