svn commit: r340181 - in head/sys: amd64/linux32 compat/linux
Alexander Leidinger
Alexander at Leidinger.net
Tue Nov 6 15:18:18 UTC 2018
Targeted for 12.0-release?
Relnotes yes (linux64 support for NVidia driver)?
--
Send from a mobile device, please forgive brevity and misspellings.
Am 06.11.2018 2:51 nachm. schrieb Tijl Coosemans <tijl at FreeBSD.org>:
>
> Author: tijl
> Date: Tue Nov 6 13:51:08 2018
> New Revision: 340181
> URL: https://svnweb.freebsd.org/changeset/base/340181
>
> Log:
> On amd64 both Linux compat modules, linux.ko and linux64.ko, provide
> linux_ioctl_(un)register_handler that allows other driver modules to
> register ioctl handlers. The ioctl syscall implementation in each Linux
> compat module iterates over the list of handlers and forwards the call to
> the appropriate driver. Because the registration functions have the same
> name in each module it is not possible for a driver to support both 32 and
> 64 bit linux compatibility.
>
> Move the list of ioctl handlers to linux_common.ko so it is shared by
> both Linux modules and all drivers receive both 32 and 64 bit ioctl calls
> with one registration. These ioctl handlers normally forward the call
> to the FreeBSD ioctl handler which can handle both 32 and 64 bit.
>
> Keep the special COMPAT_LINUX32 ioctl handlers in linux.ko in a separate
> list for now and let the ioctl syscall iterate over that list first.
> Later, COMPAT_LINUX32 support can be added to the 64 bit ioctl handlers
> via a runtime check for ILP32 like is done for COMPAT_FREEBSD32 and then
> this separate list would disappear again. That is a much bigger effort
> however and this commit is meant to be MFCable.
>
> This enables linux64 support in x11/nvidia-driver*.
>
> PR: 206711 http://www.FreeBSD.org/cgi/query-pr.cgi?pr=206711
> Reviewed by: kib
> MFC after: 3 days
>
> Modified:
> head/sys/amd64/linux32/linux32_sysvec.c https://svnweb.FreeBSD.org/base/head/sys/amd64/linux32/linux32_sysvec
> head/sys/compat/linux/linux_common.c https://svnweb.FreeBSD.org/base/head/sys/compat/linux/linux_common
> head/sys/compat/linux/linux_ioctl.c https://svnweb.FreeBSD.org/base/head/sys/compat/linux/linux_ioctl
> head/sys/compat/linux/linux_ioctl.h https://svnweb.FreeBSD.org/base/head/sys/compat/linux/linux_ioctl
>
> Modified: head/sys/amd64/linux32/linux32_sysvec.c
> ==============================================================================
> --- head/sys/amd64/linux32/linux32_sysvec.c Tue Nov 6 12:57:38 2018 (r340180)
> +++ head/sys/amd64/linux32/linux32_sysvec.c Tue Nov 6 13:51:08 2018 (r340181)
> @@ -1071,7 +1071,7 @@ linux_elf_modevent(module_t mod, int type, void *data)
> error = EINVAL;
> if (error == 0) {
> SET_FOREACH(lihp, linux_ioctl_handler_set)
> - linux_ioctl_register_handler(*lihp);
> + linux32_ioctl_register_handler(*lihp);
> LIST_INIT(&futex_list);
> mtx_init(&futex_mtx, "ftllk", NULL, MTX_DEF);
> stclohz = (stathz ? stathz : hz);
> @@ -1093,7 +1093,7 @@ linux_elf_modevent(module_t mod, int type, void *data)
> }
> if (error == 0) {
> SET_FOREACH(lihp, linux_ioctl_handler_set)
> - linux_ioctl_unregister_handler(*lihp);
> + linux32_ioctl_unregister_handler(*lihp);
> mtx_destroy(&futex_mtx);
> if (bootverbose)
> printf("Linux ELF exec handler removed\n");
>
> Modified: head/sys/compat/linux/linux_common.c
> ==============================================================================
> --- head/sys/compat/linux/linux_common.c Tue Nov 6 12:57:38 2018 (r340180)
> +++ head/sys/compat/linux/linux_common.c Tue Nov 6 13:51:08 2018 (r340181)
> @@ -35,9 +35,11 @@ __FBSDID("$FreeBSD$");
> #include <sys/kernel.h>
> #include <sys/malloc.h>
> #include <sys/eventhandler.h>
> +#include <sys/sx.h>
> #include <sys/sysctl.h>
>
> #include <compat/linux/linux_emul.h>
> +#include <compat/linux/linux_ioctl.h>
> #include <compat/linux/linux_mib.h>
> #include <compat/linux/linux_util.h>
>
> @@ -47,6 +49,11 @@ FEATURE(linuxulator_v4l2, "V4L2 ioctl wrapper support
> MODULE_VERSION(linux_common, 1);
>
> SET_DECLARE(linux_device_handler_set, struct linux_device_handler);
> +
> +TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers =
> + TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers);
> +struct sx linux_ioctl_sx;
> +SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers");
>
> static eventhandler_tag linux_exec_tag;
> static eventhandler_tag linux_thread_dtor_tag;
>
> Modified: head/sys/compat/linux/linux_ioctl.c
> ==============================================================================
> --- head/sys/compat/linux/linux_ioctl.c Tue Nov 6 12:57:38 2018 (r340180)
> +++ head/sys/compat/linux/linux_ioctl.c Tue Nov 6 13:51:08 2018 (r340181)
> @@ -161,17 +161,19 @@ DATA_SET(linux_ioctl_handler_set, video2_handler);
> DATA_SET(linux_ioctl_handler_set, fbsd_usb);
> DATA_SET(linux_ioctl_handler_set, evdev_handler);
>
> -struct handler_element
> -{
> - TAILQ_ENTRY(handler_element) list;
> - int (*func)(struct thread *, struct linux_ioctl_args *);
> - int low, high, span;
> -};
> -
> -static TAILQ_HEAD(, handler_element) handlers =
> - TAILQ_HEAD_INITIALIZER(handlers);
> +#ifdef __i386__
> +static TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers =
> + TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers);
> static struct sx linux_ioctl_sx;
> SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers");
> +#else
> +extern TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers;
> +extern struct sx linux_ioctl_sx;
> +#endif
> +#ifdef COMPAT_LINUX32
> +static TAILQ_HEAD(, linux_ioctl_handler_element) linux32_ioctl_handlers =
> + TAILQ_HEAD_INITIALIZER(linux32_ioctl_handlers);
> +#endif
>
> /*
> * hdio related ioctls for VMWare support
> @@ -3684,7 +3686,7 @@ int
> linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
> {
> struct file *fp;
> - struct handler_element *he;
> + struct linux_ioctl_handler_element *he;
> int error, cmd;
>
> #ifdef DEBUG
> @@ -3705,7 +3707,8 @@ linux_ioctl(struct thread *td, struct linux_ioctl_args
> cmd = args->cmd & 0xffff;
> sx_slock(&linux_ioctl_sx);
> mtx_lock(&Giant);
> - TAILQ_FOREACH(he, &handlers, list) {
> +#ifdef COMPAT_LINUX32
> + TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) {
> if (cmd >= he->low && cmd <= he->high) {
> error = (*he->func)(td, args);
> if (error != ENOIOCTL) {
> @@ -3716,6 +3719,18 @@ linux_ioctl(struct thread *td, struct linux_ioctl_args
> }
> }
> }
> +#endif
> + TAILQ_FOREACH(he, &linux_ioctl_handlers, list) {
> + if (cmd >= he->low && cmd <= he->high) {
> + error = (*he->func)(td, args);
> + if (error != ENOIOCTL) {
> + mtx_unlock(&Giant);
> + sx_sunlock(&linux_ioctl_sx);
> + fdrop(fp, td);
> + return (error);
> + }
> + }
> + }
> mtx_unlock(&Giant);
> sx_sunlock(&linux_ioctl_sx);
> fdrop(fp, td);
> @@ -3737,7 +3752,7 @@ linux_ioctl(struct thread *td, struct linux_ioctl_args
> int
> linux_ioctl_register_handler(struct linux_ioctl_handler *h)
> {
> - struct handler_element *he, *cur;
> + struct linux_ioctl_handler_element *he, *cur;
>
> if (h == NULL || h->func == NULL)
> return (EINVAL);
> @@ -3747,7 +3762,7 @@ linux_ioctl_register_handler(struct linux_ioctl_handle
> * create a new element.
> */
> sx_xlock(&linux_ioctl_sx);
> - TAILQ_FOREACH(he, &handlers, list) {
> + TAILQ_FOREACH(he, &linux_ioctl_handlers, list) {
> if (he->func == h->func)
> break;
> }
> @@ -3756,7 +3771,7 @@ linux_ioctl_register_handler(struct linux_ioctl_handle
> M_LINUX, M_WAITOK);
> he->func = h->func;
> } else
> - TAILQ_REMOVE(&handlers, he, list);
> + TAILQ_REMOVE(&linux_ioctl_handlers, he, list);
>
> /* Initialize range information. */
> he->low = h->low;
> @@ -3764,14 +3779,14 @@ linux_ioctl_register_handler(struct linux_ioctl_handle
> he->span = h->high - h->low + 1;
>
> /* Add the element to the list, sorted on span. */
> - TAILQ_FOREACH(cur, &handlers, list) {
> + TAILQ_FOREACH(cur, &linux_ioctl_handlers, list) {
> if (cur->span > he->span) {
> TAILQ_INSERT_BEFORE(cur, he, list);
> sx_xunlock(&linux_ioctl_sx);
> return (0);
> }
> }
> - TAILQ_INSERT_TAIL(&handlers, he, list);
> + TAILQ_INSERT_TAIL(&linux_ioctl_handlers, he, list);
> sx_xunlock(&linux_ioctl_sx);
>
> return (0);
> @@ -3780,15 +3795,15 @@ linux_ioctl_register_handler(struct linux_ioctl_handle
> int
> linux_ioctl_unregister_handler(struct linux_ioctl_handler *h)
> {
> - struct handler_element *he;
> + struct linux_ioctl_handler_element *he;
>
> if (h == NULL || h->func == NULL)
> return (EINVAL);
>
> sx_xlock(&linux_ioctl_sx);
> - TAILQ_FOREACH(he, &handlers, list) {
> + TAILQ_FOREACH(he, &linux_ioctl_handlers, list) {
> if (he->func == h->func) {
> - TAILQ_REMOVE(&handlers, he, list);
> + TAILQ_REMOVE(&linux_ioctl_handlers, he, list);
> sx_xunlock(&linux_ioctl_sx);
> free(he, M_LINUX);
> return (0);
> @@ -3798,3 +3813,69 @@ linux_ioctl_unregister_handler(struct linux_ioctl_hand
>
> return (EINVAL);
> }
> +
> +#ifdef COMPAT_LINUX32
> +int
> +linux32_ioctl_register_handler(struct linux_ioctl_handler *h)
> +{
> + struct linux_ioctl_handler_element *he, *cur;
> +
> + if (h == NULL || h->func == NULL)
> + return (EINVAL);
> +
> + /*
> + * Reuse the element if the handler is already on the list, otherwise
> + * create a new element.
> + */
> + sx_xlock(&linux_ioctl_sx);
> + TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) {
> + if (he->func == h->func)
> + break;
> + }
> + if (he == NULL) {
> + he = malloc(sizeof(*he), M_LINUX, M_WAITOK);
> + he->func = h->func;
> + } else
> + TAILQ_REMOVE(&linux32_ioctl_handlers, he, list);
> +
> + /* Initialize range information. */
> + he->low = h->low;
> + he->high = h->high;
> + he->span = h->high - h->low + 1;
> +
> + /* Add the element to the list, sorted on span. */
> + TAILQ_FOREACH(cur, &linux32_ioctl_handlers, list) {
> + if (cur->span > he->span) {
> + TAILQ_INSERT_BEFORE(cur, he, list);
> + sx_xunlock(&linux_ioctl_sx);
> + return (0);
> + }
> + }
> + TAILQ_INSERT_TAIL(&linux32_ioctl_handlers, he, list);
> + sx_xunlock(&linux_ioctl_sx);
> +
> + return (0);
> +}
> +
> +int
> +linux32_ioctl_unregister_handler(struct linux_ioctl_handler *h)
> +{
> + struct linux_ioctl_handler_element *he;
> +
> + if (h == NULL || h->func == NULL)
> + return (EINVAL);
> +
> + sx_xlock(&linux_ioctl_sx);
> + TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) {
> + if (he->func == h->func) {
> + TAILQ_REMOVE(&linux32_ioctl_handlers, he, list);
> + sx_xunlock(&linux_ioctl_sx);
> + free(he, M_LINUX);
> + return (0);
> + }
> + }
> + sx_xunlock(&linux_ioctl_sx);
> +
> + return (EINVAL);
> +}
> +#endif
>
> Modified: head/sys/compat/linux/linux_ioctl.h
> ==============================================================================
> --- head/sys/compat/linux/linux_ioctl.h Tue Nov 6 12:57:38 2018 (r340180)
> +++ head/sys/compat/linux/linux_ioctl.h Tue Nov 6 13:51:08 2018 (r340181)
> @@ -770,7 +770,18 @@ struct linux_ioctl_handler {
> int low, high;
> };
>
> +struct linux_ioctl_handler_element
> +{
> + TAILQ_ENTRY(linux_ioctl_handler_element) list;
> + int (*func)(struct thread *, struct linux_ioctl_args *);
> + int low, high, span;
> +};
> +
> int linux_ioctl_register_handler(struct linux_ioctl_handler *h);
> int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h);
> +#ifdef COMPAT_LINUX32
> +int linux32_ioctl_register_handler(struct linux_ioctl_handler *h);
> +int linux32_ioctl_unregister_handler(struct linux_ioctl_handler *h);
> +#endif
>
> #endif /* !_LINUX_IOCTL_H_ */
>
More information about the svn-src-all
mailing list