Re: [PATCH 1/7] General notification queue with user mmap()'able ring buffer

Peter Zijlstra
2019-05-31T13:26:48Z

On Fri, May 31, 2019 at 01:02:15PM +0100, David Howells wrote:
> Peter Zijlstra <peterz@infradead.org> wrote:
>
> > Can you re-iterate the exact problem? I konw we talked about this in the
> > past, but I seem to have misplaced those memories :/
>
> Take this for example:
>
> void afs_put_call(struct afs_call *call)
> {
> struct afs_net *net = call->net;
> int n = atomic_dec_return(&call->usage);
> int o = atomic_read(&net->nr_outstanding_calls);
>
> trace_afs_call(call, afs_call_trace_put, n + 1, o,
> __builtin_return_address(0));
>
> ASSERTCMP(n, >=, 0);
> if (n == 0) {
> ...
> }
> }
>
> I am printing the usage count in the afs_call tracepoint so that I can use it
> to debug refcount bugs. If I do it like this:
>
> void afs_put_call(struct afs_call *call)
> {
> int n = refcount_read(&call->usage);
> int o = atomic_read(&net->nr_outstanding_calls);
>
> trace_afs_call(call, afs_call_trace_put, n, o,
> __builtin_return_address(0));
>
> if (refcount_dec_and_test(&call->usage)) {
> ...
> }
> }
>
> then there's a temporal gap between the usage count being read and the actual
> atomic decrement in which another CPU can alter the count. This can be
> exacerbated by an interrupt occurring, a softirq occurring or someone enabling
> the tracepoint.
>
> I can't do the tracepoint after the decrement if refcount_dec_and_test()
> returns false unless I save all the values from the object that I might need
> as the object could be destroyed any time from that point on.

Is it not the responsibility of the task that affects the 1->0
transition to actually free the memory?

That is, I'm expecting the '...' in both cases above the include the
actual freeing of the object. If this is not the case, then @usage is
not a reference count.

(and it has already been established that refcount_t doesn't work for
usage count scenarios)

Aside from that, is the problem that refcount_dec_and_test() returns a
boolean (true - last put, false - not last) instead of the refcount
value? This does indeed make it hard to print the exact count value for
the event.