Received: by 2002:a05:6602:18e:0:0:0:0 with SMTP id m14csp7400558ioo; Fri, 3 Jun 2022 06:01:34 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyIHxqsLcXnihKB0l5jV8TvdBb1zhBiQYt6fuuPu3WPp3x+UATfzmUvvhpji9K0FA4ecd5v X-Received: by 2002:a65:480a:0:b0:3c6:e629:3022 with SMTP id h10-20020a65480a000000b003c6e6293022mr8879717pgs.281.1654261294081; Fri, 03 Jun 2022 06:01:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1654261294; cv=none; d=google.com; s=arc-20160816; b=nlbGqTKnJ9lzigtueEJfTJA2LWBpiM91Cp9kIJTd4CaQ1JTEDsX7qFXHs2J9givObi +/80k7hwTGGW2fgPtudWDltKbuLym4mUT9QeU9eiqC71m0PeuL5ABVEBHiWHuNhGH8N8 mefQsd1aHEroX1m6/5mQVnRTJh9PO2QJerZCPyhQkmrnArgd90iT6HYtt8caVLlJtjnN cymJCrkEJRQKBl48DCsTuLJGAsXXRSX3SXrOLTQC0mgL4kP5ftS8tExvbf14LZcjKyXX AjcZyPziaK/Kg64c+OaIUX0bSt85u481YqnGfq123ARK0ZeTsAsxKbTk+Szz8Stuu3c3 nEXw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=i3NKfn+ix8IPierL01zwu9WC+ziebwcUWLk5MPtmKag=; b=kpMCZfl8Yp1sFHC/eg1JV1zlhmAecOgOSD8As+Qm7WgMYNm3yHJouKDnJkPLu7A4F9 KiqkYj+9NyodRb/BQCuu5sSsejGxw7VXJV1LBM/MTGj5vg4bItnmJ+ORSHncHToJKCRi oZqcuVsveyD6UoxKghAtKMBeKPup137qL08uisA0mFInU0mD6RftacHRxCPJi76IG0DP q2q0cfJ2GWMtt0GFRIwNijUyvZNQw37gWPKu02k/pn9DgqntUMmlKm9mox+MnjmLo+hc 51/X71AAiHohrBo5eQaEHNgVX3nuUGtpvGTjQoMtCjA6CjBuo7HixnG4ReYwl2QfbmWL g1Bg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@svanheule.net header.s=mail1707 header.b=g+5VeeU2; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=svanheule.net Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id f1-20020a170902ab8100b0016381c7e28dsi9527167plr.67.2022.06.03.06.00.55; Fri, 03 Jun 2022 06:01:33 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@svanheule.net header.s=mail1707 header.b=g+5VeeU2; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=svanheule.net Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239338AbiFBVEp (ORCPT + 99 others); Thu, 2 Jun 2022 17:04:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35516 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232821AbiFBVEl (ORCPT ); Thu, 2 Jun 2022 17:04:41 -0400 Received: from polaris.svanheule.net (polaris.svanheule.net [84.16.241.116]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3463A35260 for ; Thu, 2 Jun 2022 14:04:39 -0700 (PDT) Received: from terra.. (unknown [IPv6:2a02:a03f:eaf9:8401:aa9f:5d01:1b2a:e3cd]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: sander@svanheule.net) by polaris.svanheule.net (Postfix) with ESMTPSA id 2A3A12E19A6; Thu, 2 Jun 2022 23:04:34 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=svanheule.net; s=mail1707; t=1654203874; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=i3NKfn+ix8IPierL01zwu9WC+ziebwcUWLk5MPtmKag=; b=g+5VeeU2K6xjaA1vUybtfN6kd0EZL0Ac6NHq6pYLD8aNT/E0BjlhBfr6R66I18DDTFoTBR DGDtEXcNbVP/Tc042uwce/yQKffrwPu7V5gB7qqBZp90v4l5QpiAZHxMPoiWJLbgLbd/9y 9CIT85CckGQGtv6UXW7dJlhRbpQkglsAFsQ6GnUQPRpDxBoDiOZmVRBzmlGimz9lWq41tR 8TGIBuFnF4LGrt9ibf0bfIqf3Nl0eXEI7UkScMt7YLaZi1O+H/xSHxqh4vJTnGM/VoL4Jd UEk05GZPTb5uY0AhlvdAUsMhBgXpQk+WWyZx5xEMIIbb/LYREl4x5B16Esj/1g== From: Sander Vanheule To: Peter Zijlstra , Yury Norov , Andrew Morton , Valentin Schneider , Thomas Gleixner , Greg Kroah-Hartman , Marco Elver , Barry Song Cc: linux-kernel@vger.kernel.org, Andy Shevchenko , Sander Vanheule Subject: [PATCH v1 0/2] cpumask: Fix invalid uniprocessor assumptions Date: Thu, 2 Jun 2022 23:04:18 +0200 Message-Id: X-Mailer: git-send-email 2.36.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW,SPF_HELO_PASS, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On uniprocessor builds, it is currently assumed that any cpumask will contain the single CPU: cpu0. This assumption is used to provide optimised implementations. The current assumption also appears to be wrong, by ignoring the fact that users can provide empty cpumask-s. This can result in bugs as explained in [1]. This series seeks to fix this assumption, allowing for masks that contain at most cpu0, i.e. are "1" or "0". [1] https://lore.kernel.org/all/20220530082552.46113-1-sander@svanheule.net/ Best, Sander --- To test these changes, I used the following code: static void cpumask_test(const struct cpumask *mask) { int cpu; if (cpumask_empty(mask)) pr_info("testing empty mask\n"); else pr_info("testing non-empty mask\n"); pr_info("first cpu: %d\n", cpumask_first(mask)); pr_info("first zero: %d\n", cpumask_first_zero(mask)); pr_info("first and: %d\n", cpumask_first_and(mask, cpu_possible_mask)); pr_info("last cpu: %d\n", cpumask_last(mask)); pr_info("next cpu at -1: %d\n", cpumask_next(-1, mask)); pr_info("next cpu at 0: %d\n", cpumask_next(0, mask)); pr_info("next zero at -1: %d\n", cpumask_next_zero(-1, mask)); pr_info("next zero at 0: %d\n", cpumask_next_zero(0, mask)); pr_info("next and at -1: %d\n", cpumask_next_and(-1, mask, cpu_possible_mask)); pr_info("next and at 0: %d\n", cpumask_next_and(0, mask, cpu_possible_mask)); pr_info("next wrap at -1,false: %d\n", cpumask_next_wrap(-1, mask, 0, false)); pr_info("next wrap at 0,false: %d\n", cpumask_next_wrap(-1, mask, 0, false)); pr_info("next wrap at -1,true: %d\n", cpumask_next_wrap(-1, mask, 0, true)); pr_info("next wrap at 0,true: %d\n", cpumask_next_wrap(-1, mask, 0, true)); for_each_cpu(cpu, mask) pr_info("for each: %d\n", cpu); for_each_cpu_not(cpu, mask) pr_info("for each not: %d\n", cpu); for_each_cpu_wrap(cpu, mask, 0) pr_info("for each wrap: %d\n", cpu); for_each_cpu_and(cpu, mask, cpu_possible_mask) pr_info("for each and: %d\n", cpu); } static void run_tests() { cpumask_clear(&empty_mask); cpumask_test(&empty_mask); cpumask_test(cpu_possible_mask); } On an unpatched build, with NR_CPUS=1: [...] testing empty mask [...] first cpu: 0 [...] first zero: 0 [...] first and: 0 [...] last cpu: 0 [...] next cpu at -1: 0 [...] next cpu at 0: 1 [...] next zero at -1: 0 [...] next zero at 0: 1 [...] next and at -1: 0 [...] next and at 0: 1 [...] next wrap at -1,false: 0 [...] next wrap at 0,false: 0 [...] next wrap at -1,true: 0 [...] next wrap at 0,true: 0 [...] for each: 0 [...] for each not: 0 [...] for each wrap: 0 [...] for each and: 0 [...] testing non-empty mask [...] first cpu: 0 [...] first zero: 0 [...] first and: 0 [...] last cpu: 0 [...] next cpu at -1: 0 [...] next cpu at 0: 1 [...] next zero at -1: 0 [...] next zero at 0: 1 [...] next and at -1: 0 [...] next and at 0: 1 [...] next wrap at -1,false: 0 [...] next wrap at 0,false: 0 [...] next wrap at -1,true: 0 [...] next wrap at 0,true: 0 [...] for each: 0 [...] for each not: 0 [...] for each wrap: 0 [...] for each and: 0 On a patched build, with NR_CPUS=1: [...] testing empty mask [...] first cpu: 1 [...] first zero: 0 [...] first and: 1 [...] last cpu: 1 [...] next cpu at -1: 1 [...] next cpu at 0: 1 [...] next zero at -1: 0 [...] next zero at 0: 1 [...] next and at -1: 1 [...] next and at 0: 1 [...] next wrap at -1,false: 1 [...] next wrap at 0,false: 1 [...] next wrap at -1,true: 1 [...] next wrap at 0,true: 1 [...] for each not: 0 [...] testing non-empty mask [...] first cpu: 0 [...] first zero: 1 [...] first and: 0 [...] last cpu: 0 [...] next cpu at -1: 0 [...] next cpu at 0: 1 [...] next zero at -1: 1 [...] next zero at 0: 1 [...] next and at -1: 0 [...] next and at 0: 1 [...] next wrap at -1,false: 0 [...] next wrap at 0,false: 0 [...] next wrap at -1,true: 0 [...] next wrap at 0,true: 0 [...] for each: 0 [...] for each wrap: 0 For reference, the generic implementation with NR_CPUS=2, CONFIG_SMP=y [...] testing empty mask [...] first cpu: 2 [...] first zero: 0 [...] first and: 2 [...] last cpu: 2 [...] next cpu at -1: 2 [...] next cpu at 0: 2 [...] next zero at -1: 0 [...] next zero at 0: 1 [...] next and at -1: 2 [...] next and at 0: 2 [...] next wrap at -1,false: 2 [...] next wrap at 0,false: 2 [...] next wrap at -1,true: 2 [...] next wrap at 0,true: 2 [...] for each not: 0 [...] testing non-empty mask [...] first cpu: 0 [...] first zero: 1 [...] first and: 0 [...] last cpu: 0 [...] next cpu at -1: 0 [...] next cpu at 0: 2 [...] next zero at -1: 1 [...] next zero at 0: 1 [...] next and at -1: 0 [...] next and at 0: 2 [...] next wrap at -1,false: 0 [...] next wrap at 0,false: 0 [...] next wrap at -1,true: 2 [...] next wrap at 0,true: 2 [...] for each: 0 [...] for each wrap: 0 [...] for each and: 0 Sander Vanheule (2): cpumask: Fix invalid uniprocessor mask assumption cpumask: Add UP optimised for_each_*_cpu loops include/linux/cpumask.h | 42 +++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) -- 2.36.1