AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/09/11 22:06 flow patch-triage
2m Args:
null

Results:
{
  "EnableConfigs": [
    "VFIO",
    "VFIO_PCI",
    "PCI_P2PDMA",
    "ZONE_DEVICE",
    "DMA_SHARED_BUFFER"
  ],
  "FocusSymbols": [
    "vfio_pci_core_mmap",
    "vfio_pci_core_mmap_prep_dmabuf",
    "vfio_pci_mmap_huge_fault",
    "vfio_pci_dma_buf_find_pfn",
    "vfio_pci_core_feature_dma_buf_revoke",
    "vfio_pci_core_feature_dma_buf",
    "vfio_pci_dma_buf_move",
    "vfio_pci_dma_buf_cleanup",
    "vfio_pci_lock_revoke_bars",
    "vfio_pci_unrevoke_bars",
    "dma_buf_set_name"
  ],
  "KMSANReasoning": "The patch refactors dma_buf name handling and integrates DMABUF-backed PCI BAR mapping and revocation into the VFIO PCI core (including the new VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE ioctl feature and rewritten page fault handling).\n\nAnalysis with respect to uninitialized memory (KMSAN):\n1. Kernel-to-user info leaks: The new ioctl feature VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE only performs a copy_from_user() on input arguments; no kernel data is returned or copied to user space. DMA-buf naming via dma_buf_set_name_user() safely copies strings from userspace using strndup_user() and names allocated with kasprintf() are fully initialized.\n2. Uninitialized variables / fields: All heap allocations for vfio_pci_dma_buf and its phys_vec array use kzalloc_obj(), ensuring zero-initialization. All stack variables in the new/modified functions (e.g., pres, pfn, ret, fault_offset) are initialized before use. New struct fields on vfio_pci_core_device (dmabuf_lock, bars_revoked, zap_bars_on_revoke) are explicitly initialized during device init/enable.\n3. Fault handling: The PFN resolution logic operates on PCI MMIO resource addresses rather than uninitialized kernel memory pages.\n\nContrast with KASAN/LOCKDEP:\nThe risks introduced by this change center on synchronization, reference counting (kref, dma_buf, vfio_device registration, eventfd_ctx), locking hierarchies (memory_lock vs dmabuf_lock vs dma_resv lock), and potential use-after-free or race conditions during device reset, revocation, or unmap. These classes of bugs are comprehensively covered by KASAN and LOCKDEP in standard fuzzing builds. There are no uninitialized memory risks that would uniquely warrant a KMSAN session.",
  "NeedsKMSAN": false,
  "Reasoning": "This patch introduces DMABUF-backed BAR memory mappings for VFIO-PCI devices, refactoring vfio_pci_core_mmap to export DMABUFs and fundamentally reworking vfio_pci_mmap_huge_fault with multi-lock synchronization across dma_resv_lock, vfio_device registration, memory_lock, and dmabuf_lock. It also adds a new user-facing VFIO ioctl feature (VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE) for permanently revoking DMABUFs, and alters dma-buf name assignment logic and length checks in dma-buf.c. The code paths are reachable from userspace in standard QEMU/KVM virtualized environments via VFIO and DMA-BUF interfaces. Given the complex concurrency, locking invariants, mmap fault handling, and new ioctl logic, this patch warrants fuzzing.",
  "WorthFuzzing": true
}

1/1 2026/09/11 22:06 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 4181b909f1f9301a41044499b4f86a52a0c71e2f\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Fri Sep 11 22:06:41 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c\nindex d504c636dc294..8129ea11ff58c 100644\n--- a/drivers/dma-buf/dma-buf.c\n+++ b/drivers/dma-buf/dma-buf.c\n@@ -405,31 +405,29 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)\n }\n \n /**\n- * dma_buf_set_name - Set a name to a specific dma_buf to track the usage.\n- * It could support changing the name of the dma-buf if the same\n- * piece of memory is used for multiple purpose between different devices.\n+ * dma_buf_set_name_user - Set a dma_buf's name from a user string\n+ *\n+ * The string is up to DMA_BUF_NAME_LEN long, including the terminator.\n  *\n  * @dmabuf: [in]     dmabuf buffer that will be renamed.\n  * @buf:    [in]     A piece of userspace memory that contains the name of\n  *                   the dma-buf.\n  *\n- * Returns 0 on success. If the dma-buf buffer is already attached to\n- * devices, return -EBUSY.\n- *\n+ * Returns 0 on success, and any previously-set name is freed.\n  */\n-static long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf)\n+static long dma_buf_set_name_user(struct dma_buf *dmabuf, const char __user *buf)\n {\n \tchar *name = strndup_user(buf, DMA_BUF_NAME_LEN);\n+\tint ret;\n \n \tif (IS_ERR(name))\n \t\treturn PTR_ERR(name);\n \n-\tspin_lock(\u0026dmabuf-\u003ename_lock);\n-\tkfree(dmabuf-\u003ename);\n-\tdmabuf-\u003ename = name;\n-\tspin_unlock(\u0026dmabuf-\u003ename_lock);\n+\tret = dma_buf_set_name(dmabuf, name);\n+\tif (ret)\n+\t\tkfree(name);\n \n-\treturn 0;\n+\treturn ret;\n }\n \n #if IS_ENABLED(CONFIG_SYNC_FILE)\n@@ -578,7 +576,7 @@ static long dma_buf_ioctl(struct file *file,\n \n \tcase DMA_BUF_SET_NAME_A:\n \tcase DMA_BUF_SET_NAME_B:\n-\t\treturn dma_buf_set_name(dmabuf, (const char __user *)arg);\n+\t\treturn dma_buf_set_name_user(dmabuf, (const char __user *)arg);\n \n #if IS_ENABLED(CONFIG_SYNC_FILE)\n \tcase DMA_BUF_IOCTL_EXPORT_SYNC_FILE:\n@@ -854,6 +852,40 @@ void dma_buf_put(struct dma_buf *dmabuf)\n }\n EXPORT_SYMBOL_NS_GPL(dma_buf_put, \"DMA_BUF\");\n \n+/**\n+ * dma_buf_set_name - Set a dma_buf's name\n+ * It could support changing the name of the dma-buf if the same piece\n+ * of memory is used for multiple purpose between different devices.\n+ *\n+ * @dmabuf: [in]     dmabuf buffer that will be renamed.\n+ * @name:   [in]     The name of the dma-buf, allocated with kmalloc() or\n+ *                   similar.  This takes ownership of the allocation\n+ *                   on success, which will be kfree()d when the\n+ *                   dmabuf is released or a new name assigned.\n+ *\n+ * Returns 0 on success, -EINVAL if the name is NULL, or -E2BIG if the\n+ * name exceeds DMA_BUF_NAME_LEN.\n+ */\n+int dma_buf_set_name(struct dma_buf *dmabuf, char *name)\n+{\n+\tif (!name)\n+\t\treturn -EINVAL;\n+\n+\t/* dmabuffs_dname() won't use the string if the length\n+\t * (including terminator) exceeds DMA_BUF_NAME_LEN:\n+\t */\n+\tif (strlen(name) \u003e= DMA_BUF_NAME_LEN)\n+\t\treturn -E2BIG;\n+\n+\tspin_lock(\u0026dmabuf-\u003ename_lock);\n+\tkfree(dmabuf-\u003ename);\n+\tdmabuf-\u003ename = name;\n+\tspin_unlock(\u0026dmabuf-\u003ename_lock);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_NS_GPL(dma_buf_set_name, \"DMA_BUF\");\n+\n static int dma_buf_wrap_sg_table(struct sg_table **sg_table)\n {\n \tstruct scatterlist *to_sg, *from_sg;\ndiff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig\nindex 296bf01e185ec..c6d6fb09af86c 100644\n--- a/drivers/vfio/pci/Kconfig\n+++ b/drivers/vfio/pci/Kconfig\n@@ -6,6 +6,7 @@ config VFIO_PCI_CORE\n \ttristate\n \tselect VFIO_VIRQFD\n \tselect IRQ_BYPASS_MANAGER\n+\tselect DMA_SHARED_BUFFER\n \n config VFIO_PCI_INTX\n \tdef_bool y if !S390\n@@ -56,7 +57,8 @@ config VFIO_PCI_ZDEV_KVM\n \t  To enable s390x KVM vfio-pci extensions, say Y.\n \n config VFIO_PCI_DMABUF\n-\tdef_bool y if VFIO_PCI_CORE \u0026\u0026 PCI_P2PDMA \u0026\u0026 DMA_SHARED_BUFFER\n+\tdef_bool y if PCI_P2PDMA\n+\tdepends on VFIO_PCI_CORE\n \n source \"drivers/vfio/pci/mlx5/Kconfig\"\n \ndiff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile\nindex 6138f1bf241df..881452ea89be0 100644\n--- a/drivers/vfio/pci/Makefile\n+++ b/drivers/vfio/pci/Makefile\n@@ -1,8 +1,7 @@\n # SPDX-License-Identifier: GPL-2.0-only\n \n-vfio-pci-core-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o\n+vfio-pci-core-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o vfio_pci_dmabuf.o\n vfio-pci-core-$(CONFIG_VFIO_PCI_ZDEV_KVM) += vfio_pci_zdev.o\n-vfio-pci-core-$(CONFIG_VFIO_PCI_DMABUF) += vfio_pci_dmabuf.o\n obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o\n \n vfio-pci-y := vfio_pci.o\ndiff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c\nindex 86362ec424a50..14622556355eb 100644\n--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c\n+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c\n@@ -1564,6 +1564,7 @@ static int hisi_acc_vfio_pci_migrn_init_dev(struct vfio_device *core_vdev)\n \tstruct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);\n \tstruct pci_dev *pdev = to_pci_dev(core_vdev-\u003edev);\n \tstruct hisi_qm *pf_qm = hisi_acc_get_pf_qm(pdev);\n+\tint ret;\n \n \thisi_acc_vdev-\u003evf_id = pci_iov_vf_id(pdev) + 1;\n \thisi_acc_vdev-\u003epf_qm = pf_qm;\n@@ -1575,7 +1576,18 @@ static int hisi_acc_vfio_pci_migrn_init_dev(struct vfio_device *core_vdev)\n \tcore_vdev-\u003emigration_flags = VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_PRE_COPY;\n \tcore_vdev-\u003emig_ops = \u0026hisi_acc_vfio_pci_migrn_state_ops;\n \n-\treturn vfio_pci_core_init_dev(core_vdev);\n+\tret = vfio_pci_core_init_dev(core_vdev);\n+\tif (ret)\n+\t\treturn ret;\n+\t/*\n+\t * hisi_acc_vfio_pci_mmap() calls down to\n+\t * vfio_pci_core_mmap(), so BAR mappings are still\n+\t * DMABUF-backed.  They don't require a zap on revoke, so opt\n+\t * out:\n+\t */\n+\thisi_acc_vdev-\u003ecore_device.zap_bars_on_revoke = false;\n+\n+\treturn 0;\n }\n \n static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = {\ndiff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c\nindex a10ed733f0e3a..bc6ccb2e135c3 100644\n--- a/drivers/vfio/pci/vfio_pci_config.c\n+++ b/drivers/vfio/pci/vfio_pci_config.c\n@@ -590,12 +590,10 @@ static int vfio_basic_config_write(struct vfio_pci_core_device *vdev, int pos,\n \t\tvirt_mem = !!(le16_to_cpu(*virt_cmd) \u0026 PCI_COMMAND_MEMORY);\n \t\tnew_mem = !!(new_cmd \u0026 PCI_COMMAND_MEMORY);\n \n-\t\tif (!new_mem) {\n-\t\t\tvfio_pci_zap_and_down_write_memory_lock(vdev);\n-\t\t\tvfio_pci_dma_buf_move(vdev, true);\n-\t\t} else {\n+\t\tif (!new_mem)\n+\t\t\tvfio_pci_lock_revoke_bars(vdev);\n+\t\telse\n \t\t\tdown_write(\u0026vdev-\u003ememory_lock);\n-\t\t}\n \n \t\t/*\n \t\t * If the user is writing mem/io enable (new_mem/io) and we\n@@ -631,7 +629,7 @@ static int vfio_basic_config_write(struct vfio_pci_core_device *vdev, int pos,\n \t\t*virt_cmd |= cpu_to_le16(new_cmd \u0026 mask);\n \n \t\tif (__vfio_pci_memory_enabled(vdev))\n-\t\t\tvfio_pci_dma_buf_move(vdev, false);\n+\t\t\tvfio_pci_unrevoke_bars(vdev);\n \t\tup_write(\u0026vdev-\u003ememory_lock);\n \t}\n \n@@ -712,16 +710,14 @@ static int __init init_pci_cap_basic_perm(struct perm_bits *perm)\n static void vfio_lock_and_set_power_state(struct vfio_pci_core_device *vdev,\n \t\t\t\t\t  pci_power_t state)\n {\n-\tif (state \u003e= PCI_D3hot) {\n-\t\tvfio_pci_zap_and_down_write_memory_lock(vdev);\n-\t\tvfio_pci_dma_buf_move(vdev, true);\n-\t} else {\n+\tif (state \u003e= PCI_D3hot)\n+\t\tvfio_pci_lock_revoke_bars(vdev);\n+\telse\n \t\tdown_write(\u0026vdev-\u003ememory_lock);\n-\t}\n \n \tvfio_pci_set_power_state(vdev, state);\n \tif (__vfio_pci_memory_enabled(vdev))\n-\t\tvfio_pci_dma_buf_move(vdev, false);\n+\t\tvfio_pci_unrevoke_bars(vdev);\n \tup_write(\u0026vdev-\u003ememory_lock);\n }\n \n@@ -908,11 +904,10 @@ static int vfio_exp_config_write(struct vfio_pci_core_device *vdev, int pos,\n \t\t\t\t\t\t \u0026cap);\n \n \t\tif (!ret \u0026\u0026 (cap \u0026 PCI_EXP_DEVCAP_FLR)) {\n-\t\t\tvfio_pci_zap_and_down_write_memory_lock(vdev);\n-\t\t\tvfio_pci_dma_buf_move(vdev, true);\n+\t\t\tvfio_pci_lock_revoke_bars(vdev);\n \t\t\tpci_try_reset_function(vdev-\u003epdev);\n \t\t\tif (__vfio_pci_memory_enabled(vdev))\n-\t\t\t\tvfio_pci_dma_buf_move(vdev, false);\n+\t\t\t\tvfio_pci_unrevoke_bars(vdev);\n \t\t\tup_write(\u0026vdev-\u003ememory_lock);\n \t\t}\n \t}\n@@ -993,11 +988,10 @@ static int vfio_af_config_write(struct vfio_pci_core_device *vdev, int pos,\n \t\t\t\t\t\t\u0026cap);\n \n \t\tif (!ret \u0026\u0026 (cap \u0026 PCI_AF_CAP_FLR) \u0026\u0026 (cap \u0026 PCI_AF_CAP_TP)) {\n-\t\t\tvfio_pci_zap_and_down_write_memory_lock(vdev);\n-\t\t\tvfio_pci_dma_buf_move(vdev, true);\n+\t\t\tvfio_pci_lock_revoke_bars(vdev);\n \t\t\tpci_try_reset_function(vdev-\u003epdev);\n \t\t\tif (__vfio_pci_memory_enabled(vdev))\n-\t\t\t\tvfio_pci_dma_buf_move(vdev, false);\n+\t\t\t\tvfio_pci_unrevoke_bars(vdev);\n \t\t\tup_write(\u0026vdev-\u003ememory_lock);\n \t\t}\n \t}\ndiff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c\nindex 3f11a9624b9c0..911e248aa764f 100644\n--- a/drivers/vfio/pci/vfio_pci_core.c\n+++ b/drivers/vfio/pci/vfio_pci_core.c\n@@ -13,6 +13,8 @@\n #include \u003clinux/aperture.h\u003e\n #include \u003clinux/debugfs.h\u003e\n #include \u003clinux/device.h\u003e\n+#include \u003clinux/dma-buf.h\u003e\n+#include \u003clinux/dma-resv.h\u003e\n #include \u003clinux/eventfd.h\u003e\n #include \u003clinux/file.h\u003e\n #include \u003clinux/interrupt.h\u003e\n@@ -375,8 +377,7 @@ static int vfio_pci_runtime_pm_entry(struct vfio_pci_core_device *vdev,\n \t * The vdev power related flags are protected with 'memory_lock'\n \t * semaphore.\n \t */\n-\tvfio_pci_zap_and_down_write_memory_lock(vdev);\n-\tvfio_pci_dma_buf_move(vdev, true);\n+\tvfio_pci_lock_revoke_bars(vdev);\n \n \tif (vdev-\u003epm_runtime_engaged) {\n \t\tup_write(\u0026vdev-\u003ememory_lock);\n@@ -462,7 +463,7 @@ static void vfio_pci_runtime_pm_exit(struct vfio_pci_core_device *vdev)\n \tdown_write(\u0026vdev-\u003ememory_lock);\n \t__vfio_pci_runtime_pm_exit(vdev);\n \tif (__vfio_pci_memory_enabled(vdev))\n-\t\tvfio_pci_dma_buf_move(vdev, false);\n+\t\tvfio_pci_unrevoke_bars(vdev);\n \tup_write(\u0026vdev-\u003ememory_lock);\n }\n \n@@ -526,8 +527,14 @@ static int vfio_pci_core_runtime_resume(struct device *dev)\n \t */\n \tdown_write(\u0026vdev-\u003ememory_lock);\n \tif (vdev-\u003epm_wake_eventfd_ctx) {\n-\t\teventfd_signal(vdev-\u003epm_wake_eventfd_ctx);\n+\t\tstruct eventfd_ctx *ctx = vdev-\u003epm_wake_eventfd_ctx;\n+\n+\t\tvdev-\u003epm_wake_eventfd_ctx = NULL;\n \t\t__vfio_pci_runtime_pm_exit(vdev);\n+\t\tif (__vfio_pci_memory_enabled(vdev))\n+\t\t\tvfio_pci_unrevoke_bars(vdev);\n+\t\teventfd_signal(ctx);\n+\t\teventfd_ctx_put(ctx);\n \t}\n \tup_write(\u0026vdev-\u003ememory_lock);\n \n@@ -659,6 +666,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)\n \t\tvdev-\u003ehas_vga = true;\n \n \tvfio_pci_core_map_bars(vdev);\n+\tvdev-\u003ebars_revoked = false;\n \n \treturn 0;\n \n@@ -1312,6 +1320,8 @@ static int vfio_pci_ioctl_set_irqs(struct vfio_pci_core_device *vdev,\n \treturn ret;\n }\n \n+static void vfio_pci_revoke_bars(struct vfio_pci_core_device *vdev);\n+\n static int vfio_pci_ioctl_reset(struct vfio_pci_core_device *vdev,\n \t\t\t\tvoid __user *arg)\n {\n@@ -1320,7 +1330,7 @@ static int vfio_pci_ioctl_reset(struct vfio_pci_core_device *vdev,\n \tif (!vdev-\u003ereset_works)\n \t\treturn -EINVAL;\n \n-\tvfio_pci_zap_and_down_write_memory_lock(vdev);\n+\tdown_write(\u0026vdev-\u003ememory_lock);\n \n \t/*\n \t * This function can be invoked while the power state is non-D0. If\n@@ -1330,13 +1340,18 @@ static int vfio_pci_ioctl_reset(struct vfio_pci_core_device *vdev,\n \t * have NoSoftRst-, the reset function can cause the PCI config space\n \t * reset without restoring the original state (saved locally in\n \t * 'vdev-\u003epm_save').\n+\t *\n+\t * The zap is done after making the device accessible in D0,\n+\t * because a DMABUF importer could access the device as part\n+\t * of its revocation cleanup.\n \t */\n \tvfio_pci_set_power_state(vdev, PCI_D0);\n \n-\tvfio_pci_dma_buf_move(vdev, true);\n+\tvfio_pci_revoke_bars(vdev);\n+\n \tret = pci_try_reset_function(vdev-\u003epdev);\n \tif (__vfio_pci_memory_enabled(vdev))\n-\t\tvfio_pci_dma_buf_move(vdev, false);\n+\t\tvfio_pci_unrevoke_bars(vdev);\n \tup_write(\u0026vdev-\u003ememory_lock);\n \n \treturn ret;\n@@ -1625,6 +1640,8 @@ int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags,\n \t\treturn vfio_pci_core_feature_token(vdev, flags, arg, argsz);\n \tcase VFIO_DEVICE_FEATURE_DMA_BUF:\n \t\treturn vfio_pci_core_feature_dma_buf(vdev, flags, arg, argsz);\n+\tcase VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE:\n+\t\treturn vfio_pci_core_feature_dma_buf_revoke(vdev, flags, arg, argsz);\n \tdefault:\n \t\treturn -ENOTTY;\n \t}\n@@ -1704,20 +1721,37 @@ ssize_t vfio_pci_core_write(struct vfio_device *core_vdev, const char __user *bu\n }\n EXPORT_SYMBOL_GPL(vfio_pci_core_write);\n \n-static void vfio_pci_zap_bars(struct vfio_pci_core_device *vdev)\n+static void vfio_pci_revoke_bars(struct vfio_pci_core_device *vdev)\n {\n-\tstruct vfio_device *core_vdev = \u0026vdev-\u003evdev;\n-\tloff_t start = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_BAR0_REGION_INDEX);\n-\tloff_t end = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_ROM_REGION_INDEX);\n-\tloff_t len = end - start;\n+\tlockdep_assert_held_write(\u0026vdev-\u003ememory_lock);\n+\tvfio_pci_dma_buf_move(vdev, true);\n \n-\tunmap_mapping_range(core_vdev-\u003einode-\u003ei_mapping, start, len, true);\n+\t/*\n+\t * If a driver could possibly create BAR mappings in the\n+\t * vdev's address_space, do an additional zap on revoke.  See\n+\t * vfio_pci_core_init_dev().\n+\t */\n+\tif (vdev-\u003ezap_bars_on_revoke) {\n+\t\tstruct vfio_device *core_vdev = \u0026vdev-\u003evdev;\n+\t\tloff_t start = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_BAR0_REGION_INDEX);\n+\t\tloff_t end = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_ROM_REGION_INDEX);\n+\t\tloff_t len = end - start;\n+\n+\t\tunmap_mapping_range(core_vdev-\u003einode-\u003ei_mapping,\n+\t\t\t\t    start, len, true);\n+\t}\n }\n \n-void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_core_device *vdev)\n+void vfio_pci_lock_revoke_bars(struct vfio_pci_core_device *vdev)\n {\n \tdown_write(\u0026vdev-\u003ememory_lock);\n-\tvfio_pci_zap_bars(vdev);\n+\tvfio_pci_revoke_bars(vdev);\n+}\n+\n+void vfio_pci_unrevoke_bars(struct vfio_pci_core_device *vdev)\n+{\n+\tlockdep_assert_held_write(\u0026vdev-\u003ememory_lock);\n+\tvfio_pci_dma_buf_move(vdev, false);\n }\n \n u16 vfio_pci_memory_lock_and_enable(struct vfio_pci_core_device *vdev)\n@@ -1739,18 +1773,6 @@ void vfio_pci_memory_unlock_and_restore(struct vfio_pci_core_device *vdev, u16 c\n \tup_write(\u0026vdev-\u003ememory_lock);\n }\n \n-static unsigned long vma_to_pfn(struct vm_area_struct *vma)\n-{\n-\tstruct vfio_pci_core_device *vdev = vma-\u003evm_private_data;\n-\tint index = vma-\u003evm_pgoff \u003e\u003e (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);\n-\tu64 pgoff;\n-\n-\tpgoff = vma-\u003evm_pgoff \u0026\n-\t\t((1U \u003c\u003c (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);\n-\n-\treturn (pci_resource_start(vdev-\u003epdev, index) \u003e\u003e PAGE_SHIFT) + pgoff;\n-}\n-\n vm_fault_t vfio_pci_vmf_insert_pfn(struct vfio_pci_core_device *vdev,\n \t\t\t\t   struct vm_fault *vmf,\n \t\t\t\t   unsigned long pfn,\n@@ -1778,24 +1800,106 @@ static vm_fault_t vfio_pci_mmap_huge_fault(struct vm_fault *vmf,\n \t\t\t\t\t   unsigned int order)\n {\n \tstruct vm_area_struct *vma = vmf-\u003evma;\n-\tstruct vfio_pci_core_device *vdev = vma-\u003evm_private_data;\n-\tunsigned long addr = vmf-\u003eaddress \u0026 ~((PAGE_SIZE \u003c\u003c order) - 1);\n-\tunsigned long pgoff = (addr - vma-\u003evm_start) \u003e\u003e PAGE_SHIFT;\n-\tunsigned long pfn = vma_to_pfn(vma) + pgoff;\n-\tvm_fault_t ret = VM_FAULT_FALLBACK;\n-\n-\tif (is_aligned_for_order(vma, addr, pfn, order)) {\n-\t\tscoped_guard(rwsem_read, \u0026vdev-\u003ememory_lock)\n-\t\t\tret = vfio_pci_vmf_insert_pfn(vdev, vmf, pfn, order);\n+\tstruct vfio_pci_dma_buf *priv = vma-\u003evm_private_data;\n+\tstruct vfio_pci_core_device *vdev;\n+\tunsigned long pfn = 0;\n+\tvm_fault_t ret = VM_FAULT_SIGBUS;\n+\n+\t/*\n+\t * The only thing this can rely on is that the DMABUF relating\n+\t * to the VMA's vm_file exists (priv).\n+\t *\n+\t * A DMABUF for a VFIO device fd mmap() holds a reference to\n+\t * the original VFIO device fd, but an explicitly-exported\n+\t * DMABUF does not.  The original fd might have closed,\n+\t * meaning this fault can race with\n+\t * vfio_pci_dma_buf_cleanup(), meaning the buffer could have\n+\t * been revoked (in which case priv-\u003evdev might be NULL), and\n+\t * the VFIO device registration might have been dropped.\n+\t *\n+\t * With the goal of taking vdev locks in a world where vdev\n+\t * might not still exist:\n+\t *\n+\t * 1. Take the resv lock on the DMABUF:\n+\t *  - If racing cleanup got in first, the buffer is revoked;\n+\t *    stop/exit if so.\n+\t *  - If we got in first, the buffer is not revoked so vdev is\n+\t *    non-NULL, accessible, and cleanup _has not yet put the\n+\t *    VFIO device registration_.  So, the device refcount must\n+\t *    be \u003e0.\n+\t *\n+\t * 2. Take vfio_device registration (refcount guaranteed \u003e0\n+\t *    hereafter).\n+\t *\n+\t * 3. Unlock the DMABUF's resv lock:\n+\t *  - A racing cleanup can now complete.\n+\t *  - But, the device refcount \u003e0, meaning the vfio_device\n+\t *    (and vfio_pcie_core device vdev) have not yet been\n+\t *    freed.  vdev is accessible, even if the DMABUF has been\n+\t *    revoked or cleanup has happened, because\n+\t *    vfio_unregister_group_dev() can't complete.\n+\t *\n+\t * 4. Take the vdev-\u003ememory_lock then vdev-\u003edmabuf_lock:\n+\t *  - Either the DMABUF is usable, or has been cleaned up.\n+\t *  - It's not necessary to also take the resv lock, because\n+\t *    the status/vdev can't change while dmabuf_lock is held.\n+\t *  - Test the DMABUF revocation status again: if it was\n+\t *    revoked between 1 and 4, return a SIGBUS. Otherwise,\n+\t *    return a PFN.\n+\t *\n+\t * 5. Unlock, done.\n+\t */\n+\n+\tdma_resv_lock(priv-\u003edmabuf-\u003eresv, NULL);\n+\n+\tif (priv-\u003estatus != VFIO_PCI_DMABUF_OK) {\n+\t\tpr_debug_ratelimited(\"%s VA 0x%lx, pgoff 0x%lx: DMABUF revoked/cleaned up\\n\",\n+\t\t\t\t     __func__, vmf-\u003eaddress, vma-\u003evm_pgoff);\n+\t\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n+\t\treturn VM_FAULT_SIGBUS;\n+\t}\n+\n+\t/* If the buffer isn't revoked, vdev is valid */\n+\tvdev = priv-\u003evdev;\n+\n+\tif (!vfio_device_try_get_registration(\u0026vdev-\u003evdev)) {\n+\t\t/*\n+\t\t * If vdev != NULL (above), the registration should\n+\t\t * already be \u003e0 and so this try_get should never\n+\t\t * fail.\n+\t\t */\n+\t\tdev_warn_ratelimited(\u0026vdev-\u003epdev-\u003edev,\n+\t\t\t\t     \"%s: Unexpected registration failure\\n\",\n+\t\t\t\t     __func__);\n+\t\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n+\t\treturn VM_FAULT_SIGBUS;\n+\t}\n+\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n+\n+\t/* memory_lock for vfio_pci_vmf_insert_pfn() */\n+\tdown_read(\u0026vdev-\u003ememory_lock);\n+\t/* Re-test revocation status under dmabuf_lock */\n+\tdown_read(\u0026vdev-\u003edmabuf_lock);\n+\tif (priv-\u003estatus == VFIO_PCI_DMABUF_OK) {\n+\t\tint pres = vfio_pci_dma_buf_find_pfn(vdev, priv, vma,\n+\t\t\t\t\t\t     vmf-\u003eaddress,\n+\t\t\t\t\t\t     order, \u0026pfn);\n+\n+\t\tif (pres == 0)\n+\t\t\tret = vfio_pci_vmf_insert_pfn(vdev, vmf,\n+\t\t\t\t\t\t      pfn, order);\n+\t\telse if (pres == -ERANGE)\n+\t\t\tret = VM_FAULT_FALLBACK;\n \t}\n+\tup_read(\u0026vdev-\u003edmabuf_lock);\n+\tup_read(\u0026vdev-\u003ememory_lock);\n \n \tdev_dbg_ratelimited(\u0026vdev-\u003epdev-\u003edev,\n-\t\t\t   \"%s(,order = %d) BAR %ld page offset 0x%lx: 0x%x\\n\",\n-\t\t\t    __func__, order,\n-\t\t\t    vma-\u003evm_pgoff \u003e\u003e\n-\t\t\t\t(VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT),\n-\t\t\t    pgoff, (unsigned int)ret);\n+\t\t\t    \"%s(order = %d) PFN 0x%lx, VA 0x%lx, pgoff 0x%lx: 0x%x\\n\",\n+\t\t\t    __func__, order, pfn, vmf-\u003eaddress,\n+\t\t\t    vma-\u003evm_pgoff, (unsigned int)ret);\n \n+\tvfio_device_put_registration(\u0026vdev-\u003evdev);\n \treturn ret;\n }\n \n@@ -1811,6 +1915,11 @@ static const struct vm_operations_struct vfio_pci_mmap_ops = {\n #endif\n };\n \n+void vfio_pci_set_vma_ops(struct vm_area_struct *vma)\n+{\n+\tvma-\u003evm_ops = \u0026vfio_pci_mmap_ops;\n+}\n+\n int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma)\n {\n \tstruct vfio_pci_core_device *vdev =\n@@ -1819,6 +1928,7 @@ int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma\n \tunsigned int index;\n \tu64 phys_len, req_len, pgoff, req_start;\n \tvoid __iomem *bar_io;\n+\tint ret;\n \n \tindex = vma-\u003evm_pgoff \u003e\u003e (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);\n \n@@ -1858,7 +1968,12 @@ int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma\n \tif (IS_ERR(bar_io))\n \t\treturn PTR_ERR(bar_io);\n \n-\tvma-\u003evm_private_data = vdev;\n+\tret = vfio_pci_core_mmap_prep_dmabuf(vdev, vma,\n+\t\t\t\t\t     pci_resource_start(pdev, index),\n+\t\t\t\t\t     req_len, index);\n+\tif (ret)\n+\t\treturn ret;\n+\n \tvma-\u003evm_page_prot = pgprot_noncached(vma-\u003evm_page_prot);\n \tvma-\u003evm_page_prot = pgprot_decrypted(vma-\u003evm_page_prot);\n \n@@ -2195,8 +2310,19 @@ int vfio_pci_core_init_dev(struct vfio_device *core_vdev)\n \t\treturn ret;\n \tINIT_LIST_HEAD(\u0026vdev-\u003edmabufs);\n \tinit_rwsem(\u0026vdev-\u003ememory_lock);\n+\tinit_rwsem(\u0026vdev-\u003edmabuf_lock);\n \txa_init(\u0026vdev-\u003ectx);\n \n+\t/*\n+\t * If a driver overrides .mmap, it has to be assumed that it\n+\t * might not use the DMABUF-backed core mmap; this flag\n+\t * enables a zap at revoke time.  A driver can opt out by\n+\t * clearing this flag at init, if their .mmap override calls\n+\t * down to vfio_pci_core_mmap().\n+\t */\n+\tif (vdev-\u003evdev.ops-\u003emmap != vfio_pci_core_mmap)\n+\t\tvdev-\u003ezap_bars_on_revoke = true;\n+\n \treturn 0;\n }\n EXPORT_SYMBOL_GPL(vfio_pci_core_init_dev);\n@@ -2564,9 +2690,10 @@ static int vfio_pci_dev_set_hot_reset(struct vfio_device_set *dev_set,\n \t\t}\n \n \t\t/*\n-\t\t * Take the memory write lock for each device and zap BAR\n-\t\t * mappings to prevent the user accessing the device while in\n-\t\t * reset.  Locking multiple devices is prone to deadlock,\n+\t\t * Take the memory write lock for each device and\n+\t\t * zap/revoke BAR mappings to prevent the user (or\n+\t\t * peers) accessing the device while in reset.\n+\t\t * Locking multiple devices is prone to deadlock,\n \t\t * runaway and unwind if we hit contention.\n \t\t */\n \t\tif (!down_write_trylock(\u0026vdev-\u003ememory_lock)) {\n@@ -2574,8 +2701,7 @@ static int vfio_pci_dev_set_hot_reset(struct vfio_device_set *dev_set,\n \t\t\tbreak;\n \t\t}\n \n-\t\tvfio_pci_dma_buf_move(vdev, true);\n-\t\tvfio_pci_zap_bars(vdev);\n+\t\tvfio_pci_revoke_bars(vdev);\n \t}\n \n \tif (!list_entry_is_head(vdev,\n@@ -2605,7 +2731,7 @@ static int vfio_pci_dev_set_hot_reset(struct vfio_device_set *dev_set,\n \tlist_for_each_entry_from_reverse(vdev, \u0026dev_set-\u003edevice_list,\n \t\t\t\t\t vdev.dev_set_list) {\n \t\tif (vdev-\u003evdev.open_count \u0026\u0026 __vfio_pci_memory_enabled(vdev))\n-\t\t\tvfio_pci_dma_buf_move(vdev, false);\n+\t\t\tvfio_pci_unrevoke_bars(vdev);\n \t\tup_write(\u0026vdev-\u003ememory_lock);\n \t}\n \ndiff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci_dmabuf.c\nindex c16f460c01d68..7cda2bd00d25a 100644\n--- a/drivers/vfio/pci/vfio_pci_dmabuf.c\n+++ b/drivers/vfio/pci/vfio_pci_dmabuf.c\n@@ -3,25 +3,14 @@\n  */\n #include \u003clinux/dma-buf-mapping.h\u003e\n #include \u003clinux/pci-p2pdma.h\u003e\n+#include \u003clinux/dma-buf.h\u003e\n #include \u003clinux/dma-resv.h\u003e\n \n #include \"vfio_pci_priv.h\"\n \n MODULE_IMPORT_NS(\"DMA_BUF\");\n \n-struct vfio_pci_dma_buf {\n-\tstruct dma_buf *dmabuf;\n-\tstruct vfio_pci_core_device *vdev;\n-\tstruct list_head dmabufs_elm;\n-\tsize_t size;\n-\tstruct phys_vec *phys_vec;\n-\tstruct p2pdma_provider *provider;\n-\tu32 nr_ranges;\n-\tstruct kref kref;\n-\tstruct completion comp;\n-\tu8 revoked : 1;\n-};\n-\n+#ifdef CONFIG_VFIO_PCI_DMABUF\n static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,\n \t\t\t\t   struct dma_buf_attachment *attachment)\n {\n@@ -30,7 +19,7 @@ static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,\n \tif (!attachment-\u003epeer2peer)\n \t\treturn -EOPNOTSUPP;\n \n-\tif (priv-\u003erevoked)\n+\tif (READ_ONCE(priv-\u003estatus) != VFIO_PCI_DMABUF_OK)\n \t\treturn -ENODEV;\n \n \tif (!dma_buf_attach_revocable(attachment))\n@@ -39,6 +28,62 @@ static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,\n \treturn 0;\n }\n \n+static int vfio_pci_dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)\n+{\n+\tstruct vfio_pci_dma_buf *priv = dmabuf-\u003epriv;\n+\n+\t/*\n+\t * dma_buf_mmap_internal() has asserted that the VMA is\n+\t * contained within the DMABUF size before calling this.\n+\t *\n+\t * Also, if we observe that the buffer is revoked now then\n+\t * refuse the mmap().  This is a belt-and-braces early failure\n+\t * to ease debugging a revoked buffer being used.  Userspace\n+\t * might also race an mmap() against an explicit revocation,\n+\t * or an action doing a temporary revoke; race scenarios are\n+\t * still safe because the fault handler ultimately prevents\n+\t * access to a revoked buffer if it isn't caught here.\n+\t */\n+\tif (READ_ONCE(priv-\u003estatus) != VFIO_PCI_DMABUF_OK)\n+\t\treturn -ENODEV;\n+\t/*\n+\t * Make clear that anything with an offset adjustment is\n+\t * explicitly unsupported, as vfio_pci_dma_buf_find_pfn()\n+\t * maths would underflow; this doesn't happen through the\n+\t * regular DMABUF export path used with this mmap().  A DMABUF\n+\t * implicitly created for BAR mmap could have adjust \u003e 0, but\n+\t * these can't currently be re-opened and mmap()ed again.\n+\t * Catch here in case that assumption ever changes.\n+\t */\n+\tif (priv-\u003evma_pgoff_adjust)\n+\t\treturn -EINVAL;\n+\tif ((vma-\u003evm_flags \u0026 VM_SHARED) == 0)\n+\t\treturn -EINVAL;\n+\n+\tvma-\u003evm_page_prot = pgprot_noncached(vma-\u003evm_page_prot);\n+\tvma-\u003evm_page_prot = pgprot_decrypted(vma-\u003evm_page_prot);\n+\n+\t/* See comments in vfio_pci_core_mmap() re VM_ALLOW_ANY_UNCACHED. */\n+\tvm_flags_set(vma, VM_ALLOW_ANY_UNCACHED | VM_IO | VM_PFNMAP |\n+\t\t     VM_DONTEXPAND | VM_DONTDUMP);\n+\tvma-\u003evm_private_data = priv;\n+\tvfio_pci_set_vma_ops(vma);\n+\n+\treturn 0;\n+}\n+#else\n+static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,\n+\t\t\t\t   struct dma_buf_attachment *attachment)\n+{\n+\t/*\n+\t * Explicit export can't occur without the DMABUF feature, but\n+\t * DMABUFs are implicitly created for BAR mappings.  An\n+\t * .attach that fails prevents dma_buf_attach().\n+\t */\n+\treturn -EOPNOTSUPP;\n+}\n+#endif /* CONFIG_VFIO_PCI_DMABUF */\n+\n static void vfio_pci_dma_buf_done(struct kref *kref)\n {\n \tstruct vfio_pci_dma_buf *priv =\n@@ -56,7 +101,7 @@ vfio_pci_dma_buf_map(struct dma_buf_attachment *attachment,\n \n \tdma_resv_assert_held(priv-\u003edmabuf-\u003eresv);\n \n-\tif (priv-\u003erevoked)\n+\tif (priv-\u003estatus != VFIO_PCI_DMABUF_OK)\n \t\treturn ERR_PTR(-ENODEV);\n \n \tret = dma_buf_phys_vec_to_sgt(attachment, priv-\u003eprovider,\n@@ -90,22 +135,348 @@ static void vfio_pci_dma_buf_release(struct dma_buf *dmabuf)\n \t * The refcount prevents both.\n \t */\n \tif (priv-\u003evdev) {\n-\t\tdown_write(\u0026priv-\u003evdev-\u003ememory_lock);\n+\t\tdown_write(\u0026priv-\u003evdev-\u003edmabuf_lock);\n \t\tlist_del_init(\u0026priv-\u003edmabufs_elm);\n-\t\tup_write(\u0026priv-\u003evdev-\u003ememory_lock);\n+\t\tup_write(\u0026priv-\u003evdev-\u003edmabuf_lock);\n \t\tvfio_device_put_registration(\u0026priv-\u003evdev-\u003evdev);\n \t}\n+\tif (priv-\u003evfile)\n+\t\tfput(priv-\u003evfile);\n \tkfree(priv-\u003ephys_vec);\n \tkfree(priv);\n }\n \n static const struct dma_buf_ops vfio_pci_dmabuf_ops = {\n \t.attach = vfio_pci_dma_buf_attach,\n+#ifdef CONFIG_VFIO_PCI_DMABUF\n+\t.mmap = vfio_pci_dma_buf_mmap,\n+#endif\n \t.map_dma_buf = vfio_pci_dma_buf_map,\n \t.unmap_dma_buf = vfio_pci_dma_buf_unmap,\n \t.release = vfio_pci_dma_buf_release,\n };\n \n+int vfio_pci_dma_buf_find_pfn(struct vfio_pci_core_device *vdev,\n+\t\t\t      struct vfio_pci_dma_buf *priv,\n+\t\t\t      struct vm_area_struct *vma,\n+\t\t\t      unsigned long fault_addr,\n+\t\t\t      unsigned int order,\n+\t\t\t      unsigned long *out_pfn)\n+{\n+\t/*\n+\t * Given a VMA (start, end, pgoffs) and a fault address,\n+\t * search the corresponding DMABUF's phys_vec[] to find the\n+\t * range representing the address's offset into the VMA, and\n+\t * its PFN.  vdev must be the device that the DMABUF priv was\n+\t * exported from; vdev-\u003edmabuf_lock must be held, and priv\n+\t * must not be revoked.\n+\t *\n+\t * The phys_vec[] ranges represent contiguous spans of VAs\n+\t * upwards from the buffer offset 0; the actual PFNs might be\n+\t * in any order, overlap/alias, etc.  Calculate an offset of\n+\t * the desired page given VMA start/pgoff and address, then\n+\t * search upwards from 0 to find which span contains it.\n+\t *\n+\t * On success, a valid PFN for a page sized by 'order' is\n+\t * returned into out_pfn.\n+\t *\n+\t * Failure occurs if:\n+\t * - A hugepage would cross the edge of the VMA,\n+\t * - A hugepage isn't entirely contained within a range\n+\t *   (including where it straddles the boundary between\n+\t *   ranges),\n+\t * - We find a range, but the final PFN isn't aligned to the\n+\t *   requested order.\n+\t *\n+\t * Upon failure, -ERANGE is returned and the caller is\n+\t * expected to try again with a smaller order, which will\n+\t * eventually succeed.\n+\t *\n+\t * It's suboptimal if DMABUFs are created with neighbouring\n+\t * ranges that are physically contiguous, since hugepages\n+\t * can't straddle range boundaries.  (The construction of the\n+\t * ranges should merge them in this case.)\n+\t *\n+\t * Finally, vma_pgoff_adjust is used with a DMABUF created for\n+\t * a VFIO BAR mmap: a BAR mapped with vm_pgoff \u003e 0 creates a\n+\t * DMABUF such that byte 0 of the VMA corresponds to byte 0 of\n+\t * the DMABUF and byte 'vm_pgoff \u003c\u003c PAGE_SHIFT' into the BAR.\n+\t * To avoid double-offsetting in this scenario, subtracting\n+\t * vma_pgoff_adjust from this (non-zero) vm_pgoff generates\n+\t * the effective offset.  This also removes the VFIO region\n+\t * index encoded in vm_pgoff for VFIO BAR mmaps.\n+\t */\n+\n+\tconst unsigned long pagesize = PAGE_SIZE \u003c\u003c order;\n+\tunsigned long vma_off = (vma-\u003evm_pgoff - priv-\u003evma_pgoff_adjust) \u003c\u003c\n+\t\t\t\t PAGE_SHIFT;\n+\tunsigned long rounded_page_addr = ALIGN_DOWN(fault_addr, pagesize);\n+\tunsigned long rounded_page_end = rounded_page_addr + pagesize;\n+\tunsigned long fault_offset;\n+\tunsigned long fault_offset_end;\n+\tunsigned long range_start_offset = 0;\n+\tunsigned int i;\n+\tint ret;\n+\n+\tif (unlikely(!vdev))\n+\t\treturn -ENODEV;\n+\n+\t/* This prevents the dmabuf revocation state from changing under us */\n+\tlockdep_assert_held(\u0026vdev-\u003edmabuf_lock);\n+\n+\tif (unlikely(priv-\u003evdev != vdev || priv-\u003estatus != VFIO_PCI_DMABUF_OK))\n+\t\treturn -ENODEV;\n+\n+\tif (rounded_page_addr \u003c vma-\u003evm_start || rounded_page_end \u003e vma-\u003evm_end) {\n+\t\tif (order \u003e 0)\n+\t\t\treturn -ERANGE;\n+\n+\t\t/* A fault address outside of the VMA is absurd. */\n+\t\tdev_warn_ratelimited(\n+\t\t\t\u0026vdev-\u003epdev-\u003edev,\n+\t\t\t\"Fault addr 0x%lx outside VMA 0x%lx-0x%lx\\n\",\n+\t\t\tfault_addr, vma-\u003evm_start, vma-\u003evm_end);\n+\t\treturn -EFAULT;\n+\t}\n+\n+\t/*\n+\t * fault_offset[_end] is the span within the DMABUF\n+\t * corresponding to the faulting page:\n+\t */\n+\tif (unlikely(check_add_overflow(rounded_page_addr - vma-\u003evm_start,\n+\t\t\t\t\tvma_off, \u0026fault_offset) ||\n+\t\t     check_add_overflow(fault_offset, pagesize,\n+\t\t\t\t\t\u0026fault_offset_end)))\n+\t\treturn -EFAULT;\n+\n+\t/*\n+\t * Iterate over ranges in the buffer, summing their lengths:\n+\t * range_start_offset represents the current range's starting\n+\t * offset in the buffer (from 0 upwards).\n+\t *\n+\t * A failure for order == 0 is unexpected, and triggers a\n+\t * fault/warn.\n+\t */\n+\tret = (order == 0) ? -EFAULT : -ERANGE;\n+\n+\tfor (i = 0; i \u003c priv-\u003enr_ranges; i++) {\n+\t\tsize_t range_len = priv-\u003ephys_vec[i].len;\n+\n+\t\t/* Early exit if range starts after the page end */\n+\t\tif (fault_offset_end \u003c= range_start_offset)\n+\t\t\tbreak;\n+\n+\t\tif (fault_offset \u003e= range_start_offset \u0026\u0026\n+\t\t    fault_offset_end \u003c= range_start_offset + range_len) {\n+\t\t\t/*\n+\t\t\t * The faulting page is wholly contained\n+\t\t\t * within the span represented by this range,\n+\t\t\t * so validate PFN alignment for the order.\n+\t\t\t * The if() condition ensures the pfn\n+\t\t\t * arithmetic won't overflow.\n+\t\t\t */\n+\t\t\tunsigned long pfn =\n+\t\t\t\t((fault_offset - range_start_offset) +\n+\t\t\t\t priv-\u003ephys_vec[i].paddr) \u003e\u003e PAGE_SHIFT;\n+\n+\t\t\tif (IS_ALIGNED(pfn, 1 \u003c\u003c order)) {\n+\t\t\t\t*out_pfn = pfn;\n+\t\t\t\tret = 0;\n+\t\t\t}\n+\t\t\t/*\n+\t\t\t * Else order \u003e 0; ERANGE retries with smaller\n+\t\t\t * order\n+\t\t\t */\n+\t\t\tbreak;\n+\t\t}\n+\t\trange_start_offset += range_len;\n+\t}\n+\n+\tif (order == 0 \u0026\u0026 ret != 0)\n+\t\t/*\n+\t\t * The address fell outside of the span represented by\n+\t\t * the (concatenated) ranges.  As setup of a mapping\n+\t\t * ensures that the VMA is \u003c= the total size of the\n+\t\t * ranges this should never happen.  If it does, warn\n+\t\t * and SIGBUS.\n+\t\t */\n+\t\tdev_warn_ratelimited(\n+\t\t\t\u0026vdev-\u003epdev-\u003edev,\n+\t\t\t\"No range for addr 0x%lx, order %d: VMA 0x%lx-0x%lx pgoff 0x%lx, %u ranges, size 0x%zx\\n\",\n+\t\t\tfault_addr, order, vma-\u003evm_start, vma-\u003evm_end,\n+\t\t\tvma-\u003evm_pgoff, priv-\u003enr_ranges, priv-\u003esize);\n+\n+\treturn ret;\n+}\n+\n+/*\n+ * Create a DMABUF corresponding to priv, add it to vdev-\u003edmabufs list\n+ * for tracking (meaning cleanup or revocation will zap it), and take\n+ * a vfio_device registration.\n+ */\n+static int vfio_pci_dmabuf_export(struct vfio_pci_core_device *vdev,\n+\t\t\t\t  struct vfio_pci_dma_buf *priv, u32 flags)\n+{\n+\tDEFINE_DMA_BUF_EXPORT_INFO(exp_info);\n+\n+\tif (!vfio_device_try_get_registration(\u0026vdev-\u003evdev))\n+\t\treturn -ENODEV;\n+\n+\texp_info.ops = \u0026vfio_pci_dmabuf_ops;\n+\texp_info.size = priv-\u003esize;\n+\texp_info.flags = flags;\n+\texp_info.priv = priv;\n+\n+\tpriv-\u003edmabuf = dma_buf_export(\u0026exp_info);\n+\tif (IS_ERR(priv-\u003edmabuf)) {\n+\t\tvfio_device_put_registration(\u0026vdev-\u003evdev);\n+\t\treturn PTR_ERR(priv-\u003edmabuf);\n+\t}\n+\n+\tkref_init(\u0026priv-\u003ekref);\n+\tinit_completion(\u0026priv-\u003ecomp);\n+\n+\t/* dma_buf_put() now frees priv */\n+\tINIT_LIST_HEAD(\u0026priv-\u003edmabufs_elm);\n+\n+\t/*\n+\t * dmabuf_lock synchronises access (R) or updates (W) to the\n+\t * vdev-\u003edmabufs list and to bars_revoked (see below).  The\n+\t * revocation state of DMABUF elements in the list is written\n+\t * holding both dmabuf_lock(W) and resv, and tested with\n+\t * either.\n+\t *\n+\t * (memory_lock, if held -\u003e) dmabuf_lock -\u003e resv\n+\t *\n+\t * NOTE: memory_lock is strictly avoided here, to avoid a\n+\t * dependency on memory_lock when mmap_lock is held, when\n+\t * mmap() leads to export.  vfio-pci variant drivers are\n+\t * permitted to hold memory_lock across actions that might\n+\t * fault (such as user access); a deadlock could result when\n+\t * that fault path attempts to take mmap_lock (if held by an\n+\t * export waiting for memory_lock).\n+\t *\n+\t * vdev-\u003ebars_revoked tracks the BAR revocation status updated\n+\t * via vfio_pci_dma_buf_move(), so the initial DMABUF state\n+\t * follows the same criteria that later update the DMABUF\n+\t * state (BAR zap, etc.).\n+\t */\n+\tlockdep_assert_not_held(\u0026vdev-\u003ememory_lock);\n+\n+\tdown_write(\u0026vdev-\u003edmabuf_lock);\n+\tdma_resv_lock(priv-\u003edmabuf-\u003eresv, NULL);\n+\tpriv-\u003estatus = vdev-\u003ebars_revoked ? VFIO_PCI_DMABUF_TEMP_REVOKED :\n+\t\tVFIO_PCI_DMABUF_OK;\n+\tlist_add_tail(\u0026priv-\u003edmabufs_elm, \u0026vdev-\u003edmabufs);\n+\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n+\tup_write(\u0026vdev-\u003edmabuf_lock);\n+\n+\treturn 0;\n+}\n+\n+int vfio_pci_core_mmap_prep_dmabuf(struct vfio_pci_core_device *vdev,\n+\t\t\t\t   struct vm_area_struct *vma,\n+\t\t\t\t   u64 phys_start, u64 req_len,\n+\t\t\t\t   unsigned int res_index)\n+{\n+\tstruct vfio_pci_dma_buf *priv;\n+\tunsigned long vma_pgoff = vma-\u003evm_pgoff \u0026 (VFIO_PCI_OFFSET_MASK \u003e\u003e PAGE_SHIFT);\n+\tchar *bufname;\n+\tint ret;\n+\n+\tpriv = kzalloc_obj(*priv);\n+\tif (!priv)\n+\t\treturn -ENOMEM;\n+\n+\tpriv-\u003ephys_vec = kzalloc_obj(*priv-\u003ephys_vec);\n+\tif (!priv-\u003ephys_vec) {\n+\t\tret = -ENOMEM;\n+\t\tgoto err_free_priv;\n+\t}\n+\n+\t/*\n+\t * Maximum size of the friendly debug name is\n+\t * vfio1048575:ffff:ff:1f.7/5 = 26.  This fits within\n+\t * DMA_BUF_NAME_LEN, so dma_buf_set_name() below won't fail.\n+\t */\n+\tbufname = kasprintf(GFP_KERNEL, \"%s:%s/%x\",\n+\t\t\t    dev_name(\u0026vdev-\u003evdev.device), pci_name(vdev-\u003epdev),\n+\t\t\t    res_index);\n+\n+\tif (!bufname) {\n+\t\tret = -ENOMEM;\n+\t\tgoto err_free_phys;\n+\t}\n+\n+\t/*\n+\t * The DMABUF begins from the mmap()'s BAR offset, i.e. the\n+\t * start of the VMA corresponds to byte 0 of the DMABUF and\n+\t * byte (vma_pgoff \u003c\u003c PAGE_SHIFT) of the BAR.\n+\t *\n+\t * vfio_pci_dma_buf_find_pfn() reverses this offset using\n+\t * vma_pgoff_adjust, so that ultimately a fault's offset from\n+\t * the start of the _VMA_ has a consistent usage whether the\n+\t * VMA originates from an mmap() of the VFIO device here or a\n+\t * direct DMABUF mmap().  Note vma_pgoff_adjust also includes\n+\t * the encoded VFIO region index, which cancels out the index\n+\t * encoded in vm_pgoff.\n+\t */\n+\tpriv-\u003evdev = vdev;\n+\tpriv-\u003esize = req_len;\n+\tpriv-\u003enr_ranges = 1;\n+\tpriv-\u003evma_pgoff_adjust = vma-\u003evm_pgoff;\n+\n+\t/*\n+\t * The provider can be NULL _iff_ the DMABUF feature isn't\n+\t * supported, because it's only used by DMABUF import and\n+\t * attach is prohibited if the feature isn't present.\n+\t */\n+\tpriv-\u003eprovider = pcim_p2pdma_provider(vdev-\u003epdev, res_index);\n+\tif (IS_ENABLED(CONFIG_VFIO_PCI_DMABUF) \u0026\u0026 !priv-\u003eprovider) {\n+\t\tret = -EINVAL;\n+\t\tgoto err_free_name;\n+\t}\n+\n+\tpriv-\u003ephys_vec[0].paddr = phys_start + ((u64)vma_pgoff \u003c\u003c PAGE_SHIFT);\n+\tpriv-\u003ephys_vec[0].len = priv-\u003esize;\n+\n+\tret = vfio_pci_dmabuf_export(vdev, priv, O_RDWR);\n+\tif (ret)\n+\t\tgoto err_free_name;\n+\n+\tif (dma_buf_set_name(priv-\u003edmabuf, bufname)) {\n+\t\t/* Shouldn't happen, but don't leak if it does: */\n+\t\tdev_dbg_ratelimited(\u0026vdev-\u003epdev-\u003edev,\n+\t\t\t\t    \"Failed to set map name '%s'\\n\",\n+\t\t\t\t    bufname);\n+\t\tkfree(bufname);\n+\t}\n+\n+\t/*\n+\t * Ownership of the DMABUF file transfers to the VMA so that\n+\t * other users can locate the DMABUF via a VA.  Ownership of\n+\t * the original VFIO device file being mmap()ed transfers to\n+\t * priv, and is put when the DMABUF is released.  This\n+\t * intentionally does not use get_file()/vma_set_file()\n+\t * because the references are already held, and ownership\n+\t * moves.\n+\t */\n+\tpriv-\u003evfile = vma-\u003evm_file;\n+\tvma-\u003evm_file = priv-\u003edmabuf-\u003efile;\n+\tvma-\u003evm_private_data = priv;\n+\n+\treturn 0;\n+\n+err_free_name:\n+\tkfree(bufname);\n+err_free_phys:\n+\tkfree(priv-\u003ephys_vec);\n+err_free_priv:\n+\tkfree(priv);\n+\treturn ret;\n+}\n+\n+#ifdef CONFIG_VFIO_PCI_DMABUF\n /*\n  * This is a temporary \"private interconnect\" between VFIO DMABUF and iommufd.\n  * It allows the two co-operating drivers to exchange the physical address of\n@@ -128,7 +499,7 @@ int vfio_pci_dma_buf_iommufd_map(struct dma_buf_attachment *attachment,\n \t\treturn -EOPNOTSUPP;\n \n \tpriv = attachment-\u003edmabuf-\u003epriv;\n-\tif (priv-\u003erevoked)\n+\tif (priv-\u003estatus != VFIO_PCI_DMABUF_OK)\n \t\treturn -ENODEV;\n \n \t/* More than one range to iommufd will require proper DMABUF support */\n@@ -224,7 +595,6 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,\n {\n \tstruct vfio_device_feature_dma_buf get_dma_buf = {};\n \tstruct vfio_region_dma_range *dma_ranges;\n-\tDEFINE_DMA_BUF_EXPORT_INFO(exp_info);\n \tstruct vfio_pci_dma_buf *priv;\n \tsize_t length;\n \tint ret;\n@@ -284,34 +654,9 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,\n \tkfree(dma_ranges);\n \tdma_ranges = NULL;\n \n-\tif (!vfio_device_try_get_registration(\u0026vdev-\u003evdev)) {\n-\t\tret = -ENODEV;\n+\tret = vfio_pci_dmabuf_export(vdev, priv, get_dma_buf.open_flags);\n+\tif (ret)\n \t\tgoto err_free_phys;\n-\t}\n-\n-\texp_info.ops = \u0026vfio_pci_dmabuf_ops;\n-\texp_info.size = priv-\u003esize;\n-\texp_info.flags = get_dma_buf.open_flags;\n-\texp_info.priv = priv;\n-\n-\tpriv-\u003edmabuf = dma_buf_export(\u0026exp_info);\n-\tif (IS_ERR(priv-\u003edmabuf)) {\n-\t\tret = PTR_ERR(priv-\u003edmabuf);\n-\t\tgoto err_dev_put;\n-\t}\n-\n-\tkref_init(\u0026priv-\u003ekref);\n-\tinit_completion(\u0026priv-\u003ecomp);\n-\n-\t/* dma_buf_put() now frees priv */\n-\tINIT_LIST_HEAD(\u0026priv-\u003edmabufs_elm);\n-\tdown_write(\u0026vdev-\u003ememory_lock);\n-\tdma_resv_lock(priv-\u003edmabuf-\u003eresv, NULL);\n-\tpriv-\u003erevoked = !__vfio_pci_memory_enabled(vdev);\n-\tlist_add_tail(\u0026priv-\u003edmabufs_elm, \u0026vdev-\u003edmabufs);\n-\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n-\tup_write(\u0026vdev-\u003ememory_lock);\n-\n \t/*\n \t * dma_buf_fd() consumes the reference, when the file closes the dmabuf\n \t * will be released.\n@@ -322,8 +667,6 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,\n \n \treturn ret;\n \n-err_dev_put:\n-\tvfio_device_put_registration(\u0026vdev-\u003evdev);\n err_free_phys:\n \tkfree(priv-\u003ephys_vec);\n err_free_priv:\n@@ -332,6 +675,64 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,\n \tkfree(dma_ranges);\n \treturn ret;\n }\n+#endif /* CONFIG_VFIO_PCI_DMABUF */\n+\n+/* Set the DMABUF's revocation status (OK or temporarily/permanently revoked) */\n+static void vfio_pci_dma_buf_set_status(struct vfio_pci_dma_buf *priv,\n+\t\t\t\t\tenum vfio_pci_dma_buf_status new_status)\n+{\n+\tbool was_revoked;\n+\n+\t/*\n+\t * Changes to the DMABUF's revocation status are synchronised\n+\t * using dmabuf_lock:\n+\t */\n+\tlockdep_assert_held_write(\u0026priv-\u003evdev-\u003edmabuf_lock);\n+\n+\tif (priv-\u003estatus == VFIO_PCI_DMABUF_PERM_REVOKED ||\n+\t    priv-\u003estatus == new_status)\n+\t\treturn;\n+\n+\tdma_resv_lock(priv-\u003edmabuf-\u003eresv, NULL);\n+\twas_revoked = (priv-\u003estatus == VFIO_PCI_DMABUF_TEMP_REVOKED);\n+\n+\tif (new_status != VFIO_PCI_DMABUF_OK) {\n+\t\tpriv-\u003estatus = new_status; /* Temp or permanently revoked */\n+\n+\t\tif (was_revoked) {\n+\t\t\t/*\n+\t\t\t * TEMP_REVOKED is being upgraded to\n+\t\t\t * PERM_REVOKED.  The buffer is already gone,\n+\t\t\t * don't wait on it again.\n+\t\t\t */\n+\t\t\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n+\t\t\treturn;\n+\t\t}\n+\t\tdma_buf_invalidate_mappings(priv-\u003edmabuf);\n+\t\tdma_resv_wait_timeout(priv-\u003edmabuf-\u003eresv,\n+\t\t\t\t      DMA_RESV_USAGE_BOOKKEEP, false,\n+\t\t\t\t      MAX_SCHEDULE_TIMEOUT);\n+\t\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n+\t\tkref_put(\u0026priv-\u003ekref, vfio_pci_dma_buf_done);\n+\t\twait_for_completion(\u0026priv-\u003ecomp);\n+\t\tunmap_mapping_range(priv-\u003edmabuf-\u003efile-\u003ef_mapping,\n+\t\t\t\t    0, 0, true);\n+\t\t/*\n+\t\t * Re-arm the registered kref reference and the\n+\t\t * completion so the post-revoke state matches the\n+\t\t * post-creation state.  An un-revoke followed by a\n+\t\t * new mapping needs the kref to be non-zero before\n+\t\t * kref_get(), and vfio_pci_dma_buf_cleanup()\n+\t\t * delegates its drain back through this revoke\n+\t\t * path on a possibly-already-revoked dma-buf.\n+\t\t */\n+\t\tkref_init(\u0026priv-\u003ekref);\n+\t\treinit_completion(\u0026priv-\u003ecomp);\n+\t} else {\n+\t\tpriv-\u003estatus = VFIO_PCI_DMABUF_OK;\n+\t\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n+\t}\n+}\n \n void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked)\n {\n@@ -340,41 +741,17 @@ void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked)\n \n \tlockdep_assert_held_write(\u0026vdev-\u003ememory_lock);\n \n+\tdown_write(\u0026vdev-\u003edmabuf_lock);\n+\tvdev-\u003ebars_revoked = revoked;\n \tlist_for_each_entry_safe(priv, tmp, \u0026vdev-\u003edmabufs, dmabufs_elm) {\n \t\tif (!get_file_active(\u0026priv-\u003edmabuf-\u003efile))\n \t\t\tcontinue;\n-\n-\t\tif (priv-\u003erevoked != revoked) {\n-\t\t\tdma_resv_lock(priv-\u003edmabuf-\u003eresv, NULL);\n-\t\t\tif (revoked)\n-\t\t\t\tpriv-\u003erevoked = true;\n-\t\t\tdma_buf_invalidate_mappings(priv-\u003edmabuf);\n-\t\t\tdma_resv_wait_timeout(priv-\u003edmabuf-\u003eresv,\n-\t\t\t\t\t      DMA_RESV_USAGE_BOOKKEEP, false,\n-\t\t\t\t\t      MAX_SCHEDULE_TIMEOUT);\n-\t\t\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n-\t\t\tif (revoked) {\n-\t\t\t\tkref_put(\u0026priv-\u003ekref, vfio_pci_dma_buf_done);\n-\t\t\t\twait_for_completion(\u0026priv-\u003ecomp);\n-\t\t\t\t/*\n-\t\t\t\t * Re-arm the registered kref reference and the\n-\t\t\t\t * completion so the post-revoke state matches the\n-\t\t\t\t * post-creation state.  An un-revoke followed by a\n-\t\t\t\t * new mapping needs the kref to be non-zero before\n-\t\t\t\t * kref_get(), and vfio_pci_dma_buf_cleanup()\n-\t\t\t\t * delegates its drain back through this revoke\n-\t\t\t\t * path on a possibly-already-revoked dma-buf.\n-\t\t\t\t */\n-\t\t\t\tkref_init(\u0026priv-\u003ekref);\n-\t\t\t\treinit_completion(\u0026priv-\u003ecomp);\n-\t\t\t} else {\n-\t\t\t\tdma_resv_lock(priv-\u003edmabuf-\u003eresv, NULL);\n-\t\t\t\tpriv-\u003erevoked = false;\n-\t\t\t\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n-\t\t\t}\n-\t\t}\n+\t\tvfio_pci_dma_buf_set_status(priv, revoked ?\n+\t\t\t\t\t    VFIO_PCI_DMABUF_TEMP_REVOKED :\n+\t\t\t\t\t    VFIO_PCI_DMABUF_OK);\n \t\tfput(priv-\u003edmabuf-\u003efile);\n \t}\n+\tup_write(\u0026vdev-\u003edmabuf_lock);\n }\n \n void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev)\n@@ -393,14 +770,86 @@ void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev)\n \t */\n \tvfio_pci_dma_buf_move(vdev, true);\n \n+\tdown_write(\u0026vdev-\u003edmabuf_lock);\n \tlist_for_each_entry_safe(priv, tmp, \u0026vdev-\u003edmabufs, dmabufs_elm) {\n \t\tif (!get_file_active(\u0026priv-\u003edmabuf-\u003efile))\n \t\t\tcontinue;\n \n \t\tlist_del_init(\u0026priv-\u003edmabufs_elm);\n-\t\tpriv-\u003evdev = NULL;\n+\t\tWRITE_ONCE(priv-\u003evdev, NULL);\n \t\tvfio_device_put_registration(\u0026vdev-\u003evdev);\n \t\tfput(priv-\u003edmabuf-\u003efile);\n \t}\n+\tup_write(\u0026vdev-\u003edmabuf_lock);\n \tup_write(\u0026vdev-\u003ememory_lock);\n }\n+\n+#ifdef CONFIG_VFIO_PCI_DMABUF\n+int vfio_pci_core_feature_dma_buf_revoke(\n+\tstruct vfio_pci_core_device *vdev, u32 flags,\n+\tstruct vfio_device_feature_dma_buf_revoke __user *arg,\n+\tsize_t argsz)\n+{\n+\tstruct vfio_device_feature_dma_buf_revoke db_revoke;\n+\tstruct vfio_pci_dma_buf *priv;\n+\tstruct dma_buf *dmabuf;\n+\tint ret;\n+\n+\tif (!vdev-\u003epci_ops || !vdev-\u003epci_ops-\u003eget_dmabuf_phys)\n+\t\treturn -EOPNOTSUPP;\n+\n+\tret = vfio_check_feature(flags, argsz,\n+\t\t\t\t VFIO_DEVICE_FEATURE_SET,\n+\t\t\t\t sizeof(db_revoke));\n+\tif (ret != 1)\n+\t\treturn ret;\n+\n+\tif (copy_from_user(\u0026db_revoke, arg, sizeof(db_revoke)))\n+\t\treturn -EFAULT;\n+\n+\tdmabuf = dma_buf_get(db_revoke.dmabuf_fd);\n+\tif (IS_ERR(dmabuf))\n+\t\treturn PTR_ERR(dmabuf);\n+\n+\tpriv = dmabuf-\u003epriv;\n+\t/*\n+\t * Sanity-check the DMABUF is really a vfio_pci_dma_buf _and_\n+\t * relates to the VFIO device it was provided with.\n+\t *\n+\t * If the DMABUF relates to this vdev then priv-\u003evdev is\n+\t * stable because this open fd prevents cleanup.\n+\t *\n+\t * If it relates to a different vdev, reading priv-\u003evdev might\n+\t * race with a concurrent cleanup on that device.  But if so,\n+\t * it points to a non-matching vdev or NULL and is unusable\n+\t * either way.\n+\t */\n+\tif (dmabuf-\u003eops != \u0026vfio_pci_dmabuf_ops ||\n+\t    READ_ONCE(priv-\u003evdev) != vdev) {\n+\t\tret = -ENODEV;\n+\t\tgoto out_put_buf;\n+\t}\n+\n+\t/*\n+\t * memory_lock(R) is taken to stop vfio_pci_dev_set_hot_reset()\n+\t * from getting it and then blocking all devices in the dev_set behind\n+\t * this revoke's drain.\n+\t */\n+\tdown_read(\u0026vdev-\u003ememory_lock);\n+\tdown_write(\u0026vdev-\u003edmabuf_lock);\n+\tif (priv-\u003estatus == VFIO_PCI_DMABUF_PERM_REVOKED) {\n+\t\tret = -EBADFD;\n+\t} else {\n+\t\tvfio_pci_dma_buf_set_status(priv,\n+\t\t\t\t\t    VFIO_PCI_DMABUF_PERM_REVOKED);\n+\t\tret = 0;\n+\t}\n+\tup_write(\u0026vdev-\u003edmabuf_lock);\n+\tup_read(\u0026vdev-\u003ememory_lock);\n+\n+out_put_buf:\n+\tdma_buf_put(dmabuf);\n+\n+\treturn ret;\n+}\n+#endif /* CONFIG_VFIO_PCI_DMABUF */\ndiff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h\nindex fca9d0dfac90f..9cf66c19f798c 100644\n--- a/drivers/vfio/pci/vfio_pci_priv.h\n+++ b/drivers/vfio/pci/vfio_pci_priv.h\n@@ -23,6 +23,27 @@ struct vfio_pci_ioeventfd {\n \tbool\t\t\ttest_mem;\n };\n \n+enum vfio_pci_dma_buf_status {\n+\tVFIO_PCI_DMABUF_OK = 0,\n+\tVFIO_PCI_DMABUF_TEMP_REVOKED = 1,\n+\tVFIO_PCI_DMABUF_PERM_REVOKED = 2,\n+};\n+\n+struct vfio_pci_dma_buf {\n+\tstruct dma_buf *dmabuf;\n+\tstruct vfio_pci_core_device *vdev;\n+\tstruct list_head dmabufs_elm;\n+\tsize_t size;\n+\tstruct phys_vec *phys_vec;\n+\tstruct p2pdma_provider *provider;\n+\tstruct file *vfile;\n+\tu32 nr_ranges;\n+\tstruct kref kref;\n+\tstruct completion comp;\n+\tunsigned long vma_pgoff_adjust;\n+\tenum vfio_pci_dma_buf_status status;\n+};\n+\n bool vfio_pci_intx_mask(struct vfio_pci_core_device *vdev);\n void vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev);\n \n@@ -68,7 +89,8 @@ void vfio_config_free(struct vfio_pci_core_device *vdev);\n int vfio_pci_set_power_state(struct vfio_pci_core_device *vdev,\n \t\t\t     pci_power_t state);\n \n-void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_core_device *vdev);\n+void vfio_pci_lock_revoke_bars(struct vfio_pci_core_device *vdev);\n+void vfio_pci_unrevoke_bars(struct vfio_pci_core_device *vdev);\n u16 vfio_pci_memory_lock_and_enable(struct vfio_pci_core_device *vdev);\n void vfio_pci_memory_unlock_and_restore(struct vfio_pci_core_device *vdev,\n \t\t\t\t\tu16 cmd);\n@@ -114,12 +136,28 @@ static inline bool vfio_pci_is_vga(struct pci_dev *pdev)\n \treturn (pdev-\u003eclass \u003e\u003e 8) == PCI_CLASS_DISPLAY_VGA;\n }\n \n+int vfio_pci_dma_buf_find_pfn(struct vfio_pci_core_device *vdev,\n+\t\t\t      struct vfio_pci_dma_buf *priv,\n+\t\t\t      struct vm_area_struct *vma,\n+\t\t\t      unsigned long address,\n+\t\t\t      unsigned int order,\n+\t\t\t      unsigned long *out_pfn);\n+int vfio_pci_core_mmap_prep_dmabuf(struct vfio_pci_core_device *vdev,\n+\t\t\t\t   struct vm_area_struct *vma,\n+\t\t\t\t   u64 phys_start, u64 req_len,\n+\t\t\t\t   unsigned int res_index);\n+void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev);\n+void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked);\n+void vfio_pci_set_vma_ops(struct vm_area_struct *vma);\n+\n #ifdef CONFIG_VFIO_PCI_DMABUF\n int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,\n \t\t\t\t  struct vfio_device_feature_dma_buf __user *arg,\n \t\t\t\t  size_t argsz);\n-void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev);\n-void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked);\n+int vfio_pci_core_feature_dma_buf_revoke(\n+\tstruct vfio_pci_core_device *vdev, u32 flags,\n+\tstruct vfio_device_feature_dma_buf_revoke __user *arg,\n+\tsize_t argsz);\n #else\n static inline int\n vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,\n@@ -128,12 +166,12 @@ vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,\n {\n \treturn -ENOTTY;\n }\n-static inline void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev)\n-{\n-}\n-static inline void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev,\n-\t\t\t\t\t bool revoked)\n+static inline int vfio_pci_core_feature_dma_buf_revoke(\n+\tstruct vfio_pci_core_device *vdev, u32 flags,\n+\tstruct vfio_device_feature_dma_buf_revoke __user *arg,\n+\tsize_t argsz)\n {\n+\treturn -ENOTTY;\n }\n #endif\n \ndiff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h\nindex d1203da56fc5f..14d3950b63c85 100644\n--- a/include/linux/dma-buf.h\n+++ b/include/linux/dma-buf.h\n@@ -570,6 +570,8 @@ int dma_buf_fd(struct dma_buf *dmabuf, int flags);\n struct dma_buf *dma_buf_get(int fd);\n void dma_buf_put(struct dma_buf *dmabuf);\n \n+int dma_buf_set_name(struct dma_buf *dmabuf, char *name);\n+\n struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *,\n \t\t\t\t\tenum dma_data_direction);\n void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,\ndiff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h\nindex 9a1674c152aa2..44891fdb7c76e 100644\n--- a/include/linux/vfio_pci_core.h\n+++ b/include/linux/vfio_pci_core.h\n@@ -129,11 +129,13 @@ struct vfio_pci_core_device {\n \tbool\t\t\tdisable_idle_d3:1;\n \tbool\t\t\tnointxmask:1;\n \tbool\t\t\tdisable_vga:1;\n+\tbool\t\t\tzap_bars_on_revoke:1;\n \t/* Flags modified at runtime - dedicated storage unit */\n \tbool\t\t\tneeds_reset;\n \tbool\t\t\tpm_intx_masked;\n \tbool\t\t\tpm_runtime_engaged;\n \tbool\t\t\tsriov_active;\n+\tbool\t\t\tbars_revoked;\n \tstruct pci_saved_state\t*pci_saved_state;\n \tstruct pci_saved_state\t*pm_save;\n \tint\t\t\tioeventfds_nr;\n@@ -148,6 +150,7 @@ struct vfio_pci_core_device {\n \tstruct vfio_pci_core_device\t*sriov_pf_core_dev;\n \tstruct notifier_block\tnb;\n \tstruct rw_semaphore\tmemory_lock;\n+\tstruct rw_semaphore\tdmabuf_lock;\n \tstruct list_head\tdmabufs;\n };\n \ndiff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h\nindex 5de618a3a5eee..8c1d50275a412 100644\n--- a/include/uapi/linux/vfio.h\n+++ b/include/uapi/linux/vfio.h\n@@ -1534,6 +1534,30 @@ struct vfio_device_feature_dma_buf {\n  */\n #define VFIO_DEVICE_FEATURE_MIG_PRECOPY_INFOv2  12\n \n+/**\n+ * Given a dma_buf fd previously exported from the same device by\n+ * VFIO_DEVICE_FEATURE_DMA_BUF, a SET of this feature requests that\n+ * access to the corresponding DMABUF is immediately and permanently\n+ * revoked.  On successful return, the buffer is not accessible\n+ * through any mmap() or dma-buf import.  The buffer is permanently\n+ * disabled, and VFIO refuses all map, mmap, attach, etc. requests.\n+ *\n+ * Return: 0 on success, -1 and errno is set on failure:\n+ *\n+ *  EBADF, EINVAL: dmabuf_fd is not a DMABUF fd.\n+ *  EOPNOTSUPP: The VFIO device does not support DMABUF export.\n+ *  ENODEV: The DMABUF was not exported from this device.\n+ *  EBADFD: The DMABUF is already permanently revoked.\n+ *\n+ * Additionally, common errors can occur: EFAULT accessing the struct,\n+ * or EINVAL requesting an unsupported feature op.\n+ */\n+#define VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE 13\n+\n+struct vfio_device_feature_dma_buf_revoke {\n+\t__s32\tdmabuf_fd;\n+};\n+\n /* -------- API for Type1 VFIO IOMMU -------- */\n \n /**\n"
}

2/1 2026/09/11 22:06 agent patch-evaluator
1m Model:
core

Args:
null

Results:
{
  "EnableConfigs": [
    "VFIO",
    "VFIO_PCI",
    "PCI_P2PDMA",
    "ZONE_DEVICE",
    "DMA_SHARED_BUFFER"
  ],
  "FocusSymbols": [
    "vfio_pci_core_mmap",
    "vfio_pci_core_mmap_prep_dmabuf",
    "vfio_pci_mmap_huge_fault",
    "vfio_pci_dma_buf_find_pfn",
    "vfio_pci_core_feature_dma_buf_revoke",
    "vfio_pci_core_feature_dma_buf",
    "vfio_pci_dma_buf_move",
    "vfio_pci_dma_buf_cleanup",
    "vfio_pci_lock_revoke_bars",
    "vfio_pci_unrevoke_bars",
    "dma_buf_set_name"
  ],
  "Reasoning": "This patch introduces DMABUF-backed BAR memory mappings for VFIO-PCI devices, refactoring vfio_pci_core_mmap to export DMABUFs and fundamentally reworking vfio_pci_mmap_huge_fault with multi-lock synchronization across dma_resv_lock, vfio_device registration, memory_lock, and dmabuf_lock. It also adds a new user-facing VFIO ioctl feature (VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE) for permanently revoking DMABUFs, and alters dma-buf name assignment logic and length checks in dma-buf.c. The code paths are reachable from userspace in standard QEMU/KVM virtualized environments via VFIO and DMA-BUF interfaces. Given the complex concurrency, locking invariants, mmap fault handling, and new ioctl logic, this patch warrants fuzzing.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.

================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.

- REACHABILITY IS THE PRIMARY GATE:
  Fuzzing can only discover bugs in code that can actually execute in standard virtualized
  environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
  If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
  regardless of whether it adds assertions or complex logic.

- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
  Patch authors routinely label changes as "cleanups", "refactorings", or state
  "No functional change intended". Do NOT take these claims at face value.
  Code refactorings that rearrange logic, introduce helper functions, or alter state management
  in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
  If reachable executable code is modified or refactored, it MUST be fuzzed.

- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
  When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
  BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
  Even if the author believes the invariant always holds, fuzzing is essential to verify whether
  an unusual sequence of operations can violate it.

================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:

- Non-kernel and non-executable changes:
  * Modifications to Documentation/, comments, or spelling fixes.
  * User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
    that do not affect the compiled kernel image (vmlinux) or kernel modules.
  * Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
    that do not alter control flow or data structures.
  * Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
  * Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
    ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
  * Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
    physical PCI hot-unplug or manual sysfs driver unbinding.
  * Code paths exclusive to architectures other than the target architecture.

================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
  * Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
    BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
  * Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
  * Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
  * Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).

================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:

- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
  Do NOT list generic, ubiquitous functions called by almost every program in the corpus
  (including, but not limited to: general memory allocators and deallocators, page fault
  and trap handlers, or core synchronization primitives; this is not an exhaustive list).
  Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
  which severely dilutes fuzzing effort away from the actual changes.

- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
  List functions that specifically implement the logic being added or altered, or direct API entrypoints
  for the subsystem feature under review.

- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
  Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
  distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
  If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
  functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).

================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit 4181b909f1f9301a41044499b4f86a52a0c71e2f
Author: syz-cluster <triage@syzkaller.com>
Date:   Fri Sep 11 22:06:41 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index d504c636dc294..8129ea11ff58c 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -405,31 +405,29 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
 }
 
 /**
- * dma_buf_set_name - Set a name to a specific dma_buf to track the usage.
- * It could support changing the name of the dma-buf if the same
- * piece of memory is used for multiple purpose between different devices.
+ * dma_buf_set_name_user - Set a dma_buf's name from a user string
+ *
+ * The string is up to DMA_BUF_NAME_LEN long, including the terminator.
  *
  * @dmabuf: [in]     dmabuf buffer that will be renamed.
  * @buf:    [in]     A piece of userspace memory that contains the name of
  *                   the dma-buf.
  *
- * Returns 0 on success. If the dma-buf buffer is already attached to
- * devices, return -EBUSY.
- *
+ * Returns 0 on success, and any previously-set name is freed.
  */
-static long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf)
+static long dma_buf_set_name_user(struct dma_buf *dmabuf, const char __user *buf)
 {
 	char *name = strndup_user(buf, DMA_BUF_NAME_LEN);
+	int ret;
 
 	if (IS_ERR(name))
 		return PTR_ERR(name);
 
-	spin_lock(&dmabuf->name_lock);
-	kfree(dmabuf->name);
-	dmabuf->name = name;
-	spin_unlock(&dmabuf->name_lock);
+	ret = dma_buf_set_name(dmabuf, name);
+	if (ret)
+		kfree(name);
 
-	return 0;
+	return ret;
 }
 
 #if IS_ENABLED(CONFIG_SYNC_FILE)
@@ -578,7 +576,7 @@ static long dma_buf_ioctl(struct file *file,
 
 	case DMA_BUF_SET_NAME_A:
 	case DMA_BUF_SET_NAME_B:
-		return dma_buf_set_name(dmabuf, (const char __user *)arg);
+		return dma_buf_set_name_user(dmabuf, (const char __user *)arg);
 
 #if IS_ENABLED(CONFIG_SYNC_FILE)
 	case DMA_BUF_IOCTL_EXPORT_SYNC_FILE:
@@ -854,6 +852,40 @@ void dma_buf_put(struct dma_buf *dmabuf)
 }
 EXPORT_SYMBOL_NS_GPL(dma_buf_put, "DMA_BUF");
 
+/**
+ * dma_buf_set_name - Set a dma_buf's name
+ * It could support changing the name of the dma-buf if the same piece
+ * of memory is used for multiple purpose between different devices.
+ *
+ * @dmabuf: [in]     dmabuf buffer that will be renamed.
+ * @name:   [in]     The name of the dma-buf, allocated with kmalloc() or
+ *                   similar.  This takes ownership of the allocation
+ *                   on success, which will be kfree()d when the
+ *                   dmabuf is released or a new name assigned.
+ *
+ * Returns 0 on success, -EINVAL if the name is NULL, or -E2BIG if the
+ * name exceeds DMA_BUF_NAME_LEN.
+ */
+int dma_buf_set_name(struct dma_buf *dmabuf, char *name)
+{
+	if (!name)
+		return -EINVAL;
+
+	/* dmabuffs_dname() won't use the string if the length
+	 * (including terminator) exceeds DMA_BUF_NAME_LEN:
+	 */
+	if (strlen(name) >= DMA_BUF_NAME_LEN)
+		return -E2BIG;
+
+	spin_lock(&dmabuf->name_lock);
+	kfree(dmabuf->name);
+	dmabuf->name = name;
+	spin_unlock(&dmabuf->name_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_set_name, "DMA_BUF");
+
 static int dma_buf_wrap_sg_table(struct sg_table **sg_table)
 {
 	struct scatterlist *to_sg, *from_sg;
diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig
index 296bf01e185ec..c6d6fb09af86c 100644
--- a/drivers/vfio/pci/Kconfig
+++ b/drivers/vfio/pci/Kconfig
@@ -6,6 +6,7 @@ config VFIO_PCI_CORE
 	tristate
 	select VFIO_VIRQFD
 	select IRQ_BYPASS_MANAGER
+	select DMA_SHARED_BUFFER
 
 config VFIO_PCI_INTX
 	def_bool y if !S390
@@ -56,7 +57,8 @@ config VFIO_PCI_ZDEV_KVM
 	  To enable s390x KVM vfio-pci extensions, say Y.
 
 config VFIO_PCI_DMABUF
-	def_bool y if VFIO_PCI_CORE && PCI_P2PDMA && DMA_SHARED_BUFFER
+	def_bool y if PCI_P2PDMA
+	depends on VFIO_PCI_CORE
 
 source "drivers/vfio/pci/mlx5/Kconfig"
 
diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile
index 6138f1bf241df..881452ea89be0 100644
--- a/drivers/vfio/pci/Makefile
+++ b/drivers/vfio/pci/Makefile
@@ -1,8 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-vfio-pci-core-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o
+vfio-pci-core-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o vfio_pci_dmabuf.o
 vfio-pci-core-$(CONFIG_VFIO_PCI_ZDEV_KVM) += vfio_pci_zdev.o
-vfio-pci-core-$(CONFIG_VFIO_PCI_DMABUF) += vfio_pci_dmabuf.o
 obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o
 
 vfio-pci-y := vfio_pci.o
diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
index 86362ec424a50..14622556355eb 100644
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
@@ -1564,6 +1564,7 @@ static int hisi_acc_vfio_pci_migrn_init_dev(struct vfio_device *core_vdev)
 	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
 	struct pci_dev *pdev = to_pci_dev(core_vdev->dev);
 	struct hisi_qm *pf_qm = hisi_acc_get_pf_qm(pdev);
+	int ret;
 
 	hisi_acc_vdev->vf_id = pci_iov_vf_id(pdev) + 1;
 	hisi_acc_vdev->pf_qm = pf_qm;
@@ -1575,7 +1576,18 @@ static int hisi_acc_vfio_pci_migrn_init_dev(struct vfio_device *core_vdev)
 	core_vdev->migration_flags = VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_PRE_COPY;
 	core_vdev->mig_ops = &hisi_acc_vfio_pci_migrn_state_ops;
 
-	return vfio_pci_core_init_dev(core_vdev);
+	ret = vfio_pci_core_init_dev(core_vdev);
+	if (ret)
+		return ret;
+	/*
+	 * hisi_acc_vfio_pci_mmap() calls down to
+	 * vfio_pci_core_mmap(), so BAR mappings are still
+	 * DMABUF-backed.  They don't require a zap on revoke, so opt
+	 * out:
+	 */
+	hisi_acc_vdev->core_device.zap_bars_on_revoke = false;
+
+	return 0;
 }
 
 static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = {
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index a10ed733f0e3a..bc6ccb2e135c3 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -590,12 +590,10 @@ static int vfio_basic_config_write(struct vfio_pci_core_device *vdev, int pos,
 		virt_mem = !!(le16_to_cpu(*virt_cmd) & PCI_COMMAND_MEMORY);
 		new_mem = !!(new_cmd & PCI_COMMAND_MEMORY);
 
-		if (!new_mem) {
-			vfio_pci_zap_and_down_write_memory_lock(vdev);
-			vfio_pci_dma_buf_move(vdev, true);
-		} else {
+		if (!new_mem)
+			vfio_pci_lock_revoke_bars(vdev);
+		else
 			down_write(&vdev->memory_lock);
-		}
 
 		/*
 		 * If the user is writing mem/io enable (new_mem/io) and we
@@ -631,7 +629,7 @@ static int vfio_basic_config_write(struct vfio_pci_core_device *vdev, int pos,
 		*virt_cmd |= cpu_to_le16(new_cmd & mask);
 
 		if (__vfio_pci_memory_enabled(vdev))
-			vfio_pci_dma_buf_move(vdev, false);
+			vfio_pci_unrevoke_bars(vdev);
 		up_write(&vdev->memory_lock);
 	}
 
@@ -712,16 +710,14 @@ static int __init init_pci_cap_basic_perm(struct perm_bits *perm)
 static void vfio_lock_and_set_power_state(struct vfio_pci_core_device *vdev,
 					  pci_power_t state)
 {
-	if (state >= PCI_D3hot) {
-		vfio_pci_zap_and_down_write_memory_lock(vdev);
-		vfio_pci_dma_buf_move(vdev, true);
-	} else {
+	if (state >= PCI_D3hot)
+		vfio_pci_lock_revoke_bars(vdev);
+	else
 		down_write(&vdev->memory_lock);
-	}
 
 	vfio_pci_set_power_state(vdev, state);
 	if (__vfio_pci_memory_enabled(vdev))
-		vfio_pci_dma_buf_move(vdev, false);
+		vfio_pci_unrevoke_bars(vdev);
 	up_write(&vdev->memory_lock);
 }
 
@@ -908,11 +904,10 @@ static int vfio_exp_config_write(struct vfio_pci_core_device *vdev, int pos,
 						 &cap);
 
 		if (!ret && (cap & PCI_EXP_DEVCAP_FLR)) {
-			vfio_pci_zap_and_down_write_memory_lock(vdev);
-			vfio_pci_dma_buf_move(vdev, true);
+			vfio_pci_lock_revoke_bars(vdev);
 			pci_try_reset_function(vdev->pdev);
 			if (__vfio_pci_memory_enabled(vdev))
-				vfio_pci_dma_buf_move(vdev, false);
+				vfio_pci_unrevoke_bars(vdev);
 			up_write(&vdev->memory_lock);
 		}
 	}
@@ -993,11 +988,10 @@ static int vfio_af_config_write(struct vfio_pci_core_device *vdev, int pos,
 						&cap);
 
 		if (!ret && (cap & PCI_AF_CAP_FLR) && (cap & PCI_AF_CAP_TP)) {
-			vfio_pci_zap_and_down_write_memory_lock(vdev);
-			vfio_pci_dma_buf_move(vdev, true);
+			vfio_pci_lock_revoke_bars(vdev);
 			pci_try_reset_function(vdev->pdev);
 			if (__vfio_pci_memory_enabled(vdev))
-				vfio_pci_dma_buf_move(vdev, false);
+				vfio_pci_unrevoke_bars(vdev);
 			up_write(&vdev->memory_lock);
 		}
 	}
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 3f11a9624b9c0..911e248aa764f 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -13,6 +13,8 @@
 #include <linux/aperture.h>
 #include <linux/debugfs.h>
 #include <linux/device.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-resv.h>
 #include <linux/eventfd.h>
 #include <linux/file.h>
 #include <linux/interrupt.h>
@@ -375,8 +377,7 @@ static int vfio_pci_runtime_pm_entry(struct vfio_pci_core_device *vdev,
 	 * The vdev power related flags are protected with 'memory_lock'
 	 * semaphore.
 	 */
-	vfio_pci_zap_and_down_write_memory_lock(vdev);
-	vfio_pci_dma_buf_move(vdev, true);
+	vfio_pci_lock_revoke_bars(vdev);
 
 	if (vdev->pm_runtime_engaged) {
 		up_write(&vdev->memory_lock);
@@ -462,7 +463,7 @@ static void vfio_pci_runtime_pm_exit(struct vfio_pci_core_device *vdev)
 	down_write(&vdev->memory_lock);
 	__vfio_pci_runtime_pm_exit(vdev);
 	if (__vfio_pci_memory_enabled(vdev))
-		vfio_pci_dma_buf_move(vdev, false);
+		vfio_pci_unrevoke_bars(vdev);
 	up_write(&vdev->memory_lock);
 }
 
@@ -526,8 +527,14 @@ static int vfio_pci_core_runtime_resume(struct device *dev)
 	 */
 	down_write(&vdev->memory_lock);
 	if (vdev->pm_wake_eventfd_ctx) {
-		eventfd_signal(vdev->pm_wake_eventfd_ctx);
+		struct eventfd_ctx *ctx = vdev->pm_wake_eventfd_ctx;
+
+		vdev->pm_wake_eventfd_ctx = NULL;
 		__vfio_pci_runtime_pm_exit(vdev);
+		if (__vfio_pci_memory_enabled(vdev))
+			vfio_pci_unrevoke_bars(vdev);
+		eventfd_signal(ctx);
+		eventfd_ctx_put(ctx);
 	}
 	up_write(&vdev->memory_lock);
 
@@ -659,6 +666,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
 		vdev->has_vga = true;
 
 	vfio_pci_core_map_bars(vdev);
+	vdev->bars_revoked = false;
 
 	return 0;
 
@@ -1312,6 +1320,8 @@ static int vfio_pci_ioctl_set_irqs(struct vfio_pci_core_device *vdev,
 	return ret;
 }
 
+static void vfio_pci_revoke_bars(struct vfio_pci_core_device *vdev);
+
 static int vfio_pci_ioctl_reset(struct vfio_pci_core_device *vdev,
 				void __user *arg)
 {
@@ -1320,7 +1330,7 @@ static int vfio_pci_ioctl_reset(struct vfio_pci_core_device *vdev,
 	if (!vdev->reset_works)
 		return -EINVAL;
 
-	vfio_pci_zap_and_down_write_memory_lock(vdev);
+	down_write(&vdev->memory_lock);
 
 	/*
 	 * This function can be invoked while the power state is non-D0. If
@@ -1330,13 +1340,18 @@ static int vfio_pci_ioctl_reset(struct vfio_pci_core_device *vdev,
 	 * have NoSoftRst-, the reset function can cause the PCI config space
 	 * reset without restoring the original state (saved locally in
 	 * 'vdev->pm_save').
+	 *
+	 * The zap is done after making the device accessible in D0,
+	 * because a DMABUF importer could access the device as part
+	 * of its revocation cleanup.
 	 */
 	vfio_pci_set_power_state(vdev, PCI_D0);
 
-	vfio_pci_dma_buf_move(vdev, true);
+	vfio_pci_revoke_bars(vdev);
+
 	ret = pci_try_reset_function(vdev->pdev);
 	if (__vfio_pci_memory_enabled(vdev))
-		vfio_pci_dma_buf_move(vdev, false);
+		vfio_pci_unrevoke_bars(vdev);
 	up_write(&vdev->memory_lock);
 
 	return ret;
@@ -1625,6 +1640,8 @@ int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags,
 		return vfio_pci_core_feature_token(vdev, flags, arg, argsz);
 	case VFIO_DEVICE_FEATURE_DMA_BUF:
 		return vfio_pci_core_feature_dma_buf(vdev, flags, arg, argsz);
+	case VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE:
+		return vfio_pci_core_feature_dma_buf_revoke(vdev, flags, arg, argsz);
 	default:
 		return -ENOTTY;
 	}
@@ -1704,20 +1721,37 @@ ssize_t vfio_pci_core_write(struct vfio_device *core_vdev, const char __user *bu
 }
 EXPORT_SYMBOL_GPL(vfio_pci_core_write);
 
-static void vfio_pci_zap_bars(struct vfio_pci_core_device *vdev)
+static void vfio_pci_revoke_bars(struct vfio_pci_core_device *vdev)
 {
-	struct vfio_device *core_vdev = &vdev->vdev;
-	loff_t start = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_BAR0_REGION_INDEX);
-	loff_t end = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_ROM_REGION_INDEX);
-	loff_t len = end - start;
+	lockdep_assert_held_write(&vdev->memory_lock);
+	vfio_pci_dma_buf_move(vdev, true);
 
-	unmap_mapping_range(core_vdev->inode->i_mapping, start, len, true);
+	/*
+	 * If a driver could possibly create BAR mappings in the
+	 * vdev's address_space, do an additional zap on revoke.  See
+	 * vfio_pci_core_init_dev().
+	 */
+	if (vdev->zap_bars_on_revoke) {
+		struct vfio_device *core_vdev = &vdev->vdev;
+		loff_t start = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_BAR0_REGION_INDEX);
+		loff_t end = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_ROM_REGION_INDEX);
+		loff_t len = end - start;
+
+		unmap_mapping_range(core_vdev->inode->i_mapping,
+				    start, len, true);
+	}
 }
 
-void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_core_device *vdev)
+void vfio_pci_lock_revoke_bars(struct vfio_pci_core_device *vdev)
 {
 	down_write(&vdev->memory_lock);
-	vfio_pci_zap_bars(vdev);
+	vfio_pci_revoke_bars(vdev);
+}
+
+void vfio_pci_unrevoke_bars(struct vfio_pci_core_device *vdev)
+{
+	lockdep_assert_held_write(&vdev->memory_lock);
+	vfio_pci_dma_buf_move(vdev, false);
 }
 
 u16 vfio_pci_memory_lock_and_enable(struct vfio_pci_core_device *vdev)
@@ -1739,18 +1773,6 @@ void vfio_pci_memory_unlock_and_restore(struct vfio_pci_core_device *vdev, u16 c
 	up_write(&vdev->memory_lock);
 }
 
-static unsigned long vma_to_pfn(struct vm_area_struct *vma)
-{
-	struct vfio_pci_core_device *vdev = vma->vm_private_data;
-	int index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);
-	u64 pgoff;
-
-	pgoff = vma->vm_pgoff &
-		((1U << (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
-
-	return (pci_resource_start(vdev->pdev, index) >> PAGE_SHIFT) + pgoff;
-}
-
 vm_fault_t vfio_pci_vmf_insert_pfn(struct vfio_pci_core_device *vdev,
 				   struct vm_fault *vmf,
 				   unsigned long pfn,
@@ -1778,24 +1800,106 @@ static vm_fault_t vfio_pci_mmap_huge_fault(struct vm_fault *vmf,
 					   unsigned int order)
 {
 	struct vm_area_struct *vma = vmf->vma;
-	struct vfio_pci_core_device *vdev = vma->vm_private_data;
-	unsigned long addr = vmf->address & ~((PAGE_SIZE << order) - 1);
-	unsigned long pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
-	unsigned long pfn = vma_to_pfn(vma) + pgoff;
-	vm_fault_t ret = VM_FAULT_FALLBACK;
-
-	if (is_aligned_for_order(vma, addr, pfn, order)) {
-		scoped_guard(rwsem_read, &vdev->memory_lock)
-			ret = vfio_pci_vmf_insert_pfn(vdev, vmf, pfn, order);
+	struct vfio_pci_dma_buf *priv = vma->vm_private_data;
+	struct vfio_pci_core_device *vdev;
+	unsigned long pfn = 0;
+	vm_fault_t ret = VM_FAULT_SIGBUS;
+
+	/*
+	 * The only thing this can rely on is that the DMABUF relating
+	 * to the VMA's vm_file exists (priv).
+	 *
+	 * A DMABUF for a VFIO device fd mmap() holds a reference to
+	 * the original VFIO device fd, but an explicitly-exported
+	 * DMABUF does not.  The original fd might have closed,
+	 * meaning this fault can race with
+	 * vfio_pci_dma_buf_cleanup(), meaning the buffer could have
+	 * been revoked (in which case priv->vdev might be NULL), and
+	 * the VFIO device registration might have been dropped.
+	 *
+	 * With the goal of taking vdev locks in a world where vdev
+	 * might not still exist:
+	 *
+	 * 1. Take the resv lock on the DMABUF:
+	 *  - If racing cleanup got in first, the buffer is revoked;
+	 *    stop/exit if so.
+	 *  - If we got in first, the buffer is not revoked so vdev is
+	 *    non-NULL, accessible, and cleanup _has not yet put the
+	 *    VFIO device registration_.  So, the device refcount must
+	 *    be >0.
+	 *
+	 * 2. Take vfio_device registration (refcount guaranteed >0
+	 *    hereafter).
+	 *
+	 * 3. Unlock the DMABUF's resv lock:
+	 *  - A racing cleanup can now complete.
+	 *  - But, the device refcount >0, meaning the vfio_device
+	 *    (and vfio_pcie_core device vdev) have not yet been
+	 *    freed.  vdev is accessible, even if the DMABUF has been
+	 *    revoked or cleanup has happened, because
+	 *    vfio_unregister_group_dev() can't complete.
+	 *
+	 * 4. Take the vdev->memory_lock then vdev->dmabuf_lock:
+	 *  - Either the DMABUF is usable, or has been cleaned up.
+	 *  - It's not necessary to also take the resv lock, because
+	 *    the status/vdev can't change while dmabuf_lock is held.
+	 *  - Test the DMABUF revocation status again: if it was
+	 *    revoked between 1 and 4, return a SIGBUS. Otherwise,
+	 *    return a PFN.
+	 *
+	 * 5. Unlock, done.
+	 */
+
+	dma_resv_lock(priv->dmabuf->resv, NULL);
+
+	if (priv->status != VFIO_PCI_DMABUF_OK) {
+		pr_debug_ratelimited("%s VA 0x%lx, pgoff 0x%lx: DMABUF revoked/cleaned up\n",
+				     __func__, vmf->address, vma->vm_pgoff);
+		dma_resv_unlock(priv->dmabuf->resv);
+		return VM_FAULT_SIGBUS;
+	}
+
+	/* If the buffer isn't revoked, vdev is valid */
+	vdev = priv->vdev;
+
+	if (!vfio_device_try_get_registration(&vdev->vdev)) {
+		/*
+		 * If vdev != NULL (above), the registration should
+		 * already be >0 and so this try_get should never
+		 * fail.
+		 */
+		dev_warn_ratelimited(&vdev->pdev->dev,
+				     "%s: Unexpected registration failure\n",
+				     __func__);
+		dma_resv_unlock(priv->dmabuf->resv);
+		return VM_FAULT_SIGBUS;
+	}
+	dma_resv_unlock(priv->dmabuf->resv);
+
+	/* memory_lock for vfio_pci_vmf_insert_pfn() */
+	down_read(&vdev->memory_lock);
+	/* Re-test revocation status under dmabuf_lock */
+	down_read(&vdev->dmabuf_lock);
+	if (priv->status == VFIO_PCI_DMABUF_OK) {
+		int pres = vfio_pci_dma_buf_find_pfn(vdev, priv, vma,
+						     vmf->address,
+						     order, &pfn);
+
+		if (pres == 0)
+			ret = vfio_pci_vmf_insert_pfn(vdev, vmf,
+						      pfn, order);
+		else if (pres == -ERANGE)
+			ret = VM_FAULT_FALLBACK;
 	}
+	up_read(&vdev->dmabuf_lock);
+	up_read(&vdev->memory_lock);
 
 	dev_dbg_ratelimited(&vdev->pdev->dev,
-			   "%s(,order = %d) BAR %ld page offset 0x%lx: 0x%x\n",
-			    __func__, order,
-			    vma->vm_pgoff >>
-				(VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT),
-			    pgoff, (unsigned int)ret);
+			    "%s(order = %d) PFN 0x%lx, VA 0x%lx, pgoff 0x%lx: 0x%x\n",
+			    __func__, order, pfn, vmf->address,
+			    vma->vm_pgoff, (unsigned int)ret);
 
+	vfio_device_put_registration(&vdev->vdev);
 	return ret;
 }
 
@@ -1811,6 +1915,11 @@ static const struct vm_operations_struct vfio_pci_mmap_ops = {
 #endif
 };
 
+void vfio_pci_set_vma_ops(struct vm_area_struct *vma)
+{
+	vma->vm_ops = &vfio_pci_mmap_ops;
+}
+
 int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma)
 {
 	struct vfio_pci_core_device *vdev =
@@ -1819,6 +1928,7 @@ int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma
 	unsigned int index;
 	u64 phys_len, req_len, pgoff, req_start;
 	void __iomem *bar_io;
+	int ret;
 
 	index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);
 
@@ -1858,7 +1968,12 @@ int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma
 	if (IS_ERR(bar_io))
 		return PTR_ERR(bar_io);
 
-	vma->vm_private_data = vdev;
+	ret = vfio_pci_core_mmap_prep_dmabuf(vdev, vma,
+					     pci_resource_start(pdev, index),
+					     req_len, index);
+	if (ret)
+		return ret;
+
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
 
@@ -2195,8 +2310,19 @@ int vfio_pci_core_init_dev(struct vfio_device *core_vdev)
 		return ret;
 	INIT_LIST_HEAD(&vdev->dmabufs);
 	init_rwsem(&vdev->memory_lock);
+	init_rwsem(&vdev->dmabuf_lock);
 	xa_init(&vdev->ctx);
 
+	/*
+	 * If a driver overrides .mmap, it has to be assumed that it
+	 * might not use the DMABUF-backed core mmap; this flag
+	 * enables a zap at revoke time.  A driver can opt out by
+	 * clearing this flag at init, if their .mmap override calls
+	 * down to vfio_pci_core_mmap().
+	 */
+	if (vdev->vdev.ops->mmap != vfio_pci_core_mmap)
+		vdev->zap_bars_on_revoke = true;
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(vfio_pci_core_init_dev);
@@ -2564,9 +2690,10 @@ static int vfio_pci_dev_set_hot_reset(struct vfio_device_set *dev_set,
 		}
 
 		/*
-		 * Take the memory write lock for each device and zap BAR
-		 * mappings to prevent the user accessing the device while in
-		 * reset.  Locking multiple devices is prone to deadlock,
+		 * Take the memory write lock for each device and
+		 * zap/revoke BAR mappings to prevent the user (or
+		 * peers) accessing the device while in reset.
+		 * Locking multiple devices is prone to deadlock,
 		 * runaway and unwind if we hit contention.
 		 */
 		if (!down_write_trylock(&vdev->memory_lock)) {
@@ -2574,8 +2701,7 @@ static int vfio_pci_dev_set_hot_reset(struct vfio_device_set *dev_set,
 			break;
 		}
 
-		vfio_pci_dma_buf_move(vdev, true);
-		vfio_pci_zap_bars(vdev);
+		vfio_pci_revoke_bars(vdev);
 	}
 
 	if (!list_entry_is_head(vdev,
@@ -2605,7 +2731,7 @@ static int vfio_pci_dev_set_hot_reset(struct vfio_device_set *dev_set,
 	list_for_each_entry_from_reverse(vdev, &dev_set->device_list,
 					 vdev.dev_set_list) {
 		if (vdev->vdev.open_count && __vfio_pci_memory_enabled(vdev))
-			vfio_pci_dma_buf_move(vdev, false);
+			vfio_pci_unrevoke_bars(vdev);
 		up_write(&vdev->memory_lock);
 	}
 
diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci_dmabuf.c
index c16f460c01d68..7cda2bd00d25a 100644
--- a/drivers/vfio/pci/vfio_pci_dmabuf.c
+++ b/drivers/vfio/pci/vfio_pci_dmabuf.c
@@ -3,25 +3,14 @@
  */
 #include <linux/dma-buf-mapping.h>
 #include <linux/pci-p2pdma.h>
+#include <linux/dma-buf.h>
 #include <linux/dma-resv.h>
 
 #include "vfio_pci_priv.h"
 
 MODULE_IMPORT_NS("DMA_BUF");
 
-struct vfio_pci_dma_buf {
-	struct dma_buf *dmabuf;
-	struct vfio_pci_core_device *vdev;
-	struct list_head dmabufs_elm;
-	size_t size;
-	struct phys_vec *phys_vec;
-	struct p2pdma_provider *provider;
-	u32 nr_ranges;
-	struct kref kref;
-	struct completion comp;
-	u8 revoked : 1;
-};
-
+#ifdef CONFIG_VFIO_PCI_DMABUF
 static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,
 				   struct dma_buf_attachment *attachment)
 {
@@ -30,7 +19,7 @@ static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,
 	if (!attachment->peer2peer)
 		return -EOPNOTSUPP;
 
-	if (priv->revoked)
+	if (READ_ONCE(priv->status) != VFIO_PCI_DMABUF_OK)
 		return -ENODEV;
 
 	if (!dma_buf_attach_revocable(attachment))
@@ -39,6 +28,62 @@ static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,
 	return 0;
 }
 
+static int vfio_pci_dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
+{
+	struct vfio_pci_dma_buf *priv = dmabuf->priv;
+
+	/*
+	 * dma_buf_mmap_internal() has asserted that the VMA is
+	 * contained within the DMABUF size before calling this.
+	 *
+	 * Also, if we observe that the buffer is revoked now then
+	 * refuse the mmap().  This is a belt-and-braces early failure
+	 * to ease debugging a revoked buffer being used.  Userspace
+	 * might also race an mmap() against an explicit revocation,
+	 * or an action doing a temporary revoke; race scenarios are
+	 * still safe because the fault handler ultimately prevents
+	 * access to a revoked buffer if it isn't caught here.
+	 */
+	if (READ_ONCE(priv->status) != VFIO_PCI_DMABUF_OK)
+		return -ENODEV;
+	/*
+	 * Make clear that anything with an offset adjustment is
+	 * explicitly unsupported, as vfio_pci_dma_buf_find_pfn()
+	 * maths would underflow; this doesn't happen through the
+	 * regular DMABUF export path used with this mmap().  A DMABUF
+	 * implicitly created for BAR mmap could have adjust > 0, but
+	 * these can't currently be re-opened and mmap()ed again.
+	 * Catch here in case that assumption ever changes.
+	 */
+	if (priv->vma_pgoff_adjust)
+		return -EINVAL;
+	if ((vma->vm_flags & VM_SHARED) == 0)
+		return -EINVAL;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
+
+	/* See comments in vfio_pci_core_mmap() re VM_ALLOW_ANY_UNCACHED. */
+	vm_flags_set(vma, VM_ALLOW_ANY_UNCACHED | VM_IO | VM_PFNMAP |
+		     VM_DONTEXPAND | VM_DONTDUMP);
+	vma->vm_private_data = priv;
+	vfio_pci_set_vma_ops(vma);
+
+	return 0;
+}
+#else
+static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,
+				   struct dma_buf_attachment *attachment)
+{
+	/*
+	 * Explicit export can't occur without the DMABUF feature, but
+	 * DMABUFs are implicitly created for BAR mappings.  An
+	 * .attach that fails prevents dma_buf_attach().
+	 */
+	return -EOPNOTSUPP;
+}
+#endif /* CONFIG_VFIO_PCI_DMABUF */
+
 static void vfio_pci_dma_buf_done(struct kref *kref)
 {
 	struct vfio_pci_dma_buf *priv =
@@ -56,7 +101,7 @@ vfio_pci_dma_buf_map(struct dma_buf_attachment *attachment,
 
 	dma_resv_assert_held(priv->dmabuf->resv);
 
-	if (priv->revoked)
+	if (priv->status != VFIO_PCI_DMABUF_OK)
 		return ERR_PTR(-ENODEV);
 
 	ret = dma_buf_phys_vec_to_sgt(attachment, priv->provider,
@@ -90,22 +135,348 @@ static void vfio_pci_dma_buf_release(struct dma_buf *dmabuf)
 	 * The refcount prevents both.
 	 */
 	if (priv->vdev) {
-		down_write(&priv->vdev->memory_lock);
+		down_write(&priv->vdev->dmabuf_lock);
 		list_del_init(&priv->dmabufs_elm);
-		up_write(&priv->vdev->memory_lock);
+		up_write(&priv->vdev->dmabuf_lock);
 		vfio_device_put_registration(&priv->vdev->vdev);
 	}
+	if (priv->vfile)
+		fput(priv->vfile);
 	kfree(priv->phys_vec);
 	kfree(priv);
 }
 
 static const struct dma_buf_ops vfio_pci_dmabuf_ops = {
 	.attach = vfio_pci_dma_buf_attach,
+#ifdef CONFIG_VFIO_PCI_DMABUF
+	.mmap = vfio_pci_dma_buf_mmap,
+#endif
 	.map_dma_buf = vfio_pci_dma_buf_map,
 	.unmap_dma_buf = vfio_pci_dma_buf_unmap,
 	.release = vfio_pci_dma_buf_release,
 };
 
+int vfio_pci_dma_buf_find_pfn(struct vfio_pci_core_device *vdev,
+			      struct vfio_pci_dma_buf *priv,
+			      struct vm_area_struct *vma,
+			      unsigned long fault_addr,
+			      unsigned int order,
+			      unsigned long *out_pfn)
+{
+	/*
+	 * Given a VMA (start, end, pgoffs) and a fault address,
+	 * search the corresponding DMABUF's phys_vec[] to find the
+	 * range representing the address's offset into the VMA, and
+	 * its PFN.  vdev must be the device that the DMABUF priv was
+	 * exported from; vdev->dmabuf_lock must be held, and priv
+	 * must not be revoked.
+	 *
+	 * The phys_vec[] ranges represent contiguous spans of VAs
+	 * upwards from the buffer offset 0; the actual PFNs might be
+	 * in any order, overlap/alias, etc.  Calculate an offset of
+	 * the desired page given VMA start/pgoff and address, then
+	 * search upwards from 0 to find which span contains it.
+	 *
+	 * On success, a valid PFN for a page sized by 'order' is
+	 * returned into out_pfn.
+	 *
+	 * Failure occurs if:
+	 * - A hugepage would cross the edge of the VMA,
+	 * - A hugepage isn't entirely contained within a range
+	 *   (including where it straddles the boundary between
+	 *   ranges),
+	 * - We find a range, but the final PFN isn't aligned to the
+	 *   requested order.
+	 *
+	 * Upon failure, -ERANGE is returned and the caller is
+	 * expected to try again with a smaller order, which will
+	 * eventually succeed.
+	 *
+	 * It's suboptimal if DMABUFs are created with neighbouring
+	 * ranges that are physically contiguous, since hugepages
+	 * can't straddle range boundaries.  (The construction of the
+	 * ranges should merge them in this case.)
+	 *
+	 * Finally, vma_pgoff_adjust is used with a DMABUF created for
+	 * a VFIO BAR mmap: a BAR mapped with vm_pgoff > 0 creates a
+	 * DMABUF such that byte 0 of the VMA corresponds to byte 0 of
+	 * the DMABUF and byte 'vm_pgoff << PAGE_SHIFT' into the BAR.
+	 * To avoid double-offsetting in this scenario, subtracting
+	 * vma_pgoff_adjust from this (non-zero) vm_pgoff generates
+	 * the effective offset.  This also removes the VFIO region
+	 * index encoded in vm_pgoff for VFIO BAR mmaps.
+	 */
+
+	const unsigned long pagesize = PAGE_SIZE << order;
+	unsigned long vma_off = (vma->vm_pgoff - priv->vma_pgoff_adjust) <<
+				 PAGE_SHIFT;
+	unsigned long rounded_page_addr = ALIGN_DOWN(fault_addr, pagesize);
+	unsigned long rounded_page_end = rounded_page_addr + pagesize;
+	unsigned long fault_offset;
+	unsigned long fault_offset_end;
+	unsigned long range_start_offset = 0;
+	unsigned int i;
+	int ret;
+
+	if (unlikely(!vdev))
+		return -ENODEV;
+
+	/* This prevents the dmabuf revocation state from changing under us */
+	lockdep_assert_held(&vdev->dmabuf_lock);
+
+	if (unlikely(priv->vdev != vdev || priv->status != VFIO_PCI_DMABUF_OK))
+		return -ENODEV;
+
+	if (rounded_page_addr < vma->vm_start || rounded_page_end > vma->vm_end) {
+		if (order > 0)
+			return -ERANGE;
+
+		/* A fault address outside of the VMA is absurd. */
+		dev_warn_ratelimited(
+			&vdev->pdev->dev,
+			"Fault addr 0x%lx outside VMA 0x%lx-0x%lx\n",
+			fault_addr, vma->vm_start, vma->vm_end);
+		return -EFAULT;
+	}
+
+	/*
+	 * fault_offset[_end] is the span within the DMABUF
+	 * corresponding to the faulting page:
+	 */
+	if (unlikely(check_add_overflow(rounded_page_addr - vma->vm_start,
+					vma_off, &fault_offset) ||
+		     check_add_overflow(fault_offset, pagesize,
+					&fault_offset_end)))
+		return -EFAULT;
+
+	/*
+	 * Iterate over ranges in the buffer, summing their lengths:
+	 * range_start_offset represents the current range's starting
+	 * offset in the buffer (from 0 upwards).
+	 *
+	 * A failure for order == 0 is unexpected, and triggers a
+	 * fault/warn.
+	 */
+	ret = (order == 0) ? -EFAULT : -ERANGE;
+
+	for (i = 0; i < priv->nr_ranges; i++) {
+		size_t range_len = priv->phys_vec[i].len;
+
+		/* Early exit if range starts after the page end */
+		if (fault_offset_end <= range_start_offset)
+			break;
+
+		if (fault_offset >= range_start_offset &&
+		    fault_offset_end <= range_start_offset + range_len) {
+			/*
+			 * The faulting page is wholly contained
+			 * within the span represented by this range,
+			 * so validate PFN alignment for the order.
+			 * The if() condition ensures the pfn
+			 * arithmetic won't overflow.
+			 */
+			unsigned long pfn =
+				((fault_offset - range_start_offset) +
+				 priv->phys_vec[i].paddr) >> PAGE_SHIFT;
+
+			if (IS_ALIGNED(pfn, 1 << order)) {
+				*out_pfn = pfn;
+				ret = 0;
+			}
+			/*
+			 * Else order > 0; ERANGE retries with smaller
+			 * order
+			 */
+			break;
+		}
+		range_start_offset += range_len;
+	}
+
+	if (order == 0 && ret != 0)
+		/*
+		 * The address fell outside of the span represented by
+		 * the (concatenated) ranges.  As setup of a mapping
+		 * ensures that the VMA is <= the total size of the
+		 * ranges this should never happen.  If it does, warn
+		 * and SIGBUS.
+		 */
+		dev_warn_ratelimited(
+			&vdev->pdev->dev,
+			"No range for addr 0x%lx, order %d: VMA 0x%lx-0x%lx pgoff 0x%lx, %u ranges, size 0x%zx\n",
+			fault_addr, order, vma->vm_start, vma->vm_end,
+			vma->vm_pgoff, priv->nr_ranges, priv->size);
+
+	return ret;
+}
+
+/*
+ * Create a DMABUF corresponding to priv, add it to vdev->dmabufs list
+ * for tracking (meaning cleanup or revocation will zap it), and take
+ * a vfio_device registration.
+ */
+static int vfio_pci_dmabuf_export(struct vfio_pci_core_device *vdev,
+				  struct vfio_pci_dma_buf *priv, u32 flags)
+{
+	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+
+	if (!vfio_device_try_get_registration(&vdev->vdev))
+		return -ENODEV;
+
+	exp_info.ops = &vfio_pci_dmabuf_ops;
+	exp_info.size = priv->size;
+	exp_info.flags = flags;
+	exp_info.priv = priv;
+
+	priv->dmabuf = dma_buf_export(&exp_info);
+	if (IS_ERR(priv->dmabuf)) {
+		vfio_device_put_registration(&vdev->vdev);
+		return PTR_ERR(priv->dmabuf);
+	}
+
+	kref_init(&priv->kref);
+	init_completion(&priv->comp);
+
+	/* dma_buf_put() now frees priv */
+	INIT_LIST_HEAD(&priv->dmabufs_elm);
+
+	/*
+	 * dmabuf_lock synchronises access (R) or updates (W) to the
+	 * vdev->dmabufs list and to bars_revoked (see below).  The
+	 * revocation state of DMABUF elements in the list is written
+	 * holding both dmabuf_lock(W) and resv, and tested with
+	 * either.
+	 *
+	 * (memory_lock, if held ->) dmabuf_lock -> resv
+	 *
+	 * NOTE: memory_lock is strictly avoided here, to avoid a
+	 * dependency on memory_lock when mmap_lock is held, when
+	 * mmap() leads to export.  vfio-pci variant drivers are
+	 * permitted to hold memory_lock across actions that might
+	 * fault (such as user access); a deadlock could result when
+	 * that fault path attempts to take mmap_lock (if held by an
+	 * export waiting for memory_lock).
+	 *
+	 * vdev->bars_revoked tracks the BAR revocation status updated
+	 * via vfio_pci_dma_buf_move(), so the initial DMABUF state
+	 * follows the same criteria that later update the DMABUF
+	 * state (BAR zap, etc.).
+	 */
+	lockdep_assert_not_held(&vdev->memory_lock);
+
+	down_write(&vdev->dmabuf_lock);
+	dma_resv_lock(priv->dmabuf->resv, NULL);
+	priv->status = vdev->bars_revoked ? VFIO_PCI_DMABUF_TEMP_REVOKED :
+		VFIO_PCI_DMABUF_OK;
+	list_add_tail(&priv->dmabufs_elm, &vdev->dmabufs);
+	dma_resv_unlock(priv->dmabuf->resv);
+	up_write(&vdev->dmabuf_lock);
+
+	return 0;
+}
+
+int vfio_pci_core_mmap_prep_dmabuf(struct vfio_pci_core_device *vdev,
+				   struct vm_area_struct *vma,
+				   u64 phys_start, u64 req_len,
+				   unsigned int res_index)
+{
+	struct vfio_pci_dma_buf *priv;
+	unsigned long vma_pgoff = vma->vm_pgoff & (VFIO_PCI_OFFSET_MASK >> PAGE_SHIFT);
+	char *bufname;
+	int ret;
+
+	priv = kzalloc_obj(*priv);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->phys_vec = kzalloc_obj(*priv->phys_vec);
+	if (!priv->phys_vec) {
+		ret = -ENOMEM;
+		goto err_free_priv;
+	}
+
+	/*
+	 * Maximum size of the friendly debug name is
+	 * vfio1048575:ffff:ff:1f.7/5 = 26.  This fits within
+	 * DMA_BUF_NAME_LEN, so dma_buf_set_name() below won't fail.
+	 */
+	bufname = kasprintf(GFP_KERNEL, "%s:%s/%x",
+			    dev_name(&vdev->vdev.device), pci_name(vdev->pdev),
+			    res_index);
+
+	if (!bufname) {
+		ret = -ENOMEM;
+		goto err_free_phys;
+	}
+
+	/*
+	 * The DMABUF begins from the mmap()'s BAR offset, i.e. the
+	 * start of the VMA corresponds to byte 0 of the DMABUF and
+	 * byte (vma_pgoff << PAGE_SHIFT) of the BAR.
+	 *
+	 * vfio_pci_dma_buf_find_pfn() reverses this offset using
+	 * vma_pgoff_adjust, so that ultimately a fault's offset from
+	 * the start of the _VMA_ has a consistent usage whether the
+	 * VMA originates from an mmap() of the VFIO device here or a
+	 * direct DMABUF mmap().  Note vma_pgoff_adjust also includes
+	 * the encoded VFIO region index, which cancels out the index
+	 * encoded in vm_pgoff.
+	 */
+	priv->vdev = vdev;
+	priv->size = req_len;
+	priv->nr_ranges = 1;
+	priv->vma_pgoff_adjust = vma->vm_pgoff;
+
+	/*
+	 * The provider can be NULL _iff_ the DMABUF feature isn't
+	 * supported, because it's only used by DMABUF import and
+	 * attach is prohibited if the feature isn't present.
+	 */
+	priv->provider = pcim_p2pdma_provider(vdev->pdev, res_index);
+	if (IS_ENABLED(CONFIG_VFIO_PCI_DMABUF) && !priv->provider) {
+		ret = -EINVAL;
+		goto err_free_name;
+	}
+
+	priv->phys_vec[0].paddr = phys_start + ((u64)vma_pgoff << PAGE_SHIFT);
+	priv->phys_vec[0].len = priv->size;
+
+	ret = vfio_pci_dmabuf_export(vdev, priv, O_RDWR);
+	if (ret)
+		goto err_free_name;
+
+	if (dma_buf_set_name(priv->dmabuf, bufname)) {
+		/* Shouldn't happen, but don't leak if it does: */
+		dev_dbg_ratelimited(&vdev->pdev->dev,
+				    "Failed to set map name '%s'\n",
+				    bufname);
+		kfree(bufname);
+	}
+
+	/*
+	 * Ownership of the DMABUF file transfers to the VMA so that
+	 * other users can locate the DMABUF via a VA.  Ownership of
+	 * the original VFIO device file being mmap()ed transfers to
+	 * priv, and is put when the DMABUF is released.  This
+	 * intentionally does not use get_file()/vma_set_file()
+	 * because the references are already held, and ownership
+	 * moves.
+	 */
+	priv->vfile = vma->vm_file;
+	vma->vm_file = priv->dmabuf->file;
+	vma->vm_private_data = priv;
+
+	return 0;
+
+err_free_name:
+	kfree(bufname);
+err_free_phys:
+	kfree(priv->phys_vec);
+err_free_priv:
+	kfree(priv);
+	return ret;
+}
+
+#ifdef CONFIG_VFIO_PCI_DMABUF
 /*
  * This is a temporary "private interconnect" between VFIO DMABUF and iommufd.
  * It allows the two co-operating drivers to exchange the physical address of
@@ -128,7 +499,7 @@ int vfio_pci_dma_buf_iommufd_map(struct dma_buf_attachment *attachment,
 		return -EOPNOTSUPP;
 
 	priv = attachment->dmabuf->priv;
-	if (priv->revoked)
+	if (priv->status != VFIO_PCI_DMABUF_OK)
 		return -ENODEV;
 
 	/* More than one range to iommufd will require proper DMABUF support */
@@ -224,7 +595,6 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
 {
 	struct vfio_device_feature_dma_buf get_dma_buf = {};
 	struct vfio_region_dma_range *dma_ranges;
-	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
 	struct vfio_pci_dma_buf *priv;
 	size_t length;
 	int ret;
@@ -284,34 +654,9 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
 	kfree(dma_ranges);
 	dma_ranges = NULL;
 
-	if (!vfio_device_try_get_registration(&vdev->vdev)) {
-		ret = -ENODEV;
+	ret = vfio_pci_dmabuf_export(vdev, priv, get_dma_buf.open_flags);
+	if (ret)
 		goto err_free_phys;
-	}
-
-	exp_info.ops = &vfio_pci_dmabuf_ops;
-	exp_info.size = priv->size;
-	exp_info.flags = get_dma_buf.open_flags;
-	exp_info.priv = priv;
-
-	priv->dmabuf = dma_buf_export(&exp_info);
-	if (IS_ERR(priv->dmabuf)) {
-		ret = PTR_ERR(priv->dmabuf);
-		goto err_dev_put;
-	}
-
-	kref_init(&priv->kref);
-	init_completion(&priv->comp);
-
-	/* dma_buf_put() now frees priv */
-	INIT_LIST_HEAD(&priv->dmabufs_elm);
-	down_write(&vdev->memory_lock);
-	dma_resv_lock(priv->dmabuf->resv, NULL);
-	priv->revoked = !__vfio_pci_memory_enabled(vdev);
-	list_add_tail(&priv->dmabufs_elm, &vdev->dmabufs);
-	dma_resv_unlock(priv->dmabuf->resv);
-	up_write(&vdev->memory_lock);
-
 	/*
 	 * dma_buf_fd() consumes the reference, when the file closes the dmabuf
 	 * will be released.
@@ -322,8 +667,6 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
 
 	return ret;
 
-err_dev_put:
-	vfio_device_put_registration(&vdev->vdev);
 err_free_phys:
 	kfree(priv->phys_vec);
 err_free_priv:
@@ -332,6 +675,64 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
 	kfree(dma_ranges);
 	return ret;
 }
+#endif /* CONFIG_VFIO_PCI_DMABUF */
+
+/* Set the DMABUF's revocation status (OK or temporarily/permanently revoked) */
+static void vfio_pci_dma_buf_set_status(struct vfio_pci_dma_buf *priv,
+					enum vfio_pci_dma_buf_status new_status)
+{
+	bool was_revoked;
+
+	/*
+	 * Changes to the DMABUF's revocation status are synchronised
+	 * using dmabuf_lock:
+	 */
+	lockdep_assert_held_write(&priv->vdev->dmabuf_lock);
+
+	if (priv->status == VFIO_PCI_DMABUF_PERM_REVOKED ||
+	    priv->status == new_status)
+		return;
+
+	dma_resv_lock(priv->dmabuf->resv, NULL);
+	was_revoked = (priv->status == VFIO_PCI_DMABUF_TEMP_REVOKED);
+
+	if (new_status != VFIO_PCI_DMABUF_OK) {
+		priv->status = new_status; /* Temp or permanently revoked */
+
+		if (was_revoked) {
+			/*
+			 * TEMP_REVOKED is being upgraded to
+			 * PERM_REVOKED.  The buffer is already gone,
+			 * don't wait on it again.
+			 */
+			dma_resv_unlock(priv->dmabuf->resv);
+			return;
+		}
+		dma_buf_invalidate_mappings(priv->dmabuf);
+		dma_resv_wait_timeout(priv->dmabuf->resv,
+				      DMA_RESV_USAGE_BOOKKEEP, false,
+				      MAX_SCHEDULE_TIMEOUT);
+		dma_resv_unlock(priv->dmabuf->resv);
+		kref_put(&priv->kref, vfio_pci_dma_buf_done);
+		wait_for_completion(&priv->comp);
+		unmap_mapping_range(priv->dmabuf->file->f_mapping,
+				    0, 0, true);
+		/*
+		 * Re-arm the registered kref reference and the
+		 * completion so the post-revoke state matches the
+		 * post-creation state.  An un-revoke followed by a
+		 * new mapping needs the kref to be non-zero before
+		 * kref_get(), and vfio_pci_dma_buf_cleanup()
+		 * delegates its drain back through this revoke
+		 * path on a possibly-already-revoked dma-buf.
+		 */
+		kref_init(&priv->kref);
+		reinit_completion(&priv->comp);
+	} else {
+		priv->status = VFIO_PCI_DMABUF_OK;
+		dma_resv_unlock(priv->dmabuf->resv);
+	}
+}
 
 void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked)
 {
@@ -340,41 +741,17 @@ void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked)
 
 	lockdep_assert_held_write(&vdev->memory_lock);
 
+	down_write(&vdev->dmabuf_lock);
+	vdev->bars_revoked = revoked;
 	list_for_each_entry_safe(priv, tmp, &vdev->dmabufs, dmabufs_elm) {
 		if (!get_file_active(&priv->dmabuf->file))
 			continue;
-
-		if (priv->revoked != revoked) {
-			dma_resv_lock(priv->dmabuf->resv, NULL);
-			if (revoked)
-				priv->revoked = true;
-			dma_buf_invalidate_mappings(priv->dmabuf);
-			dma_resv_wait_timeout(priv->dmabuf->resv,
-					      DMA_RESV_USAGE_BOOKKEEP, false,
-					      MAX_SCHEDULE_TIMEOUT);
-			dma_resv_unlock(priv->dmabuf->resv);
-			if (revoked) {
-				kref_put(&priv->kref, vfio_pci_dma_buf_done);
-				wait_for_completion(&priv->comp);
-				/*
-				 * Re-arm the registered kref reference and the
-				 * completion so the post-revoke state matches the
-				 * post-creation state.  An un-revoke followed by a
-				 * new mapping needs the kref to be non-zero before
-				 * kref_get(), and vfio_pci_dma_buf_cleanup()
-				 * delegates its drain back through this revoke
-				 * path on a possibly-already-revoked dma-buf.
-				 */
-				kref_init(&priv->kref);
-				reinit_completion(&priv->comp);
-			} else {
-				dma_resv_lock(priv->dmabuf->resv, NULL);
-				priv->revoked = false;
-				dma_resv_unlock(priv->dmabuf->resv);
-			}
-		}
+		vfio_pci_dma_buf_set_status(priv, revoked ?
+					    VFIO_PCI_DMABUF_TEMP_REVOKED :
+					    VFIO_PCI_DMABUF_OK);
 		fput(priv->dmabuf->file);
 	}
+	up_write(&vdev->dmabuf_lock);
 }
 
 void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev)
@@ -393,14 +770,86 @@ void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev)
 	 */
 	vfio_pci_dma_buf_move(vdev, true);
 
+	down_write(&vdev->dmabuf_lock);
 	list_for_each_entry_safe(priv, tmp, &vdev->dmabufs, dmabufs_elm) {
 		if (!get_file_active(&priv->dmabuf->file))
 			continue;
 
 		list_del_init(&priv->dmabufs_elm);
-		priv->vdev = NULL;
+		WRITE_ONCE(priv->vdev, NULL);
 		vfio_device_put_registration(&vdev->vdev);
 		fput(priv->dmabuf->file);
 	}
+	up_write(&vdev->dmabuf_lock);
 	up_write(&vdev->memory_lock);
 }
+
+#ifdef CONFIG_VFIO_PCI_DMABUF
+int vfio_pci_core_feature_dma_buf_revoke(
+	struct vfio_pci_core_device *vdev, u32 flags,
+	struct vfio_device_feature_dma_buf_revoke __user *arg,
+	size_t argsz)
+{
+	struct vfio_device_feature_dma_buf_revoke db_revoke;
+	struct vfio_pci_dma_buf *priv;
+	struct dma_buf *dmabuf;
+	int ret;
+
+	if (!vdev->pci_ops || !vdev->pci_ops->get_dmabuf_phys)
+		return -EOPNOTSUPP;
+
+	ret = vfio_check_feature(flags, argsz,
+				 VFIO_DEVICE_FEATURE_SET,
+				 sizeof(db_revoke));
+	if (ret != 1)
+		return ret;
+
+	if (copy_from_user(&db_revoke, arg, sizeof(db_revoke)))
+		return -EFAULT;
+
+	dmabuf = dma_buf_get(db_revoke.dmabuf_fd);
+	if (IS_ERR(dmabuf))
+		return PTR_ERR(dmabuf);
+
+	priv = dmabuf->priv;
+	/*
+	 * Sanity-check the DMABUF is really a vfio_pci_dma_buf _and_
+	 * relates to the VFIO device it was provided with.
+	 *
+	 * If the DMABUF relates to this vdev then priv->vdev is
+	 * stable because this open fd prevents cleanup.
+	 *
+	 * If it relates to a different vdev, reading priv->vdev might
+	 * race with a concurrent cleanup on that device.  But if so,
+	 * it points to a non-matching vdev or NULL and is unusable
+	 * either way.
+	 */
+	if (dmabuf->ops != &vfio_pci_dmabuf_ops ||
+	    READ_ONCE(priv->vdev) != vdev) {
+		ret = -ENODEV;
+		goto out_put_buf;
+	}
+
+	/*
+	 * memory_lock(R) is taken to stop vfio_pci_dev_set_hot_reset()
+	 * from getting it and then blocking all devices in the dev_set behind
+	 * this revoke's drain.
+	 */
+	down_read(&vdev->memory_lock);
+	down_write(&vdev->dmabuf_lock);
+	if (priv->status == VFIO_PCI_DMABUF_PERM_REVOKED) {
+		ret = -EBADFD;
+	} else {
+		vfio_pci_dma_buf_set_status(priv,
+					    VFIO_PCI_DMABUF_PERM_REVOKED);
+		ret = 0;
+	}
+	up_write(&vdev->dmabuf_lock);
+	up_read(&vdev->memory_lock);
+
+out_put_buf:
+	dma_buf_put(dmabuf);
+
+	return ret;
+}
+#endif /* CONFIG_VFIO_PCI_DMABUF */
diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h
index fca9d0dfac90f..9cf66c19f798c 100644
--- a/drivers/vfio/pci/vfio_pci_priv.h
+++ b/drivers/vfio/pci/vfio_pci_priv.h
@@ -23,6 +23,27 @@ struct vfio_pci_ioeventfd {
 	bool			test_mem;
 };
 
+enum vfio_pci_dma_buf_status {
+	VFIO_PCI_DMABUF_OK = 0,
+	VFIO_PCI_DMABUF_TEMP_REVOKED = 1,
+	VFIO_PCI_DMABUF_PERM_REVOKED = 2,
+};
+
+struct vfio_pci_dma_buf {
+	struct dma_buf *dmabuf;
+	struct vfio_pci_core_device *vdev;
+	struct list_head dmabufs_elm;
+	size_t size;
+	struct phys_vec *phys_vec;
+	struct p2pdma_provider *provider;
+	struct file *vfile;
+	u32 nr_ranges;
+	struct kref kref;
+	struct completion comp;
+	unsigned long vma_pgoff_adjust;
+	enum vfio_pci_dma_buf_status status;
+};
+
 bool vfio_pci_intx_mask(struct vfio_pci_core_device *vdev);
 void vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev);
 
@@ -68,7 +89,8 @@ void vfio_config_free(struct vfio_pci_core_device *vdev);
 int vfio_pci_set_power_state(struct vfio_pci_core_device *vdev,
 			     pci_power_t state);
 
-void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_core_device *vdev);
+void vfio_pci_lock_revoke_bars(struct vfio_pci_core_device *vdev);
+void vfio_pci_unrevoke_bars(struct vfio_pci_core_device *vdev);
 u16 vfio_pci_memory_lock_and_enable(struct vfio_pci_core_device *vdev);
 void vfio_pci_memory_unlock_and_restore(struct vfio_pci_core_device *vdev,
 					u16 cmd);
@@ -114,12 +136,28 @@ static inline bool vfio_pci_is_vga(struct pci_dev *pdev)
 	return (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA;
 }
 
+int vfio_pci_dma_buf_find_pfn(struct vfio_pci_core_device *vdev,
+			      struct vfio_pci_dma_buf *priv,
+			      struct vm_area_struct *vma,
+			      unsigned long address,
+			      unsigned int order,
+			      unsigned long *out_pfn);
+int vfio_pci_core_mmap_prep_dmabuf(struct vfio_pci_core_device *vdev,
+				   struct vm_area_struct *vma,
+				   u64 phys_start, u64 req_len,
+				   unsigned int res_index);
+void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev);
+void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked);
+void vfio_pci_set_vma_ops(struct vm_area_struct *vma);
+
 #ifdef CONFIG_VFIO_PCI_DMABUF
 int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
 				  struct vfio_device_feature_dma_buf __user *arg,
 				  size_t argsz);
-void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev);
-void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked);
+int vfio_pci_core_feature_dma_buf_revoke(
+	struct vfio_pci_core_device *vdev, u32 flags,
+	struct vfio_device_feature_dma_buf_revoke __user *arg,
+	size_t argsz);
 #else
 static inline int
 vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
@@ -128,12 +166,12 @@ vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
 {
 	return -ENOTTY;
 }
-static inline void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev)
-{
-}
-static inline void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev,
-					 bool revoked)
+static inline int vfio_pci_core_feature_dma_buf_revoke(
+	struct vfio_pci_core_device *vdev, u32 flags,
+	struct vfio_device_feature_dma_buf_revoke __user *arg,
+	size_t argsz)
 {
+	return -ENOTTY;
 }
 #endif
 
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index d1203da56fc5f..14d3950b63c85 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -570,6 +570,8 @@ int dma_buf_fd(struct dma_buf *dmabuf, int flags);
 struct dma_buf *dma_buf_get(int fd);
 void dma_buf_put(struct dma_buf *dmabuf);
 
+int dma_buf_set_name(struct dma_buf *dmabuf, char *name);
+
 struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *,
 					enum dma_data_direction);
 void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,
diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h
index 9a1674c152aa2..44891fdb7c76e 100644
--- a/include/linux/vfio_pci_core.h
+++ b/include/linux/vfio_pci_core.h
@@ -129,11 +129,13 @@ struct vfio_pci_core_device {
 	bool			disable_idle_d3:1;
 	bool			nointxmask:1;
 	bool			disable_vga:1;
+	bool			zap_bars_on_revoke:1;
 	/* Flags modified at runtime - dedicated storage unit */
 	bool			needs_reset;
 	bool			pm_intx_masked;
 	bool			pm_runtime_engaged;
 	bool			sriov_active;
+	bool			bars_revoked;
 	struct pci_saved_state	*pci_saved_state;
 	struct pci_saved_state	*pm_save;
 	int			ioeventfds_nr;
@@ -148,6 +150,7 @@ struct vfio_pci_core_device {
 	struct vfio_pci_core_device	*sriov_pf_core_dev;
 	struct notifier_block	nb;
 	struct rw_semaphore	memory_lock;
+	struct rw_semaphore	dmabuf_lock;
 	struct list_head	dmabufs;
 };
 
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 5de618a3a5eee..8c1d50275a412 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -1534,6 +1534,30 @@ struct vfio_device_feature_dma_buf {
  */
 #define VFIO_DEVICE_FEATURE_MIG_PRECOPY_INFOv2  12
 
+/**
+ * Given a dma_buf fd previously exported from the same device by
+ * VFIO_DEVICE_FEATURE_DMA_BUF, a SET of this feature requests that
+ * access to the corresponding DMABUF is immediately and permanently
+ * revoked.  On successful return, the buffer is not accessible
+ * through any mmap() or dma-buf import.  The buffer is permanently
+ * disabled, and VFIO refuses all map, mmap, attach, etc. requests.
+ *
+ * Return: 0 on success, -1 and errno is set on failure:
+ *
+ *  EBADF, EINVAL: dmabuf_fd is not a DMABUF fd.
+ *  EOPNOTSUPP: The VFIO device does not support DMABUF export.
+ *  ENODEV: The DMABUF was not exported from this device.
+ *  EBADFD: The DMABUF is already permanently revoked.
+ *
+ * Additionally, common errors can occur: EFAULT accessing the struct,
+ * or EINVAL requesting an unsupported feature op.
+ */
+#define VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE 13
+
+struct vfio_device_feature_dma_buf_revoke {
+	__s32	dmabuf_fd;
+};
+
 /* -------- API for Type1 VFIO IOMMU -------- */
 
 /**

3/2 2026/09/11 22:06 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 24248
							output: 28
							thoughts: 2176
						

Thoughts:
**Patch Analysis: VFIO-PCI DMA-BUF Integration**

Okay, let's break this down. This patch touches a few key areas, so first, I need to understand the impact of the changes. It looks like we're integrating DMA-BUF with VFIO-PCI. Seems like a significant shift, especially in how BAR memory regions are handled.

Initially, I see the renaming of `dma_buf_set_name` to `dma_buf_set_name_user` in `dma-buf.c`. Okay, so it's now exported as `dma_buf_set_name`. This also includes a length check, which is good for avoiding overflows, I presume. The new export is accessible via `DMA_BUF_SET_NAME_A` and `DMA_BUF_SET_NAME_B` ioctls. This is interesting, but dma-buf has multiple potential interfaces, so it shouldn't be too hard to reach. I'll need to remember that.

Moving on, the Kconfig changes seem to be tying `VFIO_PCI_CORE` to `DMA_SHARED_BUFFER`. Also, it looks like `VFIO_PCI_DMABUF` is now always compiled in when `VFIO_PCI_CORE` is selected, and it depends on `PCI_P2PDMA`. The Makefile changes confirm the always-on compilation of `vfio_pci_dmabuf.o`. So far, so good, a definite change that the DMABUF functionality is now core.

The next point addresses a parameter and setting related to the hisi driver. It seems like the `zap_bars_on_revoke` setting is changed for that device, specifically. And the `vfio_pci_config.c` file shows that we're moving from a direct locking/unmapping approach to using `vfio_pci_lock_revoke_bars` and `vfio_pci_unrevoke_bars`.

Now for the meat of it, `vfio_pci_core.c`! This is where the integration gets deep. `vfio_pci_core_mmap` is now calling `vfio_pci_core_mmap_prep_dmabuf`. That is, DMA-BUF-backed BAR mmaps. BIG changes here: `vfio_pci_mmap_huge_fault` is completely reworked, along with associated locking and revocation mechanisms. The introduction of `VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE` is important. Also, `dmabuf_lock` is now a new rwsem in `vfio_pci_core_init_dev`.

Finally, `vfio_pci_dmabuf.c` brings the new code for the implementation. It looks like there is a good amount of code to enable the functionality. The status transitions (OK, TEMP_REVOKED, PERM_REVOKED) show the complexity involved in managing the memory backing.

Okay, let's determine if this is worth fuzzing. The key question is whether this code is reachable within a fuzzing environment like QEMU and syzkaller.

I need to confirm if vfio-pci devices can be emulated or created in QEMU/syzkaller. Does syzkaller test vfio-pci? Let me check the documentation...

Rereading the "WorthFuzzing" criteria... Okay, rule one is out because `dma-buf.c` *is* modified. I need to make sure this isn't "Structurally unreachable hardware" or "Unreachable execution paths." So, can VFIO-PCI be reached?

The "Reachable Drivers and Protocols" section is key. Are there virtual buses that can be exploited? Virtio, USB gadget, loopback, netlink, binder, sockets, etc.

I have to determine if vfio-pci is reachable via one of these methods or if there is a way to set up PCI devices in QEMU, since syzkaller is running in QEMU. Syzkaller can run with root. Therefore, it is important to figure out if we can bind/unbind to devices in the QEMU environment. I need to grep for VFIO and PCI interactions within the kernel source. The documentation doesn't allow me to search syzkaller syzlang descriptions. I will check the kernel source.



4/2 2026/09/11 22:07 tool grepper
0m Args:
{
  "Expression": "VFIO_PCI",
  "PathPrefix": "drivers/vfio"
}

Results:
{
  "Output": "\nFull output is too long, showing 500 out of 1011 lines.\nUse more precise expression if possible.\n\ndrivers/vfio/Makefile=13=obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o\ndrivers/vfio/Makefile:14:obj-$(CONFIG_VFIO_PCI_CORE) += pci/\ndrivers/vfio/Makefile-15-obj-$(CONFIG_VFIO_PLATFORM_BASE) += platform/\n--\ndrivers/vfio/pci/Kconfig=2=menu \"VFIO support for PCI devices\"\n--\ndrivers/vfio/pci/Kconfig-4-\ndrivers/vfio/pci/Kconfig:5:config VFIO_PCI_CORE\ndrivers/vfio/pci/Kconfig-6-\ttristate\n--\ndrivers/vfio/pci/Kconfig-10-\ndrivers/vfio/pci/Kconfig:11:config VFIO_PCI_INTX\ndrivers/vfio/pci/Kconfig-12-\tdef_bool y if !S390\ndrivers/vfio/pci/Kconfig:13:\tdepends on VFIO_PCI_CORE\ndrivers/vfio/pci/Kconfig-14-\ndrivers/vfio/pci/Kconfig:15:config VFIO_PCI\ndrivers/vfio/pci/Kconfig-16-\ttristate \"Generic VFIO support for any PCI device\"\ndrivers/vfio/pci/Kconfig:17:\tselect VFIO_PCI_CORE\ndrivers/vfio/pci/Kconfig-18-\thelp\n--\ndrivers/vfio/pci/Kconfig-23-\ndrivers/vfio/pci/Kconfig:24:if VFIO_PCI\ndrivers/vfio/pci/Kconfig:25:config VFIO_PCI_VGA\ndrivers/vfio/pci/Kconfig-26-\tbool \"Generic VFIO PCI support for VGA devices\"\n--\ndrivers/vfio/pci/Kconfig-34-\ndrivers/vfio/pci/Kconfig:35:config VFIO_PCI_IGD\ndrivers/vfio/pci/Kconfig-36-\tbool \"Generic VFIO PCI extensions for Intel graphics (GVT-d)\"\n--\ndrivers/vfio/pci/Kconfig=46=endif\ndrivers/vfio/pci/Kconfig-47-\ndrivers/vfio/pci/Kconfig:48:config VFIO_PCI_ZDEV_KVM\ndrivers/vfio/pci/Kconfig-49-\tbool \"VFIO PCI extensions for s390x KVM passthrough\"\n--\ndrivers/vfio/pci/Kconfig-58-\ndrivers/vfio/pci/Kconfig:59:config VFIO_PCI_DMABUF\ndrivers/vfio/pci/Kconfig-60-\tdef_bool y if PCI_P2PDMA\ndrivers/vfio/pci/Kconfig:61:\tdepends on VFIO_PCI_CORE\ndrivers/vfio/pci/Kconfig-62-\n--\ndrivers/vfio/pci/Makefile=3=vfio-pci-core-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o vfio_pci_dmabuf.o\ndrivers/vfio/pci/Makefile:4:vfio-pci-core-$(CONFIG_VFIO_PCI_ZDEV_KVM) += vfio_pci_zdev.o\ndrivers/vfio/pci/Makefile:5:obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o\ndrivers/vfio/pci/Makefile-6-\ndrivers/vfio/pci/Makefile=7=vfio-pci-y := vfio_pci.o\ndrivers/vfio/pci/Makefile:8:vfio-pci-$(CONFIG_VFIO_PCI_IGD) += vfio_pci_igd.o\ndrivers/vfio/pci/Makefile:9:obj-$(CONFIG_VFIO_PCI) += vfio-pci.o\ndrivers/vfio/pci/Makefile-10-\ndrivers/vfio/pci/Makefile:11:obj-$(CONFIG_MLX5_VFIO_PCI)           += mlx5/\ndrivers/vfio/pci/Makefile-12-\ndrivers/vfio/pci/Makefile:13:obj-$(CONFIG_ISM_VFIO_PCI)           += ism/\ndrivers/vfio/pci/Makefile-14-\ndrivers/vfio/pci/Makefile:15:obj-$(CONFIG_HISI_ACC_VFIO_PCI) += hisilicon/\ndrivers/vfio/pci/Makefile-16-\ndrivers/vfio/pci/Makefile:17:obj-$(CONFIG_PDS_VFIO_PCI) += pds/\ndrivers/vfio/pci/Makefile-18-\ndrivers/vfio/pci/Makefile:19:obj-$(CONFIG_VIRTIO_VFIO_PCI) += virtio/\ndrivers/vfio/pci/Makefile-20-\ndrivers/vfio/pci/Makefile:21:obj-$(CONFIG_NVGRACE_GPU_VFIO_PCI) += nvgrace-gpu/\ndrivers/vfio/pci/Makefile-22-\ndrivers/vfio/pci/Makefile:23:obj-$(CONFIG_QAT_VFIO_PCI) += qat/\ndrivers/vfio/pci/Makefile-24-\ndrivers/vfio/pci/Makefile:25:obj-$(CONFIG_XE_VFIO_PCI) += xe/\n--\ndrivers/vfio/pci/hisilicon/Kconfig-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/vfio/pci/hisilicon/Kconfig:2:config HISI_ACC_VFIO_PCI\ndrivers/vfio/pci/hisilicon/Kconfig-3-\ttristate \"VFIO support for HiSilicon ACC PCI devices\"\n--\ndrivers/vfio/pci/hisilicon/Kconfig-9-\tdepends on CRYPTO_DEV_HISI_ZIP\ndrivers/vfio/pci/hisilicon/Kconfig:10:\tselect VFIO_PCI_CORE\ndrivers/vfio/pci/hisilicon/Kconfig-11-\thelp\n--\ndrivers/vfio/pci/hisilicon/Makefile-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/vfio/pci/hisilicon/Makefile:2:obj-$(CONFIG_HISI_ACC_VFIO_PCI) += hisi-acc-vfio-pci.o\ndrivers/vfio/pci/hisilicon/Makefile-3-hisi-acc-vfio-pci-y := hisi_acc_vfio_pci.o\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c=1188=static int hisi_acc_vf_qm_init(struct hisi_acc_vf_core_device *hisi_acc_vdev)\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1230-\t\tvf_qm-\u003eio_base =\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c:1231:\t\t\tioremap(pci_resource_start(vf_dev, VFIO_PCI_BAR2_REGION_INDEX),\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c:1232:\t\t\t\tpci_resource_len(vf_dev, VFIO_PCI_BAR2_REGION_INDEX));\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1233-\t\tif (!vf_qm-\u003eio_base)\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c=1296=static int hisi_acc_pci_rw_access_check(struct vfio_device *core_vdev,\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1299-{\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c:1300:\tunsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1301-\tstruct vfio_pci_core_device *vdev =\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1303-\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c:1304:\tif (index == VFIO_PCI_BAR2_REGION_INDEX) {\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c:1305:\t\tloff_t pos = *ppos \u0026 VFIO_PCI_OFFSET_MASK;\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1306-\t\tresource_size_t end;\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c=1319=static int hisi_acc_vfio_pci_mmap(struct vfio_device *core_vdev,\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1325-\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c:1326:\tindex = vma-\u003evm_pgoff \u003e\u003e (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c:1327:\tif (index == VFIO_PCI_BAR2_REGION_INDEX) {\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1328-\t\tu64 req_len, pgoff, req_start;\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1333-\t\tpgoff = vma-\u003evm_pgoff \u0026\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c:1334:\t\t\t((1U \u003c\u003c (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1335-\t\treq_start = pgoff \u003c\u003c PAGE_SHIFT;\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c=1372=static int hisi_acc_vfio_ioctl_get_region(struct vfio_device *core_vdev,\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1378-\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c:1379:\tif (info-\u003eindex != VFIO_PCI_BAR2_REGION_INDEX)\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1380-\t\treturn vfio_pci_ioctl_get_region_info(core_vdev, info, caps);\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1381-\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c:1382:\tinfo-\u003eoffset = VFIO_PCI_INDEX_TO_OFFSET(info-\u003eindex);\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c-1383-\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h-3-\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h:4:#ifndef HISI_ACC_VFIO_PCI_H\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h:5:#define HISI_ACC_VFIO_PCI_H\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h-6-\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h=129=struct hisi_acc_vf_core_device {\n--\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h-164-};\ndrivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.h:165:#endif /* HISI_ACC_VFIO_PCI_H */\n--\ndrivers/vfio/pci/ism/Kconfig-1-# SPDX-License-Identifier: GPL-2.0\ndrivers/vfio/pci/ism/Kconfig:2:config ISM_VFIO_PCI\ndrivers/vfio/pci/ism/Kconfig-3-\ttristate \"VFIO support for ISM devices\"\ndrivers/vfio/pci/ism/Kconfig-4-\tdepends on S390\ndrivers/vfio/pci/ism/Kconfig:5:\tselect VFIO_PCI_CORE\ndrivers/vfio/pci/ism/Kconfig-6-\thelp\n--\ndrivers/vfio/pci/ism/Makefile-1-# SPDX-License-Identifier: GPL-2.0\ndrivers/vfio/pci/ism/Makefile:2:obj-$(CONFIG_ISM_VFIO_PCI) += ism-vfio-pci.o\ndrivers/vfio/pci/ism/Makefile-3-ism-vfio-pci-y := main.o\n--\ndrivers/vfio/pci/ism/main.c-10-\ndrivers/vfio/pci/ism/main.c:11:#define ISM_VFIO_PCI_OFFSET_SHIFT   48\ndrivers/vfio/pci/ism/main.c:12:#define ISM_VFIO_PCI_OFFSET_TO_INDEX(off) ((off) \u003e\u003e ISM_VFIO_PCI_OFFSET_SHIFT)\ndrivers/vfio/pci/ism/main.c:13:#define ISM_VFIO_PCI_INDEX_TO_OFFSET(index) ((u64)(index) \u003c\u003c ISM_VFIO_PCI_OFFSET_SHIFT)\ndrivers/vfio/pci/ism/main.c:14:#define ISM_VFIO_PCI_OFFSET_MASK (((u64)(1) \u003c\u003c ISM_VFIO_PCI_OFFSET_SHIFT) - 1)\ndrivers/vfio/pci/ism/main.c-15-\n--\ndrivers/vfio/pci/ism/main.c=77=static ssize_t ism_vfio_pci_do_io_r(struct vfio_pci_core_device *vdev,\n--\ndrivers/vfio/pci/ism/main.c-119- * ISM device. The ISM device also uses a 256 TiB BAR 0 for write operations,\ndrivers/vfio/pci/ism/main.c:120: * which requires a 48bit region address space (ISM_VFIO_PCI_OFFSET_SHIFT).\ndrivers/vfio/pci/ism/main.c-121- */\n--\ndrivers/vfio/pci/ism/main.c=160=static ssize_t ism_vfio_pci_bar_rw(struct vfio_pci_core_device *vdev,\n--\ndrivers/vfio/pci/ism/main.c-163-{\ndrivers/vfio/pci/ism/main.c:164:\tint bar = ISM_VFIO_PCI_OFFSET_TO_INDEX(*ppos);\ndrivers/vfio/pci/ism/main.c:165:\tloff_t pos = *ppos \u0026 ISM_VFIO_PCI_OFFSET_MASK;\ndrivers/vfio/pci/ism/main.c-166-\tresource_size_t end;\n--\ndrivers/vfio/pci/ism/main.c=190=static ssize_t ism_vfio_pci_config_rw(struct vfio_pci_core_device *vdev,\n--\ndrivers/vfio/pci/ism/main.c-197-\ndrivers/vfio/pci/ism/main.c:198:\tpos \u0026= ISM_VFIO_PCI_OFFSET_MASK;\ndrivers/vfio/pci/ism/main.c-199-\n--\ndrivers/vfio/pci/ism/main.c=220=static ssize_t ism_vfio_pci_rw(struct vfio_device *core_vdev, char __user *buf,\n--\ndrivers/vfio/pci/ism/main.c-222-{\ndrivers/vfio/pci/ism/main.c:223:\tunsigned int index = ISM_VFIO_PCI_OFFSET_TO_INDEX(*ppos);\ndrivers/vfio/pci/ism/main.c-224-\tstruct vfio_pci_core_device *vdev;\n--\ndrivers/vfio/pci/ism/main.c-232-\tswitch (index) {\ndrivers/vfio/pci/ism/main.c:233:\tcase VFIO_PCI_CONFIG_REGION_INDEX:\ndrivers/vfio/pci/ism/main.c-234-\t\tret = ism_vfio_pci_config_rw(vdev, buf, count, ppos, iswrite);\n--\ndrivers/vfio/pci/ism/main.c-236-\ndrivers/vfio/pci/ism/main.c:237:\tcase VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX:\ndrivers/vfio/pci/ism/main.c-238-\t\tret = ism_vfio_pci_bar_rw(vdev, buf, count, ppos, iswrite);\n--\ndrivers/vfio/pci/ism/main.c=262=static int ism_vfio_pci_ioctl_get_region_info(struct vfio_device *core_vdev,\n--\ndrivers/vfio/pci/ism/main.c-270-\tswitch (info-\u003eindex) {\ndrivers/vfio/pci/ism/main.c:271:\tcase VFIO_PCI_CONFIG_REGION_INDEX:\ndrivers/vfio/pci/ism/main.c:272:\t\tinfo-\u003eoffset = ISM_VFIO_PCI_INDEX_TO_OFFSET(info-\u003eindex);\ndrivers/vfio/pci/ism/main.c-273-\t\tinfo-\u003esize = pdev-\u003ecfg_size;\n--\ndrivers/vfio/pci/ism/main.c-276-\t\tbreak;\ndrivers/vfio/pci/ism/main.c:277:\tcase VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX:\ndrivers/vfio/pci/ism/main.c:278:\t\tinfo-\u003eoffset = ISM_VFIO_PCI_INDEX_TO_OFFSET(info-\u003eindex);\ndrivers/vfio/pci/ism/main.c-279-\t\tinfo-\u003esize = pci_resource_len(pdev, info-\u003eindex);\n--\ndrivers/vfio/pci/mlx5/Kconfig-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/vfio/pci/mlx5/Kconfig:2:config MLX5_VFIO_PCI\ndrivers/vfio/pci/mlx5/Kconfig-3-\ttristate \"VFIO support for MLX5 PCI devices\"\ndrivers/vfio/pci/mlx5/Kconfig-4-\tdepends on MLX5_CORE\ndrivers/vfio/pci/mlx5/Kconfig:5:\tselect VFIO_PCI_CORE\ndrivers/vfio/pci/mlx5/Kconfig-6-\tselect IOMMUFD_DRIVER\n--\ndrivers/vfio/pci/mlx5/Makefile-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/vfio/pci/mlx5/Makefile:2:obj-$(CONFIG_MLX5_VFIO_PCI) += mlx5-vfio-pci.o\ndrivers/vfio/pci/mlx5/Makefile-3-mlx5-vfio-pci-y := main.o cmd.o\n--\ndrivers/vfio/pci/nvgrace-gpu/Kconfig-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/vfio/pci/nvgrace-gpu/Kconfig:2:config NVGRACE_GPU_VFIO_PCI\ndrivers/vfio/pci/nvgrace-gpu/Kconfig-3-\ttristate \"VFIO support for the GPU in the NVIDIA Grace Hopper Superchip\"\ndrivers/vfio/pci/nvgrace-gpu/Kconfig-4-\tdepends on ARM64 || (COMPILE_TEST \u0026\u0026 64BIT)\ndrivers/vfio/pci/nvgrace-gpu/Kconfig:5:\tselect VFIO_PCI_CORE\ndrivers/vfio/pci/nvgrace-gpu/Kconfig-6-\thelp\n--\ndrivers/vfio/pci/nvgrace-gpu/Makefile-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/vfio/pci/nvgrace-gpu/Makefile:2:obj-$(CONFIG_NVGRACE_GPU_VFIO_PCI) += nvgrace-gpu-vfio-pci.o\ndrivers/vfio/pci/nvgrace-gpu/Makefile-3-nvgrace-gpu-vfio-pci-y := main.o\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-24- */\ndrivers/vfio/pci/nvgrace-gpu/main.c:25:#define RESMEM_REGION_INDEX VFIO_PCI_BAR2_REGION_INDEX\ndrivers/vfio/pci/nvgrace-gpu/main.c:26:#define USEMEM_REGION_INDEX VFIO_PCI_BAR4_REGION_INDEX\ndrivers/vfio/pci/nvgrace-gpu/main.c-27-\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=125=static int nvgrace_gpu_pfn_to_vma_pgoff(struct vm_area_struct *vma,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-130-\tunsigned int index =\ndrivers/vfio/pci/nvgrace-gpu/main.c:131:\t\tvma-\u003evm_pgoff \u003e\u003e (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);\ndrivers/vfio/pci/nvgrace-gpu/main.c-132-\tpgoff_t vma_offset_in_region = vma-\u003evm_pgoff \u0026\ndrivers/vfio/pci/nvgrace-gpu/main.c:133:\t\t((1U \u003c\u003c (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);\ndrivers/vfio/pci/nvgrace-gpu/main.c-134-\tpgoff_t pfn_offset_in_region;\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=382=static unsigned long addr_to_pgoff(struct vm_area_struct *vma,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-385-\tu64 pgoff = vma-\u003evm_pgoff \u0026\ndrivers/vfio/pci/nvgrace-gpu/main.c:386:\t\t((1U \u003c\u003c (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);\ndrivers/vfio/pci/nvgrace-gpu/main.c-387-\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=391=static vm_fault_t nvgrace_gpu_vfio_pci_huge_fault(struct vm_fault *vmf,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-397-\tunsigned int index =\ndrivers/vfio/pci/nvgrace-gpu/main.c:398:\t\tvma-\u003evm_pgoff \u003e\u003e (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);\ndrivers/vfio/pci/nvgrace-gpu/main.c-399-\tvm_fault_t ret = VM_FAULT_FALLBACK;\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=474=static int nvgrace_gpu_mmap(struct vfio_device *core_vdev,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-483-\ndrivers/vfio/pci/nvgrace-gpu/main.c:484:\tindex = vma-\u003evm_pgoff \u003e\u003e (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);\ndrivers/vfio/pci/nvgrace-gpu/main.c-485-\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-495-\tpgoff = vma-\u003evm_pgoff \u0026\ndrivers/vfio/pci/nvgrace-gpu/main.c:496:\t\t((1U \u003c\u003c (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);\ndrivers/vfio/pci/nvgrace-gpu/main.c-497-\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=533=static int nvgrace_gpu_ioctl_get_region_info(struct vfio_device *core_vdev,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-574-\ndrivers/vfio/pci/nvgrace-gpu/main.c:575:\tinfo-\u003eoffset = VFIO_PCI_INDEX_TO_OFFSET(info-\u003eindex);\ndrivers/vfio/pci/nvgrace-gpu/main.c-576-\t/*\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=623=nvgrace_gpu_read_config_emu(struct vfio_device *core_vdev,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-628-\t\t\t     core_device.vdev);\ndrivers/vfio/pci/nvgrace-gpu/main.c:629:\tu64 pos = *ppos \u0026 VFIO_PCI_OFFSET_MASK;\ndrivers/vfio/pci/nvgrace-gpu/main.c-630-\tstruct mem_region *memregion = NULL;\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=674=nvgrace_gpu_write_config_emu(struct vfio_device *core_vdev,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-679-\t\t\t     core_device.vdev);\ndrivers/vfio/pci/nvgrace-gpu/main.c:680:\tu64 pos = *ppos \u0026 VFIO_PCI_OFFSET_MASK;\ndrivers/vfio/pci/nvgrace-gpu/main.c-681-\tstruct mem_region *memregion = NULL;\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=753=nvgrace_gpu_map_and_read(struct nvgrace_gpu_pci_core_device *nvdev,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-755-{\ndrivers/vfio/pci/nvgrace-gpu/main.c:756:\tunsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);\ndrivers/vfio/pci/nvgrace-gpu/main.c:757:\tu64 offset = *ppos \u0026 VFIO_PCI_OFFSET_MASK;\ndrivers/vfio/pci/nvgrace-gpu/main.c-758-\tint ret;\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-787-\t\t\t\t\t     buf, offset, mem_count,\ndrivers/vfio/pci/nvgrace-gpu/main.c:788:\t\t\t\t\t     0, 0, false, VFIO_PCI_IO_WIDTH_8);\ndrivers/vfio/pci/nvgrace-gpu/main.c-789-\t}\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=804=nvgrace_gpu_read_mem(struct nvgrace_gpu_pci_core_device *nvdev,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-807-\tstruct vfio_pci_core_device *vdev = \u0026nvdev-\u003ecore_device;\ndrivers/vfio/pci/nvgrace-gpu/main.c:808:\tu64 offset = *ppos \u0026 VFIO_PCI_OFFSET_MASK;\ndrivers/vfio/pci/nvgrace-gpu/main.c:809:\tunsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);\ndrivers/vfio/pci/nvgrace-gpu/main.c-810-\tstruct mem_region *memregion;\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=866=nvgrace_gpu_read(struct vfio_device *core_vdev,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-868-{\ndrivers/vfio/pci/nvgrace-gpu/main.c:869:\tunsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);\ndrivers/vfio/pci/nvgrace-gpu/main.c-870-\tstruct nvgrace_gpu_pci_core_device *nvdev =\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-883-\ndrivers/vfio/pci/nvgrace-gpu/main.c:884:\tif (index == VFIO_PCI_CONFIG_REGION_INDEX)\ndrivers/vfio/pci/nvgrace-gpu/main.c-885-\t\treturn nvgrace_gpu_read_config_emu(core_vdev, buf, count, ppos);\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=895=nvgrace_gpu_map_and_write(struct nvgrace_gpu_pci_core_device *nvdev,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-898-{\ndrivers/vfio/pci/nvgrace-gpu/main.c:899:\tunsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);\ndrivers/vfio/pci/nvgrace-gpu/main.c:900:\tloff_t pos = *ppos \u0026 VFIO_PCI_OFFSET_MASK;\ndrivers/vfio/pci/nvgrace-gpu/main.c-901-\tint ret;\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-925-\t\t\t\t\t     (char __user *)buf, pos, mem_count,\ndrivers/vfio/pci/nvgrace-gpu/main.c:926:\t\t\t\t\t     0, 0, true, VFIO_PCI_IO_WIDTH_8);\ndrivers/vfio/pci/nvgrace-gpu/main.c-927-\t}\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=941=nvgrace_gpu_write_mem(struct nvgrace_gpu_pci_core_device *nvdev,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-944-\tstruct vfio_pci_core_device *vdev = \u0026nvdev-\u003ecore_device;\ndrivers/vfio/pci/nvgrace-gpu/main.c:945:\tunsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);\ndrivers/vfio/pci/nvgrace-gpu/main.c:946:\tu64 offset = *ppos \u0026 VFIO_PCI_OFFSET_MASK;\ndrivers/vfio/pci/nvgrace-gpu/main.c-947-\tstruct mem_region *memregion;\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c=996=nvgrace_gpu_write(struct vfio_device *core_vdev,\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-1002-\tstruct vfio_pci_core_device *vdev = \u0026nvdev-\u003ecore_device;\ndrivers/vfio/pci/nvgrace-gpu/main.c:1003:\tunsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);\ndrivers/vfio/pci/nvgrace-gpu/main.c-1004-\tint ret;\n--\ndrivers/vfio/pci/nvgrace-gpu/main.c-1013-\ndrivers/vfio/pci/nvgrace-gpu/main.c:1014:\tif (index == VFIO_PCI_CONFIG_REGION_INDEX)\ndrivers/vfio/pci/nvgrace-gpu/main.c-1015-\t\treturn nvgrace_gpu_write_config_emu(core_vdev, buf, count, ppos);\n--\ndrivers/vfio/pci/pds/Kconfig-3-\ndrivers/vfio/pci/pds/Kconfig:4:config PDS_VFIO_PCI\ndrivers/vfio/pci/pds/Kconfig-5-\ttristate \"VFIO support for PDS PCI devices\"\ndrivers/vfio/pci/pds/Kconfig-6-\tdepends on PDS_CORE \u0026\u0026 PCI_IOV\ndrivers/vfio/pci/pds/Kconfig:7:\tselect VFIO_PCI_CORE\ndrivers/vfio/pci/pds/Kconfig-8-\tselect IOMMUFD_DRIVER\n--\ndrivers/vfio/pci/pds/Makefile-3-\ndrivers/vfio/pci/pds/Makefile:4:obj-$(CONFIG_PDS_VFIO_PCI) += pds-vfio-pci.o\ndrivers/vfio/pci/pds/Makefile-5-\n--\ndrivers/vfio/pci/qat/Kconfig-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/vfio/pci/qat/Kconfig:2:config QAT_VFIO_PCI\ndrivers/vfio/pci/qat/Kconfig-3-\ttristate \"VFIO support for QAT VF PCI devices\"\ndrivers/vfio/pci/qat/Kconfig:4:\tselect VFIO_PCI_CORE\ndrivers/vfio/pci/qat/Kconfig-5-\tdepends on CRYPTO_DEV_QAT_4XXX || CRYPTO_DEV_QAT_420XX || CRYPTO_DEV_QAT_6XXX\n--\ndrivers/vfio/pci/qat/Makefile-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/vfio/pci/qat/Makefile:2:obj-$(CONFIG_QAT_VFIO_PCI) += qat_vfio_pci.o\ndrivers/vfio/pci/qat/Makefile-3-qat_vfio_pci-y := main.o\n--\ndrivers/vfio/pci/trace.h-11-\ndrivers/vfio/pci/trace.h:12:#if !defined(_TRACE_VFIO_PCI_H) || defined(TRACE_HEADER_MULTI_READ)\ndrivers/vfio/pci/trace.h:13:#define _TRACE_VFIO_PCI_H\ndrivers/vfio/pci/trace.h-14-\n--\ndrivers/vfio/pci/trace.h=65=TRACE_EVENT(vfio_pci_npu2_mmap,\n--\ndrivers/vfio/pci/trace.h-89-\ndrivers/vfio/pci/trace.h:90:#endif /* _TRACE_VFIO_PCI_H */\ndrivers/vfio/pci/trace.h-91-\n--\ndrivers/vfio/pci/vfio_pci.c=39=MODULE_PARM_DESC(nointxmask,\n--\ndrivers/vfio/pci/vfio_pci.c-41-\ndrivers/vfio/pci/vfio_pci.c:42:#ifdef CONFIG_VFIO_PCI_VGA\ndrivers/vfio/pci/vfio_pci.c-43-static bool disable_vga;\n--\ndrivers/vfio/pci/vfio_pci.c=128=static int vfio_pci_init_dev(struct vfio_device *core_vdev)\n--\ndrivers/vfio/pci/vfio_pci.c-141-\tvdev-\u003edisable_idle_d3 = disable_idle_d3;\ndrivers/vfio/pci/vfio_pci.c:142:#ifdef CONFIG_VFIO_PCI_VGA\ndrivers/vfio/pci/vfio_pci.c-143-\tvdev-\u003edisable_vga = disable_vga;\n--\ndrivers/vfio/pci/vfio_pci_config.c=1163=static int vfio_msi_config_write(struct vfio_pci_core_device *vdev, int pos,\n--\ndrivers/vfio/pci/vfio_pci_config.c-1183-\t\t/* MSI is enabled via ioctl */\ndrivers/vfio/pci/vfio_pci_config.c:1184:\t\tif  (vdev-\u003eirq_type != VFIO_PCI_MSI_IRQ_INDEX)\ndrivers/vfio/pci/vfio_pci_config.c-1185-\t\t\tflags \u0026= ~PCI_MSI_FLAGS_ENABLE;\n--\ndrivers/vfio/pci/vfio_pci_config.c=1743=int vfio_config_init(struct vfio_pci_core_device *vdev)\n--\ndrivers/vfio/pci/vfio_pci_config.c-1825-\ndrivers/vfio/pci/vfio_pci_config.c:1826:\tif (!IS_ENABLED(CONFIG_VFIO_PCI_INTX) || vdev-\u003enointx ||\ndrivers/vfio/pci/vfio_pci_config.c-1827-\t    !vdev-\u003epdev-\u003eirq || vdev-\u003epdev-\u003eirq == IRQ_NOTCONNECTED)\n--\ndrivers/vfio/pci/vfio_pci_config.c=1970=ssize_t vfio_pci_config_rw(struct vfio_pci_core_device *vdev, char __user *buf,\n--\ndrivers/vfio/pci/vfio_pci_config.c-1976-\ndrivers/vfio/pci/vfio_pci_config.c:1977:\tpos \u0026= VFIO_PCI_OFFSET_MASK;\ndrivers/vfio/pci/vfio_pci_config.c-1978-\n--\ndrivers/vfio/pci/vfio_pci_core.c=95=static inline bool vfio_vga_disabled(struct vfio_pci_core_device *vdev)\ndrivers/vfio/pci/vfio_pci_core.c-96-{\ndrivers/vfio/pci/vfio_pci_core.c:97:#ifdef CONFIG_VFIO_PCI_VGA\ndrivers/vfio/pci/vfio_pci_core.c-98-\treturn vdev-\u003edisable_vga;\n--\ndrivers/vfio/pci/vfio_pci_core.c=491=static int vfio_pci_core_runtime_suspend(struct device *dev)\n--\ndrivers/vfio/pci/vfio_pci_core.c-513-\t */\ndrivers/vfio/pci/vfio_pci_core.c:514:\tvdev-\u003epm_intx_masked = ((vdev-\u003eirq_type == VFIO_PCI_INTX_IRQ_INDEX) \u0026\u0026\ndrivers/vfio/pci/vfio_pci_core.c-515-\t\t\t\tvfio_pci_intx_mask(vdev));\n--\ndrivers/vfio/pci/vfio_pci_core.c=862=static int vfio_pci_get_irq_count(struct vfio_pci_core_device *vdev, int irq_type)\ndrivers/vfio/pci/vfio_pci_core.c-863-{\ndrivers/vfio/pci/vfio_pci_core.c:864:\tif (irq_type == VFIO_PCI_INTX_IRQ_INDEX) {\ndrivers/vfio/pci/vfio_pci_core.c-865-\t\treturn vdev-\u003evconfig[PCI_INTERRUPT_PIN] ? 1 : 0;\ndrivers/vfio/pci/vfio_pci_core.c:866:\t} else if (irq_type == VFIO_PCI_MSI_IRQ_INDEX) {\ndrivers/vfio/pci/vfio_pci_core.c-867-\t\tu8 pos;\n--\ndrivers/vfio/pci/vfio_pci_core.c-875-\t\t}\ndrivers/vfio/pci/vfio_pci_core.c:876:\t} else if (irq_type == VFIO_PCI_MSIX_IRQ_INDEX) {\ndrivers/vfio/pci/vfio_pci_core.c-877-\t\tu8 pos;\n--\ndrivers/vfio/pci/vfio_pci_core.c-886-\t\t}\ndrivers/vfio/pci/vfio_pci_core.c:887:\t} else if (irq_type == VFIO_PCI_ERR_IRQ_INDEX) {\ndrivers/vfio/pci/vfio_pci_core.c-888-\t\tif (pci_is_pcie(vdev-\u003epdev))\ndrivers/vfio/pci/vfio_pci_core.c-889-\t\t\treturn 1;\ndrivers/vfio/pci/vfio_pci_core.c:890:\t} else if (irq_type == VFIO_PCI_REQ_IRQ_INDEX) {\ndrivers/vfio/pci/vfio_pci_core.c-891-\t\treturn 1;\n--\ndrivers/vfio/pci/vfio_pci_core.c=911=static int vfio_pci_fill_devs(struct pci_dev *pdev, void *data)\n--\ndrivers/vfio/pci/vfio_pci_core.c-924-\ndrivers/vfio/pci/vfio_pci_core.c:925:\tif (fill-\u003eflags \u0026 VFIO_PCI_HOT_RESET_FLAG_DEV_ID) {\ndrivers/vfio/pci/vfio_pci_core.c-926-\t\tstruct iommufd_ctx *iommufd = vfio_iommufd_device_ictx(fill-\u003evdev);\n--\ndrivers/vfio/pci/vfio_pci_core.c-935-\t\tif (!vdev) {\ndrivers/vfio/pci/vfio_pci_core.c:936:\t\t\tinfo-\u003edevid = VFIO_PCI_DEVID_NOT_OWNED;\ndrivers/vfio/pci/vfio_pci_core.c-937-\t\t} else {\n--\ndrivers/vfio/pci/vfio_pci_core.c-942-\t\t\telse if (id == -ENOENT)\ndrivers/vfio/pci/vfio_pci_core.c:943:\t\t\t\tinfo-\u003edevid = VFIO_PCI_DEVID_OWNED;\ndrivers/vfio/pci/vfio_pci_core.c-944-\t\t\telse\ndrivers/vfio/pci/vfio_pci_core.c:945:\t\t\t\tinfo-\u003edevid = VFIO_PCI_DEVID_NOT_OWNED;\ndrivers/vfio/pci/vfio_pci_core.c-946-\t\t}\ndrivers/vfio/pci/vfio_pci_core.c:947:\t\t/* If devid is VFIO_PCI_DEVID_NOT_OWNED, clear owned flag. */\ndrivers/vfio/pci/vfio_pci_core.c:948:\t\tif (info-\u003edevid == VFIO_PCI_DEVID_NOT_OWNED)\ndrivers/vfio/pci/vfio_pci_core.c:949:\t\t\tfill-\u003eflags \u0026= ~VFIO_PCI_HOT_RESET_FLAG_DEV_ID_OWNED;\ndrivers/vfio/pci/vfio_pci_core.c-950-\t} else {\n--\ndrivers/vfio/pci/vfio_pci_core.c=1047=static int vfio_pci_info_atomic_cap(struct vfio_pci_core_device *vdev,\n--\ndrivers/vfio/pci/vfio_pci_core.c-1060-\t    !pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP32))\ndrivers/vfio/pci/vfio_pci_core.c:1061:\t\tcap.flags |= VFIO_PCI_ATOMIC_COMP32;\ndrivers/vfio/pci/vfio_pci_core.c-1062-\n--\ndrivers/vfio/pci/vfio_pci_core.c-1064-\t    !pci_enable_atomic_ops_to_root(pdev, PCI_EXP_DEVCAP2_ATOMIC_COMP64))\ndrivers/vfio/pci/vfio_pci_core.c:1065:\t\tcap.flags |= VFIO_PCI_ATOMIC_COMP64;\ndrivers/vfio/pci/vfio_pci_core.c-1066-\n--\ndrivers/vfio/pci/vfio_pci_core.c-1069-\t\t\t\t\t   PCI_EXP_DEVCAP2_ATOMIC_COMP128))\ndrivers/vfio/pci/vfio_pci_core.c:1070:\t\tcap.flags |= VFIO_PCI_ATOMIC_COMP128;\ndrivers/vfio/pci/vfio_pci_core.c-1071-\n--\ndrivers/vfio/pci/vfio_pci_core.c=1078=static int vfio_pci_ioctl_get_info(struct vfio_pci_core_device *vdev,\n--\ndrivers/vfio/pci/vfio_pci_core.c-1098-\ndrivers/vfio/pci/vfio_pci_core.c:1099:\tinfo.num_regions = VFIO_PCI_NUM_REGIONS + vdev-\u003enum_regions;\ndrivers/vfio/pci/vfio_pci_core.c:1100:\tinfo.num_irqs = VFIO_PCI_NUM_IRQS;\ndrivers/vfio/pci/vfio_pci_core.c-1101-\n--\ndrivers/vfio/pci/vfio_pci_core.c=1135=int vfio_pci_ioctl_get_region_info(struct vfio_device *core_vdev,\n--\ndrivers/vfio/pci/vfio_pci_core.c-1144-\tswitch (info-\u003eindex) {\ndrivers/vfio/pci/vfio_pci_core.c:1145:\tcase VFIO_PCI_CONFIG_REGION_INDEX:\ndrivers/vfio/pci/vfio_pci_core.c:1146:\t\tinfo-\u003eoffset = VFIO_PCI_INDEX_TO_OFFSET(info-\u003eindex);\ndrivers/vfio/pci/vfio_pci_core.c-1147-\t\tinfo-\u003esize = pdev-\u003ecfg_size;\n--\ndrivers/vfio/pci/vfio_pci_core.c-1150-\t\tbreak;\ndrivers/vfio/pci/vfio_pci_core.c:1151:\tcase VFIO_PCI_BAR0_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX:\ndrivers/vfio/pci/vfio_pci_core.c:1152:\t\tinfo-\u003eoffset = VFIO_PCI_INDEX_TO_OFFSET(info-\u003eindex);\ndrivers/vfio/pci/vfio_pci_core.c-1153-\t\tinfo-\u003esize = pci_resource_len(pdev, info-\u003eindex);\n--\ndrivers/vfio/pci/vfio_pci_core.c-1170-\t\tbreak;\ndrivers/vfio/pci/vfio_pci_core.c:1171:\tcase VFIO_PCI_ROM_REGION_INDEX: {\ndrivers/vfio/pci/vfio_pci_core.c-1172-\t\tvoid __iomem *io;\n--\ndrivers/vfio/pci/vfio_pci_core.c-1175-\ndrivers/vfio/pci/vfio_pci_core.c:1176:\t\tinfo-\u003eoffset = VFIO_PCI_INDEX_TO_OFFSET(info-\u003eindex);\ndrivers/vfio/pci/vfio_pci_core.c-1177-\t\tinfo-\u003eflags = 0;\n--\ndrivers/vfio/pci/vfio_pci_core.c-1202-\t}\ndrivers/vfio/pci/vfio_pci_core.c:1203:\tcase VFIO_PCI_VGA_REGION_INDEX:\ndrivers/vfio/pci/vfio_pci_core.c-1204-\t\tif (!vdev-\u003ehas_vga)\n--\ndrivers/vfio/pci/vfio_pci_core.c-1206-\ndrivers/vfio/pci/vfio_pci_core.c:1207:\t\tinfo-\u003eoffset = VFIO_PCI_INDEX_TO_OFFSET(info-\u003eindex);\ndrivers/vfio/pci/vfio_pci_core.c-1208-\t\tinfo-\u003esize = 0xc0000;\n--\ndrivers/vfio/pci/vfio_pci_core.c-1218-\ndrivers/vfio/pci/vfio_pci_core.c:1219:\t\tif (info-\u003eindex \u003e= VFIO_PCI_NUM_REGIONS + vdev-\u003enum_regions)\ndrivers/vfio/pci/vfio_pci_core.c-1220-\t\t\treturn -EINVAL;\ndrivers/vfio/pci/vfio_pci_core.c-1221-\t\tinfo-\u003eindex = array_index_nospec(\ndrivers/vfio/pci/vfio_pci_core.c:1222:\t\t\tinfo-\u003eindex, VFIO_PCI_NUM_REGIONS + vdev-\u003enum_regions);\ndrivers/vfio/pci/vfio_pci_core.c-1223-\ndrivers/vfio/pci/vfio_pci_core.c:1224:\t\ti = info-\u003eindex - VFIO_PCI_NUM_REGIONS;\ndrivers/vfio/pci/vfio_pci_core.c-1225-\ndrivers/vfio/pci/vfio_pci_core.c:1226:\t\tinfo-\u003eoffset = VFIO_PCI_INDEX_TO_OFFSET(info-\u003eindex);\ndrivers/vfio/pci/vfio_pci_core.c-1227-\t\tinfo-\u003esize = vdev-\u003eregion[i].size;\n--\ndrivers/vfio/pci/vfio_pci_core.c=1250=static int vfio_pci_ioctl_get_irq_info(struct vfio_pci_core_device *vdev,\n--\ndrivers/vfio/pci/vfio_pci_core.c-1258-\ndrivers/vfio/pci/vfio_pci_core.c:1259:\tif (info.argsz \u003c minsz || info.index \u003e= VFIO_PCI_NUM_IRQS)\ndrivers/vfio/pci/vfio_pci_core.c-1260-\t\treturn -EINVAL;\n--\ndrivers/vfio/pci/vfio_pci_core.c-1262-\tswitch (info.index) {\ndrivers/vfio/pci/vfio_pci_core.c:1263:\tcase VFIO_PCI_INTX_IRQ_INDEX ... VFIO_PCI_MSIX_IRQ_INDEX:\ndrivers/vfio/pci/vfio_pci_core.c:1264:\tcase VFIO_PCI_REQ_IRQ_INDEX:\ndrivers/vfio/pci/vfio_pci_core.c-1265-\t\tbreak;\ndrivers/vfio/pci/vfio_pci_core.c:1266:\tcase VFIO_PCI_ERR_IRQ_INDEX:\n\n"
}

5/2 2026/09/11 22:07 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 40799
							output: 29
							thoughts: 61
						

Thoughts:
**VFIO Exploration: The Syzkaller Connection**

Okay, so I'm thinking about VFIO, specifically `VFIO_PCI`. It's the standard, generic VFIO driver for PCI devices, right? My mind immediately jumps to syzkaller, which of course makes me think... is VFIO actually reachable through syzkaller? That's the real question. To answer that, I need to understand how VFIO devices are created and opened. Time to dive into the code. I'll start with `drivers/vfio/vfio_main.c`. That should give me a good handle on the foundational mechanisms.



6/2 2026/09/11 22:07 tool grepper
0m Args:
{
  "Expression": "/dev/vfio",
  "PathPrefix": "drivers/vfio"
}

Results:
{
  "Output": "drivers/vfio/Kconfig=17=config VFIO_DEVICE_CDEV\ndrivers/vfio/Kconfig:18:\tbool \"Support for the VFIO cdev /dev/vfio/devices/vfioX\"\ndrivers/vfio/Kconfig-19-\tdepends on IOMMUFD \u0026\u0026 !SPAPR_TCE_IOMMU\n--\ndrivers/vfio/Kconfig-23-\t  access. Userspace gets device fd by opening device cdev under\ndrivers/vfio/Kconfig:24:\t  /dev/vfio/devices/vfioX, and then bind the device fd with an iommufd\ndrivers/vfio/Kconfig-25-\t  to set up secure DMA context for device access.\n--\ndrivers/vfio/Kconfig=29=config VFIO_GROUP\ndrivers/vfio/Kconfig:30:\tbool \"Support for the VFIO group /dev/vfio/$group_id\"\ndrivers/vfio/Kconfig-31-\tdefault y\n--\ndrivers/vfio/Kconfig=39=config VFIO_CONTAINER\ndrivers/vfio/Kconfig:40:\tbool \"Support for the VFIO container /dev/vfio/vfio\"\ndrivers/vfio/Kconfig-41-\tselect VFIO_IOMMU_TYPE1 if MMU \u0026\u0026 (X86 || S390 || ARM || ARM64)\n--\ndrivers/vfio/container.c-4- *\ndrivers/vfio/container.c:5: * VFIO container (/dev/vfio/vfio)\ndrivers/vfio/container.c-6- */\n--\ndrivers/vfio/container.c=138=EXPORT_SYMBOL_GPL(vfio_unregister_iommu_driver);\n--\ndrivers/vfio/container.c-140-/*\ndrivers/vfio/container.c:141: * Container objects - containers are created when /dev/vfio/vfio is\ndrivers/vfio/container.c-142- * opened, but their lifecycle extends until the last user is done, so\n--\ndrivers/vfio/group.c=31=static struct vfio_device *vfio_device_get_from_name(struct vfio_group *group,\n--\ndrivers/vfio/group.c-60-/*\ndrivers/vfio/group.c:61: * VFIO Group fd, /dev/vfio/$GROUP\ndrivers/vfio/group.c-62- */\n--\ndrivers/vfio/group.c=893=int __init vfio_group_init(void)\n--\ndrivers/vfio/group.c-904-\ndrivers/vfio/group.c:905:\t/* /dev/vfio/$GROUP */\ndrivers/vfio/group.c-906-\tret = class_register(\u0026vfio_class);\n"
}

7/2 2026/09/11 22:07 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 41723
							output: 41
							thoughts: 514
						

Thoughts:
**My VFIO-PCI Thoughts**

Okay, so syzkaller is opening `/dev/vfio/vfio`, `/dev/vfio/*`, or `/dev/vfio/devices/vfio*`. I need to figure out how this works, especially within a virtualized context like GCE or QEMU. Can `vfio-pci` even be bound to a PCI device in those environments? Syzkaller runs as root, so it *can* test VFIO, which makes this even more intriguing.

First, I need to understand what PCI devices are even *present* in QEMU. Ah, right, QEMU *emulates* PCI devices like virtio-net, virtio-blk, e1000, i440fx, etc. So, can `vfio-pci` latch onto these emulated devices? Yes, it *can*! I can bind PCI devices through sysfs, using `/sys/bus/pci/drivers/vfio-pci/new_id` or by unbinding them from their current driver using `/sys/bus/pci/devices/.../driver/unbind` and then binding them to `vfio-pci`.

Now, the critical question: Is `vfio-pci` reachable in a QEMU environment? I need to determine if it is structurally unreachable hardware or something reachable. Let's refer to Section 2. It describes things like vendor-specific PCIe switches and SmartNICs. Those are the structurally unreachable parts, requiring physical hardware not emulated in standard QEMU. That is, things like `mlxsw`, `pds_core`, `qed`, `ionic`, and `amdgpu`.

Wait, is `VFIO_PCI` vendor-specific hardware? No! It's *not* a vendor-specific hardware; it's generic VFIO support for any PCI device. It's a generic PCI driver. Okay, now I need to dive a little deeper, I should look at `VFIO_PCI_DMABUF`:

`config VFIO_PCI_DMABUF`:
`def_bool y if PCI_P2PDMA`
`depends on VFIO_PCI_CORE`

Also, let's look at `dma-buf.c`! I see that `dma_buf_set_name` and `dma_buf_set_name_user` are modified. What exactly are the changes? Let's read `drivers/dma-buf/dma-buf.c` around line 405.



8/2 2026/09/11 22:07 tool read-file
0m Args:
{
  "File": "drivers/dma-buf/dma-buf.c",
  "FirstLine": 400,
  "LineCount": 45
}

Results:
{
  "Contents": " 400:\t\t\t}\n 401:\t\t}\n 402:\t\n 403:\t\tdma_resv_unlock(resv);\n 404:\t\treturn events;\n 405:\t}\n 406:\t\n 407:\t/**\n 408:\t * dma_buf_set_name_user - Set a dma_buf's name from a user string\n 409:\t *\n 410:\t * The string is up to DMA_BUF_NAME_LEN long, including the terminator.\n 411:\t *\n 412:\t * @dmabuf: [in]     dmabuf buffer that will be renamed.\n 413:\t * @buf:    [in]     A piece of userspace memory that contains the name of\n 414:\t *                   the dma-buf.\n 415:\t *\n 416:\t * Returns 0 on success, and any previously-set name is freed.\n 417:\t */\n 418:\tstatic long dma_buf_set_name_user(struct dma_buf *dmabuf, const char __user *buf)\n 419:\t{\n 420:\t\tchar *name = strndup_user(buf, DMA_BUF_NAME_LEN);\n 421:\t\tint ret;\n 422:\t\n 423:\t\tif (IS_ERR(name))\n 424:\t\t\treturn PTR_ERR(name);\n 425:\t\n 426:\t\tret = dma_buf_set_name(dmabuf, name);\n 427:\t\tif (ret)\n 428:\t\t\tkfree(name);\n 429:\t\n 430:\t\treturn ret;\n 431:\t}\n 432:\t\n 433:\t#if IS_ENABLED(CONFIG_SYNC_FILE)\n 434:\tstatic long dma_buf_export_sync_file(struct dma_buf *dmabuf,\n 435:\t\t\t\t\t     void __user *user_data)\n 436:\t{\n 437:\t\tstruct dma_buf_export_sync_file arg;\n 438:\t\tenum dma_resv_usage usage;\n 439:\t\tstruct dma_fence *fence = NULL;\n 440:\t\tstruct sync_file *sync_file;\n 441:\t\tint fd, ret;\n 442:\t\n 443:\t\tif (copy_from_user(\u0026arg, user_data, sizeof(arg)))\n 444:\t\t\treturn -EFAULT;\n"
}

9/2 2026/09/11 22:07 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 43505
							output: 41
							thoughts: 16
						

Thoughts:
Here's a summary of my thoughts, presented as though they were my own:

**Analyzing `dma_buf_set_name`**

Alright, let's dive into the implementation of `dma_buf_set_name`. This is a crucial function; it sets the name associated with a `dma_buf`. I need to consider a few key aspects, right off the bat: the implications for resource management, potential concurrency issues, and the overall design philosophy within the DMA buffer framework.

First, how does this interact with the naming conventions and potential conflict resolution? Is there a system in place to prevent naming collisions, or does this function rely on the caller to guarantee uniqueness? If it's the latter, then the documentation around using this correctly will be critically important. Poor naming could lead to unexpected behavior and hard-to-debug issues, especially in a complex system.

Secondly, what are the locking mechanisms involved, if any? Access to the `dma_buf` structure itself is undoubtedly protected, but does this function introduce any additional locks? If so, is the locking granularity optimized, and are there potential deadlock scenarios to be concerned about? Concurrency is a major pain point with DMA buffers, so getting this right is essential.

Finally, I need to consider the impact on the overall lifecycle of the `dma_buf`. Does setting the name affect its lifetime management? For instance, does it implicitly prevent the buffer from being freed while the name is still in use, perhaps through a reference count somewhere? How does the name get propagated to other components that might use the `dma_buf`? Understanding this function fully will allow me to integrate the `dma_buf` in our system to best effect.



10/2 2026/09/11 22:07 tool read-file
0m Args:
{
  "File": "drivers/dma-buf/dma-buf.c",
  "FirstLine": 850,
  "LineCount": 45
}

Results:
{
  "Contents": " 850:\t\tDMA_BUF_TRACE(trace_dma_buf_put, dmabuf);\n 851:\t\tfput(dmabuf-\u003efile);\n 852:\t}\n 853:\tEXPORT_SYMBOL_NS_GPL(dma_buf_put, \"DMA_BUF\");\n 854:\t\n 855:\t/**\n 856:\t * dma_buf_set_name - Set a dma_buf's name\n 857:\t * It could support changing the name of the dma-buf if the same piece\n 858:\t * of memory is used for multiple purpose between different devices.\n 859:\t *\n 860:\t * @dmabuf: [in]     dmabuf buffer that will be renamed.\n 861:\t * @name:   [in]     The name of the dma-buf, allocated with kmalloc() or\n 862:\t *                   similar.  This takes ownership of the allocation\n 863:\t *                   on success, which will be kfree()d when the\n 864:\t *                   dmabuf is released or a new name assigned.\n 865:\t *\n 866:\t * Returns 0 on success, -EINVAL if the name is NULL, or -E2BIG if the\n 867:\t * name exceeds DMA_BUF_NAME_LEN.\n 868:\t */\n 869:\tint dma_buf_set_name(struct dma_buf *dmabuf, char *name)\n 870:\t{\n 871:\t\tif (!name)\n 872:\t\t\treturn -EINVAL;\n 873:\t\n 874:\t\t/* dmabuffs_dname() won't use the string if the length\n 875:\t\t * (including terminator) exceeds DMA_BUF_NAME_LEN:\n 876:\t\t */\n 877:\t\tif (strlen(name) \u003e= DMA_BUF_NAME_LEN)\n 878:\t\t\treturn -E2BIG;\n 879:\t\n 880:\t\tspin_lock(\u0026dmabuf-\u003ename_lock);\n 881:\t\tkfree(dmabuf-\u003ename);\n 882:\t\tdmabuf-\u003ename = name;\n 883:\t\tspin_unlock(\u0026dmabuf-\u003ename_lock);\n 884:\t\n 885:\t\treturn 0;\n 886:\t}\n 887:\tEXPORT_SYMBOL_NS_GPL(dma_buf_set_name, \"DMA_BUF\");\n 888:\t\n 889:\tstatic int dma_buf_wrap_sg_table(struct sg_table **sg_table)\n 890:\t{\n 891:\t\tstruct scatterlist *to_sg, *from_sg;\n 892:\t\tstruct sg_table *from = *sg_table;\n 893:\t\tstruct dma_buf_sg_table_wrapper *to;\n 894:\t\tint i, ret;\n"
}

11/2 2026/09/11 22:07 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 44691
							output: 36
							thoughts: 1541
						

Thoughts:
**Initial Assessment: Complex Concurrency and DMABUF Integration in VFIO-PCI**

Okay, let's break this down. My initial focus is on the `dma_buf_set_name_user` function. I'm seeing a potential buffer overflow vulnerability. The function uses `strndup_user` with a length check that appears flawed. If the input `buf` is exactly `DMA_BUF_NAME_LEN` bytes long *without* a null terminator in the first `DMA_BUF_NAME_LEN - 1` bytes, `strndup_user` copies the full `DMA_BUF_NAME_LEN` bytes, null-terminates it, and `strlen(name)` becomes `DMA_BUF_NAME_LEN`. The subsequent check `if (strlen(name) >= DMA_BUF_NAME_LEN)` will then fail, leading to an `-E2BIG` error, which is the expected result if the intended behavior is followed. However, if the name were `DMA_BUF_NAME_LEN-1` bytes long and the null terminator is not present within the first `DMA_BUF_NAME_LEN - 1` bytes, the string is still considered valid, but the length does not match the size of the buffer.

Now, how can this be triggered? `dma_buf_set_name_user` is directly called by `dma_buf_ioctl` under `DMA_BUF_SET_NAME_A` and `DMA_BUF_SET_NAME_B`. So, I need a valid dma-buf file descriptor. Fortunately, those are relatively easy to come by: `DRM_IOCTL_PRIME_HANDLE_TO_FD`, `/dev/dma_heap/...`, `/dev/udmabuf`, or even `v4l2` can provide them.

Crucially, this `dma_buf_ioctl` call executes `dma_buf_set_name_user` and `dma_buf_set_name`.

I need to expand the scope to the entire patch. The title screams VFIO PCI BAR mmaps backed by DMABUF. Let's dig deeper:

The change introduces `vfio_pci_core_mmap_prep_dmabuf`. The code's using `dma_resv_lock`, `vfio_device_try_get_registration`, `memory_lock`, and `dmabuf_lock` in a carefully orchestrated dance, along with other functions such as `vfio_pci_core_feature_dma_buf_revoke`, `vfio_pci_dma_buf_find_pfn`, `vfio_pci_dmabuf_export`, `vfio_pci_dma_buf_mmap`, `vfio_pci_dma_buf_set_status`, and `vfio_pci_dma_buf_release`. The concurrency logic here is extensive.

Specifically, `vfio_pci_dma_buf_set_status` re-arms a kref and completions: It involves invalidating mappings, waiting on reservation locks, releasing memory regions, and re-initializing completion variables. This is a complex synchronization pattern, involving kref management, and waiting on completions.

I'm seeing a complex mix of concurrency handling, locking, mmap fault handling, revocation, and DMABUF integration, which could contain some unexpected edge-cases.

Can I fuzz this? Is it reachable in a typical syzkaller environment? VFIO is accessed via `/dev/vfio/vfio` and `/dev/vfio/<group>` or `/dev/vfio/devices/vfio*`. Syzkaller runs in QEMU with root, so I need to verify if syzkaller can open VFIO. I need to check the Kconfig dependencies for `VFIO_PCI`. My hunch is that this is reachable.



12/2 2026/09/11 22:07 tool read-file
0m Args:
{
  "File": "drivers/vfio/pci/Kconfig",
  "FirstLine": 1,
  "LineCount": 40
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0-only\n   2:\tmenu \"VFIO support for PCI devices\"\n   3:\t\tdepends on PCI\n   4:\t\n   5:\tconfig VFIO_PCI_CORE\n   6:\t\ttristate\n   7:\t\tselect VFIO_VIRQFD\n   8:\t\tselect IRQ_BYPASS_MANAGER\n   9:\t\tselect DMA_SHARED_BUFFER\n  10:\t\n  11:\tconfig VFIO_PCI_INTX\n  12:\t\tdef_bool y if !S390\n  13:\t\tdepends on VFIO_PCI_CORE\n  14:\t\n  15:\tconfig VFIO_PCI\n  16:\t\ttristate \"Generic VFIO support for any PCI device\"\n  17:\t\tselect VFIO_PCI_CORE\n  18:\t\thelp\n  19:\t\t  Support for the generic PCI VFIO bus driver which can connect any\n  20:\t\t  PCI device to the VFIO framework.\n  21:\t\n  22:\t\t  If you don't know what to do here, say N.\n  23:\t\n  24:\tif VFIO_PCI\n  25:\tconfig VFIO_PCI_VGA\n  26:\t\tbool \"Generic VFIO PCI support for VGA devices\"\n  27:\t\tdepends on X86 \u0026\u0026 VGA_ARB\n  28:\t\thelp\n  29:\t\t  Support for VGA extension to VFIO PCI.  This exposes an additional\n  30:\t\t  region on VGA devices for accessing legacy VGA addresses used by\n  31:\t\t  BIOS and generic video drivers.\n  32:\t\n  33:\t\t  If you don't know what to do here, say N.\n  34:\t\n  35:\tconfig VFIO_PCI_IGD\n  36:\t\tbool \"Generic VFIO PCI extensions for Intel graphics (GVT-d)\"\n  37:\t\tdepends on X86\n  38:\t\tdefault y\n  39:\t\thelp\n  40:\t\t  Support for Intel IGD specific extensions to enable direct\n"
}

13/2 2026/09/11 22:07 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 47627
							output: 37
							thoughts: 27
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Diving into VFIO_PCI_DMABUF**

Right, let's get down to brass tacks. I need to refresh my memory on the `VFIO_PCI_DMABUF` configuration option. Time to dig into the source tree. Specifically, I'm heading over to the `drivers/vfio/pci/Kconfig` file. I'm assuming that's where the definition and dependencies for that feature are laid out. I want to quickly understand its relationship to other VFIO and DMA-BUF components. What's required to enable it? What are the implications? Are there any hidden gotchas I need to keep in mind regarding buffer allocation or security? This deep dive is going to be quick and surgical, not an exhaustive analysis, I just need to get the lay of the land. I need to quickly ascertain the underlying details.



14/2 2026/09/11 22:07 tool read-file
0m Args:
{
  "File": "drivers/vfio/pci/Kconfig",
  "FirstLine": 45,
  "LineCount": 30
}

Results:
{
  "Contents": "  45:\t\t  To enable Intel IGD assignment through vfio-pci, say Y.\n  46:\tendif\n  47:\t\n  48:\tconfig VFIO_PCI_ZDEV_KVM\n  49:\t\tbool \"VFIO PCI extensions for s390x KVM passthrough\"\n  50:\t\tdepends on S390 \u0026\u0026 KVM\n  51:\t\tdefault y\n  52:\t\thelp\n  53:\t\t  Support s390x-specific extensions to enable support for enhancements\n  54:\t\t  to KVM passthrough capabilities, such as interpretive execution of\n  55:\t\t  zPCI instructions.\n  56:\t\n  57:\t\t  To enable s390x KVM vfio-pci extensions, say Y.\n  58:\t\n  59:\tconfig VFIO_PCI_DMABUF\n  60:\t\tdef_bool y if PCI_P2PDMA\n  61:\t\tdepends on VFIO_PCI_CORE\n  62:\t\n  63:\tsource \"drivers/vfio/pci/mlx5/Kconfig\"\n  64:\t\n  65:\tsource \"drivers/vfio/pci/ism/Kconfig\"\n  66:\t\n  67:\tsource \"drivers/vfio/pci/hisilicon/Kconfig\"\n  68:\t\n  69:\tsource \"drivers/vfio/pci/pds/Kconfig\"\n  70:\t\n  71:\tsource \"drivers/vfio/pci/virtio/Kconfig\"\n  72:\t\n  73:\tsource \"drivers/vfio/pci/nvgrace-gpu/Kconfig\"\n  74:\t\n"
}

15/2 2026/09/11 22:07 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 48320
							output: 31
							thoughts: 200
						

Thoughts:
**Examining the VFIO_PCI_DMABUF Configuration**

Okay, let's dive into this `VFIO_PCI_DMABUF` situation. First, I see it's defined as 'y' if `PCI_P2PDMA` is also set. That makes sense; direct memory access buffer support needs a peer-to-peer DMA setup. This is also dependent on `VFIO_PCI_CORE`, which I'd expect. Now, let's glance at the `drivers/vfio/pci/Makefile`. Aha! `vfio_pci_dmabuf.o` is now unconditionally linked into `vfio-pci-core`! That's a change worth noting.

I know `VFIO_PCI_CORE` also selects `DMA_SHARED_BUFFER`. And now I'm curious what *actually* enables `PCI_P2PDMA`. I think I'll quickly check the `drivers/pci/Kconfig` file to see the configuration dependencies there. This kind of interplay between config options is fascinating, and I know exactly where to look to get the whole picture.



16/2 2026/09/11 22:07 tool grepper
0m Args:
{
  "Expression": "config PCI_P2PDMA",
  "PathPrefix": "drivers/pci"
}

Results:
{
  "Output": "drivers/pci/Kconfig=197=config PCIE_TPH\n--\ndrivers/pci/Kconfig-205-\ndrivers/pci/Kconfig:206:config PCI_P2PDMA\ndrivers/pci/Kconfig-207-\tbool \"PCI peer-to-peer transfer support\"\n"
}

17/2 2026/09/11 22:07 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 48885
							output: 35
							thoughts: 23
						

Thoughts:
Here's my thought process, as requested:

**PCI_P2PDMA Dependencies: A Quick Kconfig Review**

Okay, time to dive in. My immediate thought is, "Let's track down those dependencies for `PCI_P2PDMA`." I know this driver is important, and understanding its dependencies is crucial for a whole bunch of reasons - proper module loading, avoiding conflicts, and ensuring the correct features are enabled in the build. The obvious starting point is the `drivers/pci/Kconfig` file. That's where all the kernel configuration options related to PCI devices reside, and that's exactly where I expect to find the relationships defined for `PCI_P2PDMA`. I need to ensure all the appropriate dependencies are properly set. This will help with debugging and making sure everything works as expected. I'll get to work and make sure this is accurate.



18/2 2026/09/11 22:07 tool read-file
0m Args:
{
  "File": "drivers/pci/Kconfig",
  "FirstLine": 205,
  "LineCount": 25
}

Results:
{
  "Contents": " 205:\t\n 206:\tconfig PCI_P2PDMA\n 207:\t\tbool \"PCI peer-to-peer transfer support\"\n 208:\t\tdepends on ZONE_DEVICE\n 209:\t\t#\n 210:\t\t# The need for the scatterlist DMA bus address flag means PCI P2PDMA\n 211:\t\t# requires 64bit\n 212:\t\t#\n 213:\t\tdepends on 64BIT\n 214:\t\tselect GENERIC_ALLOCATOR\n 215:\t\tselect NEED_SG_DMA_FLAGS\n 216:\t\thelp\n 217:\t\t  Enables drivers to do PCI peer-to-peer transactions to and from\n 218:\t\t  BARs that are exposed in other devices that are the part of\n 219:\t\t  the hierarchy where peer-to-peer DMA is guaranteed by the PCI\n 220:\t\t  specification to work (ie. anything below a single PCI bridge).\n 221:\t\n 222:\t\t  Many PCIe root complexes do not support P2P transactions and\n 223:\t\t  it's hard to tell which support it at all, so at this time,\n 224:\t\t  P2P DMA transactions must be between devices behind the same root\n 225:\t\t  port.\n 226:\t\n 227:\t\t  If unsure, say N.\n 228:\t\n 229:\tconfig PCI_LABEL\n"
}

19/2 2026/09/11 22:07 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 49506
							output: 46
							thoughts: 2073
						

Thoughts:
**Analysis of Kernel Patch for Fuzzing Suitability**

Okay, let's break this down systematically. My initial thought is about the dependencies of `PCI_P2PDMA`, `ZONE_DEVICE`, and `64BIT`, then `VFIO_PCI`, and how it all might relate to syzkaller's capabilities. I'm immediately wondering if syzkaller has support for `VFIO_PCI` specifically, and if it's even enabled in its configurations. The first thing to do is determine if syzkaller even fuzzes VFIO in general. I need to investigate the relevant kernel code – specifically `samples/vfio-mdev`, `drivers/vfio/mdev`, and `drivers/vfio/pci` - to determine the extent of its VFIO coverage. It's likely syzkaller already leverages file operations within `/dev`, which suggests that VFIO is already potentially reachable. I should check directly if a device can be bound to `vfio-pci`.

Now, before getting too far ahead, it's critical to review the defined "Core Triage Philosophy" and "Negative Criteria" from the provided prompt. I need to be absolutely sure what's considered *not* worth fuzzing. I'm focusing specifically on the list of structurally unreachable hardware: "Vendor-specific PCIe switches, SmartNICs, or GPU drivers... requiring physical ASIC/PCIe cards not emulated in standard QEMU". My intuition is that `VFIO_PCI` is *not* a vendor-specific driver. `VFIO_PCI` is the generic VFIO PCI driver (`vfio_pci_core.c`, `vfio_pci_dmabuf.c`, `vfio_pci_config.c`, `vfio_pci.c`) designed to bind to *any* PCI device, even emulated ones. This is the key.

The patch I'm examining directly modifies `drivers/dma-buf/dma-buf.c`, specifically `dma_buf_set_name` and `dma_buf_set_name_user`. The significance is that `dma-buf` is a core, userspace-accessible memory-sharing framework, and syzkaller's existing ioctls cover this functionality. I have to check the patch to see how the name is set and any limitations on this setting. Now I dig in to the code.

Crucially, I'm noting the changes within `dma_buf_set_name_user`. It calls `strndup_user` and then calls `dma_buf_set_name`. In `dma_buf_set_name`, a check now exists to limit the length of the string name. So, before the patch, the code copied the string without bounds. Now, the code now checks if the string length is greater than or equal to `DMA_BUF_NAME_LEN`. The change is returning `-E2BIG` (and frees `name`) now, which is a *behavioral change*. The old code would have worked. The new code returns an error. This definitely warrants fuzzing since it's a functional change in how the kernel handles userspace input via the `dma_buf_ioctl` interface.

Now, let's examine the code for the `vfio_pci` case. I will now examine how this interaction works with `dma-buf`, specifically how `vfio_pci_core` maps BARs (Base Address Registers) into user space using `mmap()`. Before this patch, the VM operations would go to `vfio_pci_mmap_ops`. After the patch, `vfio_pci_core_mmap_prep_dmabuf()` creates a DMA buffer, sets the file associated with the VMA with the DMA buffer's file, and attaches this DMA buffer to the VMA. And `vfio_pci_mmap_huge_fault` handles any potential page faults. A key detail is that `vma->vm_file` now points to the DMA buffer's file, which is a replacement of the original file. This requires a thorough analysis of `drivers/vfio/pci/vfio_pci_core.c`, especially lines 1800-1880, to understand the implications of this change and how data transfer and permissions might be affected, which is likely worth fuzzing.



20/2 2026/09/11 22:07 tool read-file
0m Args:
{
  "File": "drivers/vfio/pci/vfio_pci_core.c",
  "FirstLine": 1800,
  "LineCount": 80
}

Results:
{
  "Contents": "1800:\t\t\t\t\t\t   unsigned int order)\n1801:\t{\n1802:\t\tstruct vm_area_struct *vma = vmf-\u003evma;\n1803:\t\tstruct vfio_pci_dma_buf *priv = vma-\u003evm_private_data;\n1804:\t\tstruct vfio_pci_core_device *vdev;\n1805:\t\tunsigned long pfn = 0;\n1806:\t\tvm_fault_t ret = VM_FAULT_SIGBUS;\n1807:\t\n1808:\t\t/*\n1809:\t\t * The only thing this can rely on is that the DMABUF relating\n1810:\t\t * to the VMA's vm_file exists (priv).\n1811:\t\t *\n1812:\t\t * A DMABUF for a VFIO device fd mmap() holds a reference to\n1813:\t\t * the original VFIO device fd, but an explicitly-exported\n1814:\t\t * DMABUF does not.  The original fd might have closed,\n1815:\t\t * meaning this fault can race with\n1816:\t\t * vfio_pci_dma_buf_cleanup(), meaning the buffer could have\n1817:\t\t * been revoked (in which case priv-\u003evdev might be NULL), and\n1818:\t\t * the VFIO device registration might have been dropped.\n1819:\t\t *\n1820:\t\t * With the goal of taking vdev locks in a world where vdev\n1821:\t\t * might not still exist:\n1822:\t\t *\n1823:\t\t * 1. Take the resv lock on the DMABUF:\n1824:\t\t *  - If racing cleanup got in first, the buffer is revoked;\n1825:\t\t *    stop/exit if so.\n1826:\t\t *  - If we got in first, the buffer is not revoked so vdev is\n1827:\t\t *    non-NULL, accessible, and cleanup _has not yet put the\n1828:\t\t *    VFIO device registration_.  So, the device refcount must\n1829:\t\t *    be \u003e0.\n1830:\t\t *\n1831:\t\t * 2. Take vfio_device registration (refcount guaranteed \u003e0\n1832:\t\t *    hereafter).\n1833:\t\t *\n1834:\t\t * 3. Unlock the DMABUF's resv lock:\n1835:\t\t *  - A racing cleanup can now complete.\n1836:\t\t *  - But, the device refcount \u003e0, meaning the vfio_device\n1837:\t\t *    (and vfio_pcie_core device vdev) have not yet been\n1838:\t\t *    freed.  vdev is accessible, even if the DMABUF has been\n1839:\t\t *    revoked or cleanup has happened, because\n1840:\t\t *    vfio_unregister_group_dev() can't complete.\n1841:\t\t *\n1842:\t\t * 4. Take the vdev-\u003ememory_lock then vdev-\u003edmabuf_lock:\n1843:\t\t *  - Either the DMABUF is usable, or has been cleaned up.\n1844:\t\t *  - It's not necessary to also take the resv lock, because\n1845:\t\t *    the status/vdev can't change while dmabuf_lock is held.\n1846:\t\t *  - Test the DMABUF revocation status again: if it was\n1847:\t\t *    revoked between 1 and 4, return a SIGBUS. Otherwise,\n1848:\t\t *    return a PFN.\n1849:\t\t *\n1850:\t\t * 5. Unlock, done.\n1851:\t\t */\n1852:\t\n1853:\t\tdma_resv_lock(priv-\u003edmabuf-\u003eresv, NULL);\n1854:\t\n1855:\t\tif (priv-\u003estatus != VFIO_PCI_DMABUF_OK) {\n1856:\t\t\tpr_debug_ratelimited(\"%s VA 0x%lx, pgoff 0x%lx: DMABUF revoked/cleaned up\\n\",\n1857:\t\t\t\t\t     __func__, vmf-\u003eaddress, vma-\u003evm_pgoff);\n1858:\t\t\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n1859:\t\t\treturn VM_FAULT_SIGBUS;\n1860:\t\t}\n1861:\t\n1862:\t\t/* If the buffer isn't revoked, vdev is valid */\n1863:\t\tvdev = priv-\u003evdev;\n1864:\t\n1865:\t\tif (!vfio_device_try_get_registration(\u0026vdev-\u003evdev)) {\n1866:\t\t\t/*\n1867:\t\t\t * If vdev != NULL (above), the registration should\n1868:\t\t\t * already be \u003e0 and so this try_get should never\n1869:\t\t\t * fail.\n1870:\t\t\t */\n1871:\t\t\tdev_warn_ratelimited(\u0026vdev-\u003epdev-\u003edev,\n1872:\t\t\t\t\t     \"%s: Unexpected registration failure\\n\",\n1873:\t\t\t\t\t     __func__);\n1874:\t\t\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n1875:\t\t\treturn VM_FAULT_SIGBUS;\n1876:\t\t}\n1877:\t\tdma_resv_unlock(priv-\u003edmabuf-\u003eresv);\n1878:\t\n1879:\t\t/* memory_lock for vfio_pci_vmf_insert_pfn() */\n"
}

21/2 2026/09/11 22:07 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 54012
							output: 32
							thoughts: 2803
						

Thoughts:
**Analysis of DMA-BUF and VFIO Integration for Fuzzing**

Okay, here's the deal: this looks like a goldmine for fuzzing, especially with syzkaller. That fault handler? Prime race condition territory. And `dma_buf_set_name`? Let's see... can it be reached via QEMU and syzkaller? Yup, definitely. We've got VFIO enabled, so `/dev/vfio/vfio` is there, and VFIO devices are accessible. Syzkaller has support for `/dev/vfio`, and `dma_buf_set_name` is accessible through `dma_buf_ioctl` on any DMA-BUF file descriptor. Plus, those new ioctls on VFIO device file descriptors, `VFIO_DEVICE_FEATURE_DMA_BUF` and `VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE`, are definitely relevant.

Based on the triaging philosophy, this is *definitely* worth fuzzing. None of those negative criteria apply. This touches DMA buffer management, VFIO PCI, memory management, complex locking schemes, and a new ioctl feature. No functional change claims here. The code is reachable in QEMU.

Now, we need to extract `FocusSymbols`, `EnableConfigs`, and the `Reasoning`.

First, the `FocusSymbols`. We need to be careful to avoid ubiquitous lifecycle hot-paths, and target specific feature logic and entrypoints. No compiler-inlined static functions either.

Let's start by listing functions in C files:

From `drivers/dma-buf/dma-buf.c`:
- `dma_buf_set_name_user`
- `dma_buf_set_name`

From `drivers/vfio/pci/vfio_pci_core.c`:
- `vfio_pci_mmap_huge_fault` (rewritten)
- `vfio_pci_core_mmap` (modified)
- `vfio_pci_revoke_bars` (static)
- `vfio_pci_lock_revoke_bars`
- `vfio_pci_unrevoke_bars`
- `vfio_pci_core_init_dev`
- `vfio_pci_set_vma_ops`
- `vfio_pci_ioctl_reset` (modified locking/order)
- `vfio_pci_core_runtime_resume`

From `drivers/vfio/pci/vfio_pci_dmabuf.c`:
- `vfio_pci_dma_buf_find_pfn` (new)
- `vfio_pci_core_mmap_prep_dmabuf` (new)
- `vfio_pci_dmabuf_export` (new static helper)
- `vfio_pci_dma_buf_mmap` (new static dma_buf op)
- `vfio_pci_dma_buf_set_status` (new static helper)
- `vfio_pci_core_feature_dma_buf_revoke` (new ioctl feature handler)
- `vfio_pci_dma_buf_move` (modified)
- `vfio_pci_dma_buf_cleanup` (modified)
- `vfio_pci_core_feature_dma_buf` (modified)
- `vfio_pci_dma_buf_release` (modified)

From `drivers/vfio/pci/vfio_pci_config.c`:
- `vfio_basic_config_write`
- `vfio_lock_and_set_power_state`
- `vfio_exp_config_write`
- `vfio_af_config_write`

Okay, let's filter this list down to non-ubiquitous, specific entrypoints. I need to check the symbol table of the compiled kernel to ensure they're relevant, too. Remember to filter out the ubiquitous ones!

After careful consideration and ensuring these functions aren't overly broad:
- `dma_buf_set_name`
- `vfio_pci_core_mmap`
- `vfio_pci_core_mmap_prep_dmabuf`
- `vfio_pci_dma_buf_find_pfn`
- `vfio_pci_core_feature_dma_buf_revoke`
- `vfio_pci_core_feature_dma


22/2 2026/09/11 22:08 tool grepper
0m Args:
{
  "Expression": "dma-buf\\.o",
  "PathPrefix": "drivers/dma-buf"
}

Results:
{
  "Output": "drivers/dma-buf/Makefile-1-# SPDX-License-Identifier: GPL-2.0-only\ndrivers/dma-buf/Makefile:2:obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \\\ndrivers/dma-buf/Makefile-3-\t dma-fence-unwrap.o dma-resv.o dma-buf-mapping.o\n"
}

23/2 2026/09/11 22:08 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 57990
							output: 27
							thoughts: 24
						

Thoughts:
Here's a summary of my thought process, as requested:

**Investigating DMA-BUF Integration**

Okay, so I need to understand how the `drivers/dma-buf` subsystem is integrated into the kernel's build system. My immediate instinct is to check the parent Makefiles. I'll start with the obvious places: the top-level `Makefile` in the `drivers/` directory, and the `Makefile` itself within the `drivers/` directory. I'm looking for clues about how the build system handles including this particular directory and its contents. Does it use the standard `obj-y`, `obj-m`, `subdir-y` directives? Or is there something more specific going on given its fundamental nature? I'm hoping to quickly identify the key variables that determine whether `dma-buf` is built directly into the kernel, built as a module, or even conditionally excluded, and how its object files are ultimately linked. This information will give me a solid foundation for understanding any interactions or dependencies it might have with other subsystems, or any peculiarities in its build configuration.



24/2 2026/09/11 22:08 tool grepper
0m Args:
{
  "Expression": "dma-buf",
  "PathPrefix": "drivers/Makefile"
}

Results:
{
  "Output": "drivers/Makefile=78=obj-y\t\t\t\t+= dax/\ndrivers/Makefile:79:obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/\ndrivers/Makefile-80-obj-$(CONFIG_NUBUS)\t\t+= nubus/\n"
}

25/2 2026/09/11 22:08 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 58346
							output: 32
							thoughts: 46
						

Thoughts:
Okay, here's my take on those thoughts, tailored for an expert audience:

**Investigating a DMA-BUF Dependency**

Right, let's see, the `drivers/dma-buf/` directory seems to be heavily reliant on `CONFIG_DMA_SHARED_BUFFER`. I need to confirm this quickly. Instead of relying on memory, I'll go directly to the source. Let's check the Kconfig file within that directory, specifically `drivers/dma-buf/Kconfig`. I'll confirm that `DMA_SHARED_BUFFER` is indeed a crucial dependency or at least highly relevant to that subsystem. This is the first step in understanding the overall configuration scheme, before delving deeper into the code.



26/2 2026/09/11 22:08 tool grepper
0m Error:
no matches

Args:
{
  "Expression": "config DMA_SHARED_BUFFER",
  "PathPrefix": "drivers/dma-buf"
}

Results:
{
  "error": "no matches"
}

27/2 2026/09/11 22:08 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 58591
							output: 20
							thoughts: 16
						

Thoughts:
Here's my attempt at summarizing the thought process, tailored for an expert audience:

**Investigating `DMA_SHARED_BUFFER` Configuration**

Okay, so I need to track down the definition of `config DMA_SHARED_BUFFER`. This probably means I need to dive into the project's configuration system. Given that `config` suggests it's likely a Kconfig option or a similar configuration macro, my first instinct is to start by searching through the relevant Kconfig files. I'll need to know which directories are most likely to hold device driver or memory management configuration files to narrow my search effectively. A quick `grep` might do the trick, but I’ll need to be precise with my search terms to avoid noise from unrelated occurrences of "DMA" or "SHARED." I may need to expand the search if the initial attempt doesn't reveal the definition, possibly looking for indirect dependencies or related macros. I'm also mindful that this configuration variable could be defined in a generated header file, so I need to keep that possibility in mind as I search. Time to get started.



28/2 2026/09/11 22:08 tool grepper
0m Args:
{
  "Expression": "config DMA_SHARED_BUFFER"
}

Results:
{
  "Output": "drivers/base/Kconfig=213=source \"drivers/base/regmap/Kconfig\"\ndrivers/base/Kconfig-214-\ndrivers/base/Kconfig:215:config DMA_SHARED_BUFFER\ndrivers/base/Kconfig-216-\tbool\n"
}

29/2 2026/09/11 22:08 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 58933
							output: 47
							thoughts: 431
						

Thoughts:
**VFIO_PCI Deep Dive**

Okay, let's break this down systematically. I need to get a handle on the `VFIO_PCI` configuration and associated components. First, I'm checking the `Kconfig` file in the `drivers/vfio/pci` directory. I see `config VFIO_PCI` is a tristate option and it selects `VFIO_PCI_CORE`. Further, `VFIO_PCI_CORE` selects `VFIO_VIRQFD`, `IRQ_BYPASS_MANAGER`, and `DMA_SHARED_BUFFER`. And, crucially, `VFIO_PCI_DMABUF` is defined as a boolean (`def_bool y`) if `PCI_P2PDMA` is enabled and it depends on `VFIO_PCI_CORE`. This dependency structure is pretty standard.

Now, I'm moving over to the `Makefile` in the same directory. I see how the modules are built: `vfio-pci-core-y` gets defined with a list of object files including `vfio_pci_dmabuf.o`. The object itself is included in the build via `obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o` and `obj-$(CONFIG_VFIO_PCI) += vfio-pci.o`. All as expected.

Finally, I'm digging into `vfio_pci_dmabuf.c`. Here's where it gets interesting. I see a lot of conditional compilation using `#ifdef CONFIG_VFIO_PCI_DMABUF`.  `vfio_pci_dma_buf_mmap` is guarded by this preprocessor directive. Also, `vfio_pci_core_feature_dma_buf` and `vfio_pci_core_feature_dma_buf_revoke` are also compiled conditionally based on the same define! I'm going to verify lines 678 and 778 in `vfio_pci_dmabuf.c` right now just to be absolutely sure what's going on.



30/2 2026/09/11 22:08 tool read-file
0m Args:
{
  "File": "drivers/vfio/pci/vfio_pci_dmabuf.c",
  "FirstLine": 775,
  "LineCount": 35
}

Results:
{
  "Contents": " 775:\t\t\tif (!get_file_active(\u0026priv-\u003edmabuf-\u003efile))\n 776:\t\t\t\tcontinue;\n 777:\t\n 778:\t\t\tlist_del_init(\u0026priv-\u003edmabufs_elm);\n 779:\t\t\tWRITE_ONCE(priv-\u003evdev, NULL);\n 780:\t\t\tvfio_device_put_registration(\u0026vdev-\u003evdev);\n 781:\t\t\tfput(priv-\u003edmabuf-\u003efile);\n 782:\t\t}\n 783:\t\tup_write(\u0026vdev-\u003edmabuf_lock);\n 784:\t\tup_write(\u0026vdev-\u003ememory_lock);\n 785:\t}\n 786:\t\n 787:\t#ifdef CONFIG_VFIO_PCI_DMABUF\n 788:\tint vfio_pci_core_feature_dma_buf_revoke(\n 789:\t\tstruct vfio_pci_core_device *vdev, u32 flags,\n 790:\t\tstruct vfio_device_feature_dma_buf_revoke __user *arg,\n 791:\t\tsize_t argsz)\n 792:\t{\n 793:\t\tstruct vfio_device_feature_dma_buf_revoke db_revoke;\n 794:\t\tstruct vfio_pci_dma_buf *priv;\n 795:\t\tstruct dma_buf *dmabuf;\n 796:\t\tint ret;\n 797:\t\n 798:\t\tif (!vdev-\u003epci_ops || !vdev-\u003epci_ops-\u003eget_dmabuf_phys)\n 799:\t\t\treturn -EOPNOTSUPP;\n 800:\t\n 801:\t\tret = vfio_check_feature(flags, argsz,\n 802:\t\t\t\t\t VFIO_DEVICE_FEATURE_SET,\n 803:\t\t\t\t\t sizeof(db_revoke));\n 804:\t\tif (ret != 1)\n 805:\t\t\treturn ret;\n 806:\t\n 807:\t\tif (copy_from_user(\u0026db_revoke, arg, sizeof(db_revoke)))\n 808:\t\t\treturn -EFAULT;\n 809:\t\n"
}

31/2 2026/09/11 22:08 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 60444
							output: 25
							thoughts: 148
						

Thoughts:
**My Kernel Configuration Investigation**

Okay, so `CONFIG_VFIO_PCI_DMABUF` is clearly the key to controlling the behavior of `vfio_pci_core_feature_dma_buf_revoke`. I need to figure out what triggers its activation. Let's dig into the Kconfig options.

Right, `CONFIG_VFIO_PCI_DMABUF` is a `def_bool y if PCI_P2PDMA`. So, its activation depends directly on `PCI_P2PDMA` being enabled, with `VFIO_PCI_CORE` as a prerequisite. 

Now, what about this `CONFIG_PCI_P2PDMA`? That looks to *depend on* both `ZONE_DEVICE` and `64BIT`. Interesting.

Now, where does `ZONE_DEVICE` get enabled? Time to look in `mm/Kconfig` to trace that dependency.



32/2 2026/09/11 22:08 tool grepper
0m Args:
{
  "Expression": "config ZONE_DEVICE",
  "PathPrefix": "mm"
}

Results:
{
  "Output": "mm/Kconfig=1231=config ZONE_DMA32\n--\nmm/Kconfig-1235-\nmm/Kconfig:1236:config ZONE_DEVICE\nmm/Kconfig-1237-\tbool \"Device memory (pmem, HMM, etc...) hotplug support\"\n"
}

33/2 2026/09/11 22:08 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 60901
							output: 33
							thoughts: 17
						

Thoughts:
Here's my thought process, as an expert in my field:

**Diving into Kernel Configuration Dependencies**

Okay, so I need to check the dependencies related to `ZONE_DEVICE` within the `mm/Kconfig` file. I'm immediately thinking about how this relates to memory management, obviously. I'm probably looking for conditional compilation options here – features that are only enabled if `ZONE_DEVICE` is also enabled. I need to understand what other features or configurations hinge on this one. My experience tells me this is likely related to advanced memory configurations or hardware architectures, maybe NUMA setups or specific memory allocation strategies. I'll be looking for relationships with other memory zones, maybe some pre-existing memory management code is being reworked. I want to see how tightly this is integrated into the bigger picture. I'm expecting to see dependencies on other kernel subsystems or features, maybe some interactions with the device driver model. Time to get to it!



34/2 2026/09/11 22:08 tool read-file
0m Args:
{
  "File": "mm/Kconfig",
  "FirstLine": 1235,
  "LineCount": 20
}

Results:
{
  "Contents": "1235:\t\n1236:\tconfig ZONE_DEVICE\n1237:\t\tbool \"Device memory (pmem, HMM, etc...) hotplug support\"\n1238:\t\tdepends on MEMORY_HOTPLUG\n1239:\t\tdepends on MEMORY_HOTREMOVE\n1240:\t\tdepends on SPARSEMEM_VMEMMAP\n1241:\t\tselect XARRAY_MULTI\n1242:\t\n1243:\t\thelp\n1244:\t\t  Device memory hotplug support allows for establishing pmem,\n1245:\t\t  or other device driver discovered memory regions, in the\n1246:\t\t  memmap. This allows pfn_to_page() lookups of otherwise\n1247:\t\t  \"device-physical\" addresses which is needed for DAX, PCI_P2PDMA, and\n1248:\t\t  DEVICE_PRIVATE features among others.\n1249:\t\n1250:\t\t  Enabling this option will reduce the entropy of x86 KASLR memory\n1251:\t\t  regions. For example - on a 46 bit system, the entropy goes down\n1252:\t\t  from 16 bits to 15 bits. The actual reduction in entropy depends\n1253:\t\t  on the physical address bits, on processor features, kernel config\n1254:\t\t  (5 level page table) and physical memory present on the system.\n"
}

35/2 2026/09/11 22:08 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 61505
							output: 33
							thoughts: 61
						

Thoughts:
Here's my thought process, as requested:

**VFIO Module Configuration Deep Dive**

Okay, so I'm thinking about VFIO, and its supporting modules. My mental checklist for this kernel feature is: I need to consider `VFIO`, of course, then the `VFIO_PCI` component which is crucial for PCI device assignment. Following this, I must also take into account `PCI_P2PDMA` for peer-to-peer DMA, along with `ZONE_DEVICE` which manages device memory zones. And finally, I must keep `DMA_SHARED_BUFFER` in my thoughts.

Given that I'm focusing on the configuration aspect, I'll need to double check the kernel config for vfio. So, I need to open up `drivers/vfio/Kconfig` to review the options and dependencies.



36/2 2026/09/11 22:08 tool read-file
0m Args:
{
  "File": "drivers/vfio/Kconfig",
  "FirstLine": 1,
  "LineCount": 25
}

Results:
{
  "Contents": "   1:\t# SPDX-License-Identifier: GPL-2.0-only\n   2:\tmenuconfig VFIO\n   3:\t\ttristate \"VFIO Non-Privileged userspace driver framework\"\n   4:\t\tselect IOMMU_API\n   5:\t\tdepends on IOMMUFD || !IOMMUFD\n   6:\t\tselect INTERVAL_TREE\n   7:\t\tselect VFIO_GROUP if SPAPR_TCE_IOMMU || IOMMUFD=n\n   8:\t\tselect VFIO_DEVICE_CDEV if !VFIO_GROUP\n   9:\t\tselect VFIO_CONTAINER if IOMMUFD=n\n  10:\t\thelp\n  11:\t\t  VFIO provides a framework for secure userspace device drivers.\n  12:\t\t  See Documentation/driver-api/vfio.rst for more details.\n  13:\t\n  14:\t\t  If you don't know what to do here, say N.\n  15:\t\n  16:\tif VFIO\n  17:\tconfig VFIO_DEVICE_CDEV\n  18:\t\tbool \"Support for the VFIO cdev /dev/vfio/devices/vfioX\"\n  19:\t\tdepends on IOMMUFD \u0026\u0026 !SPAPR_TCE_IOMMU\n  20:\t\tdefault !VFIO_GROUP\n  21:\t\thelp\n  22:\t\t  The VFIO device cdev is another way for userspace to get device\n  23:\t\t  access. Userspace gets device fd by opening device cdev under\n  24:\t\t  /dev/vfio/devices/vfioX, and then bind the device fd with an iommufd\n  25:\t\t  to set up secure DMA context for device access.\n"
}

37/2 2026/09/11 22:08 llm patch-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 62202
							output: 425
							thoughts: 854
						

Thoughts:
**My Assessment: VFIO-PCI DMABUF BAR Mapping Fuzzing Readiness**

Okay, let's break this down. I'm looking at this patch and my initial thought is, "This is ripe for fuzzing." I need to be methodical here, so let's walk through my reasoning.

First, I see the key technologies involved: `VFIO`, `VFIO_PCI`, `PCI_P2PDMA`, `ZONE_DEVICE`, and `DMA_SHARED_BUFFER`. These are the building blocks, the core components this revolves around.

Now, let's solidify the specifics. I've got a list of "FocusSymbols." These are the entry points and key functions directly related to this new functionality: `vfio_pci_core_mmap`, `vfio_pci_core_mmap_prep_dmabuf`, `vfio_pci_mmap_huge_fault`, `vfio_pci_dma_buf_find_pfn`, `vfio_pci_core_feature_dma_buf_revoke`, `vfio_pci_core_feature_dma_buf`, `vfio_pci_dma_buf_move`, `vfio_pci_dma_buf_cleanup`, `vfio_pci_lock_revoke_bars`, `vfio_pci_unrevoke_bars`, and `dma_buf_set_name`. I scan this list... nope, nothing generic, nothing that's *not* tightly coupled to this specific VFIO-PCI DMABUF feature. This confirms the focused nature of the changes.

I've also double-checked the configuration requirements: `VFIO`, `VFIO_PCI`, `PCI_P2PDMA`, `ZONE_DEVICE`, and `DMA_SHARED_BUFFER`. All present and accounted for. This is important to ensure fuzzing reaches the right codepaths.

Now, to solidify the argument for fuzzing, I need to articulate this clearly. Here's my reasoning, broken down:

1.  **The Changes are Significant**: This patch fundamentally alters how BAR memory is mapped for VFIO-PCI devices, introducing DMABUF integration. This involves a new VFIO device feature (`VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE`) accessed through ioctls. Critically, it overhauls the fault handling mechanism (`vfio_pci_mmap_huge_fault`) with a complex locking strategy involving `dma_resv_lock`, `vfio_device_try_get_registration`, `memory_lock`, and `dmabuf_lock`. It also exposes a new API call (`dma_buf_set_name`) with length validation for dmabuf naming.
2.  **Reachability is Straightforward**: The code targets virtualized environments (like QEMU on amd64), common use cases for VFIO where PCI devices and the DMA-BUF subsystems are naturally accessible. Userspace interaction is via syscalls like `mmap` and `ioctl` (on VFIO device file descriptors), and `DMA_BUF_SET_NAME` (on DMABUF file descriptors). The attack surface is accessible.
3.  **Fuzzing is Warranted**: Given the scale of these changes, particularly the substantial modifications to mmap/fault handling, the intricate locking invariants, and the critical race conditions inherent in buffer revocation, *plus* the new ioctl interfaces, I'm confident in calling for fuzzing. The likelihood of uncovering subtle memory corruption, locking issues, or subtle race conditions is high.

Therefore, I'm calling it: `set-results`. Time to get some fuzzers running.



38/2 2026/09/11 22:08 tool set-results
0m Args:
{
  "EnableConfigs": [
    "VFIO",
    "VFIO_PCI",
    "PCI_P2PDMA",
    "ZONE_DEVICE",
    "DMA_SHARED_BUFFER"
  ],
  "FocusSymbols": [
    "vfio_pci_core_mmap",
    "vfio_pci_core_mmap_prep_dmabuf",
    "vfio_pci_mmap_huge_fault",
    "vfio_pci_dma_buf_find_pfn",
    "vfio_pci_core_feature_dma_buf_revoke",
    "vfio_pci_core_feature_dma_buf",
    "vfio_pci_dma_buf_move",
    "vfio_pci_dma_buf_cleanup",
    "vfio_pci_lock_revoke_bars",
    "vfio_pci_unrevoke_bars",
    "dma_buf_set_name"
  ],
  "Reasoning": "This patch introduces DMABUF-backed BAR memory mappings for VFIO-PCI devices, refactoring vfio_pci_core_mmap to export DMABUFs and fundamentally reworking vfio_pci_mmap_huge_fault with multi-lock synchronization across dma_resv_lock, vfio_device registration, memory_lock, and dmabuf_lock. It also adds a new user-facing VFIO ioctl feature (VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE) for permanently revoking DMABUFs, and alters dma-buf name assignment logic and length checks in dma-buf.c. The code paths are reachable from userspace in standard QEMU/KVM virtualized environments via VFIO and DMA-BUF interfaces. Given the complex concurrency, locking invariants, mmap fault handling, and new ioctl logic, this patch warrants fuzzing.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "VFIO",
    "VFIO_PCI",
    "PCI_P2PDMA",
    "ZONE_DEVICE",
    "DMA_SHARED_BUFFER"
  ],
  "FocusSymbols": [
    "vfio_pci_core_mmap",
    "vfio_pci_core_mmap_prep_dmabuf",
    "vfio_pci_mmap_huge_fault",
    "vfio_pci_dma_buf_find_pfn",
    "vfio_pci_core_feature_dma_buf_revoke",
    "vfio_pci_core_feature_dma_buf",
    "vfio_pci_dma_buf_move",
    "vfio_pci_dma_buf_cleanup",
    "vfio_pci_lock_revoke_bars",
    "vfio_pci_unrevoke_bars",
    "dma_buf_set_name"
  ],
  "Reasoning": "This patch introduces DMABUF-backed BAR memory mappings for VFIO-PCI devices, refactoring vfio_pci_core_mmap to export DMABUFs and fundamentally reworking vfio_pci_mmap_huge_fault with multi-lock synchronization across dma_resv_lock, vfio_device registration, memory_lock, and dmabuf_lock. It also adds a new user-facing VFIO ioctl feature (VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE) for permanently revoking DMABUFs, and alters dma-buf name assignment logic and length checks in dma-buf.c. The code paths are reachable from userspace in standard QEMU/KVM virtualized environments via VFIO and DMA-BUF interfaces. Given the complex concurrency, locking invariants, mmap fault handling, and new ioctl logic, this patch warrants fuzzing.",
  "WorthFuzzing": true
}

39/1 2026/09/11 22:08 action If
0m Args:
{
  "WorthFuzzing": true
}

Results:
null

40/2 2026/09/11 22:08 agent kmsan-evaluator
0m Model:
core

Args:
null

Results:
{
  "KMSANReasoning": "The patch refactors dma_buf name handling and integrates DMABUF-backed PCI BAR mapping and revocation into the VFIO PCI core (including the new VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE ioctl feature and rewritten page fault handling).\n\nAnalysis with respect to uninitialized memory (KMSAN):\n1. Kernel-to-user info leaks: The new ioctl feature VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE only performs a copy_from_user() on input arguments; no kernel data is returned or copied to user space. DMA-buf naming via dma_buf_set_name_user() safely copies strings from userspace using strndup_user() and names allocated with kasprintf() are fully initialized.\n2. Uninitialized variables / fields: All heap allocations for vfio_pci_dma_buf and its phys_vec array use kzalloc_obj(), ensuring zero-initialization. All stack variables in the new/modified functions (e.g., pres, pfn, ret, fault_offset) are initialized before use. New struct fields on vfio_pci_core_device (dmabuf_lock, bars_revoked, zap_bars_on_revoke) are explicitly initialized during device init/enable.\n3. Fault handling: The PFN resolution logic operates on PCI MMIO resource addresses rather than uninitialized kernel memory pages.\n\nContrast with KASAN/LOCKDEP:\nThe risks introduced by this change center on synchronization, reference counting (kref, dma_buf, vfio_device registration, eventfd_ctx), locking hierarchies (memory_lock vs dmabuf_lock vs dma_resv lock), and potential use-after-free or race conditions during device reset, revocation, or unmap. These classes of bugs are comprehensively covered by KASAN and LOCKDEP in standard fuzzing builds. There are no uninitialized memory risks that would uniquely warrant a KMSAN session.",
  "NeedsKMSAN": false
}

Instruction:
You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.

CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
  a comprehensive suite of debugging tools and sanitizers, including KASAN
  (out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
  (locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
  or page allocations) and kernel-to-user memory info-leaks.

Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.

Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.

Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
   attributes, ioctl output arguments, socket options, or BPF buffers) where fields
   or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
   or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
   could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
   uninitialized bytes of existing buffers.

Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
  dereferences, locking deadlocks, or use-after-free bugs (these are already caught
  by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
  or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.

Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
Target architecture: amd64

For your convenience, here is the diff of the changes:
commit 4181b909f1f9301a41044499b4f86a52a0c71e2f
Author: syz-cluster <triage@syzkaller.com>
Date:   Fri Sep 11 22:06:41 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index d504c636dc294..8129ea11ff58c 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -405,31 +405,29 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
 }
 
 /**
- * dma_buf_set_name - Set a name to a specific dma_buf to track the usage.
- * It could support changing the name of the dma-buf if the same
- * piece of memory is used for multiple purpose between different devices.
+ * dma_buf_set_name_user - Set a dma_buf's name from a user string
+ *
+ * The string is up to DMA_BUF_NAME_LEN long, including the terminator.
  *
  * @dmabuf: [in]     dmabuf buffer that will be renamed.
  * @buf:    [in]     A piece of userspace memory that contains the name of
  *                   the dma-buf.
  *
- * Returns 0 on success. If the dma-buf buffer is already attached to
- * devices, return -EBUSY.
- *
+ * Returns 0 on success, and any previously-set name is freed.
  */
-static long dma_buf_set_name(struct dma_buf *dmabuf, const char __user *buf)
+static long dma_buf_set_name_user(struct dma_buf *dmabuf, const char __user *buf)
 {
 	char *name = strndup_user(buf, DMA_BUF_NAME_LEN);
+	int ret;
 
 	if (IS_ERR(name))
 		return PTR_ERR(name);
 
-	spin_lock(&dmabuf->name_lock);
-	kfree(dmabuf->name);
-	dmabuf->name = name;
-	spin_unlock(&dmabuf->name_lock);
+	ret = dma_buf_set_name(dmabuf, name);
+	if (ret)
+		kfree(name);
 
-	return 0;
+	return ret;
 }
 
 #if IS_ENABLED(CONFIG_SYNC_FILE)
@@ -578,7 +576,7 @@ static long dma_buf_ioctl(struct file *file,
 
 	case DMA_BUF_SET_NAME_A:
 	case DMA_BUF_SET_NAME_B:
-		return dma_buf_set_name(dmabuf, (const char __user *)arg);
+		return dma_buf_set_name_user(dmabuf, (const char __user *)arg);
 
 #if IS_ENABLED(CONFIG_SYNC_FILE)
 	case DMA_BUF_IOCTL_EXPORT_SYNC_FILE:
@@ -854,6 +852,40 @@ void dma_buf_put(struct dma_buf *dmabuf)
 }
 EXPORT_SYMBOL_NS_GPL(dma_buf_put, "DMA_BUF");
 
+/**
+ * dma_buf_set_name - Set a dma_buf's name
+ * It could support changing the name of the dma-buf if the same piece
+ * of memory is used for multiple purpose between different devices.
+ *
+ * @dmabuf: [in]     dmabuf buffer that will be renamed.
+ * @name:   [in]     The name of the dma-buf, allocated with kmalloc() or
+ *                   similar.  This takes ownership of the allocation
+ *                   on success, which will be kfree()d when the
+ *                   dmabuf is released or a new name assigned.
+ *
+ * Returns 0 on success, -EINVAL if the name is NULL, or -E2BIG if the
+ * name exceeds DMA_BUF_NAME_LEN.
+ */
+int dma_buf_set_name(struct dma_buf *dmabuf, char *name)
+{
+	if (!name)
+		return -EINVAL;
+
+	/* dmabuffs_dname() won't use the string if the length
+	 * (including terminator) exceeds DMA_BUF_NAME_LEN:
+	 */
+	if (strlen(name) >= DMA_BUF_NAME_LEN)
+		return -E2BIG;
+
+	spin_lock(&dmabuf->name_lock);
+	kfree(dmabuf->name);
+	dmabuf->name = name;
+	spin_unlock(&dmabuf->name_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(dma_buf_set_name, "DMA_BUF");
+
 static int dma_buf_wrap_sg_table(struct sg_table **sg_table)
 {
 	struct scatterlist *to_sg, *from_sg;
diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig
index 296bf01e185ec..c6d6fb09af86c 100644
--- a/drivers/vfio/pci/Kconfig
+++ b/drivers/vfio/pci/Kconfig
@@ -6,6 +6,7 @@ config VFIO_PCI_CORE
 	tristate
 	select VFIO_VIRQFD
 	select IRQ_BYPASS_MANAGER
+	select DMA_SHARED_BUFFER
 
 config VFIO_PCI_INTX
 	def_bool y if !S390
@@ -56,7 +57,8 @@ config VFIO_PCI_ZDEV_KVM
 	  To enable s390x KVM vfio-pci extensions, say Y.
 
 config VFIO_PCI_DMABUF
-	def_bool y if VFIO_PCI_CORE && PCI_P2PDMA && DMA_SHARED_BUFFER
+	def_bool y if PCI_P2PDMA
+	depends on VFIO_PCI_CORE
 
 source "drivers/vfio/pci/mlx5/Kconfig"
 
diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile
index 6138f1bf241df..881452ea89be0 100644
--- a/drivers/vfio/pci/Makefile
+++ b/drivers/vfio/pci/Makefile
@@ -1,8 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-vfio-pci-core-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o
+vfio-pci-core-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o vfio_pci_dmabuf.o
 vfio-pci-core-$(CONFIG_VFIO_PCI_ZDEV_KVM) += vfio_pci_zdev.o
-vfio-pci-core-$(CONFIG_VFIO_PCI_DMABUF) += vfio_pci_dmabuf.o
 obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o
 
 vfio-pci-y := vfio_pci.o
diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
index 86362ec424a50..14622556355eb 100644
--- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
+++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
@@ -1564,6 +1564,7 @@ static int hisi_acc_vfio_pci_migrn_init_dev(struct vfio_device *core_vdev)
 	struct hisi_acc_vf_core_device *hisi_acc_vdev = hisi_acc_get_vf_dev(core_vdev);
 	struct pci_dev *pdev = to_pci_dev(core_vdev->dev);
 	struct hisi_qm *pf_qm = hisi_acc_get_pf_qm(pdev);
+	int ret;
 
 	hisi_acc_vdev->vf_id = pci_iov_vf_id(pdev) + 1;
 	hisi_acc_vdev->pf_qm = pf_qm;
@@ -1575,7 +1576,18 @@ static int hisi_acc_vfio_pci_migrn_init_dev(struct vfio_device *core_vdev)
 	core_vdev->migration_flags = VFIO_MIGRATION_STOP_COPY | VFIO_MIGRATION_PRE_COPY;
 	core_vdev->mig_ops = &hisi_acc_vfio_pci_migrn_state_ops;
 
-	return vfio_pci_core_init_dev(core_vdev);
+	ret = vfio_pci_core_init_dev(core_vdev);
+	if (ret)
+		return ret;
+	/*
+	 * hisi_acc_vfio_pci_mmap() calls down to
+	 * vfio_pci_core_mmap(), so BAR mappings are still
+	 * DMABUF-backed.  They don't require a zap on revoke, so opt
+	 * out:
+	 */
+	hisi_acc_vdev->core_device.zap_bars_on_revoke = false;
+
+	return 0;
 }
 
 static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = {
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index a10ed733f0e3a..bc6ccb2e135c3 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -590,12 +590,10 @@ static int vfio_basic_config_write(struct vfio_pci_core_device *vdev, int pos,
 		virt_mem = !!(le16_to_cpu(*virt_cmd) & PCI_COMMAND_MEMORY);
 		new_mem = !!(new_cmd & PCI_COMMAND_MEMORY);
 
-		if (!new_mem) {
-			vfio_pci_zap_and_down_write_memory_lock(vdev);
-			vfio_pci_dma_buf_move(vdev, true);
-		} else {
+		if (!new_mem)
+			vfio_pci_lock_revoke_bars(vdev);
+		else
 			down_write(&vdev->memory_lock);
-		}
 
 		/*
 		 * If the user is writing mem/io enable (new_mem/io) and we
@@ -631,7 +629,7 @@ static int vfio_basic_config_write(struct vfio_pci_core_device *vdev, int pos,
 		*virt_cmd |= cpu_to_le16(new_cmd & mask);
 
 		if (__vfio_pci_memory_enabled(vdev))
-			vfio_pci_dma_buf_move(vdev, false);
+			vfio_pci_unrevoke_bars(vdev);
 		up_write(&vdev->memory_lock);
 	}
 
@@ -712,16 +710,14 @@ static int __init init_pci_cap_basic_perm(struct perm_bits *perm)
 static void vfio_lock_and_set_power_state(struct vfio_pci_core_device *vdev,
 					  pci_power_t state)
 {
-	if (state >= PCI_D3hot) {
-		vfio_pci_zap_and_down_write_memory_lock(vdev);
-		vfio_pci_dma_buf_move(vdev, true);
-	} else {
+	if (state >= PCI_D3hot)
+		vfio_pci_lock_revoke_bars(vdev);
+	else
 		down_write(&vdev->memory_lock);
-	}
 
 	vfio_pci_set_power_state(vdev, state);
 	if (__vfio_pci_memory_enabled(vdev))
-		vfio_pci_dma_buf_move(vdev, false);
+		vfio_pci_unrevoke_bars(vdev);
 	up_write(&vdev->memory_lock);
 }
 
@@ -908,11 +904,10 @@ static int vfio_exp_config_write(struct vfio_pci_core_device *vdev, int pos,
 						 &cap);
 
 		if (!ret && (cap & PCI_EXP_DEVCAP_FLR)) {
-			vfio_pci_zap_and_down_write_memory_lock(vdev);
-			vfio_pci_dma_buf_move(vdev, true);
+			vfio_pci_lock_revoke_bars(vdev);
 			pci_try_reset_function(vdev->pdev);
 			if (__vfio_pci_memory_enabled(vdev))
-				vfio_pci_dma_buf_move(vdev, false);
+				vfio_pci_unrevoke_bars(vdev);
 			up_write(&vdev->memory_lock);
 		}
 	}
@@ -993,11 +988,10 @@ static int vfio_af_config_write(struct vfio_pci_core_device *vdev, int pos,
 						&cap);
 
 		if (!ret && (cap & PCI_AF_CAP_FLR) && (cap & PCI_AF_CAP_TP)) {
-			vfio_pci_zap_and_down_write_memory_lock(vdev);
-			vfio_pci_dma_buf_move(vdev, true);
+			vfio_pci_lock_revoke_bars(vdev);
 			pci_try_reset_function(vdev->pdev);
 			if (__vfio_pci_memory_enabled(vdev))
-				vfio_pci_dma_buf_move(vdev, false);
+				vfio_pci_unrevoke_bars(vdev);
 			up_write(&vdev->memory_lock);
 		}
 	}
diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
index 3f11a9624b9c0..911e248aa764f 100644
--- a/drivers/vfio/pci/vfio_pci_core.c
+++ b/drivers/vfio/pci/vfio_pci_core.c
@@ -13,6 +13,8 @@
 #include <linux/aperture.h>
 #include <linux/debugfs.h>
 #include <linux/device.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-resv.h>
 #include <linux/eventfd.h>
 #include <linux/file.h>
 #include <linux/interrupt.h>
@@ -375,8 +377,7 @@ static int vfio_pci_runtime_pm_entry(struct vfio_pci_core_device *vdev,
 	 * The vdev power related flags are protected with 'memory_lock'
 	 * semaphore.
 	 */
-	vfio_pci_zap_and_down_write_memory_lock(vdev);
-	vfio_pci_dma_buf_move(vdev, true);
+	vfio_pci_lock_revoke_bars(vdev);
 
 	if (vdev->pm_runtime_engaged) {
 		up_write(&vdev->memory_lock);
@@ -462,7 +463,7 @@ static void vfio_pci_runtime_pm_exit(struct vfio_pci_core_device *vdev)
 	down_write(&vdev->memory_lock);
 	__vfio_pci_runtime_pm_exit(vdev);
 	if (__vfio_pci_memory_enabled(vdev))
-		vfio_pci_dma_buf_move(vdev, false);
+		vfio_pci_unrevoke_bars(vdev);
 	up_write(&vdev->memory_lock);
 }
 
@@ -526,8 +527,14 @@ static int vfio_pci_core_runtime_resume(struct device *dev)
 	 */
 	down_write(&vdev->memory_lock);
 	if (vdev->pm_wake_eventfd_ctx) {
-		eventfd_signal(vdev->pm_wake_eventfd_ctx);
+		struct eventfd_ctx *ctx = vdev->pm_wake_eventfd_ctx;
+
+		vdev->pm_wake_eventfd_ctx = NULL;
 		__vfio_pci_runtime_pm_exit(vdev);
+		if (__vfio_pci_memory_enabled(vdev))
+			vfio_pci_unrevoke_bars(vdev);
+		eventfd_signal(ctx);
+		eventfd_ctx_put(ctx);
 	}
 	up_write(&vdev->memory_lock);
 
@@ -659,6 +666,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev)
 		vdev->has_vga = true;
 
 	vfio_pci_core_map_bars(vdev);
+	vdev->bars_revoked = false;
 
 	return 0;
 
@@ -1312,6 +1320,8 @@ static int vfio_pci_ioctl_set_irqs(struct vfio_pci_core_device *vdev,
 	return ret;
 }
 
+static void vfio_pci_revoke_bars(struct vfio_pci_core_device *vdev);
+
 static int vfio_pci_ioctl_reset(struct vfio_pci_core_device *vdev,
 				void __user *arg)
 {
@@ -1320,7 +1330,7 @@ static int vfio_pci_ioctl_reset(struct vfio_pci_core_device *vdev,
 	if (!vdev->reset_works)
 		return -EINVAL;
 
-	vfio_pci_zap_and_down_write_memory_lock(vdev);
+	down_write(&vdev->memory_lock);
 
 	/*
 	 * This function can be invoked while the power state is non-D0. If
@@ -1330,13 +1340,18 @@ static int vfio_pci_ioctl_reset(struct vfio_pci_core_device *vdev,
 	 * have NoSoftRst-, the reset function can cause the PCI config space
 	 * reset without restoring the original state (saved locally in
 	 * 'vdev->pm_save').
+	 *
+	 * The zap is done after making the device accessible in D0,
+	 * because a DMABUF importer could access the device as part
+	 * of its revocation cleanup.
 	 */
 	vfio_pci_set_power_state(vdev, PCI_D0);
 
-	vfio_pci_dma_buf_move(vdev, true);
+	vfio_pci_revoke_bars(vdev);
+
 	ret = pci_try_reset_function(vdev->pdev);
 	if (__vfio_pci_memory_enabled(vdev))
-		vfio_pci_dma_buf_move(vdev, false);
+		vfio_pci_unrevoke_bars(vdev);
 	up_write(&vdev->memory_lock);
 
 	return ret;
@@ -1625,6 +1640,8 @@ int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags,
 		return vfio_pci_core_feature_token(vdev, flags, arg, argsz);
 	case VFIO_DEVICE_FEATURE_DMA_BUF:
 		return vfio_pci_core_feature_dma_buf(vdev, flags, arg, argsz);
+	case VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE:
+		return vfio_pci_core_feature_dma_buf_revoke(vdev, flags, arg, argsz);
 	default:
 		return -ENOTTY;
 	}
@@ -1704,20 +1721,37 @@ ssize_t vfio_pci_core_write(struct vfio_device *core_vdev, const char __user *bu
 }
 EXPORT_SYMBOL_GPL(vfio_pci_core_write);
 
-static void vfio_pci_zap_bars(struct vfio_pci_core_device *vdev)
+static void vfio_pci_revoke_bars(struct vfio_pci_core_device *vdev)
 {
-	struct vfio_device *core_vdev = &vdev->vdev;
-	loff_t start = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_BAR0_REGION_INDEX);
-	loff_t end = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_ROM_REGION_INDEX);
-	loff_t len = end - start;
+	lockdep_assert_held_write(&vdev->memory_lock);
+	vfio_pci_dma_buf_move(vdev, true);
 
-	unmap_mapping_range(core_vdev->inode->i_mapping, start, len, true);
+	/*
+	 * If a driver could possibly create BAR mappings in the
+	 * vdev's address_space, do an additional zap on revoke.  See
+	 * vfio_pci_core_init_dev().
+	 */
+	if (vdev->zap_bars_on_revoke) {
+		struct vfio_device *core_vdev = &vdev->vdev;
+		loff_t start = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_BAR0_REGION_INDEX);
+		loff_t end = VFIO_PCI_INDEX_TO_OFFSET(VFIO_PCI_ROM_REGION_INDEX);
+		loff_t len = end - start;
+
+		unmap_mapping_range(core_vdev->inode->i_mapping,
+				    start, len, true);
+	}
 }
 
-void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_core_device *vdev)
+void vfio_pci_lock_revoke_bars(struct vfio_pci_core_device *vdev)
 {
 	down_write(&vdev->memory_lock);
-	vfio_pci_zap_bars(vdev);
+	vfio_pci_revoke_bars(vdev);
+}
+
+void vfio_pci_unrevoke_bars(struct vfio_pci_core_device *vdev)
+{
+	lockdep_assert_held_write(&vdev->memory_lock);
+	vfio_pci_dma_buf_move(vdev, false);
 }
 
 u16 vfio_pci_memory_lock_and_enable(struct vfio_pci_core_device *vdev)
@@ -1739,18 +1773,6 @@ void vfio_pci_memory_unlock_and_restore(struct vfio_pci_core_device *vdev, u16 c
 	up_write(&vdev->memory_lock);
 }
 
-static unsigned long vma_to_pfn(struct vm_area_struct *vma)
-{
-	struct vfio_pci_core_device *vdev = vma->vm_private_data;
-	int index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);
-	u64 pgoff;
-
-	pgoff = vma->vm_pgoff &
-		((1U << (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
-
-	return (pci_resource_start(vdev->pdev, index) >> PAGE_SHIFT) + pgoff;
-}
-
 vm_fault_t vfio_pci_vmf_insert_pfn(struct vfio_pci_core_device *vdev,
 				   struct vm_fault *vmf,
 				   unsigned long pfn,
@@ -1778,24 +1800,106 @@ static vm_fault_t vfio_pci_mmap_huge_fault(struct vm_fault *vmf,
 					   unsigned int order)
 {
 	struct vm_area_struct *vma = vmf->vma;
-	struct vfio_pci_core_device *vdev = vma->vm_private_data;
-	unsigned long addr = vmf->address & ~((PAGE_SIZE << order) - 1);
-	unsigned long pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
-	unsigned long pfn = vma_to_pfn(vma) + pgoff;
-	vm_fault_t ret = VM_FAULT_FALLBACK;
-
-	if (is_aligned_for_order(vma, addr, pfn, order)) {
-		scoped_guard(rwsem_read, &vdev->memory_lock)
-			ret = vfio_pci_vmf_insert_pfn(vdev, vmf, pfn, order);
+	struct vfio_pci_dma_buf *priv = vma->vm_private_data;
+	struct vfio_pci_core_device *vdev;
+	unsigned long pfn = 0;
+	vm_fault_t ret = VM_FAULT_SIGBUS;
+
+	/*
+	 * The only thing this can rely on is that the DMABUF relating
+	 * to the VMA's vm_file exists (priv).
+	 *
+	 * A DMABUF for a VFIO device fd mmap() holds a reference to
+	 * the original VFIO device fd, but an explicitly-exported
+	 * DMABUF does not.  The original fd might have closed,
+	 * meaning this fault can race with
+	 * vfio_pci_dma_buf_cleanup(), meaning the buffer could have
+	 * been revoked (in which case priv->vdev might be NULL), and
+	 * the VFIO device registration might have been dropped.
+	 *
+	 * With the goal of taking vdev locks in a world where vdev
+	 * might not still exist:
+	 *
+	 * 1. Take the resv lock on the DMABUF:
+	 *  - If racing cleanup got in first, the buffer is revoked;
+	 *    stop/exit if so.
+	 *  - If we got in first, the buffer is not revoked so vdev is
+	 *    non-NULL, accessible, and cleanup _has not yet put the
+	 *    VFIO device registration_.  So, the device refcount must
+	 *    be >0.
+	 *
+	 * 2. Take vfio_device registration (refcount guaranteed >0
+	 *    hereafter).
+	 *
+	 * 3. Unlock the DMABUF's resv lock:
+	 *  - A racing cleanup can now complete.
+	 *  - But, the device refcount >0, meaning the vfio_device
+	 *    (and vfio_pcie_core device vdev) have not yet been
+	 *    freed.  vdev is accessible, even if the DMABUF has been
+	 *    revoked or cleanup has happened, because
+	 *    vfio_unregister_group_dev() can't complete.
+	 *
+	 * 4. Take the vdev->memory_lock then vdev->dmabuf_lock:
+	 *  - Either the DMABUF is usable, or has been cleaned up.
+	 *  - It's not necessary to also take the resv lock, because
+	 *    the status/vdev can't change while dmabuf_lock is held.
+	 *  - Test the DMABUF revocation status again: if it was
+	 *    revoked between 1 and 4, return a SIGBUS. Otherwise,
+	 *    return a PFN.
+	 *
+	 * 5. Unlock, done.
+	 */
+
+	dma_resv_lock(priv->dmabuf->resv, NULL);
+
+	if (priv->status != VFIO_PCI_DMABUF_OK) {
+		pr_debug_ratelimited("%s VA 0x%lx, pgoff 0x%lx: DMABUF revoked/cleaned up\n",
+				     __func__, vmf->address, vma->vm_pgoff);
+		dma_resv_unlock(priv->dmabuf->resv);
+		return VM_FAULT_SIGBUS;
+	}
+
+	/* If the buffer isn't revoked, vdev is valid */
+	vdev = priv->vdev;
+
+	if (!vfio_device_try_get_registration(&vdev->vdev)) {
+		/*
+		 * If vdev != NULL (above), the registration should
+		 * already be >0 and so this try_get should never
+		 * fail.
+		 */
+		dev_warn_ratelimited(&vdev->pdev->dev,
+				     "%s: Unexpected registration failure\n",
+				     __func__);
+		dma_resv_unlock(priv->dmabuf->resv);
+		return VM_FAULT_SIGBUS;
+	}
+	dma_resv_unlock(priv->dmabuf->resv);
+
+	/* memory_lock for vfio_pci_vmf_insert_pfn() */
+	down_read(&vdev->memory_lock);
+	/* Re-test revocation status under dmabuf_lock */
+	down_read(&vdev->dmabuf_lock);
+	if (priv->status == VFIO_PCI_DMABUF_OK) {
+		int pres = vfio_pci_dma_buf_find_pfn(vdev, priv, vma,
+						     vmf->address,
+						     order, &pfn);
+
+		if (pres == 0)
+			ret = vfio_pci_vmf_insert_pfn(vdev, vmf,
+						      pfn, order);
+		else if (pres == -ERANGE)
+			ret = VM_FAULT_FALLBACK;
 	}
+	up_read(&vdev->dmabuf_lock);
+	up_read(&vdev->memory_lock);
 
 	dev_dbg_ratelimited(&vdev->pdev->dev,
-			   "%s(,order = %d) BAR %ld page offset 0x%lx: 0x%x\n",
-			    __func__, order,
-			    vma->vm_pgoff >>
-				(VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT),
-			    pgoff, (unsigned int)ret);
+			    "%s(order = %d) PFN 0x%lx, VA 0x%lx, pgoff 0x%lx: 0x%x\n",
+			    __func__, order, pfn, vmf->address,
+			    vma->vm_pgoff, (unsigned int)ret);
 
+	vfio_device_put_registration(&vdev->vdev);
 	return ret;
 }
 
@@ -1811,6 +1915,11 @@ static const struct vm_operations_struct vfio_pci_mmap_ops = {
 #endif
 };
 
+void vfio_pci_set_vma_ops(struct vm_area_struct *vma)
+{
+	vma->vm_ops = &vfio_pci_mmap_ops;
+}
+
 int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma)
 {
 	struct vfio_pci_core_device *vdev =
@@ -1819,6 +1928,7 @@ int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma
 	unsigned int index;
 	u64 phys_len, req_len, pgoff, req_start;
 	void __iomem *bar_io;
+	int ret;
 
 	index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);
 
@@ -1858,7 +1968,12 @@ int vfio_pci_core_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma
 	if (IS_ERR(bar_io))
 		return PTR_ERR(bar_io);
 
-	vma->vm_private_data = vdev;
+	ret = vfio_pci_core_mmap_prep_dmabuf(vdev, vma,
+					     pci_resource_start(pdev, index),
+					     req_len, index);
+	if (ret)
+		return ret;
+
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
 
@@ -2195,8 +2310,19 @@ int vfio_pci_core_init_dev(struct vfio_device *core_vdev)
 		return ret;
 	INIT_LIST_HEAD(&vdev->dmabufs);
 	init_rwsem(&vdev->memory_lock);
+	init_rwsem(&vdev->dmabuf_lock);
 	xa_init(&vdev->ctx);
 
+	/*
+	 * If a driver overrides .mmap, it has to be assumed that it
+	 * might not use the DMABUF-backed core mmap; this flag
+	 * enables a zap at revoke time.  A driver can opt out by
+	 * clearing this flag at init, if their .mmap override calls
+	 * down to vfio_pci_core_mmap().
+	 */
+	if (vdev->vdev.ops->mmap != vfio_pci_core_mmap)
+		vdev->zap_bars_on_revoke = true;
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(vfio_pci_core_init_dev);
@@ -2564,9 +2690,10 @@ static int vfio_pci_dev_set_hot_reset(struct vfio_device_set *dev_set,
 		}
 
 		/*
-		 * Take the memory write lock for each device and zap BAR
-		 * mappings to prevent the user accessing the device while in
-		 * reset.  Locking multiple devices is prone to deadlock,
+		 * Take the memory write lock for each device and
+		 * zap/revoke BAR mappings to prevent the user (or
+		 * peers) accessing the device while in reset.
+		 * Locking multiple devices is prone to deadlock,
 		 * runaway and unwind if we hit contention.
 		 */
 		if (!down_write_trylock(&vdev->memory_lock)) {
@@ -2574,8 +2701,7 @@ static int vfio_pci_dev_set_hot_reset(struct vfio_device_set *dev_set,
 			break;
 		}
 
-		vfio_pci_dma_buf_move(vdev, true);
-		vfio_pci_zap_bars(vdev);
+		vfio_pci_revoke_bars(vdev);
 	}
 
 	if (!list_entry_is_head(vdev,
@@ -2605,7 +2731,7 @@ static int vfio_pci_dev_set_hot_reset(struct vfio_device_set *dev_set,
 	list_for_each_entry_from_reverse(vdev, &dev_set->device_list,
 					 vdev.dev_set_list) {
 		if (vdev->vdev.open_count && __vfio_pci_memory_enabled(vdev))
-			vfio_pci_dma_buf_move(vdev, false);
+			vfio_pci_unrevoke_bars(vdev);
 		up_write(&vdev->memory_lock);
 	}
 
diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci_dmabuf.c
index c16f460c01d68..7cda2bd00d25a 100644
--- a/drivers/vfio/pci/vfio_pci_dmabuf.c
+++ b/drivers/vfio/pci/vfio_pci_dmabuf.c
@@ -3,25 +3,14 @@
  */
 #include <linux/dma-buf-mapping.h>
 #include <linux/pci-p2pdma.h>
+#include <linux/dma-buf.h>
 #include <linux/dma-resv.h>
 
 #include "vfio_pci_priv.h"
 
 MODULE_IMPORT_NS("DMA_BUF");
 
-struct vfio_pci_dma_buf {
-	struct dma_buf *dmabuf;
-	struct vfio_pci_core_device *vdev;
-	struct list_head dmabufs_elm;
-	size_t size;
-	struct phys_vec *phys_vec;
-	struct p2pdma_provider *provider;
-	u32 nr_ranges;
-	struct kref kref;
-	struct completion comp;
-	u8 revoked : 1;
-};
-
+#ifdef CONFIG_VFIO_PCI_DMABUF
 static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,
 				   struct dma_buf_attachment *attachment)
 {
@@ -30,7 +19,7 @@ static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,
 	if (!attachment->peer2peer)
 		return -EOPNOTSUPP;
 
-	if (priv->revoked)
+	if (READ_ONCE(priv->status) != VFIO_PCI_DMABUF_OK)
 		return -ENODEV;
 
 	if (!dma_buf_attach_revocable(attachment))
@@ -39,6 +28,62 @@ static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,
 	return 0;
 }
 
+static int vfio_pci_dma_buf_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
+{
+	struct vfio_pci_dma_buf *priv = dmabuf->priv;
+
+	/*
+	 * dma_buf_mmap_internal() has asserted that the VMA is
+	 * contained within the DMABUF size before calling this.
+	 *
+	 * Also, if we observe that the buffer is revoked now then
+	 * refuse the mmap().  This is a belt-and-braces early failure
+	 * to ease debugging a revoked buffer being used.  Userspace
+	 * might also race an mmap() against an explicit revocation,
+	 * or an action doing a temporary revoke; race scenarios are
+	 * still safe because the fault handler ultimately prevents
+	 * access to a revoked buffer if it isn't caught here.
+	 */
+	if (READ_ONCE(priv->status) != VFIO_PCI_DMABUF_OK)
+		return -ENODEV;
+	/*
+	 * Make clear that anything with an offset adjustment is
+	 * explicitly unsupported, as vfio_pci_dma_buf_find_pfn()
+	 * maths would underflow; this doesn't happen through the
+	 * regular DMABUF export path used with this mmap().  A DMABUF
+	 * implicitly created for BAR mmap could have adjust > 0, but
+	 * these can't currently be re-opened and mmap()ed again.
+	 * Catch here in case that assumption ever changes.
+	 */
+	if (priv->vma_pgoff_adjust)
+		return -EINVAL;
+	if ((vma->vm_flags & VM_SHARED) == 0)
+		return -EINVAL;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot);
+
+	/* See comments in vfio_pci_core_mmap() re VM_ALLOW_ANY_UNCACHED. */
+	vm_flags_set(vma, VM_ALLOW_ANY_UNCACHED | VM_IO | VM_PFNMAP |
+		     VM_DONTEXPAND | VM_DONTDUMP);
+	vma->vm_private_data = priv;
+	vfio_pci_set_vma_ops(vma);
+
+	return 0;
+}
+#else
+static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,
+				   struct dma_buf_attachment *attachment)
+{
+	/*
+	 * Explicit export can't occur without the DMABUF feature, but
+	 * DMABUFs are implicitly created for BAR mappings.  An
+	 * .attach that fails prevents dma_buf_attach().
+	 */
+	return -EOPNOTSUPP;
+}
+#endif /* CONFIG_VFIO_PCI_DMABUF */
+
 static void vfio_pci_dma_buf_done(struct kref *kref)
 {
 	struct vfio_pci_dma_buf *priv =
@@ -56,7 +101,7 @@ vfio_pci_dma_buf_map(struct dma_buf_attachment *attachment,
 
 	dma_resv_assert_held(priv->dmabuf->resv);
 
-	if (priv->revoked)
+	if (priv->status != VFIO_PCI_DMABUF_OK)
 		return ERR_PTR(-ENODEV);
 
 	ret = dma_buf_phys_vec_to_sgt(attachment, priv->provider,
@@ -90,22 +135,348 @@ static void vfio_pci_dma_buf_release(struct dma_buf *dmabuf)
 	 * The refcount prevents both.
 	 */
 	if (priv->vdev) {
-		down_write(&priv->vdev->memory_lock);
+		down_write(&priv->vdev->dmabuf_lock);
 		list_del_init(&priv->dmabufs_elm);
-		up_write(&priv->vdev->memory_lock);
+		up_write(&priv->vdev->dmabuf_lock);
 		vfio_device_put_registration(&priv->vdev->vdev);
 	}
+	if (priv->vfile)
+		fput(priv->vfile);
 	kfree(priv->phys_vec);
 	kfree(priv);
 }
 
 static const struct dma_buf_ops vfio_pci_dmabuf_ops = {
 	.attach = vfio_pci_dma_buf_attach,
+#ifdef CONFIG_VFIO_PCI_DMABUF
+	.mmap = vfio_pci_dma_buf_mmap,
+#endif
 	.map_dma_buf = vfio_pci_dma_buf_map,
 	.unmap_dma_buf = vfio_pci_dma_buf_unmap,
 	.release = vfio_pci_dma_buf_release,
 };
 
+int vfio_pci_dma_buf_find_pfn(struct vfio_pci_core_device *vdev,
+			      struct vfio_pci_dma_buf *priv,
+			      struct vm_area_struct *vma,
+			      unsigned long fault_addr,
+			      unsigned int order,
+			      unsigned long *out_pfn)
+{
+	/*
+	 * Given a VMA (start, end, pgoffs) and a fault address,
+	 * search the corresponding DMABUF's phys_vec[] to find the
+	 * range representing the address's offset into the VMA, and
+	 * its PFN.  vdev must be the device that the DMABUF priv was
+	 * exported from; vdev->dmabuf_lock must be held, and priv
+	 * must not be revoked.
+	 *
+	 * The phys_vec[] ranges represent contiguous spans of VAs
+	 * upwards from the buffer offset 0; the actual PFNs might be
+	 * in any order, overlap/alias, etc.  Calculate an offset of
+	 * the desired page given VMA start/pgoff and address, then
+	 * search upwards from 0 to find which span contains it.
+	 *
+	 * On success, a valid PFN for a page sized by 'order' is
+	 * returned into out_pfn.
+	 *
+	 * Failure occurs if:
+	 * - A hugepage would cross the edge of the VMA,
+	 * - A hugepage isn't entirely contained within a range
+	 *   (including where it straddles the boundary between
+	 *   ranges),
+	 * - We find a range, but the final PFN isn't aligned to the
+	 *   requested order.
+	 *
+	 * Upon failure, -ERANGE is returned and the caller is
+	 * expected to try again with a smaller order, which will
+	 * eventually succeed.
+	 *
+	 * It's suboptimal if DMABUFs are created with neighbouring
+	 * ranges that are physically contiguous, since hugepages
+	 * can't straddle range boundaries.  (The construction of the
+	 * ranges should merge them in this case.)
+	 *
+	 * Finally, vma_pgoff_adjust is used with a DMABUF created for
+	 * a VFIO BAR mmap: a BAR mapped with vm_pgoff > 0 creates a
+	 * DMABUF such that byte 0 of the VMA corresponds to byte 0 of
+	 * the DMABUF and byte 'vm_pgoff << PAGE_SHIFT' into the BAR.
+	 * To avoid double-offsetting in this scenario, subtracting
+	 * vma_pgoff_adjust from this (non-zero) vm_pgoff generates
+	 * the effective offset.  This also removes the VFIO region
+	 * index encoded in vm_pgoff for VFIO BAR mmaps.
+	 */
+
+	const unsigned long pagesize = PAGE_SIZE << order;
+	unsigned long vma_off = (vma->vm_pgoff - priv->vma_pgoff_adjust) <<
+				 PAGE_SHIFT;
+	unsigned long rounded_page_addr = ALIGN_DOWN(fault_addr, pagesize);
+	unsigned long rounded_page_end = rounded_page_addr + pagesize;
+	unsigned long fault_offset;
+	unsigned long fault_offset_end;
+	unsigned long range_start_offset = 0;
+	unsigned int i;
+	int ret;
+
+	if (unlikely(!vdev))
+		return -ENODEV;
+
+	/* This prevents the dmabuf revocation state from changing under us */
+	lockdep_assert_held(&vdev->dmabuf_lock);
+
+	if (unlikely(priv->vdev != vdev || priv->status != VFIO_PCI_DMABUF_OK))
+		return -ENODEV;
+
+	if (rounded_page_addr < vma->vm_start || rounded_page_end > vma->vm_end) {
+		if (order > 0)
+			return -ERANGE;
+
+		/* A fault address outside of the VMA is absurd. */
+		dev_warn_ratelimited(
+			&vdev->pdev->dev,
+			"Fault addr 0x%lx outside VMA 0x%lx-0x%lx\n",
+			fault_addr, vma->vm_start, vma->vm_end);
+		return -EFAULT;
+	}
+
+	/*
+	 * fault_offset[_end] is the span within the DMABUF
+	 * corresponding to the faulting page:
+	 */
+	if (unlikely(check_add_overflow(rounded_page_addr - vma->vm_start,
+					vma_off, &fault_offset) ||
+		     check_add_overflow(fault_offset, pagesize,
+					&fault_offset_end)))
+		return -EFAULT;
+
+	/*
+	 * Iterate over ranges in the buffer, summing their lengths:
+	 * range_start_offset represents the current range's starting
+	 * offset in the buffer (from 0 upwards).
+	 *
+	 * A failure for order == 0 is unexpected, and triggers a
+	 * fault/warn.
+	 */
+	ret = (order == 0) ? -EFAULT : -ERANGE;
+
+	for (i = 0; i < priv->nr_ranges; i++) {
+		size_t range_len = priv->phys_vec[i].len;
+
+		/* Early exit if range starts after the page end */
+		if (fault_offset_end <= range_start_offset)
+			break;
+
+		if (fault_offset >= range_start_offset &&
+		    fault_offset_end <= range_start_offset + range_len) {
+			/*
+			 * The faulting page is wholly contained
+			 * within the span represented by this range,
+			 * so validate PFN alignment for the order.
+			 * The if() condition ensures the pfn
+			 * arithmetic won't overflow.
+			 */
+			unsigned long pfn =
+				((fault_offset - range_start_offset) +
+				 priv->phys_vec[i].paddr) >> PAGE_SHIFT;
+
+			if (IS_ALIGNED(pfn, 1 << order)) {
+				*out_pfn = pfn;
+				ret = 0;
+			}
+			/*
+			 * Else order > 0; ERANGE retries with smaller
+			 * order
+			 */
+			break;
+		}
+		range_start_offset += range_len;
+	}
+
+	if (order == 0 && ret != 0)
+		/*
+		 * The address fell outside of the span represented by
+		 * the (concatenated) ranges.  As setup of a mapping
+		 * ensures that the VMA is <= the total size of the
+		 * ranges this should never happen.  If it does, warn
+		 * and SIGBUS.
+		 */
+		dev_warn_ratelimited(
+			&vdev->pdev->dev,
+			"No range for addr 0x%lx, order %d: VMA 0x%lx-0x%lx pgoff 0x%lx, %u ranges, size 0x%zx\n",
+			fault_addr, order, vma->vm_start, vma->vm_end,
+			vma->vm_pgoff, priv->nr_ranges, priv->size);
+
+	return ret;
+}
+
+/*
+ * Create a DMABUF corresponding to priv, add it to vdev->dmabufs list
+ * for tracking (meaning cleanup or revocation will zap it), and take
+ * a vfio_device registration.
+ */
+static int vfio_pci_dmabuf_export(struct vfio_pci_core_device *vdev,
+				  struct vfio_pci_dma_buf *priv, u32 flags)
+{
+	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
+
+	if (!vfio_device_try_get_registration(&vdev->vdev))
+		return -ENODEV;
+
+	exp_info.ops = &vfio_pci_dmabuf_ops;
+	exp_info.size = priv->size;
+	exp_info.flags = flags;
+	exp_info.priv = priv;
+
+	priv->dmabuf = dma_buf_export(&exp_info);
+	if (IS_ERR(priv->dmabuf)) {
+		vfio_device_put_registration(&vdev->vdev);
+		return PTR_ERR(priv->dmabuf);
+	}
+
+	kref_init(&priv->kref);
+	init_completion(&priv->comp);
+
+	/* dma_buf_put() now frees priv */
+	INIT_LIST_HEAD(&priv->dmabufs_elm);
+
+	/*
+	 * dmabuf_lock synchronises access (R) or updates (W) to the
+	 * vdev->dmabufs list and to bars_revoked (see below).  The
+	 * revocation state of DMABUF elements in the list is written
+	 * holding both dmabuf_lock(W) and resv, and tested with
+	 * either.
+	 *
+	 * (memory_lock, if held ->) dmabuf_lock -> resv
+	 *
+	 * NOTE: memory_lock is strictly avoided here, to avoid a
+	 * dependency on memory_lock when mmap_lock is held, when
+	 * mmap() leads to export.  vfio-pci variant drivers are
+	 * permitted to hold memory_lock across actions that might
+	 * fault (such as user access); a deadlock could result when
+	 * that fault path attempts to take mmap_lock (if held by an
+	 * export waiting for memory_lock).
+	 *
+	 * vdev->bars_revoked tracks the BAR revocation status updated
+	 * via vfio_pci_dma_buf_move(), so the initial DMABUF state
+	 * follows the same criteria that later update the DMABUF
+	 * state (BAR zap, etc.).
+	 */
+	lockdep_assert_not_held(&vdev->memory_lock);
+
+	down_write(&vdev->dmabuf_lock);
+	dma_resv_lock(priv->dmabuf->resv, NULL);
+	priv->status = vdev->bars_revoked ? VFIO_PCI_DMABUF_TEMP_REVOKED :
+		VFIO_PCI_DMABUF_OK;
+	list_add_tail(&priv->dmabufs_elm, &vdev->dmabufs);
+	dma_resv_unlock(priv->dmabuf->resv);
+	up_write(&vdev->dmabuf_lock);
+
+	return 0;
+}
+
+int vfio_pci_core_mmap_prep_dmabuf(struct vfio_pci_core_device *vdev,
+				   struct vm_area_struct *vma,
+				   u64 phys_start, u64 req_len,
+				   unsigned int res_index)
+{
+	struct vfio_pci_dma_buf *priv;
+	unsigned long vma_pgoff = vma->vm_pgoff & (VFIO_PCI_OFFSET_MASK >> PAGE_SHIFT);
+	char *bufname;
+	int ret;
+
+	priv = kzalloc_obj(*priv);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->phys_vec = kzalloc_obj(*priv->phys_vec);
+	if (!priv->phys_vec) {
+		ret = -ENOMEM;
+		goto err_free_priv;
+	}
+
+	/*
+	 * Maximum size of the friendly debug name is
+	 * vfio1048575:ffff:ff:1f.7/5 = 26.  This fits within
+	 * DMA_BUF_NAME_LEN, so dma_buf_set_name() below won't fail.
+	 */
+	bufname = kasprintf(GFP_KERNEL, "%s:%s/%x",
+			    dev_name(&vdev->vdev.device), pci_name(vdev->pdev),
+			    res_index);
+
+	if (!bufname) {
+		ret = -ENOMEM;
+		goto err_free_phys;
+	}
+
+	/*
+	 * The DMABUF begins from the mmap()'s BAR offset, i.e. the
+	 * start of the VMA corresponds to byte 0 of the DMABUF and
+	 * byte (vma_pgoff << PAGE_SHIFT) of the BAR.
+	 *
+	 * vfio_pci_dma_buf_find_pfn() reverses this offset using
+	 * vma_pgoff_adjust, so that ultimately a fault's offset from
+	 * the start of the _VMA_ has a consistent usage whether the
+	 * VMA originates from an mmap() of the VFIO device here or a
+	 * direct DMABUF mmap().  Note vma_pgoff_adjust also includes
+	 * the encoded VFIO region index, which cancels out the index
+	 * encoded in vm_pgoff.
+	 */
+	priv->vdev = vdev;
+	priv->size = req_len;
+	priv->nr_ranges = 1;
+	priv->vma_pgoff_adjust = vma->vm_pgoff;
+
+	/*
+	 * The provider can be NULL _iff_ the DMABUF feature isn't
+	 * supported, because it's only used by DMABUF import and
+	 * attach is prohibited if the feature isn't present.
+	 */
+	priv->provider = pcim_p2pdma_provider(vdev->pdev, res_index);
+	if (IS_ENABLED(CONFIG_VFIO_PCI_DMABUF) && !priv->provider) {
+		ret = -EINVAL;
+		goto err_free_name;
+	}
+
+	priv->phys_vec[0].paddr = phys_start + ((u64)vma_pgoff << PAGE_SHIFT);
+	priv->phys_vec[0].len = priv->size;
+
+	ret = vfio_pci_dmabuf_export(vdev, priv, O_RDWR);
+	if (ret)
+		goto err_free_name;
+
+	if (dma_buf_set_name(priv->dmabuf, bufname)) {
+		/* Shouldn't happen, but don't leak if it does: */
+		dev_dbg_ratelimited(&vdev->pdev->dev,
+				    "Failed to set map name '%s'\n",
+				    bufname);
+		kfree(bufname);
+	}
+
+	/*
+	 * Ownership of the DMABUF file transfers to the VMA so that
+	 * other users can locate the DMABUF via a VA.  Ownership of
+	 * the original VFIO device file being mmap()ed transfers to
+	 * priv, and is put when the DMABUF is released.  This
+	 * intentionally does not use get_file()/vma_set_file()
+	 * because the references are already held, and ownership
+	 * moves.
+	 */
+	priv->vfile = vma->vm_file;
+	vma->vm_file = priv->dmabuf->file;
+	vma->vm_private_data = priv;
+
+	return 0;
+
+err_free_name:
+	kfree(bufname);
+err_free_phys:
+	kfree(priv->phys_vec);
+err_free_priv:
+	kfree(priv);
+	return ret;
+}
+
+#ifdef CONFIG_VFIO_PCI_DMABUF
 /*
  * This is a temporary "private interconnect" between VFIO DMABUF and iommufd.
  * It allows the two co-operating drivers to exchange the physical address of
@@ -128,7 +499,7 @@ int vfio_pci_dma_buf_iommufd_map(struct dma_buf_attachment *attachment,
 		return -EOPNOTSUPP;
 
 	priv = attachment->dmabuf->priv;
-	if (priv->revoked)
+	if (priv->status != VFIO_PCI_DMABUF_OK)
 		return -ENODEV;
 
 	/* More than one range to iommufd will require proper DMABUF support */
@@ -224,7 +595,6 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
 {
 	struct vfio_device_feature_dma_buf get_dma_buf = {};
 	struct vfio_region_dma_range *dma_ranges;
-	DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
 	struct vfio_pci_dma_buf *priv;
 	size_t length;
 	int ret;
@@ -284,34 +654,9 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
 	kfree(dma_ranges);
 	dma_ranges = NULL;
 
-	if (!vfio_device_try_get_registration(&vdev->vdev)) {
-		ret = -ENODEV;
+	ret = vfio_pci_dmabuf_export(vdev, priv, get_dma_buf.open_flags);
+	if (ret)
 		goto err_free_phys;
-	}
-
-	exp_info.ops = &vfio_pci_dmabuf_ops;
-	exp_info.size = priv->size;
-	exp_info.flags = get_dma_buf.open_flags;
-	exp_info.priv = priv;
-
-	priv->dmabuf = dma_buf_export(&exp_info);
-	if (IS_ERR(priv->dmabuf)) {
-		ret = PTR_ERR(priv->dmabuf);
-		goto err_dev_put;
-	}
-
-	kref_init(&priv->kref);
-	init_completion(&priv->comp);
-
-	/* dma_buf_put() now frees priv */
-	INIT_LIST_HEAD(&priv->dmabufs_elm);
-	down_write(&vdev->memory_lock);
-	dma_resv_lock(priv->dmabuf->resv, NULL);
-	priv->revoked = !__vfio_pci_memory_enabled(vdev);
-	list_add_tail(&priv->dmabufs_elm, &vdev->dmabufs);
-	dma_resv_unlock(priv->dmabuf->resv);
-	up_write(&vdev->memory_lock);
-
 	/*
 	 * dma_buf_fd() consumes the reference, when the file closes the dmabuf
 	 * will be released.
@@ -322,8 +667,6 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
 
 	return ret;
 
-err_dev_put:
-	vfio_device_put_registration(&vdev->vdev);
 err_free_phys:
 	kfree(priv->phys_vec);
 err_free_priv:
@@ -332,6 +675,64 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
 	kfree(dma_ranges);
 	return ret;
 }
+#endif /* CONFIG_VFIO_PCI_DMABUF */
+
+/* Set the DMABUF's revocation status (OK or temporarily/permanently revoked) */
+static void vfio_pci_dma_buf_set_status(struct vfio_pci_dma_buf *priv,
+					enum vfio_pci_dma_buf_status new_status)
+{
+	bool was_revoked;
+
+	/*
+	 * Changes to the DMABUF's revocation status are synchronised
+	 * using dmabuf_lock:
+	 */
+	lockdep_assert_held_write(&priv->vdev->dmabuf_lock);
+
+	if (priv->status == VFIO_PCI_DMABUF_PERM_REVOKED ||
+	    priv->status == new_status)
+		return;
+
+	dma_resv_lock(priv->dmabuf->resv, NULL);
+	was_revoked = (priv->status == VFIO_PCI_DMABUF_TEMP_REVOKED);
+
+	if (new_status != VFIO_PCI_DMABUF_OK) {
+		priv->status = new_status; /* Temp or permanently revoked */
+
+		if (was_revoked) {
+			/*
+			 * TEMP_REVOKED is being upgraded to
+			 * PERM_REVOKED.  The buffer is already gone,
+			 * don't wait on it again.
+			 */
+			dma_resv_unlock(priv->dmabuf->resv);
+			return;
+		}
+		dma_buf_invalidate_mappings(priv->dmabuf);
+		dma_resv_wait_timeout(priv->dmabuf->resv,
+				      DMA_RESV_USAGE_BOOKKEEP, false,
+				      MAX_SCHEDULE_TIMEOUT);
+		dma_resv_unlock(priv->dmabuf->resv);
+		kref_put(&priv->kref, vfio_pci_dma_buf_done);
+		wait_for_completion(&priv->comp);
+		unmap_mapping_range(priv->dmabuf->file->f_mapping,
+				    0, 0, true);
+		/*
+		 * Re-arm the registered kref reference and the
+		 * completion so the post-revoke state matches the
+		 * post-creation state.  An un-revoke followed by a
+		 * new mapping needs the kref to be non-zero before
+		 * kref_get(), and vfio_pci_dma_buf_cleanup()
+		 * delegates its drain back through this revoke
+		 * path on a possibly-already-revoked dma-buf.
+		 */
+		kref_init(&priv->kref);
+		reinit_completion(&priv->comp);
+	} else {
+		priv->status = VFIO_PCI_DMABUF_OK;
+		dma_resv_unlock(priv->dmabuf->resv);
+	}
+}
 
 void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked)
 {
@@ -340,41 +741,17 @@ void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked)
 
 	lockdep_assert_held_write(&vdev->memory_lock);
 
+	down_write(&vdev->dmabuf_lock);
+	vdev->bars_revoked = revoked;
 	list_for_each_entry_safe(priv, tmp, &vdev->dmabufs, dmabufs_elm) {
 		if (!get_file_active(&priv->dmabuf->file))
 			continue;
-
-		if (priv->revoked != revoked) {
-			dma_resv_lock(priv->dmabuf->resv, NULL);
-			if (revoked)
-				priv->revoked = true;
-			dma_buf_invalidate_mappings(priv->dmabuf);
-			dma_resv_wait_timeout(priv->dmabuf->resv,
-					      DMA_RESV_USAGE_BOOKKEEP, false,
-					      MAX_SCHEDULE_TIMEOUT);
-			dma_resv_unlock(priv->dmabuf->resv);
-			if (revoked) {
-				kref_put(&priv->kref, vfio_pci_dma_buf_done);
-				wait_for_completion(&priv->comp);
-				/*
-				 * Re-arm the registered kref reference and the
-				 * completion so the post-revoke state matches the
-				 * post-creation state.  An un-revoke followed by a
-				 * new mapping needs the kref to be non-zero before
-				 * kref_get(), and vfio_pci_dma_buf_cleanup()
-				 * delegates its drain back through this revoke
-				 * path on a possibly-already-revoked dma-buf.
-				 */
-				kref_init(&priv->kref);
-				reinit_completion(&priv->comp);
-			} else {
-				dma_resv_lock(priv->dmabuf->resv, NULL);
-				priv->revoked = false;
-				dma_resv_unlock(priv->dmabuf->resv);
-			}
-		}
+		vfio_pci_dma_buf_set_status(priv, revoked ?
+					    VFIO_PCI_DMABUF_TEMP_REVOKED :
+					    VFIO_PCI_DMABUF_OK);
 		fput(priv->dmabuf->file);
 	}
+	up_write(&vdev->dmabuf_lock);
 }
 
 void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev)
@@ -393,14 +770,86 @@ void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev)
 	 */
 	vfio_pci_dma_buf_move(vdev, true);
 
+	down_write(&vdev->dmabuf_lock);
 	list_for_each_entry_safe(priv, tmp, &vdev->dmabufs, dmabufs_elm) {
 		if (!get_file_active(&priv->dmabuf->file))
 			continue;
 
 		list_del_init(&priv->dmabufs_elm);
-		priv->vdev = NULL;
+		WRITE_ONCE(priv->vdev, NULL);
 		vfio_device_put_registration(&vdev->vdev);
 		fput(priv->dmabuf->file);
 	}
+	up_write(&vdev->dmabuf_lock);
 	up_write(&vdev->memory_lock);
 }
+
+#ifdef CONFIG_VFIO_PCI_DMABUF
+int vfio_pci_core_feature_dma_buf_revoke(
+	struct vfio_pci_core_device *vdev, u32 flags,
+	struct vfio_device_feature_dma_buf_revoke __user *arg,
+	size_t argsz)
+{
+	struct vfio_device_feature_dma_buf_revoke db_revoke;
+	struct vfio_pci_dma_buf *priv;
+	struct dma_buf *dmabuf;
+	int ret;
+
+	if (!vdev->pci_ops || !vdev->pci_ops->get_dmabuf_phys)
+		return -EOPNOTSUPP;
+
+	ret = vfio_check_feature(flags, argsz,
+				 VFIO_DEVICE_FEATURE_SET,
+				 sizeof(db_revoke));
+	if (ret != 1)
+		return ret;
+
+	if (copy_from_user(&db_revoke, arg, sizeof(db_revoke)))
+		return -EFAULT;
+
+	dmabuf = dma_buf_get(db_revoke.dmabuf_fd);
+	if (IS_ERR(dmabuf))
+		return PTR_ERR(dmabuf);
+
+	priv = dmabuf->priv;
+	/*
+	 * Sanity-check the DMABUF is really a vfio_pci_dma_buf _and_
+	 * relates to the VFIO device it was provided with.
+	 *
+	 * If the DMABUF relates to this vdev then priv->vdev is
+	 * stable because this open fd prevents cleanup.
+	 *
+	 * If it relates to a different vdev, reading priv->vdev might
+	 * race with a concurrent cleanup on that device.  But if so,
+	 * it points to a non-matching vdev or NULL and is unusable
+	 * either way.
+	 */
+	if (dmabuf->ops != &vfio_pci_dmabuf_ops ||
+	    READ_ONCE(priv->vdev) != vdev) {
+		ret = -ENODEV;
+		goto out_put_buf;
+	}
+
+	/*
+	 * memory_lock(R) is taken to stop vfio_pci_dev_set_hot_reset()
+	 * from getting it and then blocking all devices in the dev_set behind
+	 * this revoke's drain.
+	 */
+	down_read(&vdev->memory_lock);
+	down_write(&vdev->dmabuf_lock);
+	if (priv->status == VFIO_PCI_DMABUF_PERM_REVOKED) {
+		ret = -EBADFD;
+	} else {
+		vfio_pci_dma_buf_set_status(priv,
+					    VFIO_PCI_DMABUF_PERM_REVOKED);
+		ret = 0;
+	}
+	up_write(&vdev->dmabuf_lock);
+	up_read(&vdev->memory_lock);
+
+out_put_buf:
+	dma_buf_put(dmabuf);
+
+	return ret;
+}
+#endif /* CONFIG_VFIO_PCI_DMABUF */
diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h
index fca9d0dfac90f..9cf66c19f798c 100644
--- a/drivers/vfio/pci/vfio_pci_priv.h
+++ b/drivers/vfio/pci/vfio_pci_priv.h
@@ -23,6 +23,27 @@ struct vfio_pci_ioeventfd {
 	bool			test_mem;
 };
 
+enum vfio_pci_dma_buf_status {
+	VFIO_PCI_DMABUF_OK = 0,
+	VFIO_PCI_DMABUF_TEMP_REVOKED = 1,
+	VFIO_PCI_DMABUF_PERM_REVOKED = 2,
+};
+
+struct vfio_pci_dma_buf {
+	struct dma_buf *dmabuf;
+	struct vfio_pci_core_device *vdev;
+	struct list_head dmabufs_elm;
+	size_t size;
+	struct phys_vec *phys_vec;
+	struct p2pdma_provider *provider;
+	struct file *vfile;
+	u32 nr_ranges;
+	struct kref kref;
+	struct completion comp;
+	unsigned long vma_pgoff_adjust;
+	enum vfio_pci_dma_buf_status status;
+};
+
 bool vfio_pci_intx_mask(struct vfio_pci_core_device *vdev);
 void vfio_pci_intx_unmask(struct vfio_pci_core_device *vdev);
 
@@ -68,7 +89,8 @@ void vfio_config_free(struct vfio_pci_core_device *vdev);
 int vfio_pci_set_power_state(struct vfio_pci_core_device *vdev,
 			     pci_power_t state);
 
-void vfio_pci_zap_and_down_write_memory_lock(struct vfio_pci_core_device *vdev);
+void vfio_pci_lock_revoke_bars(struct vfio_pci_core_device *vdev);
+void vfio_pci_unrevoke_bars(struct vfio_pci_core_device *vdev);
 u16 vfio_pci_memory_lock_and_enable(struct vfio_pci_core_device *vdev);
 void vfio_pci_memory_unlock_and_restore(struct vfio_pci_core_device *vdev,
 					u16 cmd);
@@ -114,12 +136,28 @@ static inline bool vfio_pci_is_vga(struct pci_dev *pdev)
 	return (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA;
 }
 
+int vfio_pci_dma_buf_find_pfn(struct vfio_pci_core_device *vdev,
+			      struct vfio_pci_dma_buf *priv,
+			      struct vm_area_struct *vma,
+			      unsigned long address,
+			      unsigned int order,
+			      unsigned long *out_pfn);
+int vfio_pci_core_mmap_prep_dmabuf(struct vfio_pci_core_device *vdev,
+				   struct vm_area_struct *vma,
+				   u64 phys_start, u64 req_len,
+				   unsigned int res_index);
+void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev);
+void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked);
+void vfio_pci_set_vma_ops(struct vm_area_struct *vma);
+
 #ifdef CONFIG_VFIO_PCI_DMABUF
 int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
 				  struct vfio_device_feature_dma_buf __user *arg,
 				  size_t argsz);
-void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev);
-void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked);
+int vfio_pci_core_feature_dma_buf_revoke(
+	struct vfio_pci_core_device *vdev, u32 flags,
+	struct vfio_device_feature_dma_buf_revoke __user *arg,
+	size_t argsz);
 #else
 static inline int
 vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
@@ -128,12 +166,12 @@ vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
 {
 	return -ENOTTY;
 }
-static inline void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev)
-{
-}
-static inline void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev,
-					 bool revoked)
+static inline int vfio_pci_core_feature_dma_buf_revoke(
+	struct vfio_pci_core_device *vdev, u32 flags,
+	struct vfio_device_feature_dma_buf_revoke __user *arg,
+	size_t argsz)
 {
+	return -ENOTTY;
 }
 #endif
 
diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h
index d1203da56fc5f..14d3950b63c85 100644
--- a/include/linux/dma-buf.h
+++ b/include/linux/dma-buf.h
@@ -570,6 +570,8 @@ int dma_buf_fd(struct dma_buf *dmabuf, int flags);
 struct dma_buf *dma_buf_get(int fd);
 void dma_buf_put(struct dma_buf *dmabuf);
 
+int dma_buf_set_name(struct dma_buf *dmabuf, char *name);
+
 struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *,
 					enum dma_data_direction);
 void dma_buf_unmap_attachment(struct dma_buf_attachment *, struct sg_table *,
diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h
index 9a1674c152aa2..44891fdb7c76e 100644
--- a/include/linux/vfio_pci_core.h
+++ b/include/linux/vfio_pci_core.h
@@ -129,11 +129,13 @@ struct vfio_pci_core_device {
 	bool			disable_idle_d3:1;
 	bool			nointxmask:1;
 	bool			disable_vga:1;
+	bool			zap_bars_on_revoke:1;
 	/* Flags modified at runtime - dedicated storage unit */
 	bool			needs_reset;
 	bool			pm_intx_masked;
 	bool			pm_runtime_engaged;
 	bool			sriov_active;
+	bool			bars_revoked;
 	struct pci_saved_state	*pci_saved_state;
 	struct pci_saved_state	*pm_save;
 	int			ioeventfds_nr;
@@ -148,6 +150,7 @@ struct vfio_pci_core_device {
 	struct vfio_pci_core_device	*sriov_pf_core_dev;
 	struct notifier_block	nb;
 	struct rw_semaphore	memory_lock;
+	struct rw_semaphore	dmabuf_lock;
 	struct list_head	dmabufs;
 };
 
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 5de618a3a5eee..8c1d50275a412 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -1534,6 +1534,30 @@ struct vfio_device_feature_dma_buf {
  */
 #define VFIO_DEVICE_FEATURE_MIG_PRECOPY_INFOv2  12
 
+/**
+ * Given a dma_buf fd previously exported from the same device by
+ * VFIO_DEVICE_FEATURE_DMA_BUF, a SET of this feature requests that
+ * access to the corresponding DMABUF is immediately and permanently
+ * revoked.  On successful return, the buffer is not accessible
+ * through any mmap() or dma-buf import.  The buffer is permanently
+ * disabled, and VFIO refuses all map, mmap, attach, etc. requests.
+ *
+ * Return: 0 on success, -1 and errno is set on failure:
+ *
+ *  EBADF, EINVAL: dmabuf_fd is not a DMABUF fd.
+ *  EOPNOTSUPP: The VFIO device does not support DMABUF export.
+ *  ENODEV: The DMABUF was not exported from this device.
+ *  EBADFD: The DMABUF is already permanently revoked.
+ *
+ * Additionally, common errors can occur: EFAULT accessing the struct,
+ * or EINVAL requesting an unsupported feature op.
+ */
+#define VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE 13
+
+struct vfio_device_feature_dma_buf_revoke {
+	__s32	dmabuf_fd;
+};
+
 /* -------- API for Type1 VFIO IOMMU -------- */
 
 /**

41/3 2026/09/11 22:08 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 23460
							output: 30
							thoughts: 2048
						

Thoughts:
**KMSAN Evaluation for this Patch Series**

Okay, let's break this down. My goal is to determine if this patch series necessitates a dedicated KMSAN fuzzing session, beyond the standard KASAN coverage we already have. We need to focus on uninitialized memory reads and potential kernel-to-user information leaks. I need to be diligent about applying the rules.

First, I'll remind myself: KASAN catches a lot (OOB, UAF, double free, etc.). KMSAN is for catching reads of *uninitialized* memory.

Now, let's go through the patch step-by-step:

1.  **`dma-buf.c` Changes**: This is the most suspect, it deals with DMA buffers and user-supplied names. It looks like `dma_buf_set_name_user` is added to copy from userspace and then call a wrapper which then frees the original userspace buffer.  Critically, `strndup_user` is used to copy the *name* from userspace. So, `dma_buf_set_name` takes ownership of the `name`, which is a copied string from userspace and then stores this into the dma buffer. This looks fairly safe, because the user-provided name is copied, and null-terminated. We aren't directly using uninitialized memory. There's a check for `strlen(name) >= DMA_BUF_NAME_LEN`, so there are explicit length checks. KASAN should handle the `strndup_user` operations. My initial instinct is that this should *not* need KMSAN, because the data is *copied* from userspace.

2.  **`VFIO` Kconfig and Makefile Changes**: These seem like build configuration changes, making sure all of `vfio_pci_dmabuf.o` is built-in. This is *unlikely* to need KMSAN, unless the conditional logic is problematic.  I'll watch out for this.

3.  **`hisi_acc_vfio_pci.c` Change**: Simple boolean initialization; unlikely to need KMSAN. `false` is perfectly initialized!

4.  **`vfio_pci_config.c` and 5. `vfio_pci_core.c` Changes**: These seem like locking and revocation updates.  It's focused on DMA buffer mapping and unmapping, again. KASAN is likely sufficient here, because locking issues would fall into this category. The `vfio_pci_mmap_huge_fault` rewrite *might* be interesting. I should make sure there are no uninitialized variables used in the fault handler, but overall, it appears safe. The fact that the fault handler uses `priv->status` indicates that the code is well-structured. The code *could* be risky, because we're interacting with the user's memory, but the patch seems to have taken precautions.

5.  **`vfio_pci_dmabuf.c` Changes**: This is the most complex section. This is *definitely* worth careful scrutiny.

    *   `vfio_pci_core_mmap_prep_dmabuf`: This allocates `priv`, `priv->phys_vec`, and `bufname`.  They are *zeroed* with `kzalloc`, which is great!  It calls `dma_buf_set_name`, as before, which copies the user provided name. So, still no risk here. It's safe so far.
    *   `vfio_pci_core_feature_dma_buf`: It uses `vfio_pci_dmabuf_export`. This is fine too, as the dma buf export happens within the VFIO driver.
    *   `vfio_pci_core_feature_dma_buf_revoke`: The concern is with `copy_from_user`. I need to ensure it doesn't copy back *to* user space uninitialized data.  It *seems* like only a `SET` feature, according to the code, and therefore this should be safe. I can double-check with grepper later. I have a gut feeling this function is fine, but I'll double check.

Therefore, the only part of this patch that might be of concern is `vfio_pci_core_feature_dma_buf_revoke`, where we had the `copy_from_user`. However, if the operation is just setting, it should be fine. I'll need to do more analysis.

**My Verdict**: Based on this initial review, my inclination is that this patch series *probably does not* warrant a dedicated KMSAN session. The changes seem to focus on


42/3 2026/09/11 22:08 tool grepper
0m Args:
{
  "Expression": "vfio_pci_core_feature_dma_buf_revoke"
}

Results:
{
  "Output": "drivers/vfio/pci/vfio_pci_core.c=1625=int vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags,\n--\ndrivers/vfio/pci/vfio_pci_core.c-1643-\tcase VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE:\ndrivers/vfio/pci/vfio_pci_core.c:1644:\t\treturn vfio_pci_core_feature_dma_buf_revoke(vdev, flags, arg, argsz);\ndrivers/vfio/pci/vfio_pci_core.c-1645-\tdefault:\n--\ndrivers/vfio/pci/vfio_pci_dmabuf.c=757=void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev)\n--\ndrivers/vfio/pci/vfio_pci_dmabuf.c-787-#ifdef CONFIG_VFIO_PCI_DMABUF\ndrivers/vfio/pci/vfio_pci_dmabuf.c:788:int vfio_pci_core_feature_dma_buf_revoke(\ndrivers/vfio/pci/vfio_pci_dmabuf.c-789-\tstruct vfio_pci_core_device *vdev, u32 flags,\n--\ndrivers/vfio/pci/vfio_pci_priv.h=154=int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,\n--\ndrivers/vfio/pci/vfio_pci_priv.h-156-\t\t\t\t  size_t argsz);\ndrivers/vfio/pci/vfio_pci_priv.h:157:int vfio_pci_core_feature_dma_buf_revoke(\ndrivers/vfio/pci/vfio_pci_priv.h-158-\tstruct vfio_pci_core_device *vdev, u32 flags,\n--\ndrivers/vfio/pci/vfio_pci_priv.h=163=vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,\n--\ndrivers/vfio/pci/vfio_pci_priv.h-168-}\ndrivers/vfio/pci/vfio_pci_priv.h:169:static inline int vfio_pci_core_feature_dma_buf_revoke(\ndrivers/vfio/pci/vfio_pci_priv.h-170-\tstruct vfio_pci_core_device *vdev, u32 flags,\n"
}

43/3 2026/09/11 22:08 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 27275
							output: 31
							thoughts: 392
						

Thoughts:
**My Analysis of Potential Vulnerabilities**

Okay, let's break this down systematically. My initial concern is always uninitialized values, so I'm honing in on `vfio_pci_dma_buf_find_pfn`. I see that the code checks the return of `vfio_pci_dma_buf_find_pfn` and proceeds to `vfio_pci_vmf_insert_pfn`. Importantly, `vfio_pci_dma_buf_find_pfn` *does* seem to explicitly initialize the `pfn` variable to zero, and then potentially overwrite that value depending on the function's return. So that mitigates my first worry. That's good, but I'm not entirely satisfied.

Now, let's shift gears and look for any blatant `copy_to_user` calls or other potential information leaks within this patch. I'm thinking about user-controlled data being copied to user space, which is a classic bug class. I'll focus on the `dma-buf.c` section since it's the primary target.

Looking at `dma_buf_set_name_user`, it calls `strndup_user`. It's reading from the user, but not writing back. The `dma_buf_set_name` function takes ownership of `name`, setting `dmabuf->name = name`. This is what I want to check; if the `dmabuf->name` member is ever copied to user space. Time to grep for that variable. That's my next step.



44/3 2026/09/11 22:08 tool grepper
0m Args:
{
  "Expression": "-\u003ename\\b",
  "PathPrefix": "drivers/dma-buf/"
}

Results:
{
  "Output": "drivers/dma-buf/dma-buf.c-39-/*\ndrivers/dma-buf/dma-buf.c:40: * dmabuf-\u003ename must be accessed with holding dmabuf-\u003ename_lock.\ndrivers/dma-buf/dma-buf.c-41- * we need to take the lock around the tracepoint call itself where\n--\ndrivers/dma-buf/dma-buf.c=150=static char *dmabuffs_dname(struct dentry *dentry, char *buffer, int buflen)\n--\ndrivers/dma-buf/dma-buf.c-157-\tspin_lock(\u0026dmabuf-\u003ename_lock);\ndrivers/dma-buf/dma-buf.c:158:\tif (dmabuf-\u003ename)\ndrivers/dma-buf/dma-buf.c:159:\t\tret = strscpy(name, dmabuf-\u003ename, sizeof(name));\ndrivers/dma-buf/dma-buf.c-160-\tspin_unlock(\u0026dmabuf-\u003ename_lock);\n--\ndrivers/dma-buf/dma-buf.c=166=static void dma_buf_release(struct dentry *dentry)\n--\ndrivers/dma-buf/dma-buf.c-189-\tmodule_put(dmabuf-\u003eowner);\ndrivers/dma-buf/dma-buf.c:190:\tkfree(dmabuf-\u003ename);\ndrivers/dma-buf/dma-buf.c-191-\tkfree(dmabuf);\n--\ndrivers/dma-buf/dma-buf.c=593=static void dma_buf_show_fdinfo(struct seq_file *m, struct file *file)\n--\ndrivers/dma-buf/dma-buf.c-601-\tspin_lock(\u0026dmabuf-\u003ename_lock);\ndrivers/dma-buf/dma-buf.c:602:\tif (dmabuf-\u003ename)\ndrivers/dma-buf/dma-buf.c:603:\t\tseq_printf(m, \"name:\\t%s\\n\", dmabuf-\u003ename);\ndrivers/dma-buf/dma-buf.c-604-\tspin_unlock(\u0026dmabuf-\u003ename_lock);\n--\ndrivers/dma-buf/dma-buf.c=869=int dma_buf_set_name(struct dma_buf *dmabuf, char *name)\n--\ndrivers/dma-buf/dma-buf.c-880-\tspin_lock(\u0026dmabuf-\u003ename_lock);\ndrivers/dma-buf/dma-buf.c:881:\tkfree(dmabuf-\u003ename);\ndrivers/dma-buf/dma-buf.c:882:\tdmabuf-\u003ename = name;\ndrivers/dma-buf/dma-buf.c-883-\tspin_unlock(\u0026dmabuf-\u003ename_lock);\n--\ndrivers/dma-buf/dma-buf.c=1765=static int dma_buf_debug_show(struct seq_file *s, void *unused)\n--\ndrivers/dma-buf/dma-buf.c-1795-\t\t\t\tfile_inode(buf_obj-\u003efile)-\u003ei_ino,\ndrivers/dma-buf/dma-buf.c:1796:\t\t\t\tbuf_obj-\u003ename ?: \"\u003cnone\u003e\");\ndrivers/dma-buf/dma-buf.c-1797-\t\tspin_unlock(\u0026buf_obj-\u003ename_lock);\n--\ndrivers/dma-buf/dma-heap.c=221=const char *dma_heap_get_name(struct dma_heap *heap)\ndrivers/dma-buf/dma-heap.c-222-{\ndrivers/dma-buf/dma-heap.c:223:\treturn heap-\u003ename;\ndrivers/dma-buf/dma-heap.c-224-}\n--\ndrivers/dma-buf/dma-heap.c=231=struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info)\n--\ndrivers/dma-buf/dma-heap.c-237-\ndrivers/dma-buf/dma-heap.c:238:\tif (!exp_info-\u003ename || !strcmp(exp_info-\u003ename, \"\")) {\ndrivers/dma-buf/dma-heap.c-239-\t\tpr_err(\"dma_heap: Cannot add heap without a name\\n\");\n--\ndrivers/dma-buf/dma-heap.c-251-\ndrivers/dma-buf/dma-heap.c:252:\theap-\u003ename = exp_info-\u003ename;\ndrivers/dma-buf/dma-heap.c-253-\theap-\u003eops = exp_info-\u003eops;\n--\ndrivers/dma-buf/dma-heap.c-279-\t\t\t\tNULL,\ndrivers/dma-buf/dma-heap.c:280:\t\t\t\theap-\u003ename);\ndrivers/dma-buf/dma-heap.c-281-\tif (IS_ERR(dev_ret)) {\n--\ndrivers/dma-buf/dma-heap.c-289-\tlist_for_each_entry(h, \u0026heap_list, list) {\ndrivers/dma-buf/dma-heap.c:290:\t\tif (!strcmp(h-\u003ename, exp_info-\u003ename)) {\ndrivers/dma-buf/dma-heap.c-291-\t\t\tmutex_unlock(\u0026heap_list_lock);\ndrivers/dma-buf/dma-heap.c-292-\t\t\tpr_err(\"dma_heap: Already registered heap named %s\\n\",\ndrivers/dma-buf/dma-heap.c:293:\t\t\t       exp_info-\u003ename);\ndrivers/dma-buf/dma-heap.c-294-\t\t\terr_ret = ERR_PTR(-EINVAL);\n--\ndrivers/dma-buf/sw_sync.c=100=static struct sync_timeline *sync_timeline_create(const char *name)\n--\ndrivers/dma-buf/sw_sync.c-109-\tobj-\u003econtext = dma_fence_context_alloc(1);\ndrivers/dma-buf/sw_sync.c:110:\tstrscpy(obj-\u003ename, name, sizeof(obj-\u003ename));\ndrivers/dma-buf/sw_sync.c-111-\n--\ndrivers/dma-buf/sw_sync.c=146=static const char *timeline_fence_get_timeline_name(struct dma_fence *fence)\n--\ndrivers/dma-buf/sw_sync.c-149-\ndrivers/dma-buf/sw_sync.c:150:\treturn parent-\u003ename;\ndrivers/dma-buf/sw_sync.c-151-}\n--\ndrivers/dma-buf/sync_debug.c=45=static void sync_print_fence(struct seq_file *s,\n--\ndrivers/dma-buf/sync_debug.c-53-\tseq_printf(s, \"  %s%sfence %s\",\ndrivers/dma-buf/sync_debug.c:54:\t\t   show ? parent-\u003ename : \"\",\ndrivers/dma-buf/sync_debug.c-55-\t\t   show ? \"_\" : \"\",\n--\ndrivers/dma-buf/sync_debug.c=70=static void sync_print_obj(struct seq_file *s, struct sync_timeline *obj)\n--\ndrivers/dma-buf/sync_debug.c-73-\ndrivers/dma-buf/sync_debug.c:74:\tseq_printf(s, \"%s: %d\\n\", obj-\u003ename, obj-\u003evalue);\ndrivers/dma-buf/sync_debug.c-75-\n--\ndrivers/dma-buf/sync_trace.h=12=TRACE_EVENT(sync_timeline,\n--\ndrivers/dma-buf/sync_trace.h-17-\tTP_STRUCT__entry(\ndrivers/dma-buf/sync_trace.h:18:\t\t\t__string(name, timeline-\u003ename)\ndrivers/dma-buf/sync_trace.h-19-\t\t\t__field(u32, value)\n"
}

45/3 2026/09/11 22:08 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 30126
							output: 47
							thoughts: 2237
						

Thoughts:
**Uncovering Potential Vulnerabilities: A Deep Dive into VFIO DMA-BUF Management**

Alright, let's break down this VFIO code with a critical eye, focusing on potential uninitialized variable vulnerabilities. My initial scan has keyed in on the `dma_buf` and related structures.

First, I see the `dma_buf_set_name` function, which is responsible for setting the name of a DMA buffer. The interesting part here is that the `name` comes from either `strndup_user` or `kasprintf`, both of which are carefully examined. Both functions ensure null-terminated, fully initialized strings, but `dma_buf_set_name` performs a `strlen` check against `DMA_BUF_NAME_LEN` and frees the buffer if the check fails. However, the value of name, if null on entry, can lead to a crash if a developer assumes `name` is valid but is then nullified by the `kfree`.

Next, I'm examining `vfio_pci_core_feature_dma_buf_revoke`. I see a `copy_from_user` operation, which immediately raises a flag. However, on closer inspection, the code only reads data from user space and doesn't write anything back. This seems safe at first glance, but if the structure, `db_revoke` can be used to control program flow, its integrity is of utmost importance.

Moving on to `vfio_pci_core_mmap_prep_dmabuf`, the allocations using `kzalloc_obj` are reassuring. It seems all fields of the newly allocated structures, `priv` and `priv->phys_vec`, are zero-initialized. I also noted that `bufname` is assigned via `kasprintf`, implying it's initialized correctly.

The `vfio_pci_core_init_dev` function initializes several crucial structures like `vdev->dmabufs`, memory locks, and a context object. The check for `vdev->vdev.ops->mmap != vfio_pci_core_mmap` and the subsequent setting of `vdev->zap_bars_on_revoke` adds an interesting wrinkle. This variable is initialized properly.

The related functions `vfio_pci_core_enable` and `hisi_acc_vfio_pci_migrn_init_dev` seem to follow proper initialization patterns.

To make sure that I didn't miss something, I went back through all the functions modified or added in this code.

*   `dma_buf_set_name_user`: The `ret` variable is initialized by the return of `dma_buf_set_name`.
*   `dma_buf_set_name`: The function explicitly returns a constant value, thereby initializing its return value, after several checks to prevent buffer overflow.
*   `hisi_acc_vfio_pci_migrn_init_dev`: It initializes `ret` and checks for errors.
*   `vfio_pci_core_runtime_resume`: It initializes a `ctx` variable with the value of `vdev->pm_wake_eventfd_ctx`.
*   `vfio_pci_mmap_huge_fault`: `pfn` is initialized to 0 and `ret` to `VM_FAULT_SIGBUS`. `vdev` is set to `priv->vdev`.
*   `vfio_pci_core_mmap`: Returns if `vfio_pci_core_mmap_prep_dmabuf` returns an error, which has been checked.
*   `vfio_pci_dma_buf_find_pfn`: `fault_offset` and `fault_offset_end` are written if `check_add_overflow` passes. The return value, `ret`, is initialized to either `-EFAULT` or `-ERANGE`. Inside the loop, `pfn` is only used if `ret` is set to `0`. `ret` is only used if the caller has `ret == 0` when calling.
*   `vfio_pci_dmabuf_export`: All fields are initialized here.
*   `vfio_pci_core_mmap_prep_dmabuf`: Both `priv` and `priv->phys_vec` are either zero-initialized or explicitly set.
*   `vfio_pci_dma_buf_set_status`: `was_revoked` is set properly.
*   `vfio_pci_core_feature_dma_buf_revoke`: The function checks and only reads from `db_revoke`.

Finally, I confirmed that there are no


46/3 2026/09/11 22:09 tool read-file
0m Args:
{
  "File": "drivers/vfio/pci/vfio_pci_dmabuf.c",
  "FirstLine": 585,
  "LineCount": 85
}

Results:
{
  "Contents": " 585:\t\tif ((u64)(length) \u0026 DMA_IOVA_USE_SWIOTLB)\n 586:\t\t\treturn -EINVAL;\n 587:\t\n 588:\t\t*lengthp = length;\n 589:\t\treturn 0;\n 590:\t}\n 591:\t\n 592:\tint vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,\n 593:\t\t\t\t\t  struct vfio_device_feature_dma_buf __user *arg,\n 594:\t\t\t\t\t  size_t argsz)\n 595:\t{\n 596:\t\tstruct vfio_device_feature_dma_buf get_dma_buf = {};\n 597:\t\tstruct vfio_region_dma_range *dma_ranges;\n 598:\t\tstruct vfio_pci_dma_buf *priv;\n 599:\t\tsize_t length;\n 600:\t\tint ret;\n 601:\t\n 602:\t\tif (!vdev-\u003epci_ops || !vdev-\u003epci_ops-\u003eget_dmabuf_phys)\n 603:\t\t\treturn -EOPNOTSUPP;\n 604:\t\n 605:\t\tret = vfio_check_feature(flags, argsz, VFIO_DEVICE_FEATURE_GET,\n 606:\t\t\t\t\t sizeof(get_dma_buf));\n 607:\t\tif (ret != 1)\n 608:\t\t\treturn ret;\n 609:\t\n 610:\t\tif (copy_from_user(\u0026get_dma_buf, arg, sizeof(get_dma_buf)))\n 611:\t\t\treturn -EFAULT;\n 612:\t\n 613:\t\tif (!get_dma_buf.nr_ranges || get_dma_buf.flags)\n 614:\t\t\treturn -EINVAL;\n 615:\t\n 616:\t\t/*\n 617:\t\t * For PCI the region_index is the BAR number like everything\n 618:\t\t * else.  Check that PCI resources have been claimed for it.\n 619:\t\t */\n 620:\t\tif (get_dma_buf.region_index \u003e= VFIO_PCI_ROM_REGION_INDEX ||\n 621:\t\t    IS_ERR(vfio_pci_core_get_iomap(vdev, get_dma_buf.region_index)))\n 622:\t\t\treturn -ENODEV;\n 623:\t\n 624:\t\tdma_ranges = memdup_array_user(\u0026arg-\u003edma_ranges, get_dma_buf.nr_ranges,\n 625:\t\t\t\t\t       sizeof(*dma_ranges));\n 626:\t\tif (IS_ERR(dma_ranges))\n 627:\t\t\treturn PTR_ERR(dma_ranges);\n 628:\t\n 629:\t\tret = validate_dmabuf_input(\u0026get_dma_buf, dma_ranges, \u0026length);\n 630:\t\tif (ret)\n 631:\t\t\tgoto err_free_ranges;\n 632:\t\n 633:\t\tpriv = kzalloc_obj(*priv);\n 634:\t\tif (!priv) {\n 635:\t\t\tret = -ENOMEM;\n 636:\t\t\tgoto err_free_ranges;\n 637:\t\t}\n 638:\t\tpriv-\u003ephys_vec = kzalloc_objs(*priv-\u003ephys_vec, get_dma_buf.nr_ranges);\n 639:\t\tif (!priv-\u003ephys_vec) {\n 640:\t\t\tret = -ENOMEM;\n 641:\t\t\tgoto err_free_priv;\n 642:\t\t}\n 643:\t\n 644:\t\tpriv-\u003evdev = vdev;\n 645:\t\tpriv-\u003enr_ranges = get_dma_buf.nr_ranges;\n 646:\t\tpriv-\u003esize = length;\n 647:\t\tret = vdev-\u003epci_ops-\u003eget_dmabuf_phys(vdev, \u0026priv-\u003eprovider,\n 648:\t\t\t\t\t\t     get_dma_buf.region_index,\n 649:\t\t\t\t\t\t     priv-\u003ephys_vec, dma_ranges,\n 650:\t\t\t\t\t\t     priv-\u003enr_ranges);\n 651:\t\tif (ret)\n 652:\t\t\tgoto err_free_phys;\n 653:\t\n 654:\t\tkfree(dma_ranges);\n 655:\t\tdma_ranges = NULL;\n 656:\t\n 657:\t\tret = vfio_pci_dmabuf_export(vdev, priv, get_dma_buf.open_flags);\n 658:\t\tif (ret)\n 659:\t\t\tgoto err_free_phys;\n 660:\t\t/*\n 661:\t\t * dma_buf_fd() consumes the reference, when the file closes the dmabuf\n 662:\t\t * will be released.\n 663:\t\t */\n 664:\t\tret = dma_buf_fd(priv-\u003edmabuf, get_dma_buf.open_flags);\n 665:\t\tif (ret \u003c 0)\n 666:\t\t\tdma_buf_put(priv-\u003edmabuf);\n 667:\t\n 668:\t\treturn ret;\n 669:\t\n"
}

47/3 2026/09/11 22:09 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 34832
							output: 46
							thoughts: 102
						

Thoughts:
**My Analysis of the vfio_pci Feature Handling**

Okay, so `vfio_pci_core_feature_dma_buf` is giving me either a file descriptor (`dma_buf_fd`) or a negative error code. No surprises there, it's not designed to copy the data directly to userspace. That's good to know, confirming the behavior I expected. But, I need to understand *how* it's all working within the ioctl context. Time to pivot.

My immediate next thought is to dig into the `vfio_pci_core_ioctl_feature` function. I need to see precisely how it's dealing with GET and SET operations, specifically in relation to those features. I'm going to look at how that function interacts with the DMA buffer mechanism.

Right, let's open up `drivers/vfio/pci/vfio_pci_core.c`. I'll jump right around line 1625. That's where I anticipate finding the core logic for the ioctl and feature handling. I'll focus on the data flow and how the dma_buf is integrated, or not, into the larger picture. I'm thinking I'll find the interface to `vfio_pci_core_feature_dma_buf` from within that IOCTL handler, which should show how they interact.



48/3 2026/09/11 22:09 tool read-file
0m Args:
{
  "File": "drivers/vfio/pci/vfio_pci_core.c",
  "FirstLine": 1620,
  "LineCount": 40
}

Results:
{
  "Contents": "1620:\t\tuuid_copy(\u0026vdev-\u003evf_token-\u003euuid, \u0026uuid);\n1621:\t\tmutex_unlock(\u0026vdev-\u003evf_token-\u003elock);\n1622:\t\treturn 0;\n1623:\t}\n1624:\t\n1625:\tint vfio_pci_core_ioctl_feature(struct vfio_device *device, u32 flags,\n1626:\t\t\t\t\tvoid __user *arg, size_t argsz)\n1627:\t{\n1628:\t\tstruct vfio_pci_core_device *vdev =\n1629:\t\t\tcontainer_of(device, struct vfio_pci_core_device, vdev);\n1630:\t\n1631:\t\tswitch (flags \u0026 VFIO_DEVICE_FEATURE_MASK) {\n1632:\t\tcase VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY:\n1633:\t\t\treturn vfio_pci_core_pm_entry(vdev, flags, arg, argsz);\n1634:\t\tcase VFIO_DEVICE_FEATURE_LOW_POWER_ENTRY_WITH_WAKEUP:\n1635:\t\t\treturn vfio_pci_core_pm_entry_with_wakeup(vdev, flags,\n1636:\t\t\t\t\t\t\t\t  arg, argsz);\n1637:\t\tcase VFIO_DEVICE_FEATURE_LOW_POWER_EXIT:\n1638:\t\t\treturn vfio_pci_core_pm_exit(vdev, flags, arg, argsz);\n1639:\t\tcase VFIO_DEVICE_FEATURE_PCI_VF_TOKEN:\n1640:\t\t\treturn vfio_pci_core_feature_token(vdev, flags, arg, argsz);\n1641:\t\tcase VFIO_DEVICE_FEATURE_DMA_BUF:\n1642:\t\t\treturn vfio_pci_core_feature_dma_buf(vdev, flags, arg, argsz);\n1643:\t\tcase VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE:\n1644:\t\t\treturn vfio_pci_core_feature_dma_buf_revoke(vdev, flags, arg, argsz);\n1645:\t\tdefault:\n1646:\t\t\treturn -ENOTTY;\n1647:\t\t}\n1648:\t}\n1649:\tEXPORT_SYMBOL_GPL(vfio_pci_core_ioctl_feature);\n1650:\t\n1651:\tstatic ssize_t vfio_pci_rw(struct vfio_pci_core_device *vdev, char __user *buf,\n1652:\t\t\t\t   size_t count, loff_t *ppos, bool iswrite)\n1653:\t{\n1654:\t\tunsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);\n1655:\t\tint ret;\n1656:\t\n1657:\t\tif (index \u003e= VFIO_PCI_NUM_REGIONS + vdev-\u003enum_regions)\n1658:\t\t\treturn -EINVAL;\n1659:\t\n"
}

49/3 2026/09/11 22:09 llm kmsan-evaluator
0m Model:
gemini-3.8-flash

Args:
null

Results:
null

Tokens:
							input: 36061
							output: 444
							thoughts: 3807
						

Thoughts:
**KMSAN Assessment: VFIO PCI DMA-BUF Revocation and Mapping**

Alright, let's break down this patch and figure out whether we need to flag it for KMSAN scrutiny. I've gone through the code, focusing on the potential for uninitialized memory usage or information leaks, and contrasting those concerns with typical KASAN/LOCKDEP issues.

My initial scan focuses on what's changed and introduced. We have `VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE` which takes input parameters. We have DMA-BUF based PCI BAR mmap support in the VFIO PCI core. We have a set of supporting functions and structures and some dma-buf name changes. I need to make sure that no kernel data is leaking to user space.

I see that the core structure, `struct vfio_pci_dma_buf`, is initialized with `kzalloc_obj`. This is good; all fields are explicitly set later on. `phys_vec` is allocated with `kzalloc_obj` or `kzalloc_objs`, ensuring zero initialization. All variables are initialized before use, and there aren't any sneaky dependencies on uninitialized memory during branching or conditional logic.

I checked the new feature `VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE`. This is a *SET* feature, meaning the kernel *reads* from userspace via `copy_from_user`. There's no copying *to* userspace that could potentially leak uninitialized data. The same is true for the `dma_buf_set_name` and related functions - we're only reading user provided data and ensuring the name does not overflow. No kernel memory is exposed to user space.

I dove into `vfio_pci_core_mmap_prep_dmabuf`, `vfio_pci_dma_buf_mmap`, and `vfio_pci_mmap_huge_fault`. Here, physical addresses for MMIO regions are being mapped. This is device memory, not kernel memory that could be uninitialized. Page fault handler and `dma_buf_find_pfn` simply find the PFN from a PCI BAR and map those, not kernel pages.

So, where are the risks? They are around concurrency and memory management. There could be race conditions during revocation, mmap/unmap, and cleanup operations. There could be locking order issues or locking deadlocks. There could be use-after-free conditions related to the lifetime of structures like the `dmabuf`, `vdev`, or the `eventfd_ctx`. *These are classic KASAN, LOCKDEP, and UAF issues*. KMSAN isn't the right tool here.

I think the analysis is sound. There are no data leaks, no uses of uninitialized memory that can be exploited, and the identified potential issues are squarely in KASAN/LOCKDEP's wheelhouse. Therefore, I'm confident in setting `NeedsKMSAN=false`.



50/3 2026/09/11 22:09 tool set-results
0m Args:
{
  "KMSANReasoning": "The patch refactors dma_buf name handling and integrates DMABUF-backed PCI BAR mapping and revocation into the VFIO PCI core (including the new VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE ioctl feature and rewritten page fault handling).\n\nAnalysis with respect to uninitialized memory (KMSAN):\n1. Kernel-to-user info leaks: The new ioctl feature VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE only performs a copy_from_user() on input arguments; no kernel data is returned or copied to user space. DMA-buf naming via dma_buf_set_name_user() safely copies strings from userspace using strndup_user() and names allocated with kasprintf() are fully initialized.\n2. Uninitialized variables / fields: All heap allocations for vfio_pci_dma_buf and its phys_vec array use kzalloc_obj(), ensuring zero-initialization. All stack variables in the new/modified functions (e.g., pres, pfn, ret, fault_offset) are initialized before use. New struct fields on vfio_pci_core_device (dmabuf_lock, bars_revoked, zap_bars_on_revoke) are explicitly initialized during device init/enable.\n3. Fault handling: The PFN resolution logic operates on PCI MMIO resource addresses rather than uninitialized kernel memory pages.\n\nContrast with KASAN/LOCKDEP:\nThe risks introduced by this change center on synchronization, reference counting (kref, dma_buf, vfio_device registration, eventfd_ctx), locking hierarchies (memory_lock vs dmabuf_lock vs dma_resv lock), and potential use-after-free or race conditions during device reset, revocation, or unmap. These classes of bugs are comprehensively covered by KASAN and LOCKDEP in standard fuzzing builds. There are no uninitialized memory risks that would uniquely warrant a KMSAN session.",
  "NeedsKMSAN": false
}

Results:
{
  "KMSANReasoning": "The patch refactors dma_buf name handling and integrates DMABUF-backed PCI BAR mapping and revocation into the VFIO PCI core (including the new VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE ioctl feature and rewritten page fault handling).\n\nAnalysis with respect to uninitialized memory (KMSAN):\n1. Kernel-to-user info leaks: The new ioctl feature VFIO_DEVICE_FEATURE_DMA_BUF_REVOKE only performs a copy_from_user() on input arguments; no kernel data is returned or copied to user space. DMA-buf naming via dma_buf_set_name_user() safely copies strings from userspace using strndup_user() and names allocated with kasprintf() are fully initialized.\n2. Uninitialized variables / fields: All heap allocations for vfio_pci_dma_buf and its phys_vec array use kzalloc_obj(), ensuring zero-initialization. All stack variables in the new/modified functions (e.g., pres, pfn, ret, fault_offset) are initialized before use. New struct fields on vfio_pci_core_device (dmabuf_lock, bars_revoked, zap_bars_on_revoke) are explicitly initialized during device init/enable.\n3. Fault handling: The PFN resolution logic operates on PCI MMIO resource addresses rather than uninitialized kernel memory pages.\n\nContrast with KASAN/LOCKDEP:\nThe risks introduced by this change center on synchronization, reference counting (kref, dma_buf, vfio_device registration, eventfd_ctx), locking hierarchies (memory_lock vs dmabuf_lock vs dma_resv lock), and potential use-after-free or race conditions during device reset, revocation, or unmap. These classes of bugs are comprehensively covered by KASAN and LOCKDEP in standard fuzzing builds. There are no uninitialized memory risks that would uniquely warrant a KMSAN session.",
  "NeedsKMSAN": false
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)