forked from torvalds/linux
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 user 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. Signed-off-by: Yi Liu <yi.l.liu@intel.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
- Loading branch information
1 parent
07b1919
commit a9a0de9
Showing
10 changed files
with
572 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# SPDX-License-Identifier: GPL-2.0-only | ||
config IOMMUFD | ||
tristate "IOMMU Userspace API" | ||
select INTERVAL_TREE | ||
select IOMMU_API | ||
default n | ||
help | ||
Provides /dev/iommu the user API to control the IOMMU subsystem as | ||
it relates to managing IO page tables that point at user space memory. | ||
|
||
This would commonly be used in combination with VFIO. | ||
|
||
If you don't know what to do here, say N. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# SPDX-License-Identifier: GPL-2.0-only | ||
iommufd-y := \ | ||
main.o | ||
|
||
obj-$(CONFIG_IOMMUFD) += iommufd.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* SPDX-License-Identifier: GPL-2.0-only */ | ||
/* Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES | ||
*/ | ||
#ifndef __IOMMUFD_PRIVATE_H | ||
#define __IOMMUFD_PRIVATE_H | ||
|
||
#include <linux/rwsem.h> | ||
#include <linux/xarray.h> | ||
#include <linux/refcount.h> | ||
#include <linux/uaccess.h> | ||
|
||
struct iommufd_ctx { | ||
struct file *file; | ||
struct xarray objects; | ||
}; | ||
|
||
struct iommufd_ctx *iommufd_fget(int fd); | ||
|
||
struct iommufd_ucmd { | ||
struct iommufd_ctx *ictx; | ||
void __user *ubuffer; | ||
u32 user_size; | ||
void *cmd; | ||
}; | ||
|
||
/* Copy the response in ucmd->cmd back to userspace. */ | ||
static inline int iommufd_ucmd_respond(struct iommufd_ucmd *ucmd, | ||
size_t cmd_len) | ||
{ | ||
if (copy_to_user(ucmd->ubuffer, ucmd->cmd, | ||
min_t(size_t, ucmd->user_size, cmd_len))) | ||
return -EFAULT; | ||
return 0; | ||
} | ||
|
||
enum iommufd_object_type { | ||
IOMMUFD_OBJ_NONE, | ||
IOMMUFD_OBJ_ANY = IOMMUFD_OBJ_NONE, | ||
}; | ||
|
||
/* Base struct for all objects with a userspace ID handle. */ | ||
struct iommufd_object { | ||
struct rw_semaphore destroy_rwsem; | ||
refcount_t users; | ||
enum iommufd_object_type type; | ||
unsigned int id; | ||
}; | ||
|
||
static inline bool iommufd_lock_obj(struct iommufd_object *obj) | ||
{ | ||
if (!down_read_trylock(&obj->destroy_rwsem)) | ||
return false; | ||
if (!refcount_inc_not_zero(&obj->users)) { | ||
up_read(&obj->destroy_rwsem); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
struct iommufd_object *iommufd_get_object(struct iommufd_ctx *ictx, u32 id, | ||
enum iommufd_object_type type); | ||
static inline void iommufd_put_object(struct iommufd_object *obj) | ||
{ | ||
refcount_dec(&obj->users); | ||
up_read(&obj->destroy_rwsem); | ||
} | ||
|
||
/** | ||
* iommufd_put_object_keep_user() - Release part of the refcount on obj | ||
* @obj - Object to release | ||
* | ||
* Objects have two protections to ensure that userspace has a consistent | ||
* experience with destruction. Normally objects are locked so that destroy will | ||
* block while there are concurrent users, and wait for the object to be | ||
* unlocked. | ||
* | ||
* However, destroy can also be blocked by holding users reference counts on the | ||
* objects, in that case destroy will immediately return EBUSY and will not wait | ||
* for reference counts to go to zero. | ||
* | ||
* This function releases the destroy lock and destroy will return EBUSY. | ||
* | ||
* It should be used in places where the users will be held beyond a single | ||
* system call. | ||
*/ | ||
static inline void iommufd_put_object_keep_user(struct iommufd_object *obj) | ||
{ | ||
up_read(&obj->destroy_rwsem); | ||
} | ||
void iommufd_object_abort(struct iommufd_ctx *ictx, struct iommufd_object *obj); | ||
void iommufd_object_abort_and_destroy(struct iommufd_ctx *ictx, | ||
struct iommufd_object *obj); | ||
void iommufd_object_finalize(struct iommufd_ctx *ictx, | ||
struct iommufd_object *obj); | ||
bool iommufd_object_destroy_user(struct iommufd_ctx *ictx, | ||
struct iommufd_object *obj); | ||
struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx, | ||
size_t size, | ||
enum iommufd_object_type type); | ||
|
||
#define iommufd_object_alloc(ictx, ptr, type) \ | ||
container_of(_iommufd_object_alloc( \ | ||
ictx, \ | ||
sizeof(*(ptr)) + BUILD_BUG_ON_ZERO( \ | ||
offsetof(typeof(*(ptr)), \ | ||
obj) != 0), \ | ||
type), \ | ||
typeof(*(ptr)), obj) | ||
|
||
#endif |
Oops, something went wrong.