Hi, On Fri, Jul 1, 2022 at 8:07 AM Alexander Aring <aahringo@xxxxxxxxxx> wrote: > > Hi, > > On Thu, Jun 30, 2022 at 12:34 PM Linus Torvalds > <torvalds@xxxxxxxxxxxxxxxxxxxx> wrote: > > > > On Thu, Jun 30, 2022 at 6:59 AM Alexander Aring <aahringo@xxxxxxxxxx> wrote: > > > > > > I send this patch series as RFC because it was necessary to do a kref > > > change after adding __cond_lock() to refcount_dec_and_lock() > > > functionality. > > > > Can you try something like this instead? > > > > This is two separate patches - one for sparse, and one for the kernel. > > > > This is only *very* lightly tested (ie I tested it on a single kernel > > file that used refcount_dec_and_lock()) > > > > yes that avoids the warnings for fs/dlm.c by calling unlock() when the > kref_put_lock() returns true. > > However there exists other users of kref_put_lock() which drops a > sparse warning now after those patches e.g. net/sunrpc/svcauth.c. > I think I can explain why. It is that kref_put_lock() has a release > callback and it's _optional_ that this release callback calls the > unlock(). If the release callback calls unlock() then the user of > kref_put_lock() signals this with a releases() annotation of the > passed release callback. > > It seems that sparse is not detecting this annotation anymore when > it's passed as callback and the function pointer parameter declaration > of kref_put_lock() does not have such annotation. The annotation gets > "dropped" then. > > If I change the parameter order and add a annotation to the release > callback, like: > > __kref_put_lock(struct kref *kref, spinlock_t *lock, > void (*release)(struct kref *kref) __releases(lock)) > #define kref_put_lock(kref, release, lock) __kref_put_lock(kref, lock, release) > > the problem is gone but forces every user to release the lock in the > release callback which isn't required and also cuts the API because > the lock which you want to call unlock() on can be not part of your > container_of(kref) struct. > > Then I did a similar thing before which would solve it for every user > because there is simply no function pointer passed as parameter and > the annotation gets never "dropped": > > #define kref_put_lock(kref, release, lock) \ > (refcount_dec_and_lock(&(kref)->refcount, lock) ? ({ release(kref); 1; }) : 0) > > Maybe a functionality of forwarding function annotation if passed as a > function pointer (function pointer declared without annotations) as in > e.g. kref_put_lock() can be added into sparse? I think the explanation above is not quite right. I am questioning myself now why it was working before... and I guess the answer is that it was working for kref_put_lock() with the callback __releases() handling. It has somehow now an additional acquire() because the __cond_acquires() change. Before the patch: no warnings: void foo_release(struct kref *kref) __releases(&foo_lock) { ... unlock(foo_lock); } ... kref_put_lock(&foo->kref, foo_release, &foo_lock); shows context imbalance warnings: void foo_release(struct kref *kref) { } if (kref_put_lock(&foo->kref, foo_release, &foo_lock)) unlock(foo_lock); After the patch it's vice versa of showing warnings or not about context imbalances. - Alex