[PATCH v6 08/12] drm/xe/bo: Block mmap of DONTNEED/purged BOs

Arvind Yadav
2026-03-03T15:20:56Z

Don't allow new CPU mmaps to BOs marked DONTNEED or PURGED.
DONTNEED BOs can have their contents discarded at any time, making
CPU access undefined behavior. PURGED BOs have no backing store and
are permanently invalid.

Return -EBUSY for DONTNEED BOs (temporary purgeable state) and
-EINVAL for purged BOs (permanent, no backing store).

The mmap offset ioctl now checks the BO's purgeable state before
allowing userspace to establish a new CPU mapping. This prevents
the race where userspace gets a valid offset but the BO is purged
before actual faulting begins.

Existing mmaps (established before DONTNEED) may still work until
pages are purged, at which point CPU faults fail with SIGBUS.

v6:
- Split DONTNEED → -EBUSY and PURGED → -EINVAL for consistency
with the rest of the series (Thomas, Matt)

Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Cc: Himal Prasad Ghimiray <himal.prasad.ghimiray@intel.com>
Signed-off-by: Arvind Yadav <arvind.yadav@intel.com>
---
drivers/gpu/drm/xe/xe_bo.c | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c
index d05a73756905..3a4965bdadf2 100644
--- a/drivers/gpu/drm/xe/xe_bo.c
+++ b/drivers/gpu/drm/xe/xe_bo.c
@@ -3396,6 +3396,8 @@ int xe_gem_mmap_offset_ioctl(struct drm_device *dev, void *data,
struct xe_device *xe = to_xe_device(dev);
struct drm_xe_gem_mmap_offset *args = data;
struct drm_gem_object *gem_obj;
+ struct xe_bo *bo;
+ int err;

if (XE_IOCTL_DBG(xe, args->extensions) ||
XE_IOCTL_DBG(xe, args->reserved[0] || args->reserved[1]))
@@ -3425,11 +3427,35 @@ int xe_gem_mmap_offset_ioctl(struct drm_device *dev, void *data,
if (XE_IOCTL_DBG(xe, !gem_obj))
return -ENOENT;

+ bo = gem_to_xe_bo(gem_obj);
+
+ /*
+ * Reject new mmap to purgeable BOs. DONTNEED BOs can be purged
+ * at any time, making CPU access undefined behavior. Purged BOs have
+ * no backing store and are permanently invalid.
+ */
+ xe_bo_lock(bo, false);
+ if (xe_bo_madv_is_dontneed(bo)) {
+ err = -EBUSY;
+ goto out_unlock;
+ }
+
+ if (xe_bo_is_purged(bo)) {
+ err = -EINVAL;
+ goto out_unlock;
+ }
+ xe_bo_unlock(bo);
+
/* The mmap offset was set up at BO allocation time. */
args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
+ xe_bo_put(bo);

- xe_bo_put(gem_to_xe_bo(gem_obj));
return 0;
+
+out_unlock:
+ xe_bo_unlock(bo);
+ xe_bo_put(bo);
+ return err;
}

/**
--
2.43.0