bug-hurd
[Top][All Lists]
Advanced

[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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]