summaryrefslogtreecommitdiff
path: root/debian
diff options
context:
space:
mode:
Diffstat (limited to 'debian')
-rw-r--r--debian/patches/ext2fs-fix-remount.patch679
-rw-r--r--debian/patches/fix-remount0001-yyy-fix-remount.patch144
-rw-r--r--debian/patches/series2
3 files changed, 680 insertions, 145 deletions
diff --git a/debian/patches/ext2fs-fix-remount.patch b/debian/patches/ext2fs-fix-remount.patch
new file mode 100644
index 00000000..120d8ae3
--- /dev/null
+++ b/debian/patches/ext2fs-fix-remount.patch
@@ -0,0 +1,679 @@
+Return-Path: <bug-hurd-bounces+4winter=informatik.uni-hamburg.de@gnu.org>
+X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on jade.jade-hamburg.de
+X-Spam-Level:
+X-Spam-Status: No, score=-3.1 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD,
+ TVD_RCVD_SPACE_BRACKET,T_DKIM_INVALID,UNPARSEABLE_RELAY,URIBL_BLOCKED
+ autolearn=ham version=3.3.1
+Received: from mailhost.informatik.uni-hamburg.de [134.100.9.70]
+ by jade.jade-hamburg.de with IMAP (fetchmail-6.3.9-rc2)
+ for <teythoon@localhost> (single-drop); Thu, 23 Jul 2015 19:35:41 +0200 (CEST)
+Received: from mailhost.informatik.uni-hamburg.de ([unix socket])
+ by mailhost (Cyrus v2.3.18) with LMTPA;
+ Thu, 23 Jul 2015 19:34:57 +0200
+X-Sieve: CMU Sieve 2.3
+Received: by mailhost.informatik.uni-hamburg.de (Postfix)
+ id 25BA94D; Thu, 23 Jul 2015 19:34:57 +0200 (CEST)
+Delivered-To: 4winter@informatik.uni-hamburg.de
+Received: from localhost (localhost [127.0.0.1])
+ by mailhost.informatik.uni-hamburg.de (Postfix) with ESMTP id 1B35E4C
+ for <4winter@informatik.uni-hamburg.de>; Thu, 23 Jul 2015 19:34:57 +0200 (CEST)
+X-Virus-Scanned: amavisd-new at informatik.uni-hamburg.de
+Received: from mailhost.informatik.uni-hamburg.de ([127.0.0.1])
+ by localhost (mailhost.informatik.uni-hamburg.de [127.0.0.1]) (amavisd-new, port 10024)
+ with LMTP id VLxwzMHbQTir for <4winter@informatik.uni-hamburg.de>;
+ Thu, 23 Jul 2015 19:34:47 +0200 (CEST)
+Received: from lists.gnu.org (lists.gnu.org [208.118.235.17])
+ (using TLSv1 with cipher AES256-SHA (256/256 bits))
+ (Client did not present a certificate)
+ by mailhost.informatik.uni-hamburg.de (Postfix) with ESMTPS id 2594F49
+ for <4winter@informatik.uni-hamburg.de>; Thu, 23 Jul 2015 19:34:46 +0200 (CEST)
+Received: from eggs.gnu.org ([2001:4830:134:3::10]:40942)
+ by lists.gnu.org with esmtp (Exim 4.71)
+ (envelope-from <jrtc27@jrtc27.com>) id 1ZIKO4-0007qU-QR
+ for bug-hurd@gnu.org; Thu, 23 Jul 2015 13:34:31 -0400
+Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)
+ (envelope-from <jrtc27@jrtc27.com>) id 1ZIKO0-0002Hh-GH
+ for bug-hurd@gnu.org; Thu, 23 Jul 2015 13:34:28 -0400
+Received: from mail-wi0-x232.google.com ([2a00:1450:400c:c05::232]:37033)
+ by eggs.gnu.org with esmtp (Exim 4.71)
+ (envelope-from <jrtc27@jrtc27.com>) id 1ZIKNz-0002Gs-Oc
+ for bug-hurd@gnu.org; Thu, 23 Jul 2015 13:34:24 -0400
+Received: by wibud3 with SMTP id ud3so3837098wib.0
+ for <bug-hurd@gnu.org>; Thu, 23 Jul 2015 10:34:22 -0700 (PDT)
+DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=jrtc27.com; s=google;
+ h=from:to:cc:subject:date:message-id;
+ bh=MZx4v6IKvYqW2p9EGv4bjIw37GP1x3TFNJaYlejzfE0=;
+ b=hkiuwxdVQ68sVd6CkTch33kqkgnZ9s4CH7SZzY38ggPING7qgOCDBCue6guf4GF2We
+ ff42ryixXeN4PfOBGuWFQV4wjPxHUvadTqU3AcVvOqbzpGaCnsoLyqbXF6XtTcEmLtGk
+ q54TByl6OjRYhlBc0l4pqkPZrMJdMwyLQLXZA=
+X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
+ d=1e100.net; s=20130820;
+ h=x-gm-message-state:from:to:cc:subject:date:message-id;
+ bh=MZx4v6IKvYqW2p9EGv4bjIw37GP1x3TFNJaYlejzfE0=;
+ b=AGdApX6eRz/QjNXK/ayMLnE5fEP7sx450w2wQNw62XwbVOtmCbTnSuZ66PhQ7ZVBym
+ mVQk0f4HpgYXWcdXGgX8+lUScJPqhM+jgktgVaRtgNCVgMf4zcbrZJdc/xRb/4UgTAHy
+ 6A5v+Z3RwqrY5cqcRzDdVafP/zD1qE824WYd7fVM0Xkmeozr5rogNfEY6ug46n2THq1v
+ hfC9WA/CRUBoAwK3Ul7+6bj7BdXAlhIl6UWDGUebfMN7ov471mJfgEDmeh5blC8WNU5/
+ dxdZ2zNPE47wHS1xkfjhXMKO7GJNgvaLUb2/jkTSV0i6b/gsGI2qzBtCXeoV7pqmhXzi
+ 3TTg==
+X-Gm-Message-State: ALoCoQkhcH2D4+79mwdeHYjrBQLxsFBIYEmUR02QpaOfkNGg5bNh4sTRLCMAG2jwoxx8+W/WfW62
+X-Received: by 10.194.58.69 with SMTP id o5mr18159012wjq.22.1437672861959;
+ Thu, 23 Jul 2015 10:34:21 -0700 (PDT)
+From: James Clarke <jrtc27@jrtc27.com>
+To: bug-hurd@gnu.org
+Subject: [PATCH v3] Fix race condition in ext2fs when remounting
+Date: Thu, 23 Jul 2015 18:33:42 +0100
+Message-Id: <1437672822-99155-1-git-send-email-jrtc27@jrtc27.com>
+X-Mailer: git-send-email 2.4.6
+X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address
+ (bad octet value).
+X-Received-From: 2a00:1450:400c:c05::232
+Cc: James Clarke <jrtc27@jrtc27.com>
+X-BeenThere: bug-hurd@gnu.org
+X-Mailman-Version: 2.1.14
+Precedence: list
+List-Id: Bug reports for the GNU Hurd <bug-hurd.gnu.org>
+List-Unsubscribe: <https://lists.gnu.org/mailman/options/bug-hurd>,
+ <mailto:bug-hurd-request@gnu.org?subject=unsubscribe>
+List-Archive: <http://lists.gnu.org/archive/html/bug-hurd>
+List-Post: <mailto:bug-hurd@gnu.org>
+List-Help: <mailto:bug-hurd-request@gnu.org?subject=help>
+List-Subscribe: <https://lists.gnu.org/mailman/listinfo/bug-hurd>,
+ <mailto:bug-hurd-request@gnu.org?subject=subscribe>
+Errors-To: bug-hurd-bounces+4winter=informatik.uni-hamburg.de@gnu.org
+Sender: bug-hurd-bounces+4winter=informatik.uni-hamburg.de@gnu.org
+
+On some systems, ext2fs.static would regularly hang at startup, as a
+race condition meant it would process paging requests while remounting.
+To fix this, libpager has been altered to allow inhibiting and resuming
+its worker threads, and ext2fs uses this to inhibit paging while
+remounting.
+
+* console/pager.c (pager_requests): New variable.
+(user_pager_init): Updated call to pager_start_workers to use new
+pager_requests variable.
+* daemons/runsystem.sh: Removed artificial delay working around the race
+condition.
+* ext2fs/ext2fs.c (diskfs_reload_global_state): Call new
+inhibit_ext2_pager and resume_ext2_pager functions, and leave sblock as
+non-NULL so it will be munmapped.
+* ext2fs/ext2fs.h (inhibit_ext2_pager,resume_ext2_pager): New functions.
+* ext2fs/pager.c (file_pager_requests): New variable.
+(create_disk_pager): Updated call to pager_start_workers to use new
+file_pager_requests variable.
+(inhibit_ext2_pager,resume_ext2_pager): New functions.
+* fatfs/fatfs.h (inhibit_fat_pager,resume_fat_pager): New functions.
+* fatfs/pager.c (file_pager_requests): New variable.
+(create_fat_pager): Updated call to pager_start_workers to use new
+file_pager_requests variable.
+(inhibit_fat_pager,resume_fat_pager): New functions.
+* libdiskfs/disk-pager.c (diskfs_disk_pager_requests): New variable.
+(diskfs_start_disk_pager): Updated call to pager_start_workers to use
+new diskfs_disk_pager_requests variable.
+* libdiskfs/diskfs-pager.h (diskfs_disk_pager_requests): New variable.
+* libpager/demuxer.c (struct pager_requests): Renamed struct requests to
+struct pager_requests. Replaced queue with queue_in and queue_out
+pointers. Added inhibit_wakeup field.
+(pager_demuxer): Updated to use new queue_in/queue_out pointers. Only
+wake up workers if not inhibited.
+(worker_func): Updated to use new queue_in/queue_out pointers. Final
+worker thread to sleep notifies the inhibit_wakeup condition variable.
+(pager_start_workers): Added out parameter for the requests instance.
+Allocate heap space shared by both queues. Initialise new inhibit_wakeup
+condition.
+(pager_inhibit_workers,pager_resume_workers): New functions.
+* libpager/pager.h (struct pager_requests): Public forward definition.
+(pager_start_workers): Added out parameter for the requests instance.
+(pager_inhibit_workers,pager_resume_workers): New functions.
+* libpager/queue.h (queue_empty): New function.
+* storeio/pager.c (pager_requests): New variable.
+(init_dev_paging): Updated call to pager_start_workers to use new
+pager_requests variable.
+---
+ console/pager.c | 3 +-
+ daemons/runsystem.sh | 3 --
+ ext2fs/ext2fs.c | 12 ++++-
+ ext2fs/ext2fs.h | 6 +++
+ ext2fs/pager.c | 33 ++++++++++++-
+ fatfs/fatfs.h | 2 +
+ fatfs/pager.c | 33 ++++++++++++-
+ libdiskfs/disk-pager.c | 3 +-
+ libdiskfs/diskfs-pager.h | 1 +
+ libpager/demuxer.c | 119 ++++++++++++++++++++++++++++++++++++++++-------
+ libpager/pager.h | 28 ++++++++++-
+ libpager/queue.h | 8 ++++
+ storeio/pager.c | 3 +-
+ 13 files changed, 227 insertions(+), 27 deletions(-)
+
+diff --git a/console/pager.c b/console/pager.c
+index 5e13ba4..818e49d 100644
+--- a/console/pager.c
++++ b/console/pager.c
+@@ -42,6 +42,7 @@ struct user_pager_info
+
+ /* We need a separate bucket for the pager ports. */
+ static struct port_bucket *pager_bucket;
++static struct pager_requests *pager_requests;
+
+
+ /* Implement the pager_clear_user_data callback from the pager library. */
+@@ -133,7 +134,7 @@ user_pager_init (void)
+ error (5, errno, "Cannot create pager bucket");
+
+ /* Start libpagers worker threads. */
+- err = pager_start_workers (pager_bucket);
++ err = pager_start_workers (pager_bucket, &pager_requests);
+ if (err)
+ error (5, err, "Cannot start pager worker threads");
+ }
+diff --git a/daemons/runsystem.sh b/daemons/runsystem.sh
+index ae25a7d..5d0ad01 100644
+--- a/daemons/runsystem.sh
++++ b/daemons/runsystem.sh
+@@ -118,9 +118,6 @@ esac
+ /hurd/mach-defpager
+
+ # This is necessary to make stat / return the correct device ids.
+-# Work around a race condition (probably in the root translator).
+-for i in `seq 1 100000` ; do : ; done # XXX
+-
+ fsysopts / --update --readonly
+
+ # Finally, start the actual init.
+diff --git a/ext2fs/ext2fs.c b/ext2fs/ext2fs.c
+index d0fdfe7..03c9eed 100644
+--- a/ext2fs/ext2fs.c
++++ b/ext2fs/ext2fs.c
+@@ -207,10 +207,20 @@ main (int argc, char **argv)
+ error_t
+ diskfs_reload_global_state ()
+ {
++ error_t err;
++
+ pokel_flush (&global_pokel);
+ pager_flush (diskfs_disk_pager, 1);
+- sblock = NULL;
++
++ /* libdiskfs is not responsible for inhibiting paging. */
++ err = inhibit_ext2_pager ();
++ if (err)
++ return err;
++
+ get_hypermetadata ();
+ map_hypermetadata ();
++
++ resume_ext2_pager ();
++
+ return 0;
+ }
+diff --git a/ext2fs/ext2fs.h b/ext2fs/ext2fs.h
+index 96d8e9d..a744685 100644
+--- a/ext2fs/ext2fs.h
++++ b/ext2fs/ext2fs.h
+@@ -201,6 +201,12 @@ struct user_pager_info
+ /* Set up the disk pager. */
+ void create_disk_pager (void);
+
++/* Inhibit the disk pager. */
++error_t inhibit_ext2_pager (void);
++
++/* Resume the disk pager. */
++void resume_ext2_pager (void);
++
+ /* Call this when we should turn off caching so that unused memory object
+ ports get freed. */
+ void drop_pager_softrefs (struct node *node);
+diff --git a/ext2fs/pager.c b/ext2fs/pager.c
+index b56c923..3e080f8 100644
+--- a/ext2fs/pager.c
++++ b/ext2fs/pager.c
+@@ -34,6 +34,10 @@ struct port_bucket *disk_pager_bucket;
+ /* A ports bucket to hold file pager ports. */
+ struct port_bucket *file_pager_bucket;
+
++/* Stores a reference to the requests instance used by the file pager so its
++ worker threads can be inhibited and resumed. */
++struct pager_requests *file_pager_requests;
++
+ pthread_spinlock_t node_to_page_lock = PTHREAD_SPINLOCK_INITIALIZER;
+
+
+@@ -1217,11 +1221,38 @@ create_disk_pager (void)
+ file_pager_bucket = ports_create_bucket ();
+
+ /* Start libpagers worker threads. */
+- err = pager_start_workers (file_pager_bucket);
++ err = pager_start_workers (file_pager_bucket, &file_pager_requests);
+ if (err)
+ ext2_panic ("can't create libpager worker threads: %s", strerror (err));
+ }
+
++error_t
++inhibit_ext2_pager (void)
++{
++ error_t err;
++
++ /* The file pager can rely on the disk pager, so inhibit the file
++ pager first. */
++
++ err = pager_inhibit_workers (file_pager_requests);
++ if (err)
++ return err;
++
++ err = pager_inhibit_workers (diskfs_disk_pager_requests);
++ /* We don't want only one pager disabled. */
++ if (err)
++ pager_resume_workers (file_pager_requests);
++
++ return err;
++}
++
++void
++resume_ext2_pager (void)
++{
++ pager_resume_workers (diskfs_disk_pager_requests);
++ pager_resume_workers (file_pager_requests);
++}
++
+ /* Call this to create a FILE_DATA pager and return a send right.
+ NODE must be locked. */
+ mach_port_t
+diff --git a/fatfs/fatfs.h b/fatfs/fatfs.h
+index 3c3d836..54c3426 100644
+--- a/fatfs/fatfs.h
++++ b/fatfs/fatfs.h
+@@ -121,6 +121,8 @@ extern struct dirrect dr_root_node;
+ void drop_pager_softrefs (struct node *);
+ void allow_pager_softrefs (struct node *);
+ void create_fat_pager (void);
++error_t inhibit_fat_pager (void);
++void resume_fat_pager (void);
+
+ void flush_node_pager (struct node *node);
+
+diff --git a/fatfs/pager.c b/fatfs/pager.c
+index 10d1fc9..d255f29 100644
+--- a/fatfs/pager.c
++++ b/fatfs/pager.c
+@@ -29,6 +29,10 @@ struct port_bucket *disk_pager_bucket;
+ /* A ports bucket to hold file pager ports. */
+ struct port_bucket *file_pager_bucket;
+
++/* Stores a reference to the requests instance used by the file pager so its
++ worker threads can be inhibited and resumed. */
++struct pager_requests *file_pager_requests;
++
+ /* Mapped image of the FAT. */
+ void *fat_image;
+
+@@ -776,11 +780,38 @@ create_fat_pager (void)
+ file_pager_bucket = ports_create_bucket ();
+
+ /* Start libpagers worker threads. */
+- err = pager_start_workers (file_pager_bucket);
++ err = pager_start_workers (file_pager_bucket, &file_pager_requests);
+ if (err)
+ error (2, err, "can't create libpager worker threads");
+ }
+
++error_t
++inhibit_fat_pager (void)
++{
++ error_t err;
++
++ /* The file pager can rely on the disk pager, so inhibit the file
++ pager first. */
++
++ err = pager_inhibit_workers (file_pager_requests);
++ if (err)
++ return err;
++
++ err = pager_inhibit_workers (diskfs_disk_pager_requests);
++ /* We don't want only one pager disabled. */
++ if (err)
++ pager_resume_workers (file_pager_requests);
++
++ return err;
++}
++
++void
++resume_fat_pager (void)
++{
++ pager_resume_workers (diskfs_disk_pager_requests);
++ pager_resume_workers (file_pager_requests);
++}
++
+ /* Call this to create a FILE_DATA pager and return a send right.
+ NODE must be locked. */
+ mach_port_t
+diff --git a/libdiskfs/disk-pager.c b/libdiskfs/disk-pager.c
+index 008aa2d..33b109c 100644
+--- a/libdiskfs/disk-pager.c
++++ b/libdiskfs/disk-pager.c
+@@ -24,6 +24,7 @@
+ __thread struct disk_image_user *diskfs_exception_diu;
+
+ struct pager *diskfs_disk_pager;
++struct requests *diskfs_disk_pager_requests;
+
+ static void fault_handler (int sig, long int sigcode, struct sigcontext *scp);
+ static struct hurd_signal_preemptor preemptor =
+@@ -43,7 +44,7 @@ diskfs_start_disk_pager (struct user_pager_info *upi,
+ mach_port_t disk_pager_port;
+
+ /* Start libpagers worker threads. */
+- err = pager_start_workers (pager_bucket);
++ err = pager_start_workers (pager_bucket, &diskfs_disk_pager_requests);
+ if (err)
+ error (2, err, "creating pager worker threads failed");
+
+diff --git a/libdiskfs/diskfs-pager.h b/libdiskfs/diskfs-pager.h
+index a253069..db99f9ff 100644
+--- a/libdiskfs/diskfs-pager.h
++++ b/libdiskfs/diskfs-pager.h
+@@ -40,6 +40,7 @@ extern void diskfs_start_disk_pager (struct user_pager_info *info,
+ size_t size, void **image);
+
+ extern struct pager *diskfs_disk_pager;
++extern struct requests *diskfs_disk_pager_requests;
+
+ struct disk_image_user
+ {
+diff --git a/libpager/demuxer.c b/libpager/demuxer.c
+index 4dd3cd8..59dd1c5 100644
+--- a/libpager/demuxer.c
++++ b/libpager/demuxer.c
+@@ -60,7 +60,7 @@ request_inp (const struct request *r)
+ /* A worker. */
+ struct worker
+ {
+- struct requests *requests; /* our pagers request queue */
++ struct pager_requests *requests; /* our pagers request queue */
+ struct queue queue; /* other workers may delegate requests to us */
+ unsigned long tag; /* tag of the object we are working on */
+ };
+@@ -68,12 +68,18 @@ struct worker
+ /* This is the queue for incoming requests. A single thread receives
+ messages from the port set, looks the service routine up, and
+ enqueues the request here. */
+-struct requests
++struct pager_requests
+ {
+ struct port_bucket *bucket;
+- struct queue queue;
++ /* Normally, both queues are the same. However, when the workers are
++ inhibited, a new queue_in is created, but queue_out is left as the
++ old value, so the workers drain queue_out but do not receive new
++ requests. */
++ struct queue *queue_in; /* the queue to add to */
++ struct queue *queue_out; /* the queue to take from */
+ int asleep;
+ pthread_cond_t wakeup;
++ pthread_cond_t inhibit_wakeup;
+ pthread_mutex_t lock;
+ struct worker workers[WORKER_COUNT];
+ };
+@@ -81,7 +87,7 @@ struct requests
+ /* Demultiplex a single message directed at a pager port; INP is the
+ message received; fill OUTP with the reply. */
+ static int
+-pager_demuxer (struct requests *requests,
++pager_demuxer (struct pager_requests *requests,
+ mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+ {
+@@ -108,10 +114,10 @@ pager_demuxer (struct requests *requests,
+
+ pthread_mutex_lock (&requests->lock);
+
+- queue_enqueue (&requests->queue, &r->item);
++ queue_enqueue (requests->queue_in, &r->item);
+
+- /* Awake worker. */
+- if (requests->asleep > 0)
++ /* Awake worker, but only if not inhibited. */
++ if (requests->asleep > 0 && requests->queue_in == requests->queue_out)
+ pthread_cond_signal (&requests->wakeup);
+
+ pthread_mutex_unlock (&requests->lock);
+@@ -160,7 +166,7 @@ static void *
+ worker_func (void *arg)
+ {
+ struct worker *self = (struct worker *) arg;
+- struct requests *requests = self->requests;
++ struct pager_requests *requests = self->requests;
+ struct request *r = NULL;
+ mig_reply_header_t reply_msg;
+
+@@ -186,9 +192,11 @@ worker_func (void *arg)
+
+ get_request_locked:
+ /* ... get a request from the global queue instead. */
+- while ((r = queue_dequeue (&requests->queue)) == NULL)
++ while ((r = queue_dequeue (requests->queue_out)) == NULL)
+ {
+ requests->asleep += 1;
++ if (requests->asleep == WORKER_COUNT)
++ pthread_cond_broadcast (&requests->inhibit_wakeup);
+ pthread_cond_wait (&requests->wakeup, &requests->lock);
+ requests->asleep -= 1;
+ }
+@@ -281,7 +289,7 @@ worker_func (void *arg)
+ static void *
+ service_paging_requests (void *arg)
+ {
+- struct requests *requests = arg;
++ struct pager_requests *requests = arg;
+
+ int demuxer (mach_msg_header_t *inp,
+ mach_msg_header_t *outp)
+@@ -298,27 +306,44 @@ service_paging_requests (void *arg)
+
+ /* Start the worker threads libpager uses to service requests. */
+ error_t
+-pager_start_workers (struct port_bucket *pager_bucket)
++pager_start_workers (struct port_bucket *pager_bucket,
++ struct pager_requests **out_requests)
+ {
+ error_t err;
+ int i;
+ pthread_t t;
+- struct requests *requests;
++ struct pager_requests *requests;
++
++ assert (out_requests != NULL);
+
+ requests = malloc (sizeof *requests);
+ if (requests == NULL)
+- return ENOMEM;
++ {
++ err = ENOMEM;
++ goto done;
++ }
+
+ requests->bucket = pager_bucket;
+ requests->asleep = 0;
+- queue_init (&requests->queue);
++
++ requests->queue_in = malloc (sizeof *requests->queue_in);
++ if (requests->queue_in == NULL)
++ {
++ err = ENOMEM;
++ goto done;
++ }
++ queue_init (requests->queue_in);
++ /* Until the workers are inhibited, both queues are the same. */
++ requests->queue_out = requests->queue_in;
++
+ pthread_cond_init (&requests->wakeup, NULL);
++ pthread_cond_init (&requests->inhibit_wakeup, NULL);
+ pthread_mutex_init (&requests->lock, NULL);
+
+ /* Make a thread to service paging requests. */
+ err = pthread_create (&t, NULL, service_paging_requests, requests);
+ if (err)
+- return err;
++ goto done;
+ pthread_detach (t);
+
+ for (i = 0; i < WORKER_COUNT; i++)
+@@ -329,9 +354,71 @@ pager_start_workers (struct port_bucket *pager_bucket)
+
+ err = pthread_create (&t, NULL, &worker_func, &requests->workers[i]);
+ if (err)
+- return err;
++ goto done;
+ pthread_detach (t);
+ }
+
++done:
++ if (err)
++ *out_requests = NULL;
++ else
++ *out_requests = requests;
++
+ return err;
+ }
++
++error_t
++pager_inhibit_workers (struct pager_requests *requests)
++{
++ error_t err = 0;
++
++ pthread_mutex_lock (&requests->lock);
++
++ /* Check the workers are not already inhibited. */
++ assert (requests->queue_out == requests->queue_in);
++
++ /* Any new paging requests will go into a new queue. */
++ struct queue *new_queue = malloc (sizeof *new_queue);
++ if (new_queue == NULL)
++ {
++ err = ENOMEM;
++ goto done_locked;
++ }
++ queue_init (new_queue);
++ requests->queue_in = new_queue;
++
++ /* Wait until all the workers are asleep and the queue has been
++ drained. All individual worker queues must have been drained, as
++ they are populated while the relevant worker is still running, and
++ it will always drain its personal queue before sleeping.
++ Check that the queue is empty, since it's possible that a request
++ came in, was queued and a worker was signalled but the lock was
++ acquired here before the worker woke up. */
++ while (requests->asleep < WORKER_COUNT || !queue_empty(requests->queue_out))
++ pthread_cond_wait (&requests->inhibit_wakeup, &requests->lock);
++
++done_locked:
++ pthread_mutex_unlock (&requests->lock);
++ return err;
++}
++
++void
++pager_resume_workers (struct pager_requests *requests)
++{
++ pthread_mutex_lock (&requests->lock);
++
++ /* Check the workers are inhibited. */
++ assert (requests->queue_out != requests->queue_in);
++ assert (requests->asleep == WORKER_COUNT);
++ assert (queue_empty(requests->queue_out));
++
++ /* The queue has been drained and will no longer be used. */
++ free (requests->queue_out);
++ requests->queue_out = requests->queue_in;
++
++ /* We need to wake up all workers, as there could be multiple requests
++ in the new queue. */
++ pthread_cond_broadcast (&requests->wakeup);
++
++ pthread_mutex_unlock (&requests->lock);
++}
+diff --git a/libpager/pager.h b/libpager/pager.h
+index fe34238..df4db68 100644
+--- a/libpager/pager.h
++++ b/libpager/pager.h
+@@ -25,8 +25,32 @@
+ scope. */
+ struct user_pager_info;
+
+-/* Start the worker threads libpager uses to service requests. */
+-error_t pager_start_workers (struct port_bucket *pager_bucket);
++struct pager_requests;
++
++/* Start the worker threads libpager uses to service requests. If no
++ error is returned, *requests will be a valid pointer, else it will be
++ set to NULL. */
++error_t
++pager_start_workers (struct port_bucket *pager_bucket,
++ struct pager_requests **requests);
++
++/* Inhibit the worker threads libpager uses to service requests,
++ blocking until all requests sent before this function is called have
++ finished.
++ Note that RPCs will not be inhibited, so new requests will
++ queue up, but will not be handled until the workers are resumed. If
++ RPCs should be inhibited as well, call ports_inhibit_bucket_rpcs with
++ the bucket used to create the workers before calling this. However,
++ inhibiting RPCs and not calling this is generally insufficient, as
++ libports is unaware of our internal worker pool, and will return once
++ all the RPCs have been queued, before they have been handled by a
++ worker thread. */
++error_t
++pager_inhibit_workers (struct pager_requests *requests);
++
++/* Resume the worker threads libpager uses to service requests. */
++void
++pager_resume_workers (struct pager_requests *requests);
+
+ /* Create a new pager. The pager will have a port created for it
+ (using libports, in BUCKET) and will be immediately ready
+diff --git a/libpager/queue.h b/libpager/queue.h
+index d3cf738..abcd3b9 100644
+--- a/libpager/queue.h
++++ b/libpager/queue.h
+@@ -19,6 +19,8 @@
+ You should have received a copy of the GNU General Public License
+ along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */
+
++#include <stdbool.h>
++
+ /* A FIFO queue with constant-time enqueue and dequeue operations. */
+ struct item {
+ struct item *next;
+@@ -59,3 +61,9 @@ queue_dequeue (struct queue *q)
+ r->next = NULL;
+ return r;
+ }
++
++static inline bool
++queue_empty (struct queue *q)
++{
++ return q->head == NULL;
++}
+diff --git a/storeio/pager.c b/storeio/pager.c
+index c260d73..f8f59cd 100644
+--- a/storeio/pager.c
++++ b/storeio/pager.c
+@@ -142,6 +142,7 @@ pager_clear_user_data (struct user_pager_info *upi)
+ }
+
+ static struct port_bucket *pager_port_bucket = 0;
++static struct pager_requests *pager_requests;
+
+ /* Initialize paging for this device. */
+ static void
+@@ -160,7 +161,7 @@ init_dev_paging ()
+ pager_port_bucket = ports_create_bucket ();
+
+ /* Start libpagers worker threads. */
+- err = pager_start_workers (pager_port_bucket);
++ err = pager_start_workers (pager_port_bucket, &pager_requests);
+ if (err)
+ {
+ errno = err;
+--
+2.4.6
+
+
diff --git a/debian/patches/fix-remount0001-yyy-fix-remount.patch b/debian/patches/fix-remount0001-yyy-fix-remount.patch
deleted file mode 100644
index 87bda76f..00000000
--- a/debian/patches/fix-remount0001-yyy-fix-remount.patch
+++ /dev/null
@@ -1,144 +0,0 @@
-From a56055334da0127cc3e88f1529704b80a61e93a2 Mon Sep 17 00:00:00 2001
-From: Justus Winter <4winter@informatik.uni-hamburg.de>
-Date: Tue, 14 Jul 2015 14:28:57 +0200
-Subject: [PATCH hurd] yyy fix remount
-
----
- ext2fs/ext2fs.c | 1 -
- ext2fs/hyper.c | 53 +++++++++++++++++++++++++++++------------------------
- 2 files changed, 29 insertions(+), 25 deletions(-)
-
-diff --git a/ext2fs/ext2fs.c b/ext2fs/ext2fs.c
-index d0fdfe7..f1ec937 100644
---- a/ext2fs/ext2fs.c
-+++ b/ext2fs/ext2fs.c
-@@ -209,7 +209,6 @@ diskfs_reload_global_state ()
- {
- pokel_flush (&global_pokel);
- pager_flush (diskfs_disk_pager, 1);
-- sblock = NULL;
- get_hypermetadata ();
- map_hypermetadata ();
- return 0;
-diff --git a/ext2fs/hyper.c b/ext2fs/hyper.c
-index 5f288bf..afbbbc2 100644
---- a/ext2fs/hyper.c
-+++ b/ext2fs/hyper.c
-@@ -60,24 +60,22 @@ get_hypermetadata (void)
- {
- error_t err;
- size_t read = 0;
--
-- if (sblock != NULL)
-- munmap (sblock, SBLOCK_SIZE);
-+ struct ext2_super_block *old_sblock, *new_sblock;
-
- err = store_read (store, SBLOCK_OFFS >> store->log2_block_size,
-- SBLOCK_SIZE, (void **)&sblock, &read);
-+ SBLOCK_SIZE, (void **)&new_sblock, &read);
- if (err || read != SBLOCK_SIZE)
- ext2_panic ("Cannot read hypermetadata");
-
-- if (sblock->s_magic != EXT2_SUPER_MAGIC
-+ if (new_sblock->s_magic != EXT2_SUPER_MAGIC
- #ifdef EXT2FS_PRE_02B_COMPAT
-- && sblock->s_magic != EXT2_PRE_02B_MAGIC
-+ && new_sblock->s_magic != EXT2_PRE_02B_MAGIC
- #endif
- )
- ext2_panic ("bad magic number %#x (should be %#x)",
-- sblock->s_magic, EXT2_SUPER_MAGIC);
-+ new_sblock->s_magic, EXT2_SUPER_MAGIC);
-
-- log2_block_size = EXT2_MIN_BLOCK_LOG_SIZE + sblock->s_log_block_size;
-+ log2_block_size = EXT2_MIN_BLOCK_LOG_SIZE + new_sblock->s_log_block_size;
- block_size = 1 << log2_block_size;
-
- if (block_size > EXT2_MAX_BLOCK_SIZE)
-@@ -97,10 +95,10 @@ get_hypermetadata (void)
- ext2_panic ("block size %d isn't a power-of-two multiple of 512!",
- block_size);
-
-- if ((store->size >> log2_block_size) < sblock->s_blocks_count)
-+ if ((store->size >> log2_block_size) < new_sblock->s_blocks_count)
- ext2_panic ("disk size (%qd bytes) too small; superblock says we need %qd",
- (long long int) store->size,
-- (long long int) sblock->s_blocks_count << log2_block_size);
-+ (long long int) new_sblock->s_blocks_count << log2_block_size);
- if (log2_dev_blocks_per_fs_block != 0
- && (store->size & ((1 << log2_dev_blocks_per_fs_block) - 1)) != 0)
- ext2_warning ("%Ld (%zd byte) device blocks "
-@@ -109,42 +107,42 @@ get_hypermetadata (void)
- store->block_size, block_size);
-
- /* Set these handy variables. */
-- inodes_per_block = block_size / EXT2_INODE_SIZE (sblock);
-+ inodes_per_block = block_size / EXT2_INODE_SIZE (new_sblock);
-
-- frag_size = EXT2_MIN_FRAG_SIZE << sblock->s_log_frag_size;
-+ frag_size = EXT2_MIN_FRAG_SIZE << new_sblock->s_log_frag_size;
- if (frag_size)
- frags_per_block = block_size / frag_size;
- else
- ext2_panic ("frag size is zero!");
-
-- if (sblock->s_rev_level > EXT2_GOOD_OLD_REV)
-+ if (new_sblock->s_rev_level > EXT2_GOOD_OLD_REV)
- {
-- if (sblock->s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPP)
-+ if (new_sblock->s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPP)
- ext2_panic ("could not mount because of unsupported optional features"
- " (0x%x)",
-- sblock->s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPP);
-- if (sblock->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP)
-+ new_sblock->s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPP);
-+ if (new_sblock->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP)
- {
- ext2_warning ("mounted readonly because of"
- " unsupported optional features (0x%x)",
-- sblock->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP);
-+ new_sblock->s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPP);
- diskfs_readonly = 1;
- }
-- if (sblock->s_inode_size != EXT2_GOOD_OLD_INODE_SIZE)
-- ext2_panic ("inode size %d isn't supported", sblock->s_inode_size);
-+ if (new_sblock->s_inode_size != EXT2_GOOD_OLD_INODE_SIZE)
-+ ext2_panic ("inode size %d isn't supported", new_sblock->s_inode_size);
- }
-
- groups_count =
-- ((sblock->s_blocks_count - sblock->s_first_data_block +
-- sblock->s_blocks_per_group - 1)
-- / sblock->s_blocks_per_group);
-+ ((new_sblock->s_blocks_count - new_sblock->s_first_data_block +
-+ new_sblock->s_blocks_per_group - 1)
-+ / new_sblock->s_blocks_per_group);
-
-- itb_per_group = sblock->s_inodes_per_group / inodes_per_block;
-+ itb_per_group = new_sblock->s_inodes_per_group / inodes_per_block;
- desc_per_block = block_size / sizeof (struct ext2_group_desc);
- addr_per_block = block_size / sizeof (block_t);
- db_per_group = (groups_count + desc_per_block - 1) / desc_per_block;
-
-- ext2fs_clean = sblock->s_state & EXT2_VALID_FS;
-+ ext2fs_clean = new_sblock->s_state & EXT2_VALID_FS;
- if (! ext2fs_clean)
- {
- ext2_warning ("FILESYSTEM NOT UNMOUNTED CLEANLY; PLEASE fsck");
-@@ -163,6 +161,13 @@ get_hypermetadata (void)
- zeroblock = (vm_address_t) mmap (0, block_size, PROT_READ, MAP_ANON, 0, 0);
- assert (zeroblock != (vm_address_t) MAP_FAILED);
- }
-+
-+ /* Switcherino! */
-+ old_sblock = sblock;
-+ sblock = new_sblock;
-+ __sync_synchronize ();
-+ if (old_sblock != NULL)
-+ munmap (old_sblock, SBLOCK_SIZE);
- }
-
- static struct ext2_super_block *mapped_sblock;
---
-2.1.4
-
diff --git a/debian/patches/series b/debian/patches/series
index 95122f1e..37f752f5 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,4 @@
+ext2fs-fix-remount.patch
libexec.patch
diskfs_no_inherit_dir_group.patch
@@ -68,4 +69,3 @@ introspection0005-libdiskfs-annotate-objects-managed-by-libports.patch
introspection0006-libpager-annotate-objects-managed-by-libports.patch
introspection0007-ext2fs-annotate-objects-managed-by-libports.patch
introspection0008-utils-rpctrace-support-attaching-to-servers.patch
-fix-remount0001-yyy-fix-remount.patch