[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH 2/3] Save handlers between calls to ioctl
From: |
olafBuddenhagen |
Subject: |
Re: [PATCH 2/3] Save handlers between calls to ioctl |
Date: |
Mon, 31 Aug 2009 10:44:09 +0200 |
User-agent: |
Mutt/1.5.19 (2009-01-05) |
Hi,
On Wed, Aug 26, 2009 at 04:44:58PM +0200, Carl Fredrik Hammar wrote:
> diff --git a/hurd/Makefile b/hurd/Makefile
> index 4ad5128..768f93a 100644
> --- a/hurd/Makefile
> +++ b/hurd/Makefile
> @@ -68,7 +68,7 @@ sig = hurdsig hurdfault siginfo hurd-raise preempt-sig \
> dtable = dtable port2fd new-fd alloc-fd intern-fd \
> getdport openport \
> fd-close fd-read fd-write hurdioctl ctty-input ctty-output \
> - fd-ioctl-call
> + fd-ioctl-call fd-ioctl-cleanup
> inlines = $(inline-headers:%.h=%-inlines)
> distribute = hurdstartup.h hurdfault.h hurdhost.h sysvshm.h \
> faultexc.defs intr-rpc.defs intr-rpc.h intr-msg.h Notes
> diff --git a/hurd/dtable.c b/hurd/dtable.c
> index 125345e..bf5a9c1 100644
> --- a/hurd/dtable.c
> +++ b/hurd/dtable.c
> @@ -1,4 +1,5 @@
> -/* Copyright (C) 1991,92,93,94,95,96,97,99 Free Software Foundation, Inc.
> +/* Copyright (C) 1991,92,93,94,95,96,97,99,2009
> + Free Software Foundation, Inc.
> This file is part of the GNU C Library.
>
> The GNU C Library is free software; you can redistribute it and/or
> @@ -70,6 +71,11 @@ init_dtable (void)
> _hurd_port_init (&new->port, MACH_PORT_NULL);
> _hurd_port_init (&new->ctty, MACH_PORT_NULL);
>
> + /* Initialize the ioctl handler. */
> + new->ioctl_handler = NULL;
> + new->ioctl_handler_map = NULL;
> + new->ioctl_handler_users = NULL;
> +
> /* Install the port in the descriptor.
> This sets up all the ctty magic. */
> _hurd_port2fd (new, _hurd_init_dtable[i], 0);
> diff --git a/hurd/fd-close.c b/hurd/fd-close.c
> index f497d75..f3d0aa5 100644
> --- a/hurd/fd-close.c
> +++ b/hurd/fd-close.c
> @@ -1,4 +1,4 @@
> -/* Copyright (C) 1994, 1995, 1997 Free Software Foundation, Inc.
> +/* Copyright (C) 1994, 1995, 1997, 2009 Free Software Foundation, Inc.
> This file is part of the GNU C Library.
>
> The GNU C Library is free software; you can redistribute it and/or
> @@ -17,6 +17,7 @@
> 02111-1307 USA. */
>
> #include <hurd/fd.h>
> +#include <dlfcn.h>
>
> error_t
> _hurd_fd_close (struct hurd_fd *fd)
> @@ -33,10 +34,20 @@ _hurd_fd_close (struct hurd_fd *fd)
> }
> else
> {
> + /* Clear the descriptor's ioctl handler, and close its liker map. */
> + if (fd->ioctl_handler_map != NULL
> + && _hurd_userlink_clear (&fd->ioctl_handler_users))
> + __libc_dlclose (fd->ioctl_handler_map);
> +
> + fd->ioctl_handler = NULL;
> + fd->ioctl_handler_map = NULL;
> + fd->ioctl_handler_users = NULL;
> +
> /* Clear the descriptor's port cells.
> This deallocates the ports if noone else is still using them. */
> _hurd_port_set (&fd->ctty, MACH_PORT_NULL);
> _hurd_port_locked_set (&fd->port, MACH_PORT_NULL);
> +
> err = 0;
> }
>
> diff --git a/hurd/fd-ioctl-call.c b/hurd/fd-ioctl-call.c
> index c5a41e8..873a5ca 100644
> --- a/hurd/fd-ioctl-call.c
> +++ b/hurd/fd-ioctl-call.c
> @@ -61,30 +61,112 @@ load_ioctl_handler (io_t port, void **map)
> }
>
>
> -/* Call D's ioctl handler, loading it from the underlying port if
> - necessary. Arguments are the same as ioctl handlers. */
> +/* Load and install D's ioctl handler. D should be locked and CRIT should
> + point to a critical section lock. CRIT is unlocked whenever D is
> + unlocked and a new lock is returned in CRIT if D needs to be relocked.
> + D is unlocked while the handler is loaded. If the underlying port
> + of D changes while it's unlocked the operation is retried with the
> + new port. This is repeated until the port remains unchanged, or
> + if it becomes null D remains unlocked and EBADF is returned. D is
> + relocked and the ioctl handler is installed. If the load failed,
> + a dummy ioctl handler is installed with a null linker map. */
>
> -int
> -_hurd_fd_call_ioctl_handler (int fd, int request, void *arg)
> +static error_t
> +install_ioctl_handler (struct hurd_fd *d, void **crit)
You haven't used --patience when generating this patch, have you?...
Makes this part rather ugly -- I refuse to read it :-)
> {
> + struct hurd_userlink ulink;
> + io_t port;
> ioctl_handler_t ioctl_handler;
> void *ioctl_handler_map;
> - int result;
> error_t err;
>
> - /* Avoid spurious "may be used uninitialized" warning. */
> - ioctl_handler_map = NULL;
> + while (!d->ioctl_handler)
> + {
> + port = _hurd_port_locked_get (&d->port, &ulink);
> + _hurd_critical_section_unlock (*crit);
> + if (port == MACH_PORT_NULL)
> + /* ULINK isn't linked when port is null. */
> + return EBADF;
> +
> + /* Avoid spurious "may be used uninitialized" warning. */
> + ioctl_handler_map = NULL;
> +
> + err = load_ioctl_handler (port, &ioctl_handler_map);
> + if (!err && ioctl_handler_map)
> + ioctl_handler = __libc_dlsym (ioctl_handler_map,
> + "hurd_ioctl_handler");
> + if (err || !ioctl_handler_map || !ioctl_handler)
> + ioctl_handler = _hurd_dummy_ioctl_handler;
> +
> + *crit = _hurd_critical_section_lock ();
> + __spin_lock (&d->port.lock);
> +
> + if (_hurd_userlink_unlink (&ulink))
> + __mach_port_deallocate (__mach_task_self (), port);
> + else if (port == d->port.port)
> + {
> + d->ioctl_handler = ioctl_handler;
> + if (ioctl_handler_map)
> + d->ioctl_handler_map = ioctl_handler_map;
> + }
> + }
> +
> + return 0;
> +}
> +
> +
> +/* Call D's ioctl handler, loading it from the underlying port if
> + necessary. Arguments are the same as ioctl handlers, except for
> + CRIT in which a new lock is returned. */
> +
> +error_t
> +_hurd_fd_call_ioctl_handler (int fd, struct hurd_fd *d, void **crit,
> + int request, void *arg, int *result)
> +{
> + struct hurd_userlink ioctl_ulink;
> + void *ioctl_handler_map;
> + error_t err;
> +
> + err = install_ioctl_handler (d, crit);
> + if (err)
> + {
> + *result = __hurd_fail (err);
> + return 0;
> + }
>
> - err = HURD_DPORT_USE (fd, load_ioctl_handler (port, &ioctl_handler_map));
> - if (!err && ioctl_handler_map)
> - ioctl_handler = __libc_dlsym (ioctl_handler_map, "hurd_ioctl_handler");
> - if (err || !ioctl_handler_map || !ioctl_handler)
> - ioctl_handler = _hurd_dummy_ioctl_handler;
> + ioctl_handler_map = d->ioctl_handler_map;
> + if (ioctl_handler_map)
> + {
> + ioctl_ulink.cleanup = &_hurd_fd_ioctl_handler_map_cleanup;
> + ioctl_ulink.cleanup_data = (void *) ioctl_handler_map;
> + _hurd_userlink_link (&d->ioctl_handler_users, &ioctl_ulink);
> + }
>
> - result = (*ioctl_handler) (fd, request, arg);
> + err = (*d->ioctl_handler) (fd, d, *crit, request, arg, result);
>
> if (ioctl_handler_map)
> - __libc_dlclose (ioctl_handler_map);
> + /* Unlink if from D's icotl user list. Relock D for the duration
> + if the handler unlocked it. */
> + {
> + void dealloc (void)
> + {
> + if (_hurd_userlink_unlink (&ioctl_ulink))
> + __libc_dlclose (ioctl_handler_map);
> + }
>
> - return result;
> + if (err)
> + dealloc ();
> + else
> + {
> + void *crit = _hurd_critical_section_lock ();
> + __spin_lock (&d->port.lock);
> +
> + dealloc ();
> +
> + __spin_unlock (&d->port.lock);
> + _hurd_critical_section_unlock (crit);
> + }
> + }
> +
> + return err;
> }
> diff --git a/hurd/fd-ioctl-cleanup.c b/hurd/fd-ioctl-cleanup.c
> new file mode 100644
> index 0000000..df6e432
> --- /dev/null
> +++ b/hurd/fd-ioctl-cleanup.c
> @@ -0,0 +1,31 @@
> +/* Cleanup function for FD ioctl handler users who longjmp.
> + Copyright (C) 2009 Free Software Foundation, Inc.
> + This file is part of the GNU C Library.
> +
> + The GNU C Library is free software; you can redistribute it and/or
> + modify it under the terms of the GNU Lesser General Public
> + License as published by the Free Software Foundation; either
> + version 2.1 of the License, or (at your option) any later version.
> +
> + The GNU C Library is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + Lesser General Public License for more details.
> +
> + You should have received a copy of the GNU Lesser General Public
> + License along with the GNU C Library; if not, write to the Free
> + Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
> + Boston, MA 02110-1301, USA. */
> +
> +#include <hurd/fd.h>
> +#include <dlfcn.h>
> +
> +/* The last user of the ioctl handler linker map DATA is now doing
> + `longjmp (ENV, VAL)', and this will unwind the frame of that last user.
> + Close the linker map he will never get back to using. */
> +
> +void
> +_hurd_fd_ioctl_handler_map_cleanup (void *data, jmp_buf env, int val)
> +{
> + __libc_dlclose (data);
> +}
> diff --git a/hurd/hurd/fd.h b/hurd/hurd/fd.h
> index 6ea9ad6..2137b6b 100644
> --- a/hurd/hurd/fd.h
> +++ b/hurd/hurd/fd.h
> @@ -30,6 +30,28 @@
> #include <sys/socket.h>
>
>
> +struct hurd_fd; /* Forward declaration. */
> +
> +/* Type of handler function, called by ioctl to do its entire job.
> + D should be _hurd_dtable[FD], and it should be valid and locked,
> + CRIT should be a critical section lock. If the ioctl is handled 0
> + is returned, D and CRIT is unlocked, and the return value of ioctl
> + is returned in RESULT, and any error is returned in ERRNO. If not
> + handled ENOTTY, or any error that prevents the ioctl from being
> + handled, is returned, leaving D and CRIT locked.
> +
> + D must be locked until a ioctl handler is found that can handle the
> + ioctl, otherwise it may get a new underlying port with a different
> + ioctl handler, which might affect the choice of ioctl handler.
> +
> + Two errors are returned so it's possible to distinguish between an
> + unhandled ioctl and a RPC that returns ENOTTY.
Why can't you use errno, as in the previous version?...
> + The latter can't be
> + handled by simply relocking D, since D's port may change while it's
> + unlocked. */
> +typedef error_t (*ioctl_handler_t) (int fd, struct hurd_fd *d, void *crit,
> + int request, void *arg, int *result);
> +
> +
> /* Structure representing a file descriptor. */
>
> struct hurd_fd
> @@ -41,6 +63,16 @@ struct hurd_fd
> the same io object but which never returns EBACKGROUND; when not,
> this is nil. */
> struct hurd_port ctty;
> +
> + /* Server provided handler for ioctls, and map for the dynamically
> + loaded module it resides in as returned by `dlopen'. The
> + module is loaded on the first call to `ioctl', before this
> + IOCTL_HANDLER is NULL, and if the load fails it is set
> + to `_hurd_dummy_ioctl_handler'. Their values are specific to PORT
> + and should be invalidated whenever `port' is changed. */
> + ioctl_handler_t ioctl_handler;
> + void *ioctl_handler_map;
> + struct hurd_userlink *ioctl_handler_users;
> };
>
>
> @@ -292,8 +324,15 @@ extern file_t __directory_name_split_at (int fd, const
> char *directory_name,
>
>
> /* Call D's ioctl handler, loading it from the underlying port if
> - necessary. Arguments are the same as ioctl handlers. */
> -extern int _hurd_fd_call_ioctl_handler (int fd, int request, void *arg);
> + necessary. Arguments are the same as ioctl handlers, except for
> + CRIT in which a new lock is returned. */
> +extern error_t _hurd_fd_call_ioctl_handler (int fd, struct hurd_fd *d,
> + void **crit, int request,
> + void *arg, int *result);
> +
> +/* Ioctl handler cleanup function for non-local exits. */
> +extern void _hurd_fd_ioctl_handler_map_cleanup (void *data, jmp_buf env,
> + int val);
>
>
> #endif /* hurd/fd.h */
> diff --git a/hurd/hurd/ioctl.h b/hurd/hurd/ioctl.h
> index f932fa1..6f3f9a4 100644
> --- a/hurd/hurd/ioctl.h
> +++ b/hurd/hurd/ioctl.h
> @@ -23,11 +23,9 @@
> #define __need___va_list
> #include <stdarg.h>
> #include <bits/ioctls.h>
> +#include <hurd/fd.h>
>
>
> -/* Type of handler function, called like ioctl to do its entire job. */
> -typedef int (*ioctl_handler_t) (int fd, int request, void *arg);
> -
> /* Structure that records an ioctl handler. */
> struct ioctl_handler
> {
> @@ -76,7 +74,8 @@ ioctl_handler_t _hurd_lookup_ioctl_handler (int request);
>
> /* A dummy handler that always fails. */
>
> -int _hurd_dummy_ioctl_handler (int fd, int request, void *arg);
> +error_t _hurd_dummy_ioctl_handler (int fd, struct hurd_fd *, void *crit,
> + int request, void *arg, int *result);
>
>
> #endif /* hurd/ioctl.h */
> diff --git a/hurd/hurdioctl.c b/hurd/hurdioctl.c
> index 0b91ee1..fb2db13 100644
> --- a/hurd/hurdioctl.c
> +++ b/hurd/hurdioctl.c
> @@ -51,21 +51,27 @@ _hurd_lookup_ioctl_handler (int request)
> }
>
> /* A dummy handler that always fails. */
> -int
> -_hurd_dummy_ioctl_handler (int fd, int request, void *arg)
> +error_t
> +_hurd_dummy_ioctl_handler (int fd, struct hurd_fd *d, void *crit,
> + int request, void *arg, int *result)
> {
> - return __hurd_fail (ENOTTY);
> + return ENOTTY;
> }
>
> #include <fcntl.h>
>
> /* Find out how many bytes may be read from FD without blocking. */
>
> -static int
> +static error_t
> fioctl (int fd,
> + struct hurd_fd *d,
> + void *crit,
> int request,
> - int *arg)
> + int *arg,
> + int *result)
> {
> + mach_port_t port;
> + struct hurd_userlink link;
> error_t err;
>
> *(volatile int *) arg = *arg;
> @@ -73,57 +79,78 @@ fioctl (int fd,
> switch (request)
> {
> default:
> - err = ENOTTY;
> + return ENOTTY;
> +
> + case FIONREAD:
> + case FIONBIO:
> + case FIOASYNC:
> + case FIOSETOWN:
> + case FIOGETOWN:
> break;
> + }
> +
> + port = _hurd_port_locked_get (&d->port, &link);
> + _hurd_critical_section_unlock (crit);
>
> + switch (request)
> + {
> case FIONREAD:
> {
> mach_msg_type_number_t navail;
> - err = HURD_DPORT_USE (fd, __io_readable (port, &navail));
> + err = __io_readable (port, &navail);
> if (!err)
> *arg = (int) navail;
> }
> break;
>
> case FIONBIO:
> - err = HURD_DPORT_USE (fd, (*arg ?
> - __io_set_some_openmodes :
> - __io_clear_some_openmodes)
> - (port, O_NONBLOCK));
> + if (*arg)
> + err = __io_set_some_openmodes (port, O_NONBLOCK);
> + else
> + err = __io_clear_some_openmodes (port, O_NONBLOCK);
> break;
>
> case FIOASYNC:
> - err = HURD_DPORT_USE (fd, (*arg ?
> - __io_set_some_openmodes :
> - __io_clear_some_openmodes)
> - (port, O_ASYNC));
> + if (*arg)
> + err = __io_set_some_openmodes (port, O_ASYNC);
> + else
> + err = __io_clear_some_openmodes (port, O_ASYNC);
> break;
>
> case FIOSETOWN:
> - err = HURD_DPORT_USE (fd, __io_mod_owner (port, *arg));
> + err = __io_mod_owner (port, *arg);
> break;
>
> case FIOGETOWN:
> - err = HURD_DPORT_USE (fd, __io_get_owner (port, arg));
> + err = __io_get_owner (port, arg);
> break;
> +
> + default:
> + assert (! "unhandled ioctl number slipped through");
> }
> + _hurd_port_free (&d->port, &link, port);
>
> - return err ? __hurd_dfail (fd, err) : 0;
> + *result = err ? __hurd_dfail (fd, err) : 0;
> + return 0;
> }
>
> _HURD_HANDLE_IOCTLS (fioctl, FIOGETOWN, FIONREAD);
>
>
> -static int
> +static error_t
> fioclex (int fd,
> - int request)
> + struct hurd_fd *d,
> + void *crit,
> + int request,
> + void *arg,
> + int *result)
> {
> int flag;
>
> switch (request)
> {
> default:
> - return __hurd_fail (ENOTTY);
> + return ENOTTY;
> case FIOCLEX:
> flag = FD_CLOEXEC;
> break;
> @@ -132,7 +159,12 @@ fioclex (int fd,
> break;
> }
>
> - return __fcntl (fd, F_SETFD, flag);
> + d->flags = flag;
> + __spin_unlock (&d->port.lock);
> + _hurd_critical_section_unlock (crit);
> +
> + *result = 0;
> + return 0;
> }
> _HURD_HANDLE_IOCTLS (fioclex, FIOCLEX, FIONCLEX);
>
> @@ -279,28 +311,53 @@ tiocsctty_internal (io_t port, io_t ctty)
> return 0;
> }
>
> -static int
> +static error_t
> tiocsctty (int fd,
> - int request) /* Always TIOCSCTTY. */
> + struct hurd_fd *d,
> + void *crit,
> + int request,
> + void *arg,
> + int *result) /* Always TIOCSCTTY. */
> {
> + struct hurd_userlink link, ctty_link;
> + io_t port, ctty;
> error_t err;
>
> - err = HURD_DPORT_USE (fd, tiocsctty_internal (port, ctty));
> - return __hurd_fail (err);
> + ctty = _hurd_port_get (&d->ctty, &ctty_link);
> + port = _hurd_port_locked_get (&d->port, &link);
> + _hurd_critical_section_unlock (crit);
> +
> + err = tiocsctty_internal (port, ctty);
> +
> + _hurd_port_free (&d->port, &link, port);
> + if (ctty != MACH_PORT_NULL)
> + _hurd_port_free (&d->ctty, &ctty_link, ctty);
> +
> + *result = __hurd_fail (err);
> + return 0;
> }
> _HURD_HANDLE_IOCTL (tiocsctty, TIOCSCTTY);
>
> /* Dissociate from the controlling terminal. */
>
> -static int
> +static error_t
> tiocnotty (int fd,
> - int request) /* Always TIOCNOTTY. */
> + struct hurd_fd *d,
> + void *crit,
> + int request,
> + void *arg,
> + int *result) /* Always TIOCNOTTY. */
> {
> + struct hurd_userlink link;
> + io_t dport;
> mach_port_t fd_cttyid;
> error_t err;
>
> - if (err = HURD_DPORT_USE (fd, __term_getctty (port, &fd_cttyid)))
> - return __hurd_fail (err);
> + dport = _hurd_port_locked_get (&d->port, &link);
> + _hurd_critical_section_unlock (crit);
> +
> + if (err = __term_getctty (dport, &fd_cttyid))
> + goto out;
>
> if (__USEPORT (CTTYID, port != fd_cttyid))
> err = EINVAL;
> @@ -308,11 +365,14 @@ tiocnotty (int fd,
> __mach_port_deallocate (__mach_task_self (), fd_cttyid);
>
> if (err)
> - return __hurd_fail (err);
> + goto out;
>
> /* Clear our cttyid port. */
> install_ctty (MACH_PORT_NULL);
>
> +out:
> + _hurd_port_free (&d->port, &link, dport);
> + *result = __hurd_fail (err);
> return 0;
> }
> _HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY);
> @@ -323,9 +383,12 @@ _HURD_HANDLE_IOCTL (tiocnotty, TIOCNOTTY);
>
> /* Fill in the buffer IFC->IFC_BUF of length IFC->IFC_LEN with a list
> of ifr structures, one for each network interface. */
> -static int
> -siocgifconf (int fd, int request, struct ifconf *ifc)
> +static error_t
> +siocgifconf (int fd, struct hurd_fd *d, void *crit,
> + int request, struct ifconf *ifc, int *result)
> {
> + struct hurd_userlink link;
> + io_t port;
> error_t err;
> size_t data_len = ifc->ifc_len;
> char *data = ifc->ifc_buf;
> @@ -333,8 +396,10 @@ siocgifconf (int fd, int request, struct ifconf *ifc)
> if (data_len <= 0)
> return 0;
>
> - err = HURD_DPORT_USE (fd, __pfinet_siocgifconf (port, ifc->ifc_len,
> - &data, &data_len));
> + port = _hurd_port_locked_get (&d->port, &link);
> + _hurd_critical_section_unlock (crit);
> +
> + err = __pfinet_siocgifconf (port, ifc->ifc_len, &data, &data_len);
> if (data_len < ifc->ifc_len)
> ifc->ifc_len = data_len;
> if (data != ifc->ifc_buf)
> @@ -342,6 +407,9 @@ siocgifconf (int fd, int request, struct ifconf *ifc)
> memcpy (ifc->ifc_buf, data, ifc->ifc_len);
> __vm_deallocate (__mach_task_self (), (vm_address_t) data, data_len);
> }
> - return err ? __hurd_dfail (fd, err) : 0;
> +
> + _hurd_port_free (&d->port, &link, port);
> + *result = err ? __hurd_dfail (fd, err) : 0;
> + return 0;
> }
> _HURD_HANDLE_IOCTL (siocgifconf, SIOCGIFCONF);
> diff --git a/hurd/new-fd.c b/hurd/new-fd.c
> index 152bb35..b2b09de 100644
> --- a/hurd/new-fd.c
> +++ b/hurd/new-fd.c
> @@ -1,4 +1,4 @@
> -/* Copyright (C) 1994, 1997, 1999 Free Software Foundation, Inc.
> +/* Copyright (C) 1994, 1997, 1999, 2009 Free Software Foundation, Inc.
> This file is part of the GNU C Library.
>
> The GNU C Library is free software; you can redistribute it and/or
> @@ -36,6 +36,11 @@ _hurd_new_fd (io_t port, io_t ctty)
>
> /* And the fcntl flags. */
> d->flags = 0;
> +
> + /* And the ioctl handler. */
> + d->ioctl_handler = NULL;
> + d->ioctl_handler_map = NULL;
> + d->ioctl_handler_users = NULL;
> }
>
> return d;
> diff --git a/hurd/port2fd.c b/hurd/port2fd.c
> index 262e6d9..4d491df 100644
> --- a/hurd/port2fd.c
> +++ b/hurd/port2fd.c
> @@ -1,4 +1,4 @@
> -/* Copyright (C) 1994, 1997, 1999, 2007 Free Software Foundation, Inc.
> +/* Copyright (C) 1994, 1997, 1999, 2007, 2009 Free Software Foundation, Inc.
> This file is part of the GNU C Library.
>
> The GNU C Library is free software; you can redistribute it and/or
> @@ -21,6 +21,7 @@
> #include <hurd/signal.h>
> #include <hurd/term.h>
> #include <fcntl.h>
> +#include <dlfcn.h>
>
> /* Store PORT in file descriptor D, doing appropriate ctty magic.
> FLAGS are as for `open'; only O_IGNORE_CTTY is meaningful.
> @@ -61,4 +62,12 @@ _hurd_port2fd (struct hurd_fd *d, io_t dport, int flags)
> }
>
> _hurd_port_set (&d->ctty, ctty);
> +
> + /* Clear ioctl handler associated with old port. */
> + if (d->ioctl_handler_map != NULL
> + && _hurd_userlink_clear (&d->ioctl_handler_users))
> + __libc_dlclose (d->ioctl_handler_map);
> + d->ioctl_handler = NULL;
> + d->ioctl_handler_map = NULL;
> + d->ioctl_handler_users = NULL;
> }
> diff --git a/sysdeps/mach/hurd/ioctl.c b/sysdeps/mach/hurd/ioctl.c
> index 736ad8e..bdc2fc2 100644
> --- a/sysdeps/mach/hurd/ioctl.c
> +++ b/sysdeps/mach/hurd/ioctl.c
> @@ -91,6 +91,9 @@ __ioctl (int fd, unsigned long int request, ...)
>
> void *arg = NULL;
>
> + struct hurd_fd *d;
> + void *crit;
> +
> error_t err;
>
> /* Send the RPC already packed up in MSG to IOPORT
> @@ -219,10 +222,25 @@ __ioctl (int fd, unsigned long int request, ...)
> va_end (ap);
> }
>
> + d = _hurd_fd_get (fd);
> + if (d == NULL)
> + return __hurd_fail (EBADF);
> +
> + crit = _hurd_critical_section_lock ();
> + __spin_lock (&d->port.lock);
> +
> + if (d->port.port == MACH_PORT_NULL)
> + {
> + __spin_unlock (&d->port.lock);
> + _hurd_critical_section_unlock (crit);
> + return __hurd_fail (EBADF);
> + }
> +
> {
> int save = errno;
> - int result = _hurd_fd_call_ioctl_handler (fd, request, arg);
> - if (result != -1 || errno != ENOTTY)
> + int result;
> + err = _hurd_fd_call_ioctl_handler (fd, d, &crit, request, arg, &result);
> + if (!err)
> return result;
>
> /* The handler doesn't grok this one. Try linked handlers. */
> @@ -230,14 +248,14 @@ __ioctl (int fd, unsigned long int request, ...)
> }
>
> {
> - /* Check for a registered handler for REQUEST. */
> ioctl_handler_t handler = _hurd_lookup_ioctl_handler (request);
> if (handler)
> {
> /* This handler groks REQUEST. Se lo puntamonos. */
> int save = errno;
> - int result = (*handler) (fd, request, arg);
> - if (result != -1 || errno != ENOTTY)
> + int result;
> + err = (*handler) (fd, d, crit, request, arg, &result);
> + if (!err)
> return result;
>
> /* The handler doesn't really grok this one.
> @@ -280,7 +298,20 @@ __ioctl (int fd, unsigned long int request, ...)
> /* Marshal the arguments into the request message and make the RPC.
> This wrapper function handles EBACKGROUND returns, turning them
> into either SIGTTOU or EIO. */
> - err = HURD_DPORT_USE (fd, _hurd_ctty_output (port, ctty, send_rpc));
> + {
> + io_t port, ctty;
> + struct hurd_userlink ulink, ctty_ulink;
> +
> + ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
> + port = _hurd_port_locked_get (&d->port, &ulink);
> + _hurd_critical_section_unlock (crit);
> +
> + err = _hurd_ctty_output (port, ctty, send_rpc);
> +
> + _hurd_port_free (&d->port, &ulink, port);
> + if (ctty != MACH_PORT_NULL)
> + _hurd_port_free (&d->ctty, &ctty_ulink, ctty);
> + }
>
> #ifdef MACH_MSG_TYPE_BIT
> t = (mach_msg_type_t *) msg.data;
I can't really comment on this locking stuff -- I'm not familiar with
libc code, nor experienced with locking in general.
BTW, could you split this into two patches: one for the locking changes;
and one for the actual persistent handler changes?... Should be much
easier to follow.
-antrik-
- [PATCH 0/2] Ioctl handler protocol patches, Carl Fredrik Hammar, 2009/08/26
- [PATCH 1/2] Add ioctl-handler interface, Carl Fredrik Hammar, 2009/08/26
- [PATCH 0/3] Use server provided ioctl-handler, Carl Fredrik Hammar, 2009/08/26
- [PATCH 1/3] Reload fd ioctl handler on each call to ioctl, Carl Fredrik Hammar, 2009/08/26
- [PATCH 2/3] Save handlers between calls to ioctl, Carl Fredrik Hammar, 2009/08/26
- Re: [PATCH 2/3] Save handlers between calls to ioctl,
olafBuddenhagen <=
- [PATCH 3/3] Use reverse authenticating ioctl-handler protocal, Carl Fredrik Hammar, 2009/08/26
- [PATCH 0/3] Test server provided ioctl-handler, Carl Fredrik Hammar, 2009/08/26
- [PATCH 1/3] Test server provided ioctl-handler, Carl Fredrik Hammar, 2009/08/26
- Re: [PATCH 1/3] Test server provided ioctl-handler, olafBuddenhagen, 2009/08/31
- [PATCH 2/3] Update to reflect ioctl_handler_t change, Carl Fredrik Hammar, 2009/08/26