On Fri, Feb 28, 2020 at 6:10 PM Darrick J. Wong <darrick.wong@xxxxxxxxxx> wrote: > > On Thu, Feb 27, 2020 at 09:36:33PM +0100, Pavel Reichl wrote: > > Refactor xfs_isilocked() to use newly introduced __xfs_rwsem_islocked(). > > __xfs_rwsem_islocked() is a helper function which encapsulates checking > > state of rw_semaphores hold by inode. > > > > Signed-off-by: Pavel Reichl <preichl@xxxxxxxxxx> > > Suggested-by: Dave Chinner <dchinner@xxxxxxxxxx> > > Suggested-by: Eric Sandeen <sandeen@xxxxxxxxxx> > > --- > > Changes from V5: > > Drop shared flag from __xfs_rwsem_islocked() > > > > > > fs/xfs/xfs_inode.c | 42 ++++++++++++++++++++++++++---------------- > > fs/xfs/xfs_inode.h | 2 +- > > 2 files changed, 27 insertions(+), 17 deletions(-) > > > > diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c > > index c5077e6326c7..4faf7827717b 100644 > > --- a/fs/xfs/xfs_inode.c > > +++ b/fs/xfs/xfs_inode.c > > @@ -345,32 +345,42 @@ xfs_ilock_demote( > > } > > > > #if defined(DEBUG) || defined(XFS_WARN) > > -int > > +static inline bool > > +__xfs_rwsem_islocked( > > + struct rw_semaphore *rwsem, > > + bool excl) > > +{ > > + if (!rwsem_is_locked(rwsem)) > > + return false; > > So, uh, I finally made the time to dig through what exactly lockdep > provides as far as testing functions, and came up with the following > truth table for the old xfs_isilocked behavior w.r.t. IOLOCK: Thank you for doing that and I'm sorry that I'm replying with such a delay. > > (nolockdep corresponds to debug_locks == 0) > > RWSEM STATE PARAMETERS TO XFS_ISILOCKED: > SHARED EXCL SHARED | EXCL > readlocked y n y > writelocked y y y > unlocked n n n > nolockdep readlocked y y y > nolockdep writelocked y y y > nolockdep unlocked n y n > > Note that EXCL × nolockdep_unlocked returns an incorrect result, but > because we only use it with ASSERTs there haven't been any failures > reported. > > And here's your new version: > > readlocked y y y > writelocked y n n > unlocked n n n > nolockdep readlocked y y y > nolockdep writelocked y y y > nolockdep unlocked n n n > > Thanks for fixing the false positive that I mentioned above. > > > + > > + if (debug_locks && excl) > > + return lockdep_is_held_type(rwsem, 1); > > This is wrong, the second parameter of lockdep_is_held_type is 0 to test > if the rwsem is write-locked; 1 to test if it is read-locked; or -1 to > test if the rwsem is read or write-locked. Thank you for noticing. > > So, this function's call signature should change so that callers can > communicate both _SHARED and _EXCL; and then you can pick the correct Thanks for the suggestion...but that's how v5 signature looked like before Christoph and Eric requested change...on the grounds that there're: * confusion over a (true, true) set of args * confusion of what happens if we pass (false, false). > "r" parameter value for the lockdep_is_held_type() call. Then all of > this becomes: > > if !debug_locks: > return rwsem_is_locked(rwsem) > > if shared and excl: > r = -1 > elif shared: > r = 1 > else: > r = 0 > return lockdep_is_held_type(rwsem, r) I tried to create a table for this code as well: readlocked y n y writelocked *n* y y unlocked n n n nolockdep readlocked y y y nolockdep writelocked y y y nolockdep unlocked n n n I think that when we query writelocked lock for being shared having 'no' for an answer may not be expected...or at least this is how I read the code. int __lock_is_held(const struct lockdep_map *lock, int read) { struct task_struct *curr = current; int i; for (i = 0; i < curr->lockdep_depth; i++) { struct held_lock *hlock = curr->held_locks + i; if (match_held_lock(hlock, lock)) { if (read == -1 || hlock->read == read) return 1; return 0; } } return 0; } Thanks for any comments > > Note also that you don't necessarily need to pass shared and excl as > separate parameters (as you did in v3); the XFS_*LOCK_{EXCL,SHARED} > definitions enable you to take care of all that with some clever bit > shifting and masking. > > --D > > > + > > + return true; > > +} > > + > > +bool > > xfs_isilocked( > > - xfs_inode_t *ip, > > + struct xfs_inode *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_ILOCK_EXCL | XFS_ILOCK_SHARED)) { > > + return __xfs_rwsem_islocked(&ip->i_lock.mr_lock, > > + (lock_flags & XFS_ILOCK_EXCL)); > > } > > > > - if (lock_flags & (XFS_MMAPLOCK_EXCL|XFS_MMAPLOCK_SHARED)) { > > - if (!(lock_flags & XFS_MMAPLOCK_SHARED)) > > - return !!ip->i_mmaplock.mr_writer; > > - return rwsem_is_locked(&ip->i_mmaplock.mr_lock); > > + if (lock_flags & (XFS_MMAPLOCK_EXCL | XFS_MMAPLOCK_SHARED)) { > > + return __xfs_rwsem_islocked(&ip->i_mmaplock.mr_lock, > > + (lock_flags & XFS_MMAPLOCK_EXCL)); > > } > > > > - if (lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) { > > - if (!(lock_flags & XFS_IOLOCK_SHARED)) > > - return !debug_locks || > > - lockdep_is_held_type(&VFS_I(ip)->i_rwsem, 0); > > - return rwsem_is_locked(&VFS_I(ip)->i_rwsem); > > + if (lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED)) { > > + return __xfs_rwsem_islocked(&VFS_I(ip)->i_rwsem, > > + (lock_flags & XFS_IOLOCK_EXCL)); > > } > > > > ASSERT(0); > > - return 0; > > + return false; > > } > > #endif > > > > diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h > > index 492e53992fa9..3d7ce355407d 100644 > > --- a/fs/xfs/xfs_inode.h > > +++ b/fs/xfs/xfs_inode.h > > @@ -416,7 +416,7 @@ void xfs_ilock(xfs_inode_t *, uint); > > int xfs_ilock_nowait(xfs_inode_t *, uint); > > void xfs_iunlock(xfs_inode_t *, uint); > > void xfs_ilock_demote(xfs_inode_t *, uint); > > -int xfs_isilocked(xfs_inode_t *, uint); > > +bool xfs_isilocked(xfs_inode_t *, uint); > > uint xfs_ilock_data_map_shared(struct xfs_inode *); > > uint xfs_ilock_attr_map_shared(struct xfs_inode *); > > > > -- > > 2.24.1 > > >