From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=204.191.154.188 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794331975; b=S2F2cNpV4/EsLiLxH2RabPfZGuhiGKeLdvR+nb08+IxKi1gcEHQlfYZ0i+0IzQEH7cV4 pjumOhP6yMkAphDsN76gr10hSKc1mS7tiR9VoqsAXnEKL6fj/8B6ENrBgadIsoRt82r3x MQiS4EFxwW4ww273AmE0wnHOZDm43kI7wAE0Sz2OPczbWupnQZLUC/koFC7+JyoKZfdUr kCJhaC474Tmn4gI+76UFk7wKXuMyDaqAN7lJXIA1mj56HCDEUvHVOLOQMIqgDrFsM6ysB LHUn7wK6+xVyFeJ+0M2rwalddPX1/ATGBl/X4a28sfPGhi7p+iG5i/msOxp7ejMoWhA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794331975; h=DMARC-Filter:DKIM-Signature:Received:Received:From:To:Cc:Date: Message-ID:X-Mailer:In-Reply-To:References:MIME-Version: Content-Transfer-Encoding:X-SA-Exim-Connect-IP:X-SA-Exim-Rcpt-To: X-SA-Exim-Mail-From:X-Spam-Checker-Version:X-Spam-Level:X-Spam-Status: Subject:X-SA-Exim-Version:X-SA-Exim-Scanned; bh=fvNynf8htGqBQBzeh500/qpOMKe3Lz0Qq4RAbYLCoo8=; b=4M4p6iywpFkqMUiV4E36Fr+85IvmYaXRmixqEVDNKtE68weNNpU4ydtSS2q8TSZZLBZt 4pzaxlW1Yr1HZJSNxyw1bytxgEQ7lg3Jsegu5vSM2qbGv0Gggz++2fA4fzJ0jalMR6dz2 IdmGNAkjbB5cjuF05S8ZkwlnyCcaDWuE52XL2NNuIfK0J5AE/GrDb9NXbhYr7scndq68o 8aHEA8nuyTJFRtSBjhxde7Oo+o3hRdcNkxVq9yIIatgPOics9G3P2pIl7ghv9juYO86/H VLpwVQXiIuXm2xUs6xcVK1D+oTL2XQDgtOtISjSpg8Dh+ihx/iqSuNy/GgMxzwBj6jg== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=deltatee.com; spf=pass smtp.mailfrom=deltatee.com; dkim=pass header.d=deltatee.com header.i=@deltatee.com header.a=rsa-sha256 header.s=20200525 header.b=J72E8Hhf; arc=none smtp.remote-ip=204.191.154.188 Received: from ale.deltatee.com (ale.deltatee.com [204.191.154.188]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (prime256v1) server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8013660A2601; Tue, 10 Nov 2026 17:32:55 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 8013660A2601 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=deltatee.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=deltatee.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=deltatee.com header.i=@deltatee.com header.a=rsa-sha256 header.s=20200525 header.b=J72E8Hhf DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=deltatee.com; s=20200525; h=Subject:MIME-Version:References:In-Reply-To: Message-ID:Date:Cc:To:From:content-disposition; bh=fvNynf8htGqBQBzeh500/qpOMKe3Lz0Qq4RAbYLCoo8=; b=J72E8Hhfg1i9J4Sg2RcTxvItCa fDsL9ZZNrwgC/NpQMhb/LPV893K6g6nPDcY6Sd8bem2PLmAYsACRNOIdFaoxMg5RwVzst0sj+JCBD PeArCjXMYlKh4lKHy+eO8FfiMt0xq2dZkCOjKWiqv7O2guuq7S2YU9Ca6n8IsP1bDV6xiyW8NJwu/ CUbCINPUg9LFVYsi4Nbgh6K5HprkWmgpWwmLpi/cEH2lep77lRMMwxhfmHS/VSYhOZPNCu8umBVKc w3LSipcbNVSiT2A9V83qMnQAUuUbXxK4m83cBocdoAB9jePENjTXYfpwJ5UdZPbMOTTk6zd3vMaG5 W4mYjnHQ==; Received: from donard.priv.deltatee.com ([172.16.1.31]) by ale.deltatee.com with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1xQpiA-00000000o1B-1YAL; Tue, 10 Nov 2026 11:32:48 -0600 Received: from logang by donard.priv.deltatee.com with local (Exim 4.98.2) (envelope-from ) id 1xQph5-00000002cH4-2YP3; Tue, 10 Nov 2026 11:31:39 -0600 From: Logan Gunthorpe To: dmaengine@vger.kernel.org, linux-kernel@vger.kernel.org, Vinod Koul Cc: Frank Li , Christoph Hellwig , Christophe Jaillet , Dave Jiang , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Kelvin Cao , Logan Gunthorpe Date: Tue, 10 Nov 2026 11:31:33 -0600 Message-ID: <20261110173137.623764-2-logang@deltatee.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20261110173137.623764-1-logang@deltatee.com> References: <20261110173137.623764-1-logang@deltatee.com> X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SA-Exim-Connect-IP: 172.16.1.31 X-SA-Exim-Rcpt-To: dmaengine@vger.kernel.org, linux-kernel@vger.kernel.org, vkoul@kernel.org, Frank.li@nxp.com, hch@infradead.org, christophe.jaillet@wanadoo.fr, dave.jiang@intel.com, linux@weissschuh.net, kelvin.cao@microchip.com, logang@deltatee.com X-SA-Exim-Mail-From: logang@deltatee.com X-Spam-Level: Subject: [PATCH v4 1/4] dmaengine: add per-channel sysfs attribute groups via chan_groups X-SA-Exim-Version: 4.2.1 (built Sun, 23 Feb 2025 07:57:16 +0000) X-SA-Exim-Scanned: Yes (on ale.deltatee.com) Each channel already gets its own struct device (dma_chan_dev), registered with device_register()/device_unregister() and torn down correctly by chan_dev_release(). Let drivers add their own sysfs attributes to that device directly, via a new dma_device.chan_groups field. This avoids drivers needing a second, separately-managed kobject to expose driver-specific attributes. That's a use-after-free issue: kobject_put() can invoke the ktype's release() and free the structure embedding dma_chan while the core (or the driver) still expects to reference it afterward, so avoiding it requires careful ordering and bookkeeping that's easy to get wrong. The channel's struct device already has the correct lifetime, and sysfs_create_group() supports the same named-subdirectory layout (attribute_group.name) that a bare kobject would provide. To let show()/store() callbacks safely recover the struct dma_chan from the struct device they're attached to without exposing dma_list_mutex itself to drivers, add a small dmaengine_chan_from_dev_lock() / dmaengine_chan_from_dev_unlock() pair that take / release the lock, and wrap them in a dmaengine_chan_from_dev CLASS so callers can write: CLASS(dmaengine_chan_from_dev, c)(dev); if (!c) return -ENODEV; Signed-off-by: Logan Gunthorpe --- drivers/dma/dmaengine.c | 27 +++++++++++++++++++++++++++ drivers/dma/dmaengine.h | 19 +++++++++++++++++++ include/linux/dmaengine.h | 4 ++++ 3 files changed, 50 insertions(+) diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 34be53487a21..38f601bf41e1 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -161,6 +161,32 @@ static struct dma_chan *dev_to_dma_chan(struct device *dev) return chan_dev->chan; } +/** + * dmaengine_chan_from_dev_lock - take dma_list_mutex and convert a channel's + * struct device to its dma_chan + * @dev: the channel's struct device, embedded in struct dma_chan_dev + * + * Returns NULL if the channel has already been unregistered. Pairs with + * dmaengine_chan_from_dev_unlock(); see the dmaengine_chan_from_dev CLASS in + * drivers/dma/dmaengine.h. + */ +struct dma_chan *dmaengine_chan_from_dev_lock(struct device *dev) +{ + mutex_lock(&dma_list_mutex); + return dev_to_dma_chan(dev); +} +EXPORT_SYMBOL_GPL(dmaengine_chan_from_dev_lock); + +/** + * dmaengine_chan_from_dev_unlock - release the channel lookup lock + * @chan: unused; matches the value produced by dmaengine_chan_from_dev_lock() + */ +void dmaengine_chan_from_dev_unlock(struct dma_chan *chan) +{ + mutex_unlock(&dma_list_mutex); +} +EXPORT_SYMBOL_GPL(dmaengine_chan_from_dev_unlock); + static ssize_t memcpy_count_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1117,6 +1143,7 @@ static int __dma_async_device_channel_register(struct dma_device *device, dmaengine_chan_dev(chan)->class = &dma_devclass; dmaengine_chan_dev(chan)->parent = device->dev; + dmaengine_chan_dev(chan)->groups = device->chan_groups; chan->chan_dev->chan = chan; chan->chan_dev->dev_id = device->dev_id; spin_lock_init(&chan->lock); diff --git a/drivers/dma/dmaengine.h b/drivers/dma/dmaengine.h index 42a3cfa7e597..f03248a091df 100644 --- a/drivers/dma/dmaengine.h +++ b/drivers/dma/dmaengine.h @@ -214,6 +214,25 @@ int dma_async_device_channel_register(struct dma_device *device, void dma_async_device_channel_unregister(struct dma_device *device, struct dma_chan *chan); +/* + * dmaengine_chan_from_dev_lock() / dmaengine_chan_from_dev_unlock() bracket + * a critical section across which a channel's struct device can be safely + * converted back to its struct dma_chan: dmaengine_chan_from_dev_lock() + * returns NULL if the channel has already been unregistered, and the lock + * it takes must be held for as long as the returned channel (or anything + * derived from it) is accessed. + * + * Use these through the dmaengine_chan_from_dev CLASS below rather than calling + * them directly. + */ +struct dma_chan *dmaengine_chan_from_dev_lock(struct device *dev); +void dmaengine_chan_from_dev_unlock(struct dma_chan *chan); + +DEFINE_CLASS(dmaengine_chan_from_dev, struct dma_chan *, + dmaengine_chan_from_dev_unlock(_T), + dmaengine_chan_from_dev_lock(dev), + struct device *dev) + #ifdef CONFIG_DEBUG_FS #include diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 805668fbe437..944c8b0f5848 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -839,6 +839,9 @@ struct dma_filter { * @dev: struct device reference for dma mapping api * @owner: owner module (automatically set based on the provided dev) * @chan_ida: unique channel ID + * @chan_groups: optional NULL-terminated array of sysfs attribute groups + * added to each channel's struct device, for driver-specific per-channel + * attributes * @src_addr_widths: bit mask of src addr widths the device supports * Width is specified in bytes, e.g. for a device supporting * a width of 4 the mask should have BIT(4) set. @@ -923,6 +926,7 @@ struct dma_device { struct device *dev; struct module *owner; struct ida chan_ida; + const struct attribute_group **chan_groups; u32 src_addr_widths; u32 dst_addr_widths; -- 2.47.3