History

iommufd: File descriptor, context, kconfig and makefiles

This is the basic infrastructure of a new miscdevice to hold the iommufd IOCTL API. It provides: - A miscdevice to create file descriptors to run the IOCTL interface over - A table based ioctl dispatch and centralized extendable pre-validation step - An xarray mapping userspace ID's to kernel objects. The design has multiple inter-related objects held within in a single IOMMUFD fd - A simple usage count to build a graph of object relations and protect against hostile userspace racing ioctls The only IOCTL provided in this patch is the generic 'destroy any object by handle' operation.

Jason Gunthorpe committed 3 years ago

Commit 2ff4bed1 parent 658234d10 files · +571 −1Browse files

Unified · Split

10 files
  1. Documentation/userspace-api/ioctl/ioctl-number.rst +1 −0
  2. MAINTAINERS +12 −0
  3. drivers/iommu/Kconfig +1 −0
  4. drivers/iommu/Makefile +1 −1
  5. drivers/iommu/iommufd/Kconfig +12 −0
  6. drivers/iommu/iommufd/Makefile +5 −0
  7. drivers/iommu/iommufd/iommufd_private.h +109 −0
  8. drivers/iommu/iommufd/main.c +344 −0
  9. include/linux/iommufd.h +31 −0
  10. include/uapi/linux/iommufd.h +55 −0
Documentation/userspace-api/ioctl/ioctl-number.rst+1−0
@@ -105,6 +105,7 @@ Code Seq# Include File Comments · 104 unmodified lines
105105 '8' all SNP8023 advanced NIC card
106106 <mailto:mcr@solidum.com>
107107 ';' 64-7F linux/vfio.h
108+';' 80-FF linux/iommufd.h
108109 '=' 00-3f uapi/linux/ptp_clock.h <mailto:richardcochran@gmail.com>
109110 '@' 00-0F linux/radeonfb.h conflict!
110111 '@' 00-0F drivers/video/aty/aty128fb.c conflict!
MAINTAINERS+12−0
@@ -10717,6 +10717,18 @@ F: drivers/iommu/dma-iommu.h · 10716 unmodified lines
1071710717 F: drivers/iommu/iova.c
1071810718 F: include/linux/iova.h
1071910719
10720+IOMMUFD
10721+M: Jason Gunthorpe <jgg@nvidia.com>
10722+M: Kevin Tian <kevin.tian@intel.com>
10723+L: iommu@lists.linux.dev
10724+S: Maintained
10725+T: git git://git.kernel.org/pub/scm/linux/kernel/git/jgg/iommufd.git
10726+F: Documentation/userspace-api/iommufd.rst
10727+F: drivers/iommu/iommufd/
10728+F: include/linux/iommufd.h
10729+F: include/uapi/linux/iommufd.h
10730+F: tools/testing/selftests/iommu/
10731+
1072010732 IOMMU SUBSYSTEM
1072110733 M: Joerg Roedel <joro@8bytes.org>
1072210734 M: Will Deacon <will@kernel.org>
drivers/iommu/Kconfig+1−0
@@ -188,6 +188,7 @@ config MSM_IOMMU · 187 unmodified lines
188188
189189 source "drivers/iommu/amd/Kconfig"
190190 source "drivers/iommu/intel/Kconfig"
191+source "drivers/iommu/iommufd/Kconfig"
191192
192193 config IRQ_REMAP
193194 bool "Support for Interrupt Remapping"
drivers/iommu/Makefile+1−1
@@ -1,5 +1,5 @@
11 # SPDX-License-Identifier: GPL-2.0
2−obj-y += amd/ intel/ arm/
2+obj-y += amd/ intel/ arm/ iommufd/
33 obj-$(CONFIG_IOMMU_API) += iommu.o
44 obj-$(CONFIG_IOMMU_API) += iommu-traces.o
55 obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o
drivers/iommu/iommufd/Kconfig+12−0
@@ -0,0 +1,12 @@
1+# SPDX-License-Identifier: GPL-2.0-only
2+config IOMMUFD
3+ tristate "IOMMU Userspace API"
4+ select INTERVAL_TREE
5+ select INTERVAL_TREE_SPAN_ITER
6+ select IOMMU_API
7+ default n
8+ help
9+ Provides /dev/iommu, the user API to control the IOMMU subsystem as
10+ it relates to managing IO page tables that point at user space memory.
11+
12+ If you don't know what to do here, say N.
drivers/iommu/iommufd/Makefile+5−0
@@ -0,0 +1,5 @@
1+# SPDX-License-Identifier: GPL-2.0-only
2+iommufd-y := \
3+ main.o
4+
5+obj-$(CONFIG_IOMMUFD) += iommufd.o
drivers/iommu/iommufd/iommufd_private.h+109−0
@@ -0,0 +1,109 @@
1+/* SPDX-License-Identifier: GPL-2.0-only */
2+/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
3+ */
4+#ifndef __IOMMUFD_PRIVATE_H
5+#define __IOMMUFD_PRIVATE_H
6+
7+#include <linux/rwsem.h>
8+#include <linux/xarray.h>
9+#include <linux/refcount.h>
10+#include <linux/uaccess.h>
11+
12+struct iommufd_ctx {
13+ struct file *file;
14+ struct xarray objects;
15+};
16+
17+struct iommufd_ucmd {
18+ struct iommufd_ctx *ictx;
19+ void __user *ubuffer;
20+ u32 user_size;
21+ void *cmd;
22+};
23+
24+/* Copy the response in ucmd->cmd back to userspace. */
25+static inline int iommufd_ucmd_respond(struct iommufd_ucmd *ucmd,
26+ size_t cmd_len)
27+{
28+ if (copy_to_user(ucmd->ubuffer, ucmd->cmd,
29+ min_t(size_t, ucmd->user_size, cmd_len)))
30+ return -EFAULT;
31+ return 0;
32+}
33+
34+enum iommufd_object_type {
35+ IOMMUFD_OBJ_NONE,
36+ IOMMUFD_OBJ_ANY = IOMMUFD_OBJ_NONE,
37+};
38+
39+/* Base struct for all objects with a userspace ID handle. */
40+struct iommufd_object {
41+ struct rw_semaphore destroy_rwsem;
42+ refcount_t users;
43+ enum iommufd_object_type type;
44+ unsigned int id;
45+};
46+
47+static inline bool iommufd_lock_obj(struct iommufd_object *obj)
48+{
49+ if (!down_read_trylock(&obj->destroy_rwsem))
50+ return false;
51+ if (!refcount_inc_not_zero(&obj->users)) {
52+ up_read(&obj->destroy_rwsem);
53+ return false;
54+ }
55+ return true;
56+}
57+
58+struct iommufd_object *iommufd_get_object(struct iommufd_ctx *ictx, u32 id,
59+ enum iommufd_object_type type);
60+static inline void iommufd_put_object(struct iommufd_object *obj)
61+{
62+ refcount_dec(&obj->users);
63+ up_read(&obj->destroy_rwsem);
64+}
65+
66+/**
67+ * iommufd_ref_to_users() - Switch from destroy_rwsem to users refcount
68+ * protection
69+ * @obj - Object to release
70+ *
71+ * Objects have two refcount protections (destroy_rwsem and the refcount_t
72+ * users). Holding either of these will prevent the object from being destroyed.
73+ *
74+ * Depending on the use case, one protection or the other is appropriate. In
75+ * most cases references are being protected by the destroy_rwsem. This allows
76+ * orderly destruction of the object because iommufd_object_destroy_user() will
77+ * wait for it to become unlocked. However, as a rwsem, it cannot be held across
78+ * a system call return. So cases that have longer term needs must switch
79+ * to the weaker users refcount_t.
80+ *
81+ * With users protection iommufd_object_destroy_user() will return false,
82+ * refusing to destroy the object, causing -EBUSY to userspace.
83+ */
84+static inline void iommufd_ref_to_users(struct iommufd_object *obj)
85+{
86+ up_read(&obj->destroy_rwsem);
87+ /* iommufd_lock_obj() obtains users as well */
88+}
89+void iommufd_object_abort(struct iommufd_ctx *ictx, struct iommufd_object *obj);
90+void iommufd_object_abort_and_destroy(struct iommufd_ctx *ictx,
91+ struct iommufd_object *obj);
92+void iommufd_object_finalize(struct iommufd_ctx *ictx,
93+ struct iommufd_object *obj);
94+bool iommufd_object_destroy_user(struct iommufd_ctx *ictx,
95+ struct iommufd_object *obj);
96+struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx,
97+ size_t size,
98+ enum iommufd_object_type type);
99+
100+#define iommufd_object_alloc(ictx, ptr, type) \
101+ container_of(_iommufd_object_alloc( \
102+ ictx, \
103+ sizeof(*(ptr)) + BUILD_BUG_ON_ZERO( \
104+ offsetof(typeof(*(ptr)), \
105+ obj) != 0), \
106+ type), \
107+ typeof(*(ptr)), obj)
108+
109+#endif
drivers/iommu/iommufd/main.c+344−0
@@ -0,0 +1,344 @@
1+// SPDX-License-Identifier: GPL-2.0-only
2+/* Copyright (C) 2021 Intel Corporation
3+ * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
4+ *
5+ * iommufd provides control over the IOMMU HW objects created by IOMMU kernel
6+ * drivers. IOMMU HW objects revolve around IO page tables that map incoming DMA
7+ * addresses (IOVA) to CPU addresses.
8+ */
9+#define pr_fmt(fmt) "iommufd: " fmt
10+
11+#include <linux/file.h>
12+#include <linux/fs.h>
13+#include <linux/module.h>
14+#include <linux/slab.h>
15+#include <linux/miscdevice.h>
16+#include <linux/mutex.h>
17+#include <linux/bug.h>
18+#include <uapi/linux/iommufd.h>
19+#include <linux/iommufd.h>
20+
21+#include "iommufd_private.h"
22+
23+struct iommufd_object_ops {
24+ void (*destroy)(struct iommufd_object *obj);
25+};
26+static const struct iommufd_object_ops iommufd_object_ops[];
27+
28+struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx,
29+ size_t size,
30+ enum iommufd_object_type type)
31+{
32+ struct iommufd_object *obj;
33+ int rc;
34+
35+ obj = kzalloc(size, GFP_KERNEL_ACCOUNT);
36+ if (!obj)
37+ return ERR_PTR(-ENOMEM);
38+ obj->type = type;
39+ init_rwsem(&obj->destroy_rwsem);
40+ refcount_set(&obj->users, 1);
41+
42+ /*
43+ * Reserve an ID in the xarray but do not publish the pointer yet since
44+ * the caller hasn't initialized it yet. Once the pointer is published
45+ * in the xarray and visible to other threads we can't reliably destroy
46+ * it anymore, so the caller must complete all errorable operations
47+ * before calling iommufd_object_finalize().
48+ */
49+ rc = xa_alloc(&ictx->objects, &obj->id, XA_ZERO_ENTRY,
50+ xa_limit_32b, GFP_KERNEL_ACCOUNT);
51+ if (rc)
52+ goto out_free;
53+ return obj;
54+out_free:
55+ kfree(obj);
56+ return ERR_PTR(rc);
57+}
58+
59+/*
60+ * Allow concurrent access to the object.
61+ *
62+ * Once another thread can see the object pointer it can prevent object
63+ * destruction. Expect for special kernel-only objects there is no in-kernel way
64+ * to reliably destroy a single object. Thus all APIs that are creating objects
65+ * must use iommufd_object_abort() to handle their errors and only call
66+ * iommufd_object_finalize() once object creation cannot fail.
67+ */
68+void iommufd_object_finalize(struct iommufd_ctx *ictx,
69+ struct iommufd_object *obj)
70+{
71+ void *old;
72+
73+ old = xa_store(&ictx->objects, obj->id, obj, GFP_KERNEL);
74+ /* obj->id was returned from xa_alloc() so the xa_store() cannot fail */
75+ WARN_ON(old);
76+}
77+
78+/* Undo _iommufd_object_alloc() if iommufd_object_finalize() was not called */
79+void iommufd_object_abort(struct iommufd_ctx *ictx, struct iommufd_object *obj)
80+{
81+ void *old;
82+
83+ old = xa_erase(&ictx->objects, obj->id);
84+ WARN_ON(old);
85+ kfree(obj);
86+}
87+
88+/*
89+ * Abort an object that has been fully initialized and needs destroy, but has
90+ * not been finalized.
91+ */
92+void iommufd_object_abort_and_destroy(struct iommufd_ctx *ictx,
93+ struct iommufd_object *obj)
94+{
95+ iommufd_object_ops[obj->type].destroy(obj);
96+ iommufd_object_abort(ictx, obj);
97+}
98+
99+struct iommufd_object *iommufd_get_object(struct iommufd_ctx *ictx, u32 id,
100+ enum iommufd_object_type type)
101+{
102+ struct iommufd_object *obj;
103+
104+ xa_lock(&ictx->objects);
105+ obj = xa_load(&ictx->objects, id);
106+ if (!obj || (type != IOMMUFD_OBJ_ANY && obj->type != type) ||
107+ !iommufd_lock_obj(obj))
108+ obj = ERR_PTR(-ENOENT);
109+ xa_unlock(&ictx->objects);
110+ return obj;
111+}
112+
113+/*
114+ * The caller holds a users refcount and wants to destroy the object. Returns
115+ * true if the object was destroyed. In all cases the caller no longer has a
116+ * reference on obj.
117+ */
118+bool iommufd_object_destroy_user(struct iommufd_ctx *ictx,
119+ struct iommufd_object *obj)
120+{
121+ /*
122+ * The purpose of the destroy_rwsem is to ensure deterministic
123+ * destruction of objects used by external drivers and destroyed by this
124+ * function. Any temporary increment of the refcount must hold the read
125+ * side of this, such as during ioctl execution.
126+ */
127+ down_write(&obj->destroy_rwsem);
128+ xa_lock(&ictx->objects);
129+ refcount_dec(&obj->users);
130+ if (!refcount_dec_if_one(&obj->users)) {
131+ xa_unlock(&ictx->objects);
132+ up_write(&obj->destroy_rwsem);
133+ return false;
134+ }
135+ __xa_erase(&ictx->objects, obj->id);
136+ xa_unlock(&ictx->objects);
137+ up_write(&obj->destroy_rwsem);
138+
139+ iommufd_object_ops[obj->type].destroy(obj);
140+ kfree(obj);
141+ return true;
142+}
143+
144+static int iommufd_destroy(struct iommufd_ucmd *ucmd)
145+{
146+ struct iommu_destroy *cmd = ucmd->cmd;
147+ struct iommufd_object *obj;
148+
149+ obj = iommufd_get_object(ucmd->ictx, cmd->id, IOMMUFD_OBJ_ANY);
150+ if (IS_ERR(obj))
151+ return PTR_ERR(obj);
152+ iommufd_ref_to_users(obj);
153+ /* See iommufd_ref_to_users() */
154+ if (!iommufd_object_destroy_user(ucmd->ictx, obj))
155+ return -EBUSY;
156+ return 0;
157+}
158+
159+static int iommufd_fops_open(struct inode *inode, struct file *filp)
160+{
161+ struct iommufd_ctx *ictx;
162+
163+ ictx = kzalloc(sizeof(*ictx), GFP_KERNEL_ACCOUNT);
164+ if (!ictx)
165+ return -ENOMEM;
166+
167+ xa_init_flags(&ictx->objects, XA_FLAGS_ALLOC1 | XA_FLAGS_ACCOUNT);
168+ ictx->file = filp;
169+ filp->private_data = ictx;
170+ return 0;
171+}
172+
173+static int iommufd_fops_release(struct inode *inode, struct file *filp)
174+{
175+ struct iommufd_ctx *ictx = filp->private_data;
176+ struct iommufd_object *obj;
177+
178+ /*
179+ * The objects in the xarray form a graph of "users" counts, and we have
180+ * to destroy them in a depth first manner. Leaf objects will reduce the
181+ * users count of interior objects when they are destroyed.
182+ *
183+ * Repeatedly destroying all the "1 users" leaf objects will progress
184+ * until the entire list is destroyed. If this can't progress then there
185+ * is some bug related to object refcounting.
186+ */
187+ while (!xa_empty(&ictx->objects)) {
188+ unsigned int destroyed = 0;
189+ unsigned long index;
190+
191+ xa_for_each(&ictx->objects, index, obj) {
192+ if (!refcount_dec_if_one(&obj->users))
193+ continue;
194+ destroyed++;
195+ xa_erase(&ictx->objects, index);
196+ iommufd_object_ops[obj->type].destroy(obj);
197+ kfree(obj);
198+ }
199+ /* Bug related to users refcount */
200+ if (WARN_ON(!destroyed))
201+ break;
202+ }
203+ kfree(ictx);
204+ return 0;
205+}
206+
207+union ucmd_buffer {
208+ struct iommu_destroy destroy;
209+};
210+
211+struct iommufd_ioctl_op {
212+ unsigned int size;
213+ unsigned int min_size;
214+ unsigned int ioctl_num;
215+ int (*execute)(struct iommufd_ucmd *ucmd);
216+};
217+
218+#define IOCTL_OP(_ioctl, _fn, _struct, _last) \
219+ [_IOC_NR(_ioctl) - IOMMUFD_CMD_BASE] = { \
220+ .size = sizeof(_struct) + \
221+ BUILD_BUG_ON_ZERO(sizeof(union ucmd_buffer) < \
222+ sizeof(_struct)), \
223+ .min_size = offsetofend(_struct, _last), \
224+ .ioctl_num = _ioctl, \
225+ .execute = _fn, \
226+ }
227+static const struct iommufd_ioctl_op iommufd_ioctl_ops[] = {
228+ IOCTL_OP(IOMMU_DESTROY, iommufd_destroy, struct iommu_destroy, id),
229+};
230+
231+static long iommufd_fops_ioctl(struct file *filp, unsigned int cmd,
232+ unsigned long arg)
233+{
234+ const struct iommufd_ioctl_op *op;
235+ struct iommufd_ucmd ucmd = {};
236+ union ucmd_buffer buf;
237+ unsigned int nr;
238+ int ret;
239+
240+ ucmd.ictx = filp->private_data;
241+ ucmd.ubuffer = (void __user *)arg;
242+ ret = get_user(ucmd.user_size, (u32 __user *)ucmd.ubuffer);
243+ if (ret)
244+ return ret;
245+
246+ nr = _IOC_NR(cmd);
247+ if (nr < IOMMUFD_CMD_BASE ||
248+ (nr - IOMMUFD_CMD_BASE) >= ARRAY_SIZE(iommufd_ioctl_ops))
249+ return -ENOIOCTLCMD;
250+ op = &iommufd_ioctl_ops[nr - IOMMUFD_CMD_BASE];
251+ if (op->ioctl_num != cmd)
252+ return -ENOIOCTLCMD;
253+ if (ucmd.user_size < op->min_size)
254+ return -EINVAL;
255+
256+ ucmd.cmd = &buf;
257+ ret = copy_struct_from_user(ucmd.cmd, op->size, ucmd.ubuffer,
258+ ucmd.user_size);
259+ if (ret)
260+ return ret;
261+ ret = op->execute(&ucmd);
262+ return ret;
263+}
264+
265+static const struct file_operations iommufd_fops = {
266+ .owner = THIS_MODULE,
267+ .open = iommufd_fops_open,
268+ .release = iommufd_fops_release,
269+ .unlocked_ioctl = iommufd_fops_ioctl,
270+};
271+
272+/**
273+ * iommufd_ctx_get - Get a context reference
274+ * @ictx: Context to get
275+ *
276+ * The caller must already hold a valid reference to ictx.
277+ */
278+void iommufd_ctx_get(struct iommufd_ctx *ictx)
279+{
280+ get_file(ictx->file);
281+}
282+EXPORT_SYMBOL_NS_GPL(iommufd_ctx_get, IOMMUFD);
283+
284+/**
285+ * iommufd_ctx_from_file - Acquires a reference to the iommufd context
286+ * @file: File to obtain the reference from
287+ *
288+ * Returns a pointer to the iommufd_ctx, otherwise ERR_PTR. The struct file
289+ * remains owned by the caller and the caller must still do fput. On success
290+ * the caller is responsible to call iommufd_ctx_put().
291+ */
292+struct iommufd_ctx *iommufd_ctx_from_file(struct file *file)
293+{
294+ struct iommufd_ctx *ictx;
295+
296+ if (file->f_op != &iommufd_fops)
297+ return ERR_PTR(-EBADFD);
298+ ictx = file->private_data;
299+ iommufd_ctx_get(ictx);
300+ return ictx;
301+}
302+EXPORT_SYMBOL_NS_GPL(iommufd_ctx_from_file, IOMMUFD);
303+
304+/**
305+ * iommufd_ctx_put - Put back a reference
306+ * @ictx: Context to put back
307+ */
308+void iommufd_ctx_put(struct iommufd_ctx *ictx)
309+{
310+ fput(ictx->file);
311+}
312+EXPORT_SYMBOL_NS_GPL(iommufd_ctx_put, IOMMUFD);
313+
314+static const struct iommufd_object_ops iommufd_object_ops[] = {
315+};
316+
317+static struct miscdevice iommu_misc_dev = {
318+ .minor = MISC_DYNAMIC_MINOR,
319+ .name = "iommu",
320+ .fops = &iommufd_fops,
321+ .nodename = "iommu",
322+ .mode = 0660,
323+};
324+
325+static int __init iommufd_init(void)
326+{
327+ int ret;
328+
329+ ret = misc_register(&iommu_misc_dev);
330+ if (ret)
331+ return ret;
332+ return 0;
333+}
334+
335+static void __exit iommufd_exit(void)
336+{
337+ misc_deregister(&iommu_misc_dev);
338+}
339+
340+module_init(iommufd_init);
341+module_exit(iommufd_exit);
342+
343+MODULE_DESCRIPTION("I/O Address Space Management for passthrough devices");
344+MODULE_LICENSE("GPL");
include/linux/iommufd.h+31−0
@@ -0,0 +1,31 @@
1+/* SPDX-License-Identifier: GPL-2.0-only */
2+/*
3+ * Copyright (C) 2021 Intel Corporation
4+ * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES
5+ */
6+#ifndef __LINUX_IOMMUFD_H
7+#define __LINUX_IOMMUFD_H
8+
9+#include <linux/types.h>
10+#include <linux/errno.h>
11+#include <linux/err.h>
12+
13+struct iommufd_ctx;
14+struct file;
15+
16+void iommufd_ctx_get(struct iommufd_ctx *ictx);
17+
18+#if IS_ENABLED(CONFIG_IOMMUFD)
19+struct iommufd_ctx *iommufd_ctx_from_file(struct file *file);
20+void iommufd_ctx_put(struct iommufd_ctx *ictx);
21+#else /* !CONFIG_IOMMUFD */
22+static inline struct iommufd_ctx *iommufd_ctx_from_file(struct file *file)
23+{
24+ return ERR_PTR(-EOPNOTSUPP);
25+}
26+
27+static inline void iommufd_ctx_put(struct iommufd_ctx *ictx)
28+{
29+}
30+#endif /* CONFIG_IOMMUFD */
31+#endif
include/uapi/linux/iommufd.h+55−0
@@ -0,0 +1,55 @@
1+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2+/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES.
3+ */
4+#ifndef _UAPI_IOMMUFD_H
5+#define _UAPI_IOMMUFD_H
6+
7+#include <linux/types.h>
8+#include <linux/ioctl.h>
9+
10+#define IOMMUFD_TYPE (';')
11+
12+/**
13+ * DOC: General ioctl format
14+ *
15+ * The ioctl interface follows a general format to allow for extensibility. Each
16+ * ioctl is passed in a structure pointer as the argument providing the size of
17+ * the structure in the first u32. The kernel checks that any structure space
18+ * beyond what it understands is 0. This allows userspace to use the backward
19+ * compatible portion while consistently using the newer, larger, structures.
20+ *
21+ * ioctls use a standard meaning for common errnos:
22+ *
23+ * - ENOTTY: The IOCTL number itself is not supported at all
24+ * - E2BIG: The IOCTL number is supported, but the provided structure has
25+ * non-zero in a part the kernel does not understand.
26+ * - EOPNOTSUPP: The IOCTL number is supported, and the structure is
27+ * understood, however a known field has a value the kernel does not
28+ * understand or support.
29+ * - EINVAL: Everything about the IOCTL was understood, but a field is not
30+ * correct.
31+ * - ENOENT: An ID or IOVA provided does not exist.
32+ * - ENOMEM: Out of memory.
33+ * - EOVERFLOW: Mathematics overflowed.
34+ *
35+ * As well as additional errnos, within specific ioctls.
36+ */
37+enum {
38+ IOMMUFD_CMD_BASE = 0x80,
39+ IOMMUFD_CMD_DESTROY = IOMMUFD_CMD_BASE,
40+};
41+
42+/**
43+ * struct iommu_destroy - ioctl(IOMMU_DESTROY)
44+ * @size: sizeof(struct iommu_destroy)
45+ * @id: iommufd object ID to destroy. Can by any destroyable object type.
46+ *
47+ * Destroy any object held within iommufd.
48+ */
49+struct iommu_destroy {
50+ __u32 size;
51+ __u32 id;
52+};
53+#define IOMMU_DESTROY _IO(IOMMUFD_TYPE, IOMMUFD_CMD_DESTROY)
54+
55+#endif