diff options
author | Michael I. Bushnell <mib@gnu.org> | 1996-07-18 04:35:29 +0000 |
---|---|---|
committer | Michael I. Bushnell <mib@gnu.org> | 1996-07-18 04:35:29 +0000 |
commit | 94cef36797600d11a50d09828fa80df8a73dfd1c (patch) | |
tree | b7cba9afef95489eedef534d3e6946eb13f595ba /libtreefs/trans-help.c | |
parent | 88dbbbf9e48e24f1ac007c1e4eeffd9caf8e2fad (diff) |
*** empty log message ***
Diffstat (limited to 'libtreefs/trans-help.c')
-rw-r--r-- | libtreefs/trans-help.c | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/libtreefs/trans-help.c b/libtreefs/trans-help.c new file mode 100644 index 00000000..b28e93e1 --- /dev/null +++ b/libtreefs/trans-help.c @@ -0,0 +1,129 @@ +/* Helper routines for dealing with translators + + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.ai.mit.edu> + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "trivfs.h" + +/* Return the active translator control port for NODE. If there is no + translator, active or passive, MACH_PORT_NULL is returned in CONTROL_PORT. + If there is a translator, it is started if necessary, and returned in + CONTROL_PORT. *DIR_PORT should be a port right to use as the new + translators parent directory. If it is MACH_PORT_NULL, a port is created + from DIR and PARENT_PORT and stored in *DIR_PORT; otherwise DIR and + PARENT_PORT are not used. Neither NODE or DIR should be locked when + calling this function. */ +error_t +treefs_node_get_active_trans (struct treefs_node *node, + struct treefs_node *dir, + mach_port_t parent_port, + mach_port_t *control_port, + mach_port_t *dir_port) +{ + /* Fill in dir_port */ + void make_dir_port () + { + mutex_lock (&dir->lock); + *dir_port = treefs_node_make_right (dir, 0, parent_port, 0); + mach_port_insert_right (mach_task_self (), + *dir_port, *dir_port, MACH_MSG_TYPE_MAKE_SEND); + mutex_unlock (&dir->lock); + } + + mutex_lock (&node->active_trans.lock); + + if (node->active_trans.control != MACH_PORT_NULL) + { + mach_port_t control = node->active_trans.control; + mach_port_mod_refs (mach_task_self (), control, + MACH_PORT_RIGHT_SEND, 1); + mutex_unlock (&node->active_trans.lock); + + /* Now we have a copy of the translator port that isn't + dependent on the translator lock itself. Relock + the directory, make a port from it, and then call + fsys_getroot. */ + + if (*dir_port == MACH_PORT_NULL) + make_dir_port (); + + *control_port = control; + + return 0; + } + + mutex_unlock (&node->active_trans.lock); + + /* If we get here, then we have no active control port. + Check to see if there is a passive translator, and if so + repeat the translator check. */ + mutex_lock (&node->lock); + if (!node->istranslated) + { + *control_port = MACH_PORT_NULL; + return 0; + } + + err = treefs_node_get_translator (node, trans, &trans_len); + if (err == E2BIG) + { + trans = alloca (trans_len); + err = treefs_node_get_translator (node, trans, &trans_len); + } + if (err) + { + mutex_unlock (&node->lock); + return err; + } + + if (*dir_port == MACH_PORT_NULL) + { + mutex_unlock (&node->lock); + make_dir_port (); + mutex_lock (&node->lock); + } + + /* Try starting the translator (this unlocks NODE). */ + err = treefs_start_translator (node, trans, trans_len, *dir_port); + if (err) + return err; + + /* Try again now that we've started the translator... This call + should be tail recursive. */ + return + treefs_node_get_active_trans (node, dir, parent_port, + control_port, dir_port); +} + +/* Drop the active translator CONTROL_PORT on NODE, unless it's no longer the + current active translator, in which case just drop a reference to it. */ +void +treefs_node_drop_active_trans (struct treefs_node *node, + mach_port_t control_port) +{ + mutex_lock (&node->active_trans.lock); + /* Only zero the control port if it hasn't changed. */ + if (node->active_trans.control == control) + fshelp_translator_drop (&node->active_trans); + mutex_unlock (&node->active_trans.lock); + + /* And we're done with this port. */ + mach_port_deallocate (mach_task_self (), control_port); +} |