|
@@ -453,254 +453,3 @@ out_error_or_again:
|
|
|
return error;
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * This is a wrapper routine around the xfs_ilock() routine
|
|
|
- * used to centralize some grungy code. It is used in places
|
|
|
- * that wish to lock the inode solely for reading the extents.
|
|
|
- * The reason these places can't just call xfs_ilock(SHARED)
|
|
|
- * is that the inode lock also guards to bringing in of the
|
|
|
- * extents from disk for a file in b-tree format. If the inode
|
|
|
- * is in b-tree format, then we need to lock the inode exclusively
|
|
|
- * until the extents are read in. Locking it exclusively all
|
|
|
- * the time would limit our parallelism unnecessarily, though.
|
|
|
- * What we do instead is check to see if the extents have been
|
|
|
- * read in yet, and only lock the inode exclusively if they
|
|
|
- * have not.
|
|
|
- *
|
|
|
- * The function returns a value which should be given to the
|
|
|
- * corresponding xfs_iunlock_map_shared(). This value is
|
|
|
- * the mode in which the lock was actually taken.
|
|
|
- */
|
|
|
-uint
|
|
|
-xfs_ilock_map_shared(
|
|
|
- xfs_inode_t *ip)
|
|
|
-{
|
|
|
- uint lock_mode;
|
|
|
-
|
|
|
- if ((ip->i_d.di_format == XFS_DINODE_FMT_BTREE) &&
|
|
|
- ((ip->i_df.if_flags & XFS_IFEXTENTS) == 0)) {
|
|
|
- lock_mode = XFS_ILOCK_EXCL;
|
|
|
- } else {
|
|
|
- lock_mode = XFS_ILOCK_SHARED;
|
|
|
- }
|
|
|
-
|
|
|
- xfs_ilock(ip, lock_mode);
|
|
|
-
|
|
|
- return lock_mode;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * This is simply the unlock routine to go with xfs_ilock_map_shared().
|
|
|
- * All it does is call xfs_iunlock() with the given lock_mode.
|
|
|
- */
|
|
|
-void
|
|
|
-xfs_iunlock_map_shared(
|
|
|
- xfs_inode_t *ip,
|
|
|
- unsigned int lock_mode)
|
|
|
-{
|
|
|
- xfs_iunlock(ip, lock_mode);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * The xfs inode contains 2 locks: a multi-reader lock called the
|
|
|
- * i_iolock and a multi-reader lock called the i_lock. This routine
|
|
|
- * allows either or both of the locks to be obtained.
|
|
|
- *
|
|
|
- * The 2 locks should always be ordered so that the IO lock is
|
|
|
- * obtained first in order to prevent deadlock.
|
|
|
- *
|
|
|
- * ip -- the inode being locked
|
|
|
- * lock_flags -- this parameter indicates the inode's locks
|
|
|
- * to be locked. It can be:
|
|
|
- * XFS_IOLOCK_SHARED,
|
|
|
- * XFS_IOLOCK_EXCL,
|
|
|
- * XFS_ILOCK_SHARED,
|
|
|
- * XFS_ILOCK_EXCL,
|
|
|
- * XFS_IOLOCK_SHARED | XFS_ILOCK_SHARED,
|
|
|
- * XFS_IOLOCK_SHARED | XFS_ILOCK_EXCL,
|
|
|
- * XFS_IOLOCK_EXCL | XFS_ILOCK_SHARED,
|
|
|
- * XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL
|
|
|
- */
|
|
|
-void
|
|
|
-xfs_ilock(
|
|
|
- xfs_inode_t *ip,
|
|
|
- uint lock_flags)
|
|
|
-{
|
|
|
- /*
|
|
|
- * You can't set both SHARED and EXCL for the same lock,
|
|
|
- * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
|
|
|
- * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
|
|
|
- */
|
|
|
- ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
|
|
|
- (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
|
|
|
- ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
|
|
|
- (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
|
|
|
- ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
|
|
|
-
|
|
|
- if (lock_flags & XFS_IOLOCK_EXCL)
|
|
|
- mrupdate_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
|
|
|
- else if (lock_flags & XFS_IOLOCK_SHARED)
|
|
|
- mraccess_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
|
|
|
-
|
|
|
- if (lock_flags & XFS_ILOCK_EXCL)
|
|
|
- mrupdate_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
|
|
|
- else if (lock_flags & XFS_ILOCK_SHARED)
|
|
|
- mraccess_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
|
|
|
-
|
|
|
- trace_xfs_ilock(ip, lock_flags, _RET_IP_);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * This is just like xfs_ilock(), except that the caller
|
|
|
- * is guaranteed not to sleep. It returns 1 if it gets
|
|
|
- * the requested locks and 0 otherwise. If the IO lock is
|
|
|
- * obtained but the inode lock cannot be, then the IO lock
|
|
|
- * is dropped before returning.
|
|
|
- *
|
|
|
- * ip -- the inode being locked
|
|
|
- * lock_flags -- this parameter indicates the inode's locks to be
|
|
|
- * to be locked. See the comment for xfs_ilock() for a list
|
|
|
- * of valid values.
|
|
|
- */
|
|
|
-int
|
|
|
-xfs_ilock_nowait(
|
|
|
- xfs_inode_t *ip,
|
|
|
- uint lock_flags)
|
|
|
-{
|
|
|
- /*
|
|
|
- * You can't set both SHARED and EXCL for the same lock,
|
|
|
- * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
|
|
|
- * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
|
|
|
- */
|
|
|
- ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
|
|
|
- (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
|
|
|
- ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
|
|
|
- (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
|
|
|
- ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
|
|
|
-
|
|
|
- if (lock_flags & XFS_IOLOCK_EXCL) {
|
|
|
- if (!mrtryupdate(&ip->i_iolock))
|
|
|
- goto out;
|
|
|
- } else if (lock_flags & XFS_IOLOCK_SHARED) {
|
|
|
- if (!mrtryaccess(&ip->i_iolock))
|
|
|
- goto out;
|
|
|
- }
|
|
|
- if (lock_flags & XFS_ILOCK_EXCL) {
|
|
|
- if (!mrtryupdate(&ip->i_lock))
|
|
|
- goto out_undo_iolock;
|
|
|
- } else if (lock_flags & XFS_ILOCK_SHARED) {
|
|
|
- if (!mrtryaccess(&ip->i_lock))
|
|
|
- goto out_undo_iolock;
|
|
|
- }
|
|
|
- trace_xfs_ilock_nowait(ip, lock_flags, _RET_IP_);
|
|
|
- return 1;
|
|
|
-
|
|
|
- out_undo_iolock:
|
|
|
- if (lock_flags & XFS_IOLOCK_EXCL)
|
|
|
- mrunlock_excl(&ip->i_iolock);
|
|
|
- else if (lock_flags & XFS_IOLOCK_SHARED)
|
|
|
- mrunlock_shared(&ip->i_iolock);
|
|
|
- out:
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * xfs_iunlock() is used to drop the inode locks acquired with
|
|
|
- * xfs_ilock() and xfs_ilock_nowait(). The caller must pass
|
|
|
- * in the flags given to xfs_ilock() or xfs_ilock_nowait() so
|
|
|
- * that we know which locks to drop.
|
|
|
- *
|
|
|
- * ip -- the inode being unlocked
|
|
|
- * lock_flags -- this parameter indicates the inode's locks to be
|
|
|
- * to be unlocked. See the comment for xfs_ilock() for a list
|
|
|
- * of valid values for this parameter.
|
|
|
- *
|
|
|
- */
|
|
|
-void
|
|
|
-xfs_iunlock(
|
|
|
- xfs_inode_t *ip,
|
|
|
- uint lock_flags)
|
|
|
-{
|
|
|
- /*
|
|
|
- * You can't set both SHARED and EXCL for the same lock,
|
|
|
- * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
|
|
|
- * and XFS_ILOCK_EXCL are valid values to set in lock_flags.
|
|
|
- */
|
|
|
- ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) !=
|
|
|
- (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
|
|
|
- ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) !=
|
|
|
- (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
|
|
|
- ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
|
|
|
- ASSERT(lock_flags != 0);
|
|
|
-
|
|
|
- if (lock_flags & XFS_IOLOCK_EXCL)
|
|
|
- mrunlock_excl(&ip->i_iolock);
|
|
|
- else if (lock_flags & XFS_IOLOCK_SHARED)
|
|
|
- mrunlock_shared(&ip->i_iolock);
|
|
|
-
|
|
|
- if (lock_flags & XFS_ILOCK_EXCL)
|
|
|
- mrunlock_excl(&ip->i_lock);
|
|
|
- else if (lock_flags & XFS_ILOCK_SHARED)
|
|
|
- mrunlock_shared(&ip->i_lock);
|
|
|
-
|
|
|
- trace_xfs_iunlock(ip, lock_flags, _RET_IP_);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * give up write locks. the i/o lock cannot be held nested
|
|
|
- * if it is being demoted.
|
|
|
- */
|
|
|
-void
|
|
|
-xfs_ilock_demote(
|
|
|
- xfs_inode_t *ip,
|
|
|
- uint lock_flags)
|
|
|
-{
|
|
|
- ASSERT(lock_flags & (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL));
|
|
|
- ASSERT((lock_flags & ~(XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)) == 0);
|
|
|
-
|
|
|
- if (lock_flags & XFS_ILOCK_EXCL)
|
|
|
- mrdemote(&ip->i_lock);
|
|
|
- if (lock_flags & XFS_IOLOCK_EXCL)
|
|
|
- mrdemote(&ip->i_iolock);
|
|
|
-
|
|
|
- trace_xfs_ilock_demote(ip, lock_flags, _RET_IP_);
|
|
|
-}
|
|
|
-
|
|
|
-#ifdef DEBUG
|
|
|
-int
|
|
|
-xfs_isilocked(
|
|
|
- xfs_inode_t *ip,
|
|
|
- uint lock_flags)
|
|
|
-{
|
|
|
- if (lock_flags & (XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)) {
|
|
|
- if (!(lock_flags & XFS_ILOCK_SHARED))
|
|
|
- return !!ip->i_lock.mr_writer;
|
|
|
- return rwsem_is_locked(&ip->i_lock.mr_lock);
|
|
|
- }
|
|
|
-
|
|
|
- if (lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) {
|
|
|
- if (!(lock_flags & XFS_IOLOCK_SHARED))
|
|
|
- return !!ip->i_iolock.mr_writer;
|
|
|
- return rwsem_is_locked(&ip->i_iolock.mr_lock);
|
|
|
- }
|
|
|
-
|
|
|
- ASSERT(0);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-void
|
|
|
-__xfs_iflock(
|
|
|
- struct xfs_inode *ip)
|
|
|
-{
|
|
|
- wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IFLOCK_BIT);
|
|
|
- DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IFLOCK_BIT);
|
|
|
-
|
|
|
- do {
|
|
|
- prepare_to_wait_exclusive(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
|
|
|
- if (xfs_isiflocked(ip))
|
|
|
- io_schedule();
|
|
|
- } while (!xfs_iflock_nowait(ip));
|
|
|
-
|
|
|
- finish_wait(wq, &wait.wait);
|
|
|
-}
|