summaryrefslogtreecommitdiff
path: root/debian/patches/translatorslist-detect-passive-translators.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/translatorslist-detect-passive-translators.patch')
-rw-r--r--debian/patches/translatorslist-detect-passive-translators.patch712
1 files changed, 0 insertions, 712 deletions
diff --git a/debian/patches/translatorslist-detect-passive-translators.patch b/debian/patches/translatorslist-detect-passive-translators.patch
deleted file mode 100644
index 25823bc7..00000000
--- a/debian/patches/translatorslist-detect-passive-translators.patch
+++ /dev/null
@@ -1,712 +0,0 @@
-diff --git a/libdiskfs/dir-lookup.c b/libdiskfs/dir-lookup.c
-index 86116e3..3950bf9 100644
---- a/libdiskfs/dir-lookup.c
-+++ b/libdiskfs/dir-lookup.c
-@@ -1,6 +1,6 @@
- /* libdiskfs implementation of fs.defs:dir_lookup
- Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-- 2002, 2008, 2013 Free Software Foundation, Inc.
-+ 2002, 2008, 2013, 2014 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
-@@ -74,6 +74,10 @@ diskfs_S_dir_lookup (struct protid *dircred,
- if (! relpath)
- return ENOMEM;
-
-+ /* Keep a pointer to the start of the path for length
-+ calculations. */
-+ char *path_start = path;
-+
- *returned_port_poly = MACH_MSG_TYPE_MAKE_SEND;
- *retry = FS_RETRY_NORMAL;
- retryname[0] = '\0';
-@@ -274,11 +278,16 @@ diskfs_S_dir_lookup (struct protid *dircred,
- goto out;
-
- dirport = ports_get_send_right (newpi);
-- ports_port_deref (newpi);
-- newpi = 0;
- if (np != dnp)
- pthread_mutex_unlock (&dnp->lock);
-
-+ /* Check if an active translator is currently running. If
-+ not, fshelp_fetch_root will start one. In that case, we
-+ need to register it in the list of active
-+ translators. */
-+ boolean_t register_translator =
-+ np->transbox.active == MACH_PORT_NULL;
-+
- error = fshelp_fetch_root (&np->transbox, dircred->po,
- dirport, dircred->user,
- lastcomp ? flags : 0,
-@@ -301,9 +310,35 @@ diskfs_S_dir_lookup (struct protid *dircred,
- *end++ = '/';
- strcpy (end, nextname);
- }
-+
-+ if (register_translator)
-+ {
-+ char *translator_path = strdupa (relpath);
-+ if (nextname != NULL)
-+ {
-+ /* This was not the last path component.
-+ NEXTNAME points to the next component, locate
-+ the end of the current component and use it
-+ to trim TRANSLATOR_PATH. */
-+ char *end = nextname;
-+ while (*end != 0)
-+ end--;
-+ translator_path[end - path_start] = '\0';
-+ }
-+
-+ error = fshelp_set_active_translator (&newpi->pi,
-+ translator_path,
-+ np->transbox.active);
-+ if (error)
-+ goto out;
-+ }
-+
- goto out;
- }
-
-+ ports_port_deref (newpi);
-+ newpi = NULL;
-+
- /* ENOENT means there was a hiccup, and the translator
- vanished while NP was unlocked inside fshelp_fetch_root.
- Reacquire the locks, and continue as normal. */
-diff --git a/libdiskfs/file-set-trans.c b/libdiskfs/file-set-trans.c
-index 8de2e64..58f6255 100644
---- a/libdiskfs/file-set-trans.c
-+++ b/libdiskfs/file-set-trans.c
-@@ -1,5 +1,5 @@
- /* libdiskfs implementation of fs.defs: file_set_translator
-- Copyright (C) 1992,93,94,95,96,99,2001,02,13
-+ Copyright (C) 1992,93,94,95,96,99,2001,02,13,14
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or
-@@ -208,20 +208,8 @@ diskfs_S_file_set_translator (struct protid *cred,
-
- pthread_mutex_unlock (&np->lock);
-
-- if (! error && cred->po->path)
-- error = fshelp_set_active_translator (cred->po->path, active);
--
-- if (! error && active != MACH_PORT_NULL)
-- {
-- mach_port_t old;
-- error = mach_port_request_notification (mach_task_self (), active,
-- MACH_NOTIFY_DEAD_NAME, 0,
-- cred->pi.port_right,
-- MACH_MSG_TYPE_MAKE_SEND_ONCE,
-- &old);
-- if (old != MACH_PORT_NULL)
-- mach_port_deallocate (mach_task_self (), old);
-- }
-+ if (! error && cred->po->path && active_flags & FS_TRANS_SET)
-+ error = fshelp_set_active_translator (&cred->pi, cred->po->path, active);
-
- return error;
- }
-diff --git a/libfshelp/fshelp.h b/libfshelp/fshelp.h
-index a7702ca..5d3a0ce 100644
---- a/libfshelp/fshelp.h
-+++ b/libfshelp/fshelp.h
-@@ -1,5 +1,5 @@
- /* FS helper library definitions
-- Copyright (C) 1994,95,96,97,98,99,2000,01,02,13
-+ Copyright (C) 1994,95,96,97,98,99,2000,01,02,13,14
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or
-@@ -34,14 +34,20 @@
-
-
- /* Keeping track of active translators */
--/* These routines keep a list of active translators. They are
-- self-contained and do not require multi threading or the ports
-- library. */
-+/* These routines keep a list of active translators. They do not
-+ require multi threading but depend on the ports library. */
-+
-+struct port_info;
-
- /* Record an active translator being bound to the given file name
-- NAME. ACTIVE is the control port of the translator. */
-+ NAME. ACTIVE is the control port of the translator. PI references
-+ a receive port that is used to request dead name notifications,
-+ typically the port for the underlying node passed to the
-+ translator. */
- error_t
--fshelp_set_active_translator (const char *name, mach_port_t active);
-+fshelp_set_active_translator (struct port_info *pi,
-+ const char *name,
-+ mach_port_t active);
-
- /* Remove the active translator specified by its control port ACTIVE.
- If there is no active translator with the given control port, this
-diff --git a/libfshelp/translator-list.c b/libfshelp/translator-list.c
-index 87dcb21..3ece711 100644
---- a/libfshelp/translator-list.c
-+++ b/libfshelp/translator-list.c
-@@ -1,6 +1,6 @@
- /* A list of active translators.
-
-- Copyright (C) 2013 Free Software Foundation, Inc.
-+ Copyright (C) 2013,14 Free Software Foundation, Inc.
-
- Written by Justus Winter <4winter@informatik.uni-hamburg.de>
-
-@@ -22,6 +22,7 @@
- #include <argz.h>
- #include <hurd/fsys.h>
- #include <hurd/ihash.h>
-+#include <hurd/ports.h>
- #include <mach.h>
- #include <mach/notify.h>
- #include <pthread.h>
-@@ -33,6 +34,7 @@
-
- struct translator
- {
-+ struct port_info *pi;
- char *name;
- mach_port_t active;
- };
-@@ -49,8 +51,10 @@ translator_ihash_cleanup (void *element, void *arg)
- {
- struct translator *translator = element;
-
-- /* No need to deallocate port, we only keep the name of the
-- port, not a reference. */
-+ if (translator->pi)
-+ ports_port_deref (translator->pi);
-+ /* No need to deallocate translator->active, we only keep the name of
-+ the port, not a reference. */
- free (translator->name);
- free (translator);
- }
-@@ -58,7 +62,9 @@ translator_ihash_cleanup (void *element, void *arg)
- /* Record an active translator being bound to the given file name
- NAME. ACTIVE is the control port of the translator. */
- error_t
--fshelp_set_active_translator (const char *name, mach_port_t active)
-+fshelp_set_active_translator (struct port_info *pi,
-+ const char *name,
-+ mach_port_t active)
- {
- error_t err = 0;
- pthread_mutex_lock (&translator_ihash_lock);
-@@ -79,6 +85,7 @@ fshelp_set_active_translator (const char *name, mach_port_t active)
- return ENOMEM;
-
- t->active = MACH_PORT_NULL;
-+ t->pi = NULL;
- t->name = strdup (name);
- if (! t->name)
- {
-@@ -93,9 +100,31 @@ fshelp_set_active_translator (const char *name, mach_port_t active)
-
- update:
- if (active)
-- /* No need to increment the reference count, we only keep the
-- name, not a reference. */
-- t->active = active;
-+ {
-+ if (t->pi != pi)
-+ {
-+ mach_port_t old;
-+ err = mach_port_request_notification (mach_task_self (), active,
-+ MACH_NOTIFY_DEAD_NAME, 0,
-+ pi->port_right,
-+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
-+ &old);
-+ if (err)
-+ return err;
-+ if (old != MACH_PORT_NULL)
-+ mach_port_deallocate (mach_task_self (), old);
-+
-+ if (t->pi)
-+ ports_port_deref (t->pi);
-+
-+ ports_port_ref (pi);
-+ t->pi = pi;
-+ }
-+
-+ /* No need to increment the reference count, we only keep the
-+ name, not a reference. */
-+ t->active = active;
-+ }
- else
- hurd_ihash_remove (&translator_ihash, (hurd_ihash_key_t) t);
-
-diff --git a/libnetfs/dir-lookup.c b/libnetfs/dir-lookup.c
-index 74351fa..99a8746 100644
---- a/libnetfs/dir-lookup.c
-+++ b/libnetfs/dir-lookup.c
-@@ -1,5 +1,5 @@
- /*
-- Copyright (C) 1995,96,97,98,99,2000,01,02,13
-+ Copyright (C) 1995,96,97,98,99,2000,01,02,13,14
- Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
-
-@@ -67,6 +67,10 @@ netfs_S_dir_lookup (struct protid *diruser,
- if (! relpath)
- return ENOMEM;
-
-+ /* Keep a pointer to the start of the filename for length
-+ calculations. */
-+ char *filename_start = filename;
-+
- *retry_port_type = MACH_MSG_TYPE_MAKE_SEND;
- *do_retry = FS_RETRY_NORMAL;
- *retry_name = '\0';
-@@ -256,10 +260,16 @@ netfs_S_dir_lookup (struct protid *diruser,
- }
- }
-
-+ boolean_t register_translator;
- if (! error)
- {
- dirport = ports_get_send_right (newpi);
-- ports_port_deref (newpi);
-+
-+ /* Check if an active translator is currently running. If
-+ not, fshelp_fetch_root will start one. In that case, we
-+ need to register it in the list of active
-+ translators. */
-+ register_translator = np->transbox.active == MACH_PORT_NULL;
-
- error = fshelp_fetch_root (&np->transbox, diruser->po,
- dirport,
-@@ -283,9 +293,38 @@ netfs_S_dir_lookup (struct protid *diruser,
- strcat (retry_name, "/");
- strcat (retry_name, nextname);
- }
-+
-+ if (register_translator)
-+ {
-+ char *translator_path = strdupa (relpath);
-+ if (nextname != NULL)
-+ {
-+ /* This was not the last path component.
-+ NEXTNAME points to the next component, locate
-+ the end of the current component and use it
-+ to trim TRANSLATOR_PATH. */
-+ char *end = nextname;
-+ while (*end != 0)
-+ end--;
-+ translator_path[end - filename_start] = '\0';
-+ }
-+
-+ error = fshelp_set_active_translator (&newpi->pi,
-+ translator_path,
-+ np->transbox.active);
-+ if (error)
-+ {
-+ ports_port_deref (newpi);
-+ goto out;
-+ }
-+ }
-+
-+ ports_port_deref (newpi);
- goto out;
- }
-
-+ ports_port_deref (newpi);
-+
- /* ENOENT means there was a hiccup, and the translator vanished
- while NP was unlocked inside fshelp_fetch_root; continue as normal. */
- error = 0;
-diff --git a/libnetfs/file-set-translator.c b/libnetfs/file-set-translator.c
-index a9883a3..b46eb02 100644
---- a/libnetfs/file-set-translator.c
-+++ b/libnetfs/file-set-translator.c
-@@ -1,5 +1,6 @@
- /*
-- Copyright (C) 1996, 1997, 1999, 2001, 2013 Free Software Foundation, Inc.
-+ Copyright (C) 1996, 1997, 1999, 2001, 2013, 2014
-+ Free Software Foundation, Inc.
- Written by Michael I. Bushnell, p/BSG.
-
- This file is part of the GNU Hurd.
-@@ -175,20 +176,8 @@ netfs_S_file_set_translator (struct protid *user,
- }
- }
-
-- if (! err && user->po->path)
-- err = fshelp_set_active_translator (user->po->path, active);
--
-- if (! err && active != MACH_PORT_NULL)
-- {
-- mach_port_t old;
-- err = mach_port_request_notification (mach_task_self (), active,
-- MACH_NOTIFY_DEAD_NAME, 0,
-- user->pi.port_right,
-- MACH_MSG_TYPE_MAKE_SEND_ONCE,
-- &old);
-- if (old != MACH_PORT_NULL)
-- mach_port_deallocate (mach_task_self (), old);
-- }
-+ if (! err && user->po->path && active_flags & FS_TRANS_SET)
-+ err = fshelp_set_active_translator (&user->pi, user->po->path, active);
-
- out:
- pthread_mutex_unlock (&np->lock);
-diff --git a/trans/mtab.c b/trans/mtab.c
-index 250de7d..75ef1d3 100644
---- a/trans/mtab.c
-+++ b/trans/mtab.c
-@@ -1,6 +1,6 @@
- /* This is an mtab translator.
-
-- Copyright (C) 2013 Free Software Foundation, Inc.
-+ Copyright (C) 2013,14 Free Software Foundation, Inc.
-
- Written by Justus Winter <4winter@informatik.uni-hamburg.de>
-
-@@ -27,6 +27,7 @@
- #include <hurd/trivfs.h>
- #include <inttypes.h>
- #include <mntent.h>
-+#include <pthread.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
-@@ -39,6 +40,7 @@
-
- static char *target_path = NULL;
- static int insecure = 0;
-+static int all_translators = 0;
-
- /* Our control port. */
- struct trivfs_control *control;
-@@ -47,6 +49,7 @@ struct trivfs_control *control;
- They keep track of the content and file position of the client. */
- struct mtab
- {
-+ pthread_mutex_t lock;
- char *contents;
- size_t contents_len;
- off_t offs;
-@@ -58,6 +61,9 @@ static const struct argp_option options[] =
- {
- {"insecure", 'I', 0, 0,
- "Follow translators not bound to nodes owned by you or root"},
-+ {"all-translators", 'A', 0, 0,
-+ "List all translators, even those that are probably not "
-+ "filesystem translators"},
- {}
- };
-
-@@ -70,6 +76,10 @@ error_t parse_opt (int key, char *arg, struct argp_state *state)
- insecure = 1;
- break;
-
-+ case 'A':
-+ all_translators = 1;
-+ break;
-+
- case ARGP_KEY_ARG:
- target_path = realpath (arg, NULL);
- if (! target_path)
-@@ -233,9 +243,13 @@ main (int argc, char *argv[])
- error (4, err, "trivfs_startup");
-
- /* Launch. */
-- ports_manage_port_operations_one_thread (control->pi.bucket,
-- trivfs_demuxer,
-- 0);
-+ ports_manage_port_operations_multithread (control->pi.bucket,
-+ trivfs_demuxer,
-+ /* idle thread timeout */
-+ 30 * 1000,
-+ /* idle server timeout */
-+ 0,
-+ NULL);
- }
- else
- {
-@@ -271,6 +285,32 @@ mtab_add_entry (struct mtab *mtab, const char *entry, size_t length)
- return 0;
- }
-
-+/* Check whether the given NODE is a directory on a filesystem
-+ translator. */
-+static boolean_t
-+is_filesystem_translator (file_t node)
-+{
-+ error_t err;
-+ char *data = NULL;
-+ size_t datacnt = 0;
-+ int amount;
-+ err = dir_readdir (node, &data, &datacnt, 0, 1, 0, &amount);
-+ if (data != NULL && datacnt > 0)
-+ vm_deallocate (mach_task_self (), (vm_address_t) data, datacnt);
-+
-+ /* Filesystem translators return either no error, or, if NODE has
-+ not been looked up with O_READ, EBADF to dir_readdir
-+ requests. */
-+ switch (err)
-+ {
-+ case 0:
-+ case EBADF:
-+ return TRUE;
-+ default:
-+ return FALSE;
-+ }
-+}
-+
- /* Populates the given MTAB object with the information for PATH. If
- INSECURE is given, also follow translators bound to nodes not owned
- by root or the current user. */
-@@ -282,7 +322,6 @@ mtab_populate (struct mtab *mtab, const char *path, int insecure)
-
- /* These resources are freed in the epilogue. */
- file_t node = MACH_PORT_NULL;
-- fsys_t fsys = MACH_PORT_NULL;
- char *argz = NULL;
- size_t argz_len = 0;
- char **argv = NULL;
-@@ -295,16 +334,16 @@ mtab_populate (struct mtab *mtab, const char *path, int insecure)
- char *children = NULL;
- size_t children_len = 0;
-
-- /* Get the underlying node. */
-- node = file_name_lookup (path, O_NOTRANS, 0666);
-- if (node == MACH_PORT_NULL)
-- {
-- err = errno;
-- goto errout;
-- }
--
- if (! insecure)
- {
-+ /* Get the underlying node. */
-+ node = file_name_lookup (path, O_NOTRANS, 0666);
-+ if (node == MACH_PORT_NULL)
-+ {
-+ err = errno;
-+ goto errout;
-+ }
-+
- /* Check who owns the node the translator is bound to. */
- io_statbuf_t st;
- err = io_stat (node, &st);
-@@ -316,28 +355,11 @@ mtab_populate (struct mtab *mtab, const char *path, int insecure)
- err = EPERM;
- goto errout;
- }
-- }
--
-- err = file_get_translator_cntl (node, &fsys);
-- if (err == EPERM)
-- /* If we do not have permission to do that, it cannot be a node
-- bound to our control port, so ignore this error. */
-- err = 0;
--
-- if (err == ENXIO && strcmp (path, "/") == 0)
-- /* The root translator fails differently, but this can't be bound
-- to our control port either, so ignore this error. */
-- err = 0;
-
-- if (err)
-- return err;
--
-- if (control && control->pi.port_right == fsys)
-- /* This node is bound to our control port, ignore it. */
-- goto errout;
-+ mach_port_deallocate (mach_task_self (), node);
-+ }
-
-- /* Re-do the lookup without O_NOTRANS to get the root node. */
-- mach_port_deallocate (mach_task_self (), node);
-+ /* (Re-)do the lookup without O_NOTRANS to get the root node. */
- node = file_name_lookup (path, 0, 0666);
- if (node == MACH_PORT_NULL)
- {
-@@ -345,6 +367,12 @@ mtab_populate (struct mtab *mtab, const char *path, int insecure)
- goto errout;
- }
-
-+ if (! (all_translators || is_filesystem_translator (node)))
-+ {
-+ err = 0;
-+ goto errout;
-+ }
-+
- /* Query its options. */
- err = file_get_fs_options (node, &argz, &argz_len);
- if (err)
-@@ -461,9 +489,6 @@ mtab_populate (struct mtab *mtab, const char *path, int insecure)
- if (node != MACH_PORT_NULL)
- mach_port_deallocate (mach_task_self (), node);
-
-- if (fsys != MACH_PORT_NULL)
-- mach_port_deallocate (mach_task_self (), fsys);
--
- if (argz)
- vm_deallocate (mach_task_self (), (vm_address_t) argz, argz_len);
-
-@@ -590,18 +615,44 @@ open_hook (struct trivfs_peropen *peropen)
- peropen->hook = mtab;
-
- /* Initialize the fields. */
-+ pthread_mutex_init (&mtab->lock, NULL);
- mtab->offs = 0;
- mtab->contents = NULL;
- mtab->contents_len = 0;
-
-- return mtab_populate (mtab, target_path, insecure);
-+ /* The mtab object is initialized, but not yet populated. We delay
-+ that until that data is really needed. This avoids the following
-+ problems:
-+
-+ Suppose you have
-+
-+ settrans -ac /foo /hurd/mtab /
-+
-+ If you now access /foo, the mtab translator will walk the tree of
-+ all active translators starting from /. If it visits /foo, it
-+ will talk to itself. Previously the translator migitated this by
-+ comparing the control port of the translator with its own. This
-+ does not work if you got two mtab translators like this:
-+
-+ settrans -ac /foo /hurd/mtab /
-+ settrans -ac /bar /hurd/mtab /
-+
-+ With a single-threaded mtab server this results in a dead-lock,
-+ with a multi-threaded server this will create more and more
-+ threads.
-+
-+ Delaying the data generation until it is really needed cleanly
-+ avoids these kind of problems. */
-+ return 0;
- }
-
- static void
- close_hook (struct trivfs_peropen *peropen)
- {
-- free (((struct mtab *) peropen->hook)->contents);
-- free (peropen->hook);
-+ struct mtab *op = peropen->hook;
-+ pthread_mutex_destroy (&op->lock);
-+ free (op->contents);
-+ free (op);
- }
-
- /* Read data from an IO object. If offset is -1, read from the object
-@@ -613,6 +664,7 @@ trivfs_S_io_read (struct trivfs_protid *cred,
- char **data, mach_msg_type_number_t *data_len,
- loff_t offs, mach_msg_type_number_t amount)
- {
-+ error_t err = 0;
- struct mtab *op;
-
- /* Deny access if they have bad credentials. */
-@@ -624,6 +676,15 @@ trivfs_S_io_read (struct trivfs_protid *cred,
-
- /* Get the offset. */
- op = cred->po->hook;
-+ pthread_mutex_lock (&op->lock);
-+
-+ if (op->contents == NULL)
-+ {
-+ err = mtab_populate (op, target_path, insecure);
-+ if (err)
-+ goto out;
-+ }
-+
- if (offs == -1)
- offs = op->offs;
-
-@@ -640,7 +701,10 @@ trivfs_S_io_read (struct trivfs_protid *cred,
- {
- *data = mmap (0, amount, PROT_READ|PROT_WRITE, MAP_ANON, 0, 0);
- if (*data == MAP_FAILED)
-- return ENOMEM;
-+ {
-+ err = ENOMEM;
-+ goto out;
-+ }
- }
-
- /* Copy the constant data into the buffer. */
-@@ -651,7 +715,9 @@ trivfs_S_io_read (struct trivfs_protid *cred,
- }
-
- *data_len = amount;
-- return 0;
-+ out:
-+ pthread_mutex_unlock (&op->lock);
-+ return err;
- }
-
-
-@@ -661,10 +727,19 @@ trivfs_S_io_seek (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t reply_type,
- off_t offs, int whence, off_t *new_offs)
- {
-+ error_t err = 0;
- if (! cred)
- return EOPNOTSUPP;
-
- struct mtab *op = cred->po->hook;
-+ pthread_mutex_lock (&op->lock);
-+
-+ if (op->contents == NULL)
-+ {
-+ err = mtab_populate (op, target_path, insecure);
-+ if (err)
-+ goto out;
-+ }
-
- switch (whence)
- {
-@@ -681,10 +756,12 @@ trivfs_S_io_seek (struct trivfs_protid *cred,
- break;
- }
- default:
-- return EINVAL;
-+ err = EINVAL;
- }
-
-- return 0;
-+ out:
-+ pthread_mutex_unlock (&op->lock);
-+ return err;
- }
-
- /* If this variable is set, it is called every time a new peropen
-@@ -703,6 +780,7 @@ trivfs_S_io_readable (struct trivfs_protid *cred,
- mach_port_t reply, mach_msg_type_name_t replytype,
- mach_msg_type_number_t *amount)
- {
-+ error_t err = 0;
- if (!cred)
- return EOPNOTSUPP;
-
-@@ -710,9 +788,19 @@ trivfs_S_io_readable (struct trivfs_protid *cred,
- return EINVAL;
-
- struct mtab *op = cred->po->hook;
-+ pthread_mutex_lock (&op->lock);
-+
-+ if (op->contents == NULL)
-+ {
-+ error_t err = mtab_populate (op, target_path, insecure);
-+ if (err)
-+ goto out;
-+ }
-
- *amount = op->contents_len - op->offs;
-- return 0;
-+ out:
-+ pthread_mutex_unlock (&op->lock);
-+ return err;
- }
-
- /* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.