Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/xe/userptr: properly setup pfn_flags_mask

Currently we just leave it uninitialised, which at first looks harmless,
however we also don't zero out the pfn array, and with pfn_flags_mask
the idea is to be able set individual flags for a given range of pfn or
completely ignore them, outside of default_flags. So here we end up with
pfn[i] & pfn_flags_mask, and if both are uninitialised we might get back
an unexpected flags value, like asking for read only with default_flags,
but getting back write on top, leading to potentially bogus behaviour.

To fix this ensure we zero the pfn_flags_mask, such that hmm only
considers the default_flags and not also the initial pfn[i] value.

v2 (Thomas):
- Prefer proper initializer.

Fixes: 81e058a3e7fd ("drm/xe: Introduce helper to populate userptr")
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Thomas Hellström <thomas.hellstrom@intel.com>
Cc: <stable@vger.kernel.org> # v6.10+
Reviewed-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: Tejas Upadhyay <tejas.upadhyay@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250226174748.294285-2-matthew.auld@intel.com
(cherry picked from commit dd8c01e42f4c5c1eaf02f003d7d588ba6706aa71)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>

authored by

Matthew Auld and committed by
Rodrigo Vivi
475d06e0 30bfc151

+10 -8
+10 -8
drivers/gpu/drm/xe/xe_hmm.c
··· 166 166 { 167 167 unsigned long timeout = 168 168 jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT); 169 - unsigned long *pfns, flags = HMM_PFN_REQ_FAULT; 169 + unsigned long *pfns; 170 170 struct xe_userptr *userptr; 171 171 struct xe_vma *vma = &uvma->vma; 172 172 u64 userptr_start = xe_vma_userptr(vma); 173 173 u64 userptr_end = userptr_start + xe_vma_size(vma); 174 174 struct xe_vm *vm = xe_vma_vm(vma); 175 - struct hmm_range hmm_range; 175 + struct hmm_range hmm_range = { 176 + .pfn_flags_mask = 0, /* ignore pfns */ 177 + .default_flags = HMM_PFN_REQ_FAULT, 178 + .start = userptr_start, 179 + .end = userptr_end, 180 + .notifier = &uvma->userptr.notifier, 181 + .dev_private_owner = vm->xe, 182 + }; 176 183 bool write = !xe_vma_read_only(vma); 177 184 unsigned long notifier_seq; 178 185 u64 npages; ··· 206 199 return -ENOMEM; 207 200 208 201 if (write) 209 - flags |= HMM_PFN_REQ_WRITE; 202 + hmm_range.default_flags |= HMM_PFN_REQ_WRITE; 210 203 211 204 if (!mmget_not_zero(userptr->notifier.mm)) { 212 205 ret = -EFAULT; 213 206 goto free_pfns; 214 207 } 215 208 216 - hmm_range.default_flags = flags; 217 209 hmm_range.hmm_pfns = pfns; 218 - hmm_range.notifier = &userptr->notifier; 219 - hmm_range.start = userptr_start; 220 - hmm_range.end = userptr_end; 221 - hmm_range.dev_private_owner = vm->xe; 222 210 223 211 while (true) { 224 212 hmm_range.notifier_seq = mmu_interval_read_begin(&userptr->notifier);