On 13/11/17(Mon) 17:29, Visa Hankala wrote:
> On Mon, Nov 13, 2017 at 01:25:42PM +0100, Martin Pieuchot wrote:
> > I'd love is somebody could do the changes in the rwlock API to let us
> > check if we're holding a lock.  Maybe this is already present in
> > witness(4), visa?
> 
> witness(4) does maintain data about lock ownership. The patch below
> might do the trick for rwlocks without adding extra state tracking.

I wouldn't mind a solution that's always on.  I'm afraid it will take
some time before we can enable WITNESS regularly.

> The patch also fixes the witness-side initialization of statically
> initialized locks, in functions witness_checkorder() and
> witness_lock(). The fix belongs to a separate commit though.

You should commit that.

Note that the diff below still includes a false positive.  If the
current thread doesn't have the read-lock but another one has it,
then RW_READ will still be returned.

> Index: share/man/man9/rwlock.9
> ===================================================================
> RCS file: src/share/man/man9/rwlock.9,v
> retrieving revision 1.20
> diff -u -p -r1.20 rwlock.9
> --- share/man/man9/rwlock.9   30 Oct 2017 13:33:36 -0000      1.20
> +++ share/man/man9/rwlock.9   13 Nov 2017 17:05:51 -0000
> @@ -33,6 +33,7 @@
>  .Nm rw_assert_anylock ,
>  .Nm rw_assert_unlocked ,
>  .Nm rw_status ,
> +.Nm rw_status_curproc ,
>  .Nm RWLOCK_INITIALIZER ,
>  .Nm rrw_init ,
>  .Nm rrw_init_flags ,
> @@ -68,6 +69,8 @@
>  .Fn rw_assert_unlocked "struct rwlock *rwl"
>  .Ft int
>  .Fn rw_status "struct rwlock *rwl"
> +.Ft int
> +.Fn rw_status_curproc "struct rwlock *rwl"
>  .Fn RWLOCK_INITIALIZER "const char *name"
>  .Ft void
>  .Fn rrw_init "struct rrwlock *rrwl" "const char *name"
> @@ -181,7 +184,7 @@ functions check the status
>  .Fa rwl ,
>  panicking if it is not write-, read-, any-, or unlocked, respectively.
>  .Pp
> -.Nm rw_status
> +.Fn rw_status
>  returns the current state of the lock:
>  .Pp
>  .Bl -tag -width "RW_WRITE_OTHER" -offset indent -compact
> @@ -194,6 +197,22 @@ Lock is read locked.
>  The current thread may be one of the threads that has it locked.
>  .It 0
>  Lock is not locked.
> +.El
> +.Pp
> +.Fn rw_status_curproc
> +returns the current state of the lock relative to the calling thread:
> +.Pp
> +.Bl -tag -width "RW_WRITE_OTHER" -offset indent -compact
> +.It Dv RW_WRITE
> +Lock is write locked by the calling thread.
> +.It Dv RW_READ
> +Lock is read locked.
> +The current thread may be one of the threads that has it locked.
> +If the kernel has been compiled with
> +.Xr witness 4 ,
> +the status is exact, and the lock is read locked by the current thread.
> +.It 0
> +Lock is not locked by the calling thread.
>  .El
>  .Pp
>  A lock declaration may be initialised with the
> Index: sys/kern/kern_rwlock.c
> ===================================================================
> RCS file: src/sys/kern/kern_rwlock.c,v
> retrieving revision 1.32
> diff -u -p -r1.32 kern_rwlock.c
> --- sys/kern/kern_rwlock.c    24 Oct 2017 08:53:15 -0000      1.32
> +++ sys/kern/kern_rwlock.c    13 Nov 2017 17:05:51 -0000
> @@ -325,6 +325,34 @@ rw_status(struct rwlock *rwl)
>       return (0);
>  }
>  
> +int
> +rw_status_curproc(struct rwlock *rwl)
> +{
> +     unsigned long owner;
> +#ifdef WITNESS
> +     int status = witness_status(&rwl->rwl_lock_obj);
> +
> +     if (status != -1) {
> +             if (status & LA_XLOCKED)
> +                     return (RW_WRITE);
> +             if (status & LA_SLOCKED)
> +                     return (RW_READ);
> +             return (0);
> +     }
> +#endif
> +
> +     owner = rwl->rwl_owner;
> +     if (owner & RWLOCK_WRLOCK) {
> +             if (RW_PROC(curproc) == RW_PROC(owner))
> +                     return (RW_WRITE);
> +             else
> +                     return (0);
> +     }
> +     if (owner)
> +             return RW_READ;
> +     return (0);
> +}
> +
>  #ifdef DIAGNOSTIC
>  void
>  rw_assert_wrlock(struct rwlock *rwl)
> Index: sys/kern/subr_witness.c
> ===================================================================
> RCS file: src/sys/kern/subr_witness.c,v
> retrieving revision 1.4
> diff -u -p -r1.4 subr_witness.c
> --- sys/kern/subr_witness.c   12 Aug 2017 03:13:23 -0000      1.4
> +++ sys/kern/subr_witness.c   13 Nov 2017 17:05:51 -0000
> @@ -744,8 +744,8 @@ witness_checkorder(struct lock_object *l
>       struct witness *w, *w1;
>       int i, j, s;
>  
> -     if (witness_cold || witness_watch < 1 || lock->lo_witness == NULL ||
> -         panicstr != NULL)
> +     if (witness_cold || witness_watch < 1 || panicstr != NULL ||
> +         (lock->lo_flags & LO_WITNESS) == 0)
>               return;
>  
>       w = lock->lo_witness;
> @@ -1078,8 +1078,8 @@ witness_lock(struct lock_object *lock, i
>       struct witness *w;
>       int s;
>  
> -     if (witness_cold || witness_watch == -1 || lock->lo_witness == NULL ||
> -         panicstr != NULL)
> +     if (witness_cold || witness_watch == -1 || panicstr != NULL ||
> +         (lock->lo_flags & LO_WITNESS) == 0)
>               return;
>  
>       w = lock->lo_witness;
> @@ -2004,6 +2004,42 @@ witness_assert(const struct lock_object 
>  
>       }
>  #endif       /* INVARIANT_SUPPORT */
> +}
> +
> +int
> +witness_status(struct lock_object *lock)
> +{
> +     struct lock_instance *instance;
> +     struct lock_class *class;
> +     int status = 0;
> +
> +     if (witness_cold || witness_watch < 1 || panicstr != NULL ||
> +         (lock->lo_flags & LO_WITNESS) == 0)
> +             return -1;
> +
> +     class = LOCK_CLASS(lock);
> +     if ((class->lc_flags & LC_SLEEPLOCK) != 0)
> +             instance = find_instance(curproc->p_sleeplocks, lock);
> +     else if ((class->lc_flags & LC_SPINLOCK) != 0)
> +             instance = find_instance(
> +                 witness_cpu[cpu_number()].wc_spinlocks, lock);
> +     else
> +             panic("lock (%s) %s is not sleep or spin!",
> +                 class->lc_name, lock->lo_name);
> +
> +     if (instance != NULL) {
> +             status |= LA_LOCKED;
> +             if (instance->li_flags & LI_EXCLUSIVE)
> +                     status |= LA_XLOCKED;
> +             else
> +                     status |= LA_SLOCKED;
> +             if (instance->li_flags & LI_RECURSEMASK)
> +                     status |= LA_RECURSED;
> +             else
> +                     status |= LA_NOTRECURSED;
> +     }
> +
> +     return (status);
>  }
>  
>  static void
> Index: sys/sys/rwlock.h
> ===================================================================
> RCS file: src/sys/sys/rwlock.h,v
> retrieving revision 1.22
> diff -u -p -r1.22 rwlock.h
> --- sys/sys/rwlock.h  12 Aug 2017 23:27:44 -0000      1.22
> +++ sys/sys/rwlock.h  13 Nov 2017 17:05:51 -0000
> @@ -170,6 +170,7 @@ void      rw_assert_unlocked(struct rwlock *)
>  int  _rw_enter(struct rwlock *, int LOCK_FL_VARS);
>  void _rw_exit(struct rwlock * LOCK_FL_VARS);
>  int  rw_status(struct rwlock *);
> +int  rw_status_curproc(struct rwlock *);
>  
>  #define rw_enter(rwl, flags) _rw_enter(rwl, flags LOCK_FILE_LINE)
>  #define rw_exit(rwl)         _rw_exit(rwl LOCK_FILE_LINE)
> Index: sys/sys/systm.h
> ===================================================================
> RCS file: src/sys/sys/systm.h,v
> retrieving revision 1.135
> diff -u -p -r1.135 systm.h
> --- sys/sys/systm.h   13 Nov 2017 14:41:46 -0000      1.135
> +++ sys/sys/systm.h   13 Nov 2017 17:05:52 -0000
> @@ -323,7 +323,7 @@ do {                                                      
>                 \
>  
>  #define      NET_ASSERT_LOCKED()                                             
> \
>  do {                                                                 \
> -     int _s = rw_status(&netlock);                                   \
> +     int _s = rw_status_curproc(&netlock);                           \
>       if ((splassert_ctl > 0) && (_s != RW_WRITE && _s != RW_READ))   \
>               splassert_fail(RW_READ, _s, __func__);                  \
>  } while (0)
> Index: sys/sys/witness.h
> ===================================================================
> RCS file: src/sys/sys/witness.h,v
> retrieving revision 1.1
> diff -u -p -r1.1 witness.h
> --- sys/sys/witness.h 20 Apr 2017 12:59:36 -0000      1.1
> +++ sys/sys/witness.h 13 Nov 2017 17:05:52 -0000
> @@ -88,6 +88,7 @@ int witness_line(struct lock_object *);
>  void witness_norelease(struct lock_object *);
>  void witness_releaseok(struct lock_object *);
>  const char *witness_file(struct lock_object *);
> +int  witness_status(struct lock_object *);
>  void witness_thread_exit(struct proc *);
>  
>  #ifdef       WITNESS
> 

Reply via email to