Received: by 2002:a05:6a10:af89:0:0:0:0 with SMTP id iu9csp3623729pxb; Mon, 24 Jan 2022 13:46:25 -0800 (PST) X-Google-Smtp-Source: ABdhPJxrqDNykAFQkp2vS5OnpNRkdmshc16DztUpgXA1s16edPfBVOXLr0PJ9r2wAi5DHDP2VIY9 X-Received: by 2002:a17:902:7c93:b0:14b:3020:1dad with SMTP id y19-20020a1709027c9300b0014b30201dadmr11378761pll.77.1643060785059; Mon, 24 Jan 2022 13:46:25 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1643060785; cv=none; d=google.com; s=arc-20160816; b=gIDA4BSd6I4POYOc21iCMHD2/FuqE8uTPNtEfHzNsBJAtQDuKip5gHKKE9E6kl6SJG mKD7I3xCem/Cw+59nI4kkHH+7e6nfs5QInOMpWuVcBWRL9WstpHed3C8aQMK0apXqOoZ z/UjXyPpoidQHQKJy0+lKsgBGFPfzQbznSzAoM378Ix3oEI1R1VP0AU/m1akCR+g6pri pdO+9IpgjUwB2ey5vwSY3VPOlXiO0339u5d3gx/VOjbc1T6/MxDIshufehQFU2qV5Wmd gM0ATomh2ICdsFBMy4GrLZLuX4oe4fHAFl46RGwPz52ooSsCKfh4ZmG7WQXXae5nmqF6 YRxA== 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 :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=NDV8xfEvRSw97WMpg58Cj9fo7fqi22+qkgRP3norm20=; b=YUIn9LSzR3JOfojZjUHfdBADPlRLUO+cDT9rOk/vm+kip7df/y6BfaIMaXBLenPcAq jhE1qGyqNL/W2PY/aoDElkJGluegc8kgLa8dJgIL9DCwHzM+BSSVp9v3/4gHrpHKI6M4 AyCwb2PWB5wRha7ZZt8VYFK+SI72UoiSsEeD9W1qPsNAb4GrUulVD75r6nAN9YEA47we sj/UW3jKpyZdNUnTdjh1+2CbREBnbTj8aWgCZZXWLFSMM5z9c/rHG+H/JoXj8ebtfb+e zYoVWc7iZyxcZ+TeBlG/Bz25mG9ydD8PfAuwPY6ec0XHdJGZ3AWafQl7M4ajUXKAz+Df g7Cg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=aqFLcsiR; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id s84si6039406pgs.644.2022.01.24.13.46.13; Mon, 24 Jan 2022 13:46:25 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=aqFLcsiR; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1451443AbiAXVW4 (ORCPT + 99 others); Mon, 24 Jan 2022 16:22:56 -0500 Received: from ams.source.kernel.org ([145.40.68.75]:50276 "EHLO ams.source.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1442810AbiAXUzY (ORCPT ); Mon, 24 Jan 2022 15:55:24 -0500 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 58B59B8105C; Mon, 24 Jan 2022 20:55:23 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7DB13C340E5; Mon, 24 Jan 2022 20:55:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1643057722; bh=l+gtYq5zMqIJC9T7FFg/WoG6gd4YYnKZA2mw7RhH/1s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aqFLcsiR+XlvMopzzu8l53+x4PZ59325kFSFLrjyu5PEQhdx4Gq2jo2QXYyLv21W7 R9TW9YO5jS24UqrBgBkEOD4NRyedNDzOjpagisDdw31MEYrx6W4PoSsPpD4pgfSe7M 9vA055luz9pmECekrDoeOgZNbzhM2Wj6DWdlk2/Q= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Jonathan Cameron , Pengutronix Kernel Team , Dmitry Torokhov , Oleksij Rempel , Stable@vger.kernel.org Subject: [PATCH 5.16 0058/1039] iio: trigger: Fix a scheduling whilst atomic issue seen on tsc2046 Date: Mon, 24 Jan 2022 19:30:47 +0100 Message-Id: <20220124184127.096367441@linuxfoundation.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220124184125.121143506@linuxfoundation.org> References: <20220124184125.121143506@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Jonathan Cameron commit 9020ef659885f2622cfb386cc229b6d618362895 upstream. IIO triggers are software IRQ chips that split an incoming IRQ into separate IRQs routed to all devices using the trigger. When all consumers are done then a trigger callback reenable() is called. There are a few circumstances under which this can happen in atomic context. 1) A single user of the trigger that calls the iio_trigger_done() function from interrupt context. 2) A race between disconnecting the last device from a trigger and the trigger itself sucessfully being disabled. To avoid a resulting scheduling whilst atomic, close this second corner by using schedule_work() to ensure the reenable is not done in atomic context. Note that drivers must be careful to manage the interaction of set_state() and reenable() callbacks to ensure appropriate reference counting if they are relying on the same hardware controls. Deliberately taking this the slow path rather than via a fixes tree because the error has hard to hit and I would like it to soak for a while before hitting a release kernel. Signed-off-by: Jonathan Cameron Cc: Pengutronix Kernel Team Cc: Dmitry Torokhov Tested-by: Oleksij Rempel Cc: Link: https://lore.kernel.org/r/20211017172209.112387-1-jic23@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/iio/industrialio-trigger.c | 36 +++++++++++++++++++++++++++++++++++- include/linux/iio/trigger.h | 2 ++ 2 files changed, 37 insertions(+), 1 deletion(-) --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -162,6 +162,39 @@ static struct iio_trigger *iio_trigger_a return trig; } +static void iio_reenable_work_fn(struct work_struct *work) +{ + struct iio_trigger *trig = container_of(work, struct iio_trigger, + reenable_work); + + /* + * This 'might' occur after the trigger state is set to disabled - + * in that case the driver should skip reenabling. + */ + trig->ops->reenable(trig); +} + +/* + * In general, reenable callbacks may need to sleep and this path is + * not performance sensitive, so just queue up a work item + * to reneable the trigger for us. + * + * Races that can cause this. + * 1) A handler occurs entirely in interrupt context so the counter + * the final decrement is still in this interrupt. + * 2) The trigger has been removed, but one last interrupt gets through. + * + * For (1) we must call reenable, but not in atomic context. + * For (2) it should be safe to call reenanble, if drivers never blindly + * reenable after state is off. + */ +static void iio_trigger_notify_done_atomic(struct iio_trigger *trig) +{ + if (atomic_dec_and_test(&trig->use_count) && trig->ops && + trig->ops->reenable) + schedule_work(&trig->reenable_work); +} + void iio_trigger_poll(struct iio_trigger *trig) { int i; @@ -173,7 +206,7 @@ void iio_trigger_poll(struct iio_trigger if (trig->subirqs[i].enabled) generic_handle_irq(trig->subirq_base + i); else - iio_trigger_notify_done(trig); + iio_trigger_notify_done_atomic(trig); } } } @@ -535,6 +568,7 @@ struct iio_trigger *viio_trigger_alloc(s trig->dev.type = &iio_trig_type; trig->dev.bus = &iio_bus_type; device_initialize(&trig->dev); + INIT_WORK(&trig->reenable_work, iio_reenable_work_fn); mutex_init(&trig->pool_lock); trig->subirq_base = irq_alloc_descs(-1, 0, --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -55,6 +55,7 @@ struct iio_trigger_ops { * @attached_own_device:[INTERN] if we are using our own device as trigger, * i.e. if we registered a poll function to the same * device as the one providing the trigger. + * @reenable_work: [INTERN] work item used to ensure reenable can sleep. **/ struct iio_trigger { const struct iio_trigger_ops *ops; @@ -74,6 +75,7 @@ struct iio_trigger { unsigned long pool[BITS_TO_LONGS(CONFIG_IIO_CONSUMERS_PER_TRIGGER)]; struct mutex pool_lock; bool attached_own_device; + struct work_struct reenable_work; };