[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 2/3] Save handlers between calls to ioctl
From: |
Carl Fredrik Hammar |
Subject: |
[PATCH 2/3] Save handlers between calls to ioctl |
Date: |
Wed, 26 Aug 2009 16:44:58 +0200 |
* hurd/hurd/ioctl.h (ioctl_handler_t): Move from here...
* hurd/hurd/fd.h (ioctl_handler_t): ...to here.
Change return type.
Add `d', `crit', and `result' arguments.
Change all callers and ioctl handlers.
(hurd_fd): Add ioctl handler members.
* hurd/fd-close.c: Update copyright years.
(_hurd_fd_close): Clear ioctl handler and deallocate linker map.
* hurd/fd-ioctl-call.c (_hurd_fd_call_ioctl_handler):
Change return type.
Add `d', `crit', and `result' arguments.
Handle descriptor locking.
Save ioctl handler between calls.
Change all callers.
* hurd/new-fd.c: Update copyright years.
(_hurd_new_fd): Initialize ioctl handler.
* hurd/port2fd.c: Update copyright years.
(_hurd_port2fd): Initialize ioctl handler.
* hurd/dtable.c: Update copyright years.
(init_dtable): Initialize ioctl handler.
* hurd/fd-ioctl-cleanup.c: New file.
* hurd/Makefile (dtable): Add `fd-ioctl-cleanup'.
* sysdeps/mach/hurd/ioctl.c (__ioctl): Lock descriptor.
---
hurd/Makefile | 2 +-
hurd/dtable.c | 8 ++-
hurd/fd-close.c | 13 ++++-
hurd/fd-ioctl-call.c | 112 +++++++++++++++++++++++++++++++-----
hurd/fd-ioctl-cleanup.c | 31 ++++++++++
hurd/hurd/fd.h | 43 +++++++++++++-
hurd/hurd/ioctl.h | 7 +-
hurd/hurdioctl.c | 140 +++++++++++++++++++++++++++++++++------------
hurd/new-fd.c | 7 ++-
hurd/port2fd.c | 11 +++-
sysdeps/mach/hurd/ioctl.c | 43 ++++++++++++--
11 files changed, 349 insertions(+), 68 deletions(-)
create mode 100644 hurd/fd-ioctl-cleanup.c
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)
{
+ 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. 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;
--
1.6.3.3
- [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 <=
- [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