Received: by 2002:a5b:505:0:0:0:0:0 with SMTP id o5csp141479ybp; Wed, 16 Oct 2019 15:22:20 -0700 (PDT) X-Google-Smtp-Source: APXvYqxJW9NKJbkWXSzcODWUKPn4xM8pwA5Thkmne32dfpDlCqj7pn/4P70yZuAoAzJnyzjIHLbt X-Received: by 2002:a05:6402:1a3b:: with SMTP id be27mr533353edb.210.1571264539905; Wed, 16 Oct 2019 15:22:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1571264539; cv=none; d=google.com; s=arc-20160816; b=cUsJ1UssqK5xDtStt25qLg0rzwFkcp3sGknTvrViejrZvZH9qrFELiacaRB9VY9vEi e6dS2OvzqPEai7sLuXqHjOnh9Qn2PtN1Xm1hNN5gGiTweONKvDQLCOs8ONkGZmh1EFkS flgfriMmYgSMBWUsDBXcZyE5Jelrp172vcKqU+hI/RICNXfMwWNXgu//R3Zd9JrGHX31 1IVUyq41YOdMgGMK1RIItOxI6bjd6BlGXVp3DPMis0fXf9lO8ec3oU2xCa8LW5ZxP2q7 9IZttcnOhXxLCUOsOv9eZ0G17Nyk9KpQQb6SHxQmsJ/Vd1CqvpojXo08PJ1fNNcLio5d gEbA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=ES8PPxqISv6le2aU+Na1jJhECeSWLsXBsBUpCljFmNc=; b=p2XPXNM877MfRiYiQhI0Vs9nF7P3pHqfApEWacX91SaRiKgOMBPLYUUtap3Vej5Wnx 3MTwhkCIH7AaXpS4d3nHoRhKKn0EYuqCcJk/5yif6Cjec0hxe+aoAXJuZwAJ6BrMfzx7 v+58z2iCRxvdLfRHsHEUJxYUGCz+Wf/Kwg3AJXaHmijJPa0FVjEJtMM8YJqVNEXJLbZH de0yoioxeV7G74MhPNFjYwC7y8we0mQQqc3oTGncBpwovIPdYtTL+QPGMpwV3xoyDT7/ 22OJqWhG0MwzM7QX7X2VZUddFC6vqRWMpZEIdoR796pBtbhNIJxTgZTRdPwIox/EEPAi jGWw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=oO69GKlE; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g21si224584edm.116.2019.10.16.15.21.56; Wed, 16 Oct 2019 15:22:19 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=oO69GKlE; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2405898AbfJPPx7 (ORCPT + 99 others); Wed, 16 Oct 2019 11:53:59 -0400 Received: from mail-ot1-f66.google.com ([209.85.210.66]:41224 "EHLO mail-ot1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2405891AbfJPPx7 (ORCPT ); Wed, 16 Oct 2019 11:53:59 -0400 Received: by mail-ot1-f66.google.com with SMTP id g13so20573230otp.8 for ; Wed, 16 Oct 2019 08:53:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=ES8PPxqISv6le2aU+Na1jJhECeSWLsXBsBUpCljFmNc=; b=oO69GKlEUEmZWfog28/tduGmrNxTECrWedf44ep3BiJWADibe3BtF/qSPOt+lHQnrd HMZ/O6vy/oZ1Mn29CFgrBvva1cxYf0fsP2Iv2I85mFP+PSSHxMWS5bWwvJtAkW4KeQ4X zHsZ4zn4Ud3sy3FtVlyWWHfups+bSfs5dcKPEQoYxyP86YUHE43Ssz5B42ovDjgprbuJ QoImASQ3r2C39DI1HTT9w7MtYoLRwjzHESnKd/q21EZ4qeAz9arZ/6uRGqW264QE2D9u M4kZpDAKBF3fk3pugbmFA+dNIL07VCSKkOnXhdXNc50ltBiqs8ufauu0rzHnctKYwyTf J+zg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=ES8PPxqISv6le2aU+Na1jJhECeSWLsXBsBUpCljFmNc=; b=HGTHarZCc3qkbz3EKhKknxYmFzAWfRjO8SumFDByHSc4yGH9ylG7iEcFj15EUp7qxm ep6xjGJqhh1EKPyI6PxkU0hg75ANa6DOt6E4NrIOUdnlFibHIS0U26YGpykezc+PqXBi 7xtSJDkZWXp9kGQXNI5oqmApD2gBaZG3g4MGtCt21NS3eRuSqOaO57w8RXaU4GY1xxFF rXprQEklKdoYPR4C2Lfz29zp7Y7Exn3aSuJALO6So9BWMnpW404huSN9/NVqkF+NjZug 2hgqq/qpRA2uoS37Y+Ll+CPuieWfXKTR8+10BTr3TO5W/UYGo4sXB8tjJn+KVybQM/jK 8Ydg== X-Gm-Message-State: APjAAAXGthNsttoXgEA8e7u+SeS9DYOKwd9DjgNiKYLuJvD1Me1dmQi/ /zGtgyLqK1GBTz+umhtUs3lh5wj271rHeYXclKEEwQ== X-Received: by 2002:a9d:7590:: with SMTP id s16mr8514934otk.2.1571241237486; Wed, 16 Oct 2019 08:53:57 -0700 (PDT) MIME-Version: 1.0 References: <20191016083959.186860-1-elver@google.com> <20191016083959.186860-2-elver@google.com> <20191016151643.GC46264@lakrids.cambridge.arm.com> In-Reply-To: <20191016151643.GC46264@lakrids.cambridge.arm.com> From: Marco Elver Date: Wed, 16 Oct 2019 17:53:45 +0200 Message-ID: Subject: Re: [PATCH 1/8] kcsan: Add Kernel Concurrency Sanitizer infrastructure To: Mark Rutland Cc: LKMM Maintainers -- Akira Yokosawa , Alan Stern , Alexander Potapenko , Andrea Parri , Andrey Konovalov , Andy Lutomirski , ard.biesheuvel@linaro.org, Arnd Bergmann , Boqun Feng , Borislav Petkov , Daniel Axtens , Daniel Lustig , dave.hansen@linux.intel.com, dhowells@redhat.com, Dmitry Vyukov , "H. Peter Anvin" , Ingo Molnar , Jade Alglave , Joel Fernandes , Jonathan Corbet , Josh Poimboeuf , Luc Maranget , Nicholas Piggin , "Paul E. McKenney" , Peter Zijlstra , Thomas Gleixner , Will Deacon , kasan-dev , linux-arch , "open list:DOCUMENTATION" , linux-efi@vger.kernel.org, linux-kbuild@vger.kernel.org, LKML , Linux Memory Management List , "the arch/x86 maintainers" Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed, 16 Oct 2019 at 17:16, Mark Rutland wrote: > > On Wed, Oct 16, 2019 at 10:39:52AM +0200, Marco Elver wrote: > > diff --git a/include/linux/sched.h b/include/linux/sched.h > > index 2c2e56bd8913..34a1d9310304 100644 > > --- a/include/linux/sched.h > > +++ b/include/linux/sched.h > > @@ -1171,6 +1171,13 @@ struct task_struct { > > #ifdef CONFIG_KASAN > > unsigned int kasan_depth; > > #endif > > +#ifdef CONFIG_KCSAN > > + /* See comments at kernel/kcsan/core.c: struct cpu_state. */ > > + int kcsan_disable; > > + int kcsan_atomic_next; > > + int kcsan_atomic_region; > > + bool kcsan_atomic_region_flat; > > +#endif > > Should these be unsigned? I prefer to keep them int, as they can become negative (rather than underflow with unsigned), if we e.g. have unbalanced kcsan_enable_current etc. Since we do not need the full unsigned range (these values should stay relatively small), int is more than enough. > > +/* > > + * Per-CPU state that should be used instead of 'current' if we are not in a > > + * task. > > + */ > > +struct cpu_state { > > + int disable; /* disable counter */ > > + int atomic_next; /* number of following atomic ops */ > > + > > + /* > > + * We use separate variables to store if we are in a nestable or flat > > + * atomic region. This helps make sure that an atomic region with > > + * nesting support is not suddenly aborted when a flat region is > > + * contained within. Effectively this allows supporting nesting flat > > + * atomic regions within an outer nestable atomic region. Support for > > + * this is required as there are cases where a seqlock reader critical > > + * section (flat atomic region) is contained within a seqlock writer > > + * critical section (nestable atomic region), and the "mismatching > > + * kcsan_end_atomic()" warning would trigger otherwise. > > + */ > > + int atomic_region; > > + bool atomic_region_flat; > > +}; > > +static DEFINE_PER_CPU(struct cpu_state, this_state) = { > > + .disable = 0, > > + .atomic_next = 0, > > + .atomic_region = 0, > > + .atomic_region_flat = 0, > > +}; > > These are the same as in task_struct, so I think it probably makes sense > to have a common structure for these, e.g. > > | struct kcsan_ctx { > | int disable; > | int atomic_next; > | int atomic_region; > | bool atomic_region_flat; > | }; > > ... which you then place within task_struct, e.g. > > | #ifdef CONFIG_KCSAN > | struct kcsan_ctx kcsan_ctx; > | #endif > > ... and here, e.g. > > | static DEFINE_PER_CPU(struct kcsan_ctx, kcsan_cpu_ctx); > > That would simplify a number of cases below where you have to choose one > or the other, as you can choose the pointer, then handle the rest in a > common way. > > e.g. for: > > > +static inline bool is_atomic(const volatile void *ptr) > > +{ > > + if (in_task()) { > > + if (unlikely(current->kcsan_atomic_next > 0)) { > > + --current->kcsan_atomic_next; > > + return true; > > + } > > + if (unlikely(current->kcsan_atomic_region > 0 || > > + current->kcsan_atomic_region_flat)) > > + return true; > > + } else { /* interrupt */ > > + if (unlikely(this_cpu_read(this_state.atomic_next) > 0)) { > > + this_cpu_dec(this_state.atomic_next); > > + return true; > > + } > > + if (unlikely(this_cpu_read(this_state.atomic_region) > 0 || > > + this_cpu_read(this_state.atomic_region_flat))) > > + return true; > > + } > > + > > + return kcsan_is_atomic(ptr); > > +} > > ... you could have something like: > > | struct kcsan_ctx *kcsan_get_ctx(void) > | { > | return in_task() ? ¤t->kcsan_ctx : this_cpu_ptr(kcsan_cpu_ctx); > | } > | > | static inline bool is_atomic(const volatile void *ptr) > | { > | struct kcsan_ctx *ctx = kcsan_get_ctx(); > | if (unlikely(ctx->atomic_next > 0) { > | --ctx->atomic_next; > | return true; > | } > | if (unlikely(ctx->atomic_region > 0 || ctx->atomic_region_flat)) > | return true; > | > | return kcsan_is_atomic(ptr); > | } > > ... avoiding duplicating the checks for task/irq contexts. > > It's not clear to me how either that or the original code works if a > softirq is interrupted by a hardirq. IIUC most of the fields should > remain stable over that window, since the hardirq should balance most > changes it makes before returning, but I don't think that's true for > atomic_next. Can't that be corrupted from the PoV of the softirq > handler? As you say, these fields should balance. So far I have not observed any issues. For atomic_next I'm not concerned as it is an approximation either way (see seqlock patch), and it's fine if there is a small error. > [...] > > > +void kcsan_begin_atomic(bool nest) > > +{ > > + if (nest) { > > + if (in_task()) > > + ++current->kcsan_atomic_region; > > + else > > + this_cpu_inc(this_state.atomic_region); > > + } else { > > + if (in_task()) > > + current->kcsan_atomic_region_flat = true; > > + else > > + this_cpu_write(this_state.atomic_region_flat, true); > > + } > > +} > > Assuming my suggestion above wasn't bogus, this can be: > > | void kcsan_begin_atomic(boot nest) > | { > | struct kcsan_ctx *ctx = kcsan_get_ctx(); > | if (nest) > | ctx->atomic_region++; > | else > | ctx->atomic_region_flat = true; > | } > > > +void kcsan_end_atomic(bool nest) > > +{ > > + if (nest) { > > + int prev = > > + in_task() ? > > + current->kcsan_atomic_region-- : > > + (this_cpu_dec_return(this_state.atomic_region) + > > + 1); > > + if (prev == 0) { > > + kcsan_begin_atomic(true); /* restore to 0 */ > > + kcsan_disable_current(); > > + WARN(1, "mismatching %s", __func__); > > + kcsan_enable_current(); > > + } > > + } else { > > + if (in_task()) > > + current->kcsan_atomic_region_flat = false; > > + else > > + this_cpu_write(this_state.atomic_region_flat, false); > > + } > > +} > > ... similarly: > > | void kcsan_end_atomic(bool nest) > | { > | struct kcsan_ctx *ctx = kcsan_get_ctx(); > | > | if (nest) > | if (ctx->kcsan_atomic_region--) { > | kcsan_begin_atomic(true); /* restore to 0 */ > | kcsan_disable_current(); > | WARN(1, "mismatching %s"\ __func__); > | kcsan_enable_current(); > | } > | } else { > | ctx->atomic_region_flat = true; > | } > | } > > > +void kcsan_atomic_next(int n) > > +{ > > + if (in_task()) > > + current->kcsan_atomic_next = n; > > + else > > + this_cpu_write(this_state.atomic_next, n); > > +} > > ... and: > > | void kcsan_atomic_nextint n) > | { > | kcsan_get_ctx()->atomic_next = n; > | } Otherwise, yes, this makes much more sense and I will just introduce the struct and integrate the above suggestions for v2. Many thanks, -- Marco