Shared-memory allocator services (e.g., Android's gralloc)
allocate dma-bufs on behalf of client processes in different
cgroups. Today those allocations are charged to the allocator's
own cgroup, leaving client cgroups with no visibility into their
actual memory consumption and defeating resource limits.
This series adds memory cgroup accounting for dma-buf allocations,
building on T.J. Mercier's earlier series [1] and incorporating
feedback from previous versions and LPC discussions [2].
Patch 1 introduces the MEMCG_DMABUF stat and reserve/commit/cancel
and uncharge helpers. Rather than charging at the page level via
__GFP_ACCOUNT (which would require every dma-buf exporter to implement
charging, and makes cross-cgroup transfer impractical without access
to backing pages), we track charges externally on struct dma_buf via
a MEMCG_DMABUF stat counter and route all accounting through a single
path, removing the __GFP_ACCOUNT flag from system-heap allocations
to avoid double counting.
Patch 2 adds a charge_fd field to DMA_HEAP_IOCTL_ALLOC, accepting
either a pidfd or a cgroupfd to identify the target cgroup at
allocation time. If the target cgroup cannot accommodate the charge,
the allocation returns -ENOMEM.
Patches 3-6 add access control for cross-cgroup charging. Letting
userspace decide who to charge needs to be a privileged operation
because it has material impact on OOM decission and resource limits.
We gate it via LSM hooks for the two charge_fd flavours:
security_dma_buf_charge_task() gates the pidfd path (target
identified by task credentials) and security_dma_buf_charge_cgroup()
gates the cgroupfd path (target identified by cgroup directory label),
with SELinux implementations under a dma_buf object class.
Patch 7 adds DMA_BUF_IOCTL_XFER_CHARGE, a general ioctl on any
dma-buf fd to transfer charges post-allocation. This covers the
double-hop allocator case (SurfaceFlinger -> gralloc -> kernel)
and works for buffers from any exporter (DRM, V4L2, etc.). A new
memcg_account flag is added for dma_buf_export() to ensure that
transfer/charge is only applied for buffers backed by reclaimable
system memory. If the receiving cgroup lacks capacity for the charge,
the ioctl returns -ENOMEM and the original charge is preserved.
Patch 8 adds selftests.
Known limitations:
- Single-owner model: a dma-buf carries one memcg charge regardless
of how many processes share it.
- Only memcg accounting. CMA heaps would additionally need dmem
controller integration.
- If a transfer of an uncharged buffer fails, it remains uncharged.
The allocator (userspace) is expected to handle this (retry, free, ...).
- The LSM hooks are intentionally narrow. Broader cgroup access controls
(e.g. for the memfd/kexec handover case [2]) could be a separate effort
reusing the same pattern.
- Only system heap sets memcg_account today. Other exporters
(DRM, V4L2, etc.) can opt in by setting the flag, but are not
covered by this series.
[1] https://lore.kernel.org/cgroups/20230109213809.418135-1-tjmercier@google.co…
[2] https://lpc.events/event/20/contributions/2416/
Signed-off-by: Albert Esteve <aesteve(a)redhat.com>
---
Changes in v3:
- Split mem_cgroup_charge_dmabuf() into reserve/commit/cancel three-phase API
- Extract mem_cgroup_get_from_fd() helper shared by allocate and xfer paths
- Rename __padding to flags in struct dma_buf_transfer_charge
- Fix UAF race: move mod_memcg_state() before cmpxchg in transfer
- Add memcg_account opt-in flag; xfer returns -EOPNOTSUPP if unset
- Wrap dma_buf_charge_cgroup hook in #ifdef CONFIG_CGROUPS
- Fix TOCTOU in SELinux charge_cgroup xattr length handling
- Link to v2: https://lore.kernel.org/r/20261021-v2_20230123_tjmercier_google_com-v2-0-ef…
Changes in v2:
- Move charge_pid_fd to charge_fd, accepting cgroupfd in addition
to pidfd per Christian König.
- New DMA_BUF_IOCTL_XFER_CHARGE ioctl for post-allocation charge
transfer on any dma-buf, not just dma-heap buffers per Christian König
and T.J. Mercier.
- Moved __GFP_ACCOUNT removal to patch 1 per Barry Song.
- dma-buf charge/uncharge helpers take struct dma_buf * directly
to avoid the need for caller to manage size calculations.
- Added test_xfer_charge_cgroupfd_self to dmabuf-heap selftests.
- Added LSM and SELinux hooks for cgroupfd-based charging.
- Rebased to v7.3-rc7.
- Link to v1: https://lore.kernel.org/r/20260512-v2_20230123_tjmercier_google_com-v1-0-63…
---
Albert Esteve (7):
dma-heap: charge dma-buf memory via explicit memcg
security: dma-buf: Add dma_buf_charge_task LSM hook
security: dma-buf: Add dma_buf_charge_cgroup LSM hook
selinux: Restrict cross-cgroup dma-buf charging
selinux: Restrict dma-buf direct cgroup charging
dma-buf: transfer memcg charges via DMA_BUF_IOCTL_XFER_CHARGE
selftests/dmabuf-heaps: Add dma-buf memcg accounting tests
T.J. Mercier (1):
memcg: Add MEMCG_DMABUF accounting infrastructure
Documentation/admin-guide/cgroup-v2.rst | 5 +
drivers/dma-buf/dma-buf.c | 46 ++++
drivers/dma-buf/dma-heap.c | 28 +-
drivers/dma-buf/heaps/cma_heap.c | 3 +-
drivers/dma-buf/heaps/system_heap.c | 22 +-
drivers/tee/tee_heap.c | 3 +-
include/linux/dma-buf.h | 9 +
include/linux/dma-heap.h | 3 +-
include/linux/lsm_hook_defs.h | 4 +
include/linux/memcontrol.h | 52 ++++
include/linux/security.h | 18 ++
include/uapi/linux/dma-buf.h | 26 ++
include/uapi/linux/dma-heap.h | 7 +
mm/memcontrol.c | 192 ++++++++++++++
security/security.c | 34 +++
security/selinux/hooks.c | 44 ++++
security/selinux/include/classmap.h | 1 +
tools/testing/selftests/cgroup/Makefile | 2 +-
tools/testing/selftests/cgroup/test_memcontrol.c | 290 ++++++++++++++++++++-
tools/testing/selftests/dmabuf-heaps/config | 1 +
tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c | 227 +++++++++++++++-
tools/testing/selftests/dmabuf-heaps/vmtest.sh | 226 ++++++++++++++++
22 files changed, 1228 insertions(+), 15 deletions(-)
---
base-commit: 24a19b953e2a3d0ea5a8c4951a0ab8f32720c907
change-id: 20260508-v2_20230123_tjmercier_google_com-f44fcfb16530
Best regards,
--
Albert Esteve <aesteve(a)redhat.com>
On 10/27/26 14:34, Mikko Perttunen wrote:
> On Tuesday, October 27, 2026 9:33 PM Jason Gunthorpe wrote:
>> On Tue, Oct 27, 2026 at 12:42:32PM +0900, Mikko Perttunen wrote:
>>
>>>> This page-side use predates the series, so the fault is not itself a v2
>>>> regression. Is dma_buf_sgt_attach() valid for this call site, or does Tegra
>>>> need a page/physical mapping type first?
>>>
>>> Sounds like a bug in TegraDRM; we should be using the DMA addr/length
>>> for the explicit IOMMU mapping as the sgt attachment is for the dummy
>>> DRM device explicitly intended to give us physical addresses.
>>
>> No, you cannot connect dmabuf to an iommu_domain. It is 100% always
>> illegal. DMABUF does not support this. Do not pass sg_dma to iommu
>> functions either.
>
> Sure, I agree -- so let's say it's a bug on top of the baseline crimes
> TegraDRM commits :)
Well the initial crime was to abuse sgt to transport dma addresses, don't document how all of this works and then be surprised when everything blew up.
But yeah don't touch the pages in sgt exposed by DMA-buf, that is pretty much one of the most fundamental rules we have now.
Regards,
Christian.
>
>>
>>> I'm currently in the process of removing the whole explicit IOMMU path
>>> so if this only occurs with CONFIG_DMABUF_DEBUG enabled, I don't think
>>> there's a pressing need to fix this before then.
>>
>> Yes I think this is probably the only way to fix it :| You have to
>> always use the DMA API
>>
>> Jason
>>
>
>
>
>
On Tue, Oct 27, 2026 at 07:03:29AM -0600, Jens Axboe wrote:
> On 10/27/26 3:08 AM, Li Wang wrote:
> > From: Mengmeng Zhao <zhaomengmeng(a)kylinos.cn>
> >
> > This patch introduces a driver that allows moving data between a GPU
> > dma-buf and a regular file on NVME without staging it through the page
> > cache. Userspace registers the GPU dma-buf with the device, then issues
> > read and write requests via the device's ioctls. Each transfer is direct
> > I/O: an ITER_DMABUF_MAP iterator is passed to the file's read_iter or
> > write_iter, and the filesystem's iomap path submits REQ_DMABUF bios that
> > already carry the dma addresses.
> >
> > Signed-off-by: Mengmeng Zhao <zhaomengmeng(a)kylinos.cn>
> > Signed-off-by: Li Wang <liwang(a)kylinos.cn>
> > ---
> > .../userspace-api/ioctl/ioctl-number.rst | 2 +
> > drivers/dma-buf/dma-buf-io.c | 3 +
> > drivers/misc/Kconfig | 16 +
> > drivers/misc/Makefile | 1 +
> > drivers/misc/fgds.c | 506 ++++++++++++++++++
> > fs/iomap/buffered-io.c | 11 +
> > fs/iomap/direct-io.c | 23 +-
> > fs/xfs/xfs_file.c | 4 +
> > include/linux/iov_iter.h | 4 +
> > include/uapi/linux/fgds.h | 124 +++++
> > lib/iov_iter.c | 1 +
> > mm/filemap.c | 22 +-
> > 12 files changed, 713 insertions(+), 4 deletions(-)
> > create mode 100644 drivers/misc/fgds.c
> > create mode 100644 include/uapi/linux/fgds.h
>
> What's the point of this, when you can just use io_uring to do
> the same?!
Agreed, I thought that the summary of the last round of reviews was
"this isn't needed at all". Li, what changed from that?
thanks,
greg k-h
On Tue, Oct 27, 2026 at 12:42:32PM +0900, Mikko Perttunen wrote:
> > This page-side use predates the series, so the fault is not itself a v2
> > regression. Is dma_buf_sgt_attach() valid for this call site, or does Tegra
> > need a page/physical mapping type first?
>
> Sounds like a bug in TegraDRM; we should be using the DMA addr/length
> for the explicit IOMMU mapping as the sgt attachment is for the dummy
> DRM device explicitly intended to give us physical addresses.
No, you cannot connect dmabuf to an iommu_domain. It is 100% always
illegal. DMABUF does not support this. Do not pass sg_dma to iommu
functions either.
> I'm currently in the process of removing the whole explicit IOMMU path
> so if this only occurs with CONFIG_DMABUF_DEBUG enabled, I don't think
> there's a pressing need to fix this before then.
Yes I think this is probably the only way to fix it :| You have to
always use the DMA API
Jason
On Tue, Oct 27, 2026 at 03:15:34AM +0100, Karl Mehltretter wrote:
> On Mon, Oct 26, 2026 at 04:36:14PM +0100, Alistair Popple wrote:
>
> Testing the series on a Jetson Nano exposed this path. A 3 MiB system-heap
> buffer was imported into Tegra DRM and scanned out over HDMI. With
> CONFIG_DMABUF_DEBUG=y the PRIME import succeeded, but scanout immediately
> produced display SMMU faults starting at 0x300000.
Why is this being reported here? Shouldn't CONFIG_DMABUF_DEBUG=y have
always caused tegra to fail?
> > @@ -475,7 +475,7 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm,
> > * domain, map it first to the DRM device to get an sgt.
> > */
> > if (tegra->domain) {
> > - attach = dma_buf_attach(buf, drm->dev);
> > + attach = dma_buf_sgt_attach(buf, drm->dev);
>
> tegra_bo_import() passes the attachment SGT to iommu_map_sgtable(),
> which
This is illegal use of dmabuf, this was discussed in some other driver
recently.
All DRM drivers trying to use custom iommu domains are busted this
way. AFAIK there is no solution besides "don't do that".
> This page-side use predates the series, so the fault is not itself a v2
> regression. Is dma_buf_sgt_attach() valid for this call site, or does Tegra
> need a page/physical mapping type first?
Tegra is broken.
Jason
On 10/27/26 03:15, Karl Mehltretter wrote:
> On Mon, Oct 26, 2026 at 04:36:14PM +0100, Alistair Popple wrote:
>
> Testing the series on a Jetson Nano exposed this path. A 3 MiB system-heap
> buffer was imported into Tegra DRM and scanned out over HDMI. With
> CONFIG_DMABUF_DEBUG=y the PRIME import succeeded, but scanout immediately
> produced display SMMU faults starting at 0x300000.
>
> Tracing the fault led here:
>
>> @@ -475,7 +475,7 @@ static struct tegra_bo *tegra_bo_import(struct drm_device *drm,
>> * domain, map it first to the DRM device to get an sgt.
>> */
>> if (tegra->domain) {
>> - attach = dma_buf_attach(buf, drm->dev);
>> + attach = dma_buf_sgt_attach(buf, drm->dev);
>
> tegra_bo_import() passes the attachment SGT to iommu_map_sgtable(), which
> uses sg_phys() and sg->length. The SGT mapping contract only guarantees the
> DMA address and length fields. The debug wrapper clears the page-side fields,
> so iommu_map_sgtable() maps zero bytes.
>
> Tegra only treats negative returns as errors and keeps the reserved
> IOVA, which scanout then faults on.
>
> This page-side use predates the series, so the fault is not itself a v2
> regression. Is dma_buf_sgt_attach() valid for this call site, or does Tegra
> need a page/physical mapping type first?
Sharing page/physical to be used with the IOMMU functions through DMA-buf is an absolutely hard NAK from my side.
We still need to figure out how to do this between KVM, IOMMUFD and virtio so that it is limited to only those three.
Regards,
Christian.
>
> Karl
On Mon, Oct 26, 2026 at 11:51:11AM +0530, Jayant Shekhar wrote:
> DCP platforms place the display pipeline under firmware control, so Linux
What is a DCP platform?
> cannot discover display resources through direct register access. The DRM
> driver therefore needs device-tree descriptions of the Qualcomm transport
> wrapper, display topology, IOMMU contexts, and panel connections.
>
> Add bindings for the Qualcomm DCP transport wrapper and VirtIO display
> subsystem. Document the IPCC power-notify resources, transport and
> framebuffer IOMMU contexts, firmware-visible IOVA range, INTF graph, and
> DSI panel connections. The wrapper creates a standard VirtIO-MMIO child
> after the IPCC power-notify sequence has completed.
It's still DT for real hardware, so I wonder why no SoC specific
compatibles were used.
Best regards,
Krzysztof