Messages in this thread | | | Date | Sat, 17 Aug 2019 10:27:39 -0400 (EDT) | From | Mathieu Desnoyers <> | Subject | Re: [PATCH 1/1] Fix: trace sched switch start/stop racy updates |
| |
----- On Aug 16, 2019, at 3:15 PM, rostedt rostedt@goodmis.org wrote:
> On Fri, 16 Aug 2019 13:19:20 -0400 (EDT) > Mathieu Desnoyers <mathieu.desnoyers@efficios.com> wrote: > >> ----- On Aug 16, 2019, at 12:25 PM, rostedt rostedt@goodmis.org wrote: >> >> > On Fri, 16 Aug 2019 10:26:43 -0400 Mathieu Desnoyers >> > <mathieu.desnoyers@efficios.com> wrote: >> > >> [...] >> >> >> >> Also, write and read to/from those variables should be done with >> >> WRITE_ONCE() and READ_ONCE(), given that those are read within tracing >> >> probes without holding the sched_register_mutex. >> >> >> > >> > I understand the READ_ONCE() but is the WRITE_ONCE() truly necessary? >> > It's done while holding the mutex. It's not that critical of a path, >> > and makes the code look ugly. >> >> The update is done while holding the mutex, but the read-side does not >> hold that mutex, so it can observe the intermediate state caused by >> store-tearing or invented stores which can be generated by the compiler >> on the update-side. >> >> Please refer to the following LWN article: >> >> https://lwn.net/Articles/793253/ >> >> Sections: >> - "Store tearing" >> - "Invented stores" >> >> Arguably, based on that article, store tearing is only observed in the >> wild for constants (which is not the case here), and invented stores >> seem to require specific code patterns. But I wonder why we would ever want to >> pair a fragile non-volatile store with a READ_ONCE() ? Considering the pain >> associated to reproduce and hunt down this kind of issue in the wild, I would >> be tempted to enforce that any READ_ONCE() operating on a variable would either >> need to be paired with WRITE_ONCE() or with atomic operations, so those can >> eventually be validated by static code checkers and code sanitizers. > > My issue is that this is just a case to decide if we should cache a > comm or not. It's a helper, nothing more. There's no guarantee that > something will get cached.
I get your point wrt WRITE_ONCE(): since it's a cache it should not have user-visible effects if a temporary incorrect value is observed. Well in reality, it's not a cache: if the lookup fails, it returns "<...>" instead, so cache lookup failure ends up not providing any useful data in the trace. Let's assume this is a known and documented tracer limitation.
However, wrt READ_ONCE(), things are different. The variable read ends up being used to control various branches in the code, and the compiler could decide to re-fetch the variable (with a different state), and therefore cause _some_ of the branches to be inconsistent. See tracing_record_taskinfo_sched_switch() and tracing_record_taskinfo() @flags parameter.
AFAIU the current code should not generate any out-of-bound writes in case of re-fetch, but no comment in there documents how fragile this is.
Thanks,
Mathieu
-- Mathieu Desnoyers EfficiOS Inc. http://www.efficios.com
| |