Page MenuHomeFreeBSD

LinuxKPI: update rcu_dereference_*() and lockdep_is_held()
Needs ReviewPublic

Authored by bz on Sun, Sep 29, 12:59 AM.
Tags
None
Referenced Files
Unknown Object (File)
Thu, Oct 17, 9:53 AM
Unknown Object (File)
Wed, Oct 16, 3:14 PM
Unknown Object (File)
Mon, Oct 7, 6:34 PM
Unknown Object (File)
Mon, Oct 7, 10:51 AM
Unknown Object (File)
Fri, Oct 4, 1:26 PM
Unknown Object (File)
Fri, Oct 4, 10:35 AM
Unknown Object (File)
Tue, Oct 1, 11:53 AM

Details

Reviewers
kevans
wulf
Group Reviewers
linuxkpi
Summary

Update rcu_dereference_{check,protected}() to call the check and log
once if if fails and if the RCU debug sysctl is turned on.
Also add proper checks for conditions passed in to these functions.
For that implement linux_rcu_read_lock_locked().

(While here also remove extraneous extern for function prototypes).

Update lockdep_is_held() to always be an inline function with argument
annotation so that we do no longer have unused variables
in callers which only call lockdep_is_held().

Sponsored by: The FreeBSD Foundation
MFC after: 3 days

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 59911
Build 56796: arc lint + arc unit

Event Timeline

bz requested review of this revision.Sun, Sep 29, 12:59 AM
bz planned changes to this revision.Fri, Oct 4, 8:51 PM

These give false positives given check is aliased to it as well. I am working on an update.

Updated with proper condition checks also for the "check" variant and
added a sysctl to enable the RCU debug logging as it seems it could
possibly be noisy currently.

bz retitled this revision from LinuxKPI: update rcu_dereference_protected() and lockdep_is_held() to LinuxKPI: update rcu_dereference_*() and lockdep_is_held().Fri, Oct 4, 11:49 PM
bz edited the summary of this revision. (Show Details)

Anyone? x11 for drm-kmod testing at least?

sys/compat/linuxkpi/common/include/linux/lockdep.h
95

return (true) is probably preferable

Return true instea dof the 1 lockdep_is_held used to return as suggested by @emaste

wulf added inline comments.
sys/compat/linuxkpi/common/src/linux_rcu.c
270

Our in_epoch() does different thing in preemptible case. See sys/kern/subr_epoch.c:in_epoch_verbose_preempt()
It scans through list of threads entered in to the epoch section and compares each entry with curthread.
Probably we should do the same with only difference of comparing each entry with current.

But I am not an RCU/epoch expert.

bz marked an inline comment as done.
bz added a subscriber: kevans.
bz added inline comments.
sys/compat/linuxkpi/common/src/linux_rcu.c
263

Insert:

/* If the thread is not pinned it is not in an epoch. */
if (td->td_pinned == 0)
        return (false);
270

Adding @kevans given he wrote that code in sys/kern/subr_epoch.c

The more I look at the surrounding code tonight the more I am confused about the possibility of a race condition.

sys/compat/linuxkpi/common/src/linux_rcu.c
270

At second glance:

  1. current should be checked to be initialized before usage as it may results in unexpected malloc()
  2. ts->rcu_recurse[type] check is enough
  3. td->td_pinned and epoch_record.active checks are not needed but may be MPASS-ed in positive case
  4. No need in critical section as it protects atomic operation (aligned int read)
  1. Linux name of this routine is (s)rcu_read_lock_held
bz marked 2 inline comments as done.

Update based on suggestions by @wulf

The only note: It looks that rcu_read_lock_held() always returns true on non-debug builds: https://elixir.bootlin.com/linux/v6.11.3/source/include/linux/rcupdate.h#L351

This revision is now accepted and ready to land.Wed, Oct 16, 12:13 PM

Wrap the rcu_read_lock_held() implementation in INVARIANTS and otherwise
just return true as pointed out by @wulf.

This revision now requires review to proceed.Wed, Oct 16, 2:26 PM

The only note: It looks that rcu_read_lock_held() always returns true on non-debug builds: https://elixir.bootlin.com/linux/v6.11.3/source/include/linux/rcupdate.h#L351

Done. If you are happy, did you by any chance test this with some drm-kmod graphics that we don't run into surprises there?

Heh, this broke build of drm-kmod's master branch:

/home/wulf/dvp/drm-kmod/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c:187:15: error: expression result unused [-Werror,-Wunused-value]
  187 |         if (unlikely(rcu_dereference_protected(*ptr, 1))) {
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/wulf/dvp/freebsd/wulf/sys/compat/linuxkpi/common/include/linux/rcupdate.h:115:5: note: expanded from macro 'rcu_dereference_protected'
  115 |     __rcu_dereference_protected((p), (c),                               \
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  116 |         __rcu_var_name(protected, __func__, __LINE__))
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/wulf/dvp/freebsd/wulf/sys/compat/linuxkpi/common/include/linux/rcupdate.h:109:5: note: expanded from macro '__rcu_dereference_protected'
  109 |     RCU_WARN_ONCE(!(c), "%s:%d: condition for %s failed\n",             \
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  110 |         __func__, __LINE__, __XSTRING(n));                              \
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/wulf/dvp/freebsd/wulf/sys/compat/linuxkpi/common/include/linux/rcupdate.h:45:3: note: expanded from macro 'RCU_WARN_ONCE'
   45 |                 1;                                                      \
      |                 ^
/home/wulf/dvp/freebsd/wulf/sys/compat/linuxkpi/common/include/linux/compiler.h:82:43: note: expanded from macro 'unlikely'
   82 | #define unlikely(x)                     __builtin_expect(!!(x), 0)

Heh, this broke build of drm-kmod's master branch:

/home/wulf/dvp/drm-kmod/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c:187:15: error: expression result unused [-Werror,-Wunused-value]
  187 |         if (unlikely(rcu_dereference_protected(*ptr, 1))) {
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/wulf/dvp/freebsd/wulf/sys/compat/linuxkpi/common/include/linux/rcupdate.h:115:5: note: expanded from macro 'rcu_dereference_protected'
  115 |     __rcu_dereference_protected((p), (c),                               \
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  116 |         __rcu_var_name(protected, __func__, __LINE__))
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/wulf/dvp/freebsd/wulf/sys/compat/linuxkpi/common/include/linux/rcupdate.h:109:5: note: expanded from macro '__rcu_dereference_protected'
  109 |     RCU_WARN_ONCE(!(c), "%s:%d: condition for %s failed\n",             \
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  110 |         __func__, __LINE__, __XSTRING(n));                              \
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/wulf/dvp/freebsd/wulf/sys/compat/linuxkpi/common/include/linux/rcupdate.h:45:3: note: expanded from macro 'RCU_WARN_ONCE'
   45 |                 1;                                                      \
      |                 ^
/home/wulf/dvp/freebsd/wulf/sys/compat/linuxkpi/common/include/linux/compiler.h:82:43: note: expanded from macro 'unlikely'
   82 | #define unlikely(x)                     __builtin_expect(!!(x), 0)

I have an update (also compiling 5.1-lts) but drm-kmod master is still broken for LINT kernels in ACPI.
Will upload updated diff in a few minutes.

Update to unbreak drm-kmod (master/LINT still fails in ACPI, GENERIC* compiled; 6.1-lts also compiled fully)

It works good on Intel Skylake

It works good on Intel Skylake

I also only have intel to test with; does that mean this is good to go?