Documentation/process/botching-up-ioctls.rst

Source file repositories/reference/linux-study-clean/Documentation/process/botching-up-ioctls.rst

File Facts

System
Linux kernel
Corpus path
Documentation/process/botching-up-ioctls.rst
Extension
.rst
Size
11574 bytes
Lines
226
Domain
Support Tooling And Documentation
Bucket
Documentation
Inferred role
Support Tooling And Documentation: documentation
Status
atlas-only

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

=================================
(How to avoid) Botching up ioctls
=================================

From: https://blog.ffwll.ch/2013/11/botching-up-ioctls.html

By: Daniel Vetter, Copyright © 2013 Intel Corporation

One clear insight kernel graphics hackers gained in the past few years is that
trying to come up with a unified interface to manage the execution units and
memory on completely different GPUs is a futile effort. So nowadays every
driver has its own set of ioctls to allocate memory and submit work to the GPU.
Which is nice, since there's no more insanity in the form of fake-generic, but
actually only used once interfaces. But the clear downside is that there's much
more potential to screw things up.

To avoid repeating all the same mistakes again I've written up some of the
lessons learned while botching the job for the drm/i915 driver. Most of these
only cover technicalities and not the big-picture issues like what the command
submission ioctl exactly should look like. Learning these lessons is probably
something every GPU driver has to do on its own.


Prerequisites
-------------

First the prerequisites. Without these you have already failed, because you
will need to add a 32-bit compat layer:

 * Only use fixed sized integers. To avoid conflicts with typedefs in userspace
   the kernel has special types like __u32, __s64. Use them.

 * Align everything to the natural size and use explicit padding. 32-bit
   platforms don't necessarily align 64-bit values to 64-bit boundaries, but
   64-bit platforms do. So we always need padding to the natural size to get
   this right.

 * Pad the entire struct to a multiple of 64-bits if the structure contains
   64-bit types - the structure size will otherwise differ on 32-bit versus
   64-bit. Having a different structure size hurts when passing arrays of
   structures to the kernel, or if the kernel checks the structure size, which
   e.g. the drm core does.

 * Pointers are __u64, cast from/to a uintptr_t on the userspace side and
   from/to a void __user * in the kernel. Try really hard not to delay this
   conversion or worse, fiddle the raw __u64 through your code since that
   diminishes the checking tools like sparse can provide. The macro
   u64_to_user_ptr can be used in the kernel to avoid warnings about integers
   and pointers of different sizes.


Basics
------

With the joys of writing a compat layer avoided we can take a look at the basic
fumbles. Neglecting these will make backward and forward compatibility a real
pain. And since getting things wrong on the first attempt is guaranteed you
will have a second iteration or at least an extension for any given interface.

 * Have a clear way for userspace to figure out whether your new ioctl or ioctl
   extension is supported on a given kernel. If you can't rely on old kernels
   rejecting the new flags/modes or ioctls (since doing that was botched in the
   past) then you need a driver feature flag or revision number somewhere.

 * Have a plan for extending ioctls with new flags or new fields at the end of
   the structure. The drm core checks the passed-in size for each ioctl call
   and zero-extends any mismatches between kernel and userspace. That helps,
   but isn't a complete solution since newer userspace on older kernels won't
   notice that the newly added fields at the end get ignored. So this still
   needs a new driver feature flags.

Annotation

Implementation Notes