summaryrefslogtreecommitdiff
path: root/debian/patches
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/console_ignore_bdf_err.patch17
-rw-r--r--debian/patches/diskfs_no_inherit_dir_group.patch29
-rw-r--r--debian/patches/exec_filename_exec.patch338
-rw-r--r--debian/patches/exec_filename_fs.patch1035
-rw-r--r--debian/patches/exec_filename_use.patch113
-rw-r--r--debian/patches/ext2fs_large_stores.patch2274
-rw-r--r--debian/patches/ext2fs_large_stores_pthread.patch344
-rw-r--r--debian/patches/external.patch114
-rw-r--r--debian/patches/hurd_console_startup.patch32
-rw-r--r--debian/patches/init_try_runsystem.gnu.patch19
-rw-r--r--debian/patches/libdde_addr_fix.patch37
-rw-r--r--debian/patches/libdde_addr_list.patch423
-rw-r--r--debian/patches/libdde_devres.patch366
-rw-r--r--debian/patches/libdde_dma_head.patch93
-rw-r--r--debian/patches/libdde_ethoc.patch25
-rw-r--r--debian/patches/libdde_ethtool.patch98
-rw-r--r--debian/patches/libdde_group_addr.patch429
-rw-r--r--debian/patches/libdde_mdio.patch359
-rw-r--r--debian/patches/libdde_netdev_tx_t.patch66
-rw-r--r--debian/patches/libdde_pci-needs_freset.patch39
-rw-r--r--debian/patches/libdde_pci_ids.h.patch515
-rw-r--r--debian/patches/libdde_phy.patch60
-rw-r--r--debian/patches/libdde_pr_cont.patch26
-rw-r--r--debian/patches/libdde_rcu.patch816
-rw-r--r--debian/patches/libdde_rculist.patch12
-rw-r--r--debian/patches/libdde_rx_queue.patch70
-rw-r--r--debian/patches/libdde_trans_start.patch138
-rw-r--r--debian/patches/libdde_ucast_list.patch488
-rw-r--r--debian/patches/libdde_workqueue.patch55
-rw-r--r--debian/patches/libexec.patch103
-rw-r--r--debian/patches/libmachdev.patch35
-rw-r--r--debian/patches/libports_stability.patch20
-rw-r--r--debian/patches/makedev.diff17
-rw-r--r--debian/patches/pfinet_dhcp.patch560
-rw-r--r--debian/patches/posix-sigcodes.patch270
-rw-r--r--debian/patches/proxy-defpager.diff62
-rw-r--r--debian/patches/random-default-fast.patch13
-rw-r--r--debian/patches/rc.patch78
-rw-r--r--debian/patches/run.patch18
-rw-r--r--debian/patches/series43
-rw-r--r--debian/patches/startup-usr-support.patch27
-rw-r--r--debian/patches/stat_round.patch57
-rw-r--r--debian/patches/tmp_exec_startup.patch54
-rw-r--r--debian/patches/uptime_w_path_fix.patch16
44 files changed, 9803 insertions, 0 deletions
diff --git a/debian/patches/console_ignore_bdf_err.patch b/debian/patches/console_ignore_bdf_err.patch
new file mode 100644
index 00000000..c3ea30cb
--- /dev/null
+++ b/debian/patches/console_ignore_bdf_err.patch
@@ -0,0 +1,17 @@
+reduce-font overestimates the number of characters in the font.
+
+diff --git a/console-client/bdf.c b/console-client/bdf.c
+index 30501f4..ee8aa30 100644
+--- a/console-client/bdf.c
++++ b/console-client/bdf.c
+@@ -415,8 +415,10 @@ bdf_read (FILE *filep, bdf_font_t *font, int *linecount)
+ glyphs. */
+ if (!strcmp (line, "ENDFONT"))
+ {
++ /*
+ if (parser.glyphs != bdf->glyphs_count)
+ err = BDF_COUNT_MISMATCH;
++ */
+ done = 1;
+ }
+ else
diff --git a/debian/patches/diskfs_no_inherit_dir_group.patch b/debian/patches/diskfs_no_inherit_dir_group.patch
new file mode 100644
index 00000000..8d17f3e0
--- /dev/null
+++ b/debian/patches/diskfs_no_inherit_dir_group.patch
@@ -0,0 +1,29 @@
+Follow POSIX rules for gid of new nodes.
+---
+ opts-common.c | 2 +-
+ libdiskfs/init-init.c | 3 +++
+ 2 file changed, 4 insertion(+), 1 deletion(-)
+
+--- a/libdiskfs/init-init.c
++++ b/libdiskfs/init-init.c
+@@ -57,6 +57,9 @@ diskfs_init_diskfs (void)
+ {
+ error_t err;
+
++ /* See `node-create.c'. */
++ _diskfs_no_inherit_dir_group = 1;
++
+ if (diskfs_boot_filesystem ())
+ /* This is a boot filesystem, we have to do some things specially. */
+ {
+--- a/libdiskfs/opts-common.c
++++ b/libdiskfs/opts-common.c
+@@ -52,7 +52,7 @@ const struct argp_option diskfs_common_options[] =
+ {"nogrpid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"sysvgroups", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"inherit-dir-group", OPT_INHERIT_DIR_GROUP, 0, 0,
+- "Create new nodes with gid of parent dir (default)"},
++ "Create new nodes with gid of parent dir"},
+ {"grpid", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {"bsdgroups", 0, 0, OPTION_ALIAS | OPTION_HIDDEN},
+ {0, 0}
diff --git a/debian/patches/exec_filename_exec.patch b/debian/patches/exec_filename_exec.patch
new file mode 100644
index 00000000..41b66a82
--- /dev/null
+++ b/debian/patches/exec_filename_exec.patch
@@ -0,0 +1,338 @@
+From 011df9d35eb68132cdb14a0f55e2435375e2cfce Mon Sep 17 00:00:00 2001
+From: Emilio Pozuelo Monfort <pochu27@gmail.com>
+Date: Wed, 26 May 2010 00:15:37 +0200
+Subject: [PATCH 1/3] Add a new exec_exec_file_name RPC
+
+* hurd/exec.defs (exec_exec_file_name): New RPC.
+(exec_exec): Label as deprecated.
+* doc/hurd.texi: Updated.
+* exec/exec.c (S_exec_exec_file_name): New function.
+(S_exec_exec): Label as deprecated.
+(do_exec): Add argument.
+* exec/hashexec.c (check_hashbang): Add argument.
+Don't guess the file name if file_name_exec is set.
+* exec/priv.h (check_hashbang): Add argument.
+---
+ doc/hurd.texi | 8 ++++----
+ exec/exec.c | 50 +++++++++++++++++++++++++++++++++++++++++++++-----
+ exec/hashexec.c | 18 ++++++++++++------
+ exec/priv.h | 4 +++-
+ hurd/exec.defs | 19 +++++++++++++++++--
+ 5 files changed, 81 insertions(+), 18 deletions(-)
+
+Index: hurd-debian/doc/hurd.texi
+===================================================================
+--- hurd-debian.orig/doc/hurd.texi 2012-06-03 20:17:54.000000000 +0000
++++ hurd-debian/doc/hurd.texi 2012-06-05 04:32:07.000000000 +0000
+@@ -102,7 +102,7 @@
+ documentation was last updated for version @value{VERSION} of the Hurd.
+
+ Copyright @copyright{} 1994, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
+-2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
++2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+
+ @quotation
+ Permission is granted to make and distribute verbatim copies of
+@@ -2770,14 +2770,14 @@
+ authentication handle that was not previously present (as opposed to
+ merely reordering them), then the @code{EXEC_SECURE} and
+ @code{EXEC_NEWTASK} flags should both be added in the call to
+-@code{exec_exec}.
++@code{exec_exec_file_name}.
+
+ The server then needs to open a new port onto the executed file which
+ will not share any file pointers with the port the user passed in,
+ opened with @code{O_READ}. Finally, all the information (mutated
+ appropriately for setuid/setgid) should be sent to the execserver with
+-@code{exec_exec}. Whatever error code @code{exec_exec} returns should
+-returned to the caller of @code{file_exec}.
++@code{exec_exec_file_name}. Whatever error code @code{exec_exec_file_name}
++returns should be returned to the caller of @code{file_exec}.
+
+ @node File Locking
+ @subsection File Locking
+Index: hurd-debian/exec/exec.c
+===================================================================
+--- hurd-debian.orig/exec/exec.c 2012-06-03 17:08:36.000000000 +0000
++++ hurd-debian/exec/exec.c 2012-06-05 04:19:51.000000000 +0000
+@@ -1,6 +1,6 @@
+ /* GNU Hurd standard exec server.
+- Copyright (C) 1992,93,94,95,96,98,99,2000,01,02,04
+- Free Software Foundation, Inc.
++ Copyright (C) 1992 ,1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
++ 2002, 2004, 2010 Free Software Foundation, Inc.
+ Written by Roland McGrath.
+
+ Can exec ELF format directly.
+@@ -1357,6 +1357,7 @@
+ do_exec (file_t file,
+ task_t oldtask,
+ int flags,
++ char *filename,
+ char *argv, mach_msg_type_number_t argvlen, boolean_t argv_copy,
+ char *envp, mach_msg_type_number_t envplen, boolean_t envp_copy,
+ mach_port_t *dtable, mach_msg_type_number_t dtablesize,
+@@ -1452,7 +1453,7 @@
+ {
+ /* Check for a #! executable file. */
+ check_hashbang (&e,
+- file, oldtask, flags,
++ file, oldtask, flags, filename,
+ argv, argvlen, argv_copy,
+ envp, envplen, envp_copy,
+ dtable, dtablesize, dtable_copy,
+@@ -2055,6 +2056,7 @@
+ return e.error;
+ }
+
++/* Deprecated. */
+ kern_return_t
+ S_exec_exec (struct trivfs_protid *protid,
+ file_t file,
+@@ -2071,6 +2073,44 @@
+ mach_port_t *deallocnames, mach_msg_type_number_t ndeallocnames,
+ mach_port_t *destroynames, mach_msg_type_number_t ndestroynames)
+ {
++ return S_exec_exec_file_name (protid,
++ file,
++ oldtask,
++ flags,
++ "",
++ argv, argvlen, argv_copy,
++ envp, envplen, envp_copy,
++ dtable, dtablesize,
++ dtable_copy,
++ portarray, nports,
++ portarray_copy,
++ intarray, nints,
++ intarray_copy,
++ deallocnames, ndeallocnames,
++ destroynames, ndestroynames);
++}
++
++kern_return_t
++S_exec_exec_file_name (struct trivfs_protid *protid,
++ file_t file,
++ task_t oldtask,
++ int flags,
++ char *filename,
++ char *argv, mach_msg_type_number_t argvlen,
++ boolean_t argv_copy,
++ char *envp, mach_msg_type_number_t envplen,
++ boolean_t envp_copy,
++ mach_port_t *dtable, mach_msg_type_number_t dtablesize,
++ boolean_t dtable_copy,
++ mach_port_t *portarray, mach_msg_type_number_t nports,
++ boolean_t portarray_copy,
++ int *intarray, mach_msg_type_number_t nints,
++ boolean_t intarray_copy,
++ mach_port_t *deallocnames,
++ mach_msg_type_number_t ndeallocnames,
++ mach_port_t *destroynames,
++ mach_msg_type_number_t ndestroynames)
++{
+ if (! protid)
+ return EOPNOTSUPP;
+
+@@ -2111,7 +2151,7 @@
+ trivfs_protid_portclasses[0]);
+ if (protid)
+ {
+- err = do_exec (file, oldtask, 0,
++ err = do_exec (file, oldtask, 0, filename,
+ argv, argvlen, argv_copy,
+ envp, envplen, envp_copy,
+ dtable, dtablesize, dtable_copy,
+@@ -2158,7 +2198,7 @@
+ /* There were no user-specified exec servers,
+ or none of them could be found. */
+
+- return do_exec (file, oldtask, flags,
++ return do_exec (file, oldtask, flags, filename,
+ argv, argvlen, argv_copy,
+ envp, envplen, envp_copy,
+ dtable, dtablesize, dtable_copy,
+Index: hurd-debian/exec/hashexec.c
+===================================================================
+--- hurd-debian.orig/exec/hashexec.c 2012-06-03 17:08:36.000000000 +0000
++++ hurd-debian/exec/hashexec.c 2012-06-05 04:32:38.000000000 +0000
+@@ -1,5 +1,6 @@
+ /* GNU Hurd standard exec server, #! script execution support.
+- Copyright (C) 1995,96,97,98,99,2000,02 Free Software Foundation, Inc.
++ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2010
++ Free Software Foundation, Inc.
+ Written by Roland McGrath.
+
+ This file is part of the GNU Hurd.
+@@ -35,6 +36,7 @@
+ file_t file,
+ task_t oldtask,
+ int flags,
++ char *file_name_exec,
+ char *argv, u_int argvlen, boolean_t argv_copy,
+ char *envp, u_int envplen, boolean_t envp_copy,
+ mach_port_t *dtable, u_int dtablesize, boolean_t dtable_copy,
+@@ -225,10 +227,12 @@
+ file_name = NULL;
+ else if (! (flags & EXEC_SECURE))
+ {
+- /* Try to figure out the file's name. We guess that if ARGV[0]
+- contains a slash, it might be the name of the file; and that
+- if it contains no slash, looking for files named by ARGV[0] in
+- the `PATH' environment variable might find it. */
++ /* Try to figure out the file's name. If FILE_NAME_EXEC
++ is not NULL, then it's the file's name. Otherwise we
++ guess that if ARGV[0] contains a slash, it might be
++ the name of the file; and that if it contains no slash,
++ looking for files named by ARGV[0] in the `PATH'
++ environment variable might find it. */
+
+ error_t error;
+ char *name;
+@@ -278,7 +282,9 @@
+ else
+ name = argv;
+
+- if (strchr (name, '/') != NULL)
++ if (file_name_exec && file_name_exec[0] != '\0')
++ error = lookup (name = file_name_exec, 0, &name_file);
++ else if (strchr (name, '/') != NULL)
+ error = lookup (name, 0, &name_file);
+ else if ((error = hurd_catch_signal
+ (sigmask (SIGBUS) | sigmask (SIGSEGV),
+Index: hurd-debian/exec/priv.h
+===================================================================
+--- hurd-debian.orig/exec/priv.h 2012-06-03 17:08:36.000000000 +0000
++++ hurd-debian/exec/priv.h 2012-06-05 03:36:44.000000000 +0000
+@@ -1,5 +1,6 @@
+ /* GNU Hurd standard exec server, private declarations.
+- Copyright (C) 1992,93,94,95,96,99,2000,02, 04 Free Software Foundation, Inc.
++ Copyright (C) 1992, 1993, 1994, 1995, 1996, 1999, 2000, 2002, 2004,
++ 2010 Free Software Foundation, Inc.
+ Written by Roland McGrath.
+
+ This file is part of the GNU Hurd.
+@@ -36,6 +37,7 @@
+ #include <link.h> /* This gives us the ElfW macro. */
+ #include <fcntl.h>
+ #include "exec_S.h"
++#include "exec_experimental_S.h"
+
+
+ #ifndef exec_priv_h
+@@ -171,6 +173,7 @@
+ file_t file,
+ task_t oldtask,
+ int flags,
++ char *filename,
+ char *argv, u_int argvlen, boolean_t argv_copy,
+ char *envp, u_int envplen, boolean_t envp_copy,
+ mach_port_t *dtable, u_int dtablesize,
+Index: hurd-debian/hurd/exec.defs
+===================================================================
+--- hurd-debian.orig/hurd/exec.defs 2012-06-03 17:08:36.000000000 +0000
++++ hurd-debian/hurd/exec.defs 2012-06-03 20:17:55.000000000 +0000
+@@ -1,5 +1,6 @@
+ /* Interface definitions for the exec servers.
+- Copyright (C) 1991,92,93,94,95,2001 Free Software Foundation, Inc.
++ Copyright (C) 1991, 1992, 1993, 1994, 1995, 2001, 2010
++ Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+@@ -29,6 +30,7 @@
+
+ INTR_INTERFACE
+
++/* Deprecated: use exec_exec_file_name instead. */
+ routine exec_exec (
+ execserver: file_t;
+ file: mach_port_send_t;
+Index: hurd-debian/hurd/exec_experimental.defs
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ hurd-debian/hurd/exec_experimental.defs 2012-06-03 20:17:55.000000000 +0000
+@@ -0,0 +1,46 @@
++/* Interface definitions for the exec servers.
++ Copyright (C) 1991, 1992, 1993, 1994, 1995, 2001, 2010, 2012
++ Free Software Foundation, Inc.
++
++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 the GNU Hurd; see the file COPYING. If not, write to
++the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
++
++/* Written by Michael I. Bushnell and Roland McGrath. */
++
++subsystem exec_experimental 434242;
++
++#include <hurd/hurd_types.defs>
++
++#ifdef EXEC_IMPORTS
++EXEC_IMPORTS
++#endif
++
++INTR_INTERFACE
++
++routine exec_exec_file_name (
++ execserver: file_t;
++ file: mach_port_send_t;
++ oldtask: task_t;
++ flags: int;
++ filename: string_t;
++ argv: data_t SCP;
++ envp: data_t SCP;
++ dtable: portarray_t SCP;
++ portarray: portarray_t SCP;
++ intarray: intarray_t SCP;
++ deallocnames: mach_port_name_array_t;
++ destroynames: mach_port_name_array_t);
++
+Index: hurd-debian/exec/Makefile
+===================================================================
+--- hurd-debian.orig/exec/Makefile 2012-06-03 17:08:36.000000000 +0000
++++ hurd-debian/exec/Makefile 2012-06-05 03:39:06.000000000 +0000
+@@ -23,7 +23,7 @@
+ SRCS = exec.c main.c hashexec.c hostarch.c \
+ $(gzip-sources) $(bzip2-sources)
+ OBJS = main.o hostarch.o exec.o hashexec.o \
+- execServer.o exec_startupServer.o \
++ execServer.o exec_startupServer.o exec_experimentalServer.o \
+ $(gzip-objects) $(bzip2-objects)
+ gzip-sources = unzip.c util.c inflate.c
+ gzip-objects = $(gzip-sources:%.c=%.o)
+@@ -37,6 +37,7 @@
+ OTHERLIBS = -lpthread
+
+ exec-MIGSFLAGS = -imacros $(srcdir)/execmutations.h
++exec_experimental-MIGSFLAGS = -imacros $(srcdir)/execmutations.h
+
+ include ../Makeconf
+
+Index: hurd-debian/exec/main.c
+===================================================================
+--- hurd-debian.orig/exec/main.c 2012-06-03 17:08:36.000000000 +0000
++++ hurd-debian/exec/main.c 2012-06-05 01:28:09.000000000 +0000
+@@ -58,9 +58,11 @@
+ exec_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+ {
+ extern int exec_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
++ extern int exec_experimental_server (mach_msg_header_t *inp, mach_msg_header_t *outp);
+ extern int exec_startup_server (mach_msg_header_t *, mach_msg_header_t *);
+ return (exec_startup_server (inp, outp) ||
+ exec_server (inp, outp) ||
++ exec_experimental_server (inp, outp) ||
+ trivfs_demuxer (inp, outp));
+ }
+
diff --git a/debian/patches/exec_filename_fs.patch b/debian/patches/exec_filename_fs.patch
new file mode 100644
index 00000000..a4b5589a
--- /dev/null
+++ b/debian/patches/exec_filename_fs.patch
@@ -0,0 +1,1035 @@
+From ba528e4a9db131112aa09edfdbb3449b55618578 Mon Sep 17 00:00:00 2001
+From: Emilio Pozuelo Monfort <pochu27@gmail.com>
+Date: Wed, 26 May 2010 01:27:40 +0200
+Subject: [PATCH 2/3] Add a file_exec_file_name RPC
+
+* hurd/fs.defs (file_exec): Deprecate in favor of...
+(file_exec_file_name): ...this new RPC.
+Change all implementations and forward old implementations to
+the new version. Change all callers but fallback to old version.
+Change comments and documentation.
+---
+ TODO | 2 +-
+ doc/hurd.texi | 16 ++++----
+ exec/hashexec.c | 32 ++++++++++----
+ hurd/fs.defs | 28 +++++++++++--
+ hurd/hurd_types.h | 9 ++--
+ init/init.c | 81 ++++++++++++++++++++++++++----------
+ libdiskfs/boot-start.c | 2 +-
+ libdiskfs/file-exec.c | 75 ++++++++++++++++++++++++++++------
+ libfshelp/start-translator-long.c | 21 +++++++---
+ libnetfs/file-exec.c | 67 ++++++++++++++++++++++++++----
+ libtrivfs/file-exec.c | 27 ++++++++++++-
+ trans/fakeroot.c | 59 ++++++++++++++++++++++++---
+ utils/login.c | 23 +++++++---
+ 13 files changed, 350 insertions(+), 92 deletions(-)
+
+Index: hurd-debian/TODO
+===================================================================
+--- hurd-debian.orig/TODO 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/TODO 2013-06-19 23:32:37.000000000 +0000
+@@ -136,7 +136,7 @@
+
+ ** libtrivfs
+ *** Allow for read/write/exec to be passed down.
+-*** Implement file_exec when appropriate. !!
++*** Implement file_exec_file_name when appropriate. !!
+ *** Provide for the visible owner, etc., to be held in command-line args
+ instead of the underlying node, when it's important. !!
+
+Index: hurd-debian/doc/hurd.texi
+===================================================================
+--- hurd-debian.orig/doc/hurd.texi 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/doc/hurd.texi 2013-06-19 23:32:37.000000000 +0000
+@@ -2738,10 +2738,10 @@
+ @node Program Execution
+ @subsection Program Execution
+
+-@findex file_exec
++@findex file_exec_file_name
+ Execution of programs on the Hurd is done through fileservers with the
+-@code{file_exec} RPC. The fileserver is expected to verify that the
+-user is allowed to execute the file, make whatever modifications to the
++@code{file_exec_file_name} RPC. The fileserver is expected to verify that
++the user is allowed to execute the file, make whatever modifications to the
+ ports are necessary for setuid execution, and then invoke the standard
+ execserver found on @file{/servers/exec}.
+
+@@ -2753,13 +2753,13 @@
+ be returned. In addition, at least one of the execute bits must be on. A
+ failure of this check should result in @code{EACCES}---not
+ @code{ENOEXEC}. It is not proper for the fileserver ever to respond to
+-the @code{file_exec} RPC with @code{ENOEXEC}.
++the @code{file_exec_file_name} RPC with @code{ENOEXEC}.
+
+ If either the setuid or setgid bits are set, the server needs to
+ construct a new authentication handle with the additional new ID's.
+-Then all the ports passed to @code{file_exec} need to be reauthenticated
+-with the new handle. If the fileserver is unable to make the new
+-authentication handle (for example, because it is not running as root)
++Then all the ports passed to @code{file_exec_file_name} need to be
++reauthenticated with the new handle. If the fileserver is unable to make the
++new authentication handle (for example, because it is not running as root)
+ it is not acceptable to return an error; in such a case the server
+ should simply silently fail to implement the setuid/setgid semantics.
+
+@@ -2774,7 +2774,7 @@
+ opened with @code{O_READ}. Finally, all the information (mutated
+ appropriately for setuid/setgid) should be sent to the execserver with
+ @code{exec_exec_file_name}. Whatever error code @code{exec_exec_file_name}
+-returns should be returned to the caller of @code{file_exec}.
++returns should be returned to the caller of @code{file_exec_file_name}.
+
+ @node File Locking
+ @subsection File Locking
+Index: hurd-debian/exec/hashexec.c
+===================================================================
+--- hurd-debian.orig/exec/hashexec.c 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/exec/hashexec.c 2013-06-19 23:32:37.000000000 +0000
+@@ -24,6 +24,9 @@
+ #include <unistd.h>
+ #include <envz.h>
+ #include <sys/param.h>
++#ifdef HAVE_FILE_EXEC_FILE_NAME
++#include <hurd/fs_experimental.h>
++#endif
+
+ /* This is called to check E for a #! interpreter specification. E has
+ already been prepared (successfully) and checked (unsuccessfully). If
+@@ -421,16 +424,32 @@
+ /* We cannot open the interpreter file to execute it. Lose! */
+ return;
+
++#ifdef HAVE_FILE_EXEC_FILE_NAME
+ /* Execute the interpreter program. */
+- e->error = file_exec (interp_file,
+- oldtask, flags,
+- new_argv, new_argvlen, envp, envplen,
+- new_dtable ?: dtable, MACH_MSG_TYPE_COPY_SEND,
+- new_dtable ? new_dtablesize : dtablesize,
+- portarray, MACH_MSG_TYPE_COPY_SEND, nports,
+- intarray, nints,
+- deallocnames, ndeallocnames,
+- destroynames, ndestroynames);
++ e->error = file_exec_file_name (interp_file,
++ oldtask, flags, interp,
++ new_argv, new_argvlen, envp, envplen,
++ new_dtable ?: dtable,
++ MACH_MSG_TYPE_COPY_SEND,
++ new_dtable ? new_dtablesize : dtablesize,
++ portarray, MACH_MSG_TYPE_COPY_SEND, nports,
++ intarray, nints,
++ deallocnames, ndeallocnames,
++ destroynames, ndestroynames);
++ /* For backwards compatibility. Just drop it when we kill file_exec. */
++ if (e->error == MIG_BAD_ID)
++#endif
++ e->error = file_exec (interp_file,
++ oldtask, flags,
++ new_argv, new_argvlen, envp, envplen,
++ new_dtable ?: dtable, MACH_MSG_TYPE_COPY_SEND,
++ new_dtable ? new_dtablesize : dtablesize,
++ portarray, MACH_MSG_TYPE_COPY_SEND, nports,
++ intarray, nints,
++ deallocnames, ndeallocnames,
++ destroynames, ndestroynames);
++
++
+ mach_port_deallocate (mach_task_self (), interp_file);
+
+ if (! e->error)
+Index: hurd-debian/hurd/fs.defs
+===================================================================
+--- hurd-debian.orig/hurd/fs.defs 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/hurd/fs.defs 2013-06-19 23:32:37.000000000 +0000
+@@ -1,5 +1,6 @@
+ /* Definitions for the filesystem interface.
+- Copyright (C) 1994,95,96,97,98,99,2002 Free Software Foundation, Inc.
++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2002, 2010
++ Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+@@ -35,7 +36,8 @@
+ /* Overlay a task with a file. Necessary initialization, including
+ authentication changes associated with set[ug]id execution must be
+ handled by the filesystem. Filesystems normally implement this by
+- using exec_newtask or exec_loadtask as appropriate. */
++ using exec_newtask or exec_loadtask as appropriate.
++ Deprecated: use file_exec_file_name instead. */
+ routine file_exec (
+ exec_file: file_t;
+ RPT
+@@ -129,8 +131,8 @@
+ (regardless of the current open modes for this port). ALLOWED is a
+ bitwise OR of O_READ, O_WRITE, and O_EXEC. This is not necessarily the
+ same as what an open or exec would allow; O_EXEC is set for root even if
+- no executable bits are on (in which case file_exec should fail) and
+- O_WRITE is set a directory can be modified, even though it can't be
++ no executable bits are on (in which case file_exec_file_name should fail)
++ and O_WRITE is set a directory can be modified, even though it can't be
+ written directly. */
+ routine file_check_access (
+ file: file_t;
+Index: hurd-debian/hurd/hurd_types.h
+===================================================================
+--- hurd-debian.orig/hurd/hurd_types.h 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/hurd/hurd_types.h 2013-06-19 23:32:37.000000000 +0000
+@@ -1,5 +1,6 @@
+ /* C declarations for Hurd server interfaces
+- Copyright (C) 1993,94,95,96,98,99,2001,02 Free Software Foundation, Inc.
++ Copyright (C) 1993, 1994, 1995, 1996, 1998, 1999, 2001, 2002,
++ 2010 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+@@ -78,7 +79,7 @@
+ /* Many such parameters and flags are also defined in various libc
+ headers. */
+
+-/* Bits for flags in fs.defs:file_exec and exec.defs:exec_* calls: */
++/* Bits for flags in fs.defs:file_exec_file_name and exec.defs:exec_* calls: */
+ #define EXEC_NEWTASK 0x00000001 /* Create new task; kill old one. */
+ #define EXEC_SECURE 0x00000002 /* Use secure values of portarray, etc. */
+ #define EXEC_DEFAULTS 0x00000004 /* Use defaults for unspecified ports. */
+@@ -344,7 +345,7 @@
+ #define FSTYPE_MEMFS 0x00000019 /* In-core filesystem */
+ #define FSTYPE_ISO9660 0x0000001a /* ISO9660 */
+
+-/* Standard port assignments for file_exec and exec_* */
++/* Standard port assignments for file_exec_file_name and exec_* */
+ enum
+ {
+ INIT_PORT_CWDIR,
+@@ -358,7 +359,7 @@
+ INIT_PORT_MAX
+ };
+
+-/* Standard ints for file_exec and exec_* */
++/* Standard ints for file_exec_file_name and exec_* */
+ enum
+ {
+ INIT_UMASK,
+Index: hurd-debian/init/init.c
+===================================================================
+--- hurd-debian.orig/init/init.c 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/init/init.c 2013-06-19 23:32:37.000000000 +0000
+@@ -1,7 +1,7 @@
+ /* Start and maintain hurd core servers and system run state
+
+ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+- 2005, 2008 Free Software Foundation, Inc.
++ 2005, 2008, 2010 Free Software Foundation, Inc.
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or modify
+@@ -24,6 +24,9 @@
+ one file. */
+ #include <hurd.h>
+ #include <hurd/fs.h>
++#ifdef HAVE_FILE_EXEC_FILE_NAME
++#include <hurd/fs_experimental.h>
++#endif
+ #include <hurd/fsys.h>
+ #include <device/device.h>
+ #include <stdio.h>
+@@ -375,13 +378,28 @@
+ printf ("Pausing for %s\n", prog);
+ getchar ();
+ }
+- err = file_exec (file, *task, 0,
+- (char *)prog, strlen (prog) + 1, /* Args. */
+- startup_envz, startup_envz_len,
+- default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
+- ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
+- default_ints, INIT_INT_MAX,
+- NULL, 0, NULL, 0);
++#ifdef HAVE_FILE_EXEC_FILE_NAME
++ err = file_exec_file_name (file, *task, 0, (char *)prog,
++ (char *)prog,
++ strlen (prog) + 1, /* Args. */
++ startup_envz, startup_envz_len,
++ default_dtable,
++ MACH_MSG_TYPE_COPY_SEND, 3,
++ ports, MACH_MSG_TYPE_COPY_SEND,
++ INIT_PORT_MAX,
++ default_ints, INIT_INT_MAX,
++ NULL, 0, NULL, 0);
++ /* For backwards compatibility. Just drop it when we kill
++ file_exec. */
++ if (err == MIG_BAD_ID)
++#endif
++ err = file_exec (file, *task, 0,
++ (char *)prog, strlen (prog) + 1, /* Args. */
++ startup_envz, startup_envz_len,
++ default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
++ ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
++ default_ints, INIT_INT_MAX,
++ NULL, 0, NULL, 0);
+ if (!err)
+ break;
+
+@@ -468,14 +486,27 @@
+ ++progname;
+ else
+ progname = filename;
+- err = file_exec (file, task, 0,
+- args, arglen,
+- startup_envz, startup_envz_len,
+- default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
+- default_ports, MACH_MSG_TYPE_COPY_SEND,
+- INIT_PORT_MAX,
+- default_ints, INIT_INT_MAX,
+- NULL, 0, NULL, 0);
++#ifdef HAVE_FILE_EXEC_FILE_NAME
++ err = file_exec_file_name (file, task, 0, filename,
++ args, arglen,
++ startup_envz, startup_envz_len,
++ default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
++ default_ports, MACH_MSG_TYPE_COPY_SEND,
++ INIT_PORT_MAX,
++ default_ints, INIT_INT_MAX,
++ NULL, 0, NULL, 0);
++ /* For backwards compatibility. Just drop it when we kill file_exec. */
++ if (err == MIG_BAD_ID)
++#endif
++ err = file_exec (file, task, 0,
++ args, arglen,
++ startup_envz, startup_envz_len,
++ default_dtable, MACH_MSG_TYPE_COPY_SEND, 3,
++ default_ports, MACH_MSG_TYPE_COPY_SEND,
++ INIT_PORT_MAX,
++ default_ints, INIT_INT_MAX,
++ NULL, 0, NULL, 0);
++
+ mach_port_deallocate (mach_task_self (), default_ports[INIT_PORT_PROC]);
+ mach_port_deallocate (mach_task_self (), task);
+ if (ctty != MACH_PORT_NULL)
+@@ -1059,13 +1090,26 @@
+ getchar ();
+ }
+
+- err = file_exec (file, child_task, 0,
+- args, arglen,
+- startup_envz, startup_envz_len,
+- NULL, MACH_MSG_TYPE_COPY_SEND, 0, /* No fds. */
+- default_ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
+- default_ints, INIT_INT_MAX,
+- NULL, 0, NULL, 0);
++#ifdef HAVE_FILE_EXEC_FILE_NAME
++ err = file_exec_file_name (file, child_task, 0, args,
++ args, arglen,
++ startup_envz, startup_envz_len,
++ NULL, MACH_MSG_TYPE_COPY_SEND, 0, /* No fds. */
++ default_ports, MACH_MSG_TYPE_COPY_SEND,
++ INIT_PORT_MAX,
++ default_ints, INIT_INT_MAX,
++ NULL, 0, NULL, 0);
++ /* For backwards compatibility. Just drop it when we kill file_exec. */
++ if (err == MIG_BAD_ID)
++#endif
++ err = file_exec (file, child_task, 0,
++ args, arglen,
++ startup_envz, startup_envz_len,
++ NULL, MACH_MSG_TYPE_COPY_SEND, 0, /* No fds. */
++ default_ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
++ default_ints, INIT_INT_MAX,
++ NULL, 0, NULL, 0);
++
+ mach_port_deallocate (mach_task_self (), default_ports[INIT_PORT_PROC]);
+ mach_port_deallocate (mach_task_self (), file);
+ if (err)
+Index: hurd-debian/libdiskfs/boot-start.c
+===================================================================
+--- hurd-debian.orig/libdiskfs/boot-start.c 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/libdiskfs/boot-start.c 2013-06-19 23:32:37.000000000 +0000
+@@ -207,7 +207,7 @@
+ diskfs_exec_ctl = MACH_PORT_NULL; /* Not used after this. */
+ }
+
+- /* Cache the exec server port for file_exec to use. */
++ /* Cache the exec server port for file_exec_file_name to use. */
+ _hurd_port_set (&_diskfs_exec_portcell, diskfs_exec);
+
+ if (_diskfs_boot_command)
+Index: hurd-debian/libdiskfs/file-exec.c
+===================================================================
+--- hurd-debian.orig/libdiskfs/file-exec.c 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/libdiskfs/file-exec.c 2013-06-19 23:32:37.000000000 +0000
+@@ -1,5 +1,6 @@
+-/* File execution (file_exec RPC) for diskfs servers, using exec server.
+- Copyright (C) 1993,94,95,96,97,98,2000,02 Free Software Foundation, Inc.
++/* File execution (file_exec_file_name RPC) for diskfs servers, using exec server.
++ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2002,
++ 2010 Free Software Foundation, Inc.
+
+ This file is part of the GNU Hurd.
+
+@@ -21,10 +22,14 @@
+
+ #include "priv.h"
+ #include "fs_S.h"
++#include "fs_experimental_S.h"
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <hurd/exec.h>
+ #include <hurd/paths.h>
++#ifdef HAVE_EXEC_EXEC_FILE_NAME
++#include <hurd/exec_experimental.h>
++#endif
+ #include <string.h>
+ #include <idvec.h>
+
+@@ -47,6 +52,39 @@
+ mach_port_t *destroynames,
+ size_t destroynameslen)
+ {
++ return diskfs_S_file_exec_file_name (cred,
++ task,
++ flags,
++ "",
++ argv, argvlen,
++ envp, envplen,
++ fds, fdslen,
++ portarray, portarraylen,
++ intarray, intarraylen,
++ deallocnames, deallocnameslen,
++ destroynames, destroynameslen);
++}
++
++kern_return_t
++diskfs_S_file_exec_file_name (struct protid *cred,
++ task_t task,
++ int flags,
++ char *filename,
++ char *argv,
++ size_t argvlen,
++ char *envp,
++ size_t envplen,
++ mach_port_t *fds,
++ size_t fdslen,
++ mach_port_t *portarray,
++ size_t portarraylen,
++ int *intarray,
++ size_t intarraylen,
++ mach_port_t *deallocnames,
++ size_t deallocnameslen,
++ mach_port_t *destroynames,
++ size_t destroynameslen)
++{
+ struct node *np;
+ uid_t uid;
+ gid_t gid;
+@@ -136,9 +174,9 @@
+
+ if (! err)
+ /* Make a new peropen for the exec server to access the file, since any
+- seeking the exec server might want to do should not affect the
+- original peropen on which file_exec was called. (The new protid for
+- this peropen clones the caller's iouser to preserve the caller's
++ seeking the exec server might want to do should not affect the original
++ peropen on which file_exec_file_name was called. (The new protid
++ for this peropen clones the caller's iouser to preserve the caller's
+ authentication credentials.) The new peropen's openmodes must have
+ O_READ even if the caller had only O_EXEC privilege, so the exec
+ server can read the executable file. We also include O_EXEC so that
+@@ -159,14 +197,31 @@
+ do
+ {
+ right = ports_get_send_right (newpi);
+- err = exec_exec (execserver,
+- right, MACH_MSG_TYPE_COPY_SEND,
+- task, flags, argv, argvlen, envp, envplen,
+- fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
+- portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
+- intarray, intarraylen,
+- deallocnames, deallocnameslen,
+- destroynames, destroynameslen);
++#ifdef HAVE_EXEC_EXEC_FILE_NAME
++ err = exec_exec_file_name (execserver,
++ right, MACH_MSG_TYPE_COPY_SEND,
++ task, flags, filename,
++ argv, argvlen, envp, envplen,
++ fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
++ portarray, MACH_MSG_TYPE_COPY_SEND,
++ portarraylen,
++ intarray, intarraylen,
++ deallocnames, deallocnameslen,
++ destroynames, destroynameslen);
++ /* For backwards compatibility. Just drop it when we kill
++ exec_exec. */
++ if (err == MIG_BAD_ID)
++#endif
++ err = exec_exec (execserver,
++ right, MACH_MSG_TYPE_COPY_SEND,
++ task, flags, argv, argvlen, envp, envplen,
++ fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
++ portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
++ intarray, intarraylen,
++ deallocnames, deallocnameslen,
++ destroynames, destroynameslen);
++
++
+ mach_port_deallocate (mach_task_self (), right);
+ if (err == MACH_SEND_INVALID_DEST)
+ {
+Index: hurd-debian/libfshelp/start-translator-long.c
+===================================================================
+--- hurd-debian.orig/libfshelp/start-translator-long.c 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/libfshelp/start-translator-long.c 2013-06-19 23:32:37.000000000 +0000
+@@ -1,5 +1,6 @@
+ /*
+- Copyright (C) 1995,96,99,2000,02, 04 Free Software Foundation, Inc.
++ Copyright (C) 1995, 1996, 1999, 2000, 2002, 2004, 2010
++ Free Software Foundation, Inc.
+ Written by Miles Bader and Michael I. Bushnell.
+
+ This file is part of the GNU Hurd.
+@@ -27,6 +28,9 @@
+ #include <string.h>
+ #include <assert.h>
+ #include "fshelp.h"
++#ifdef HAVE_FILE_EXEC_FILE_NAME
++#include <hurd/fs_experimental.h>
++#endif
+
+
+ /* The data passed in the various messages we're interested in. */
+@@ -272,12 +276,22 @@
+ saveport = ports[INIT_PORT_BOOTSTRAP];
+ ports[INIT_PORT_BOOTSTRAP] = bootstrap;
+
++#ifdef HAVE_FILE_EXEC_FILE_NAME
+ /* Try and exec the translator in TASK... */
+- err = file_exec (executable, task, EXEC_DEFAULTS,
+- argz, argz_len, 0, 0,
+- fds, fds_type, fds_len,
+- ports, ports_type, ports_len,
+- ints, ints_len, 0, 0, 0, 0);
++ err = file_exec_file_name (executable, task, EXEC_DEFAULTS, name,
++ argz, argz_len, 0, 0,
++ fds, fds_type, fds_len,
++ ports, ports_type, ports_len,
++ ints, ints_len, 0, 0, 0, 0);
++ /* For backwards compatibility. Just drop it when we kill file_exec. */
++ if (err == MIG_BAD_ID)
++#endif
++ err = file_exec (executable, task, EXEC_DEFAULTS,
++ argz, argz_len, 0, 0,
++ fds, fds_type, fds_len,
++ ports, ports_type, ports_len,
++ ints, ints_len, 0, 0, 0, 0);
++
+ ports_moved = 1;
+
+ if (ports_type == MACH_MSG_TYPE_COPY_SEND)
+Index: hurd-debian/libnetfs/file-exec.c
+===================================================================
+--- hurd-debian.orig/libnetfs/file-exec.c 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/libnetfs/file-exec.c 2013-06-19 23:32:37.000000000 +0000
+@@ -1,5 +1,6 @@
+ /*
+- Copyright (C) 1996,97,2000,01,02 Free Software Foundation, Inc.
++ Copyright (C) 1996, 1997, 2000, 2001, 2002, 2010
++ Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ This file is part of the GNU Hurd.
+@@ -23,10 +24,14 @@
+ #include "netfs.h"
+ #include "execserver.h"
+ #include "fs_S.h"
++#include "fs_experimental_S.h"
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <hurd/exec.h>
+ #include <hurd/paths.h>
++#ifdef HAVE_EXEC_EXEC_FILE_NAME
++#include <hurd/exec_experimental.h>
++#endif
+ #include <string.h>
+ #include <idvec.h>
+
+@@ -49,6 +54,39 @@
+ mach_port_t *destroynames,
+ size_t destroynameslen)
+ {
++ return netfs_S_file_exec_file_name (cred,
++ task,
++ flags,
++ "",
++ argv, argvlen,
++ envp, envplen,
++ fds, fdslen,
++ portarray, portarraylen,
++ intarray, intarraylen,
++ deallocnames, deallocnameslen,
++ destroynames, destroynameslen);
++}
++
++kern_return_t
++netfs_S_file_exec_file_name (struct protid *cred,
++ task_t task,
++ int flags,
++ char *filename,
++ char *argv,
++ size_t argvlen,
++ char *envp,
++ size_t envplen,
++ mach_port_t *fds,
++ size_t fdslen,
++ mach_port_t *portarray,
++ size_t portarraylen,
++ int *intarray,
++ size_t intarraylen,
++ mach_port_t *deallocnames,
++ size_t deallocnameslen,
++ mach_port_t *destroynames,
++ size_t destroynameslen)
++{
+ struct node *np;
+ error_t err;
+ uid_t uid;
+@@ -133,14 +171,31 @@
+ if (newpi)
+ {
+ right = ports_get_send_right (newpi);
+- err = exec_exec (_netfs_exec,
+- right, MACH_MSG_TYPE_COPY_SEND,
+- task, flags, argv, argvlen, envp, envplen,
+- fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
+- portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
+- intarray, intarraylen,
+- deallocnames, deallocnameslen,
+- destroynames, destroynameslen);
++#ifdef HAVE_EXEC_EXEC_FILE_NAME
++ err = exec_exec_file_name (_netfs_exec,
++ right, MACH_MSG_TYPE_COPY_SEND,
++ task, flags, filename,
++ argv, argvlen, envp, envplen,
++ fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
++ portarray, MACH_MSG_TYPE_COPY_SEND,
++ portarraylen,
++ intarray, intarraylen,
++ deallocnames, deallocnameslen,
++ destroynames, destroynameslen);
++ /* For backwards compatibility. Just drop it when we kill
++ exec_exec. */
++ if (err == MIG_BAD_ID)
++#endif
++ err = exec_exec (_netfs_exec,
++ right, MACH_MSG_TYPE_COPY_SEND,
++ task, flags, argv, argvlen, envp, envplen,
++ fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
++ portarray, MACH_MSG_TYPE_COPY_SEND,
++ portarraylen,
++ intarray, intarraylen,
++ deallocnames, deallocnameslen,
++ destroynames, destroynameslen);
++
+ mach_port_deallocate (mach_task_self (), right);
+ ports_port_deref (newpi);
+ }
+Index: hurd-debian/libtrivfs/file-exec.c
+===================================================================
+--- hurd-debian.orig/libtrivfs/file-exec.c 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/libtrivfs/file-exec.c 2013-06-19 23:32:37.000000000 +0000
+@@ -1,5 +1,5 @@
+ /*
+- Copyright (C) 1994,2002 Free Software Foundation, Inc.
++ Copyright (C) 1994, 2002, 2010 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
+@@ -40,3 +40,28 @@
+ {
+ return EOPNOTSUPP;
+ }
++
++kern_return_t
++trivfs_S_file_exec_file_name (trivfs_protid_t exec_file,
++ mach_port_t reply,
++ mach_msg_type_name_t replyPoly,
++ mach_port_t exec_task,
++ int flags,
++ string_t filename,
++ data_t argv,
++ mach_msg_type_number_t argvCnt,
++ data_t envp,
++ mach_msg_type_number_t envpCnt,
++ portarray_t fdarray,
++ mach_msg_type_number_t fdarrayCnt,
++ portarray_t portarray,
++ mach_msg_type_number_t portarrayCnt,
++ intarray_t intarray,
++ mach_msg_type_number_t intarrayCnt,
++ mach_port_array_t deallocnames,
++ mach_msg_type_number_t deallocnamesCnt,
++ mach_port_array_t destroynames,
++ mach_msg_type_number_t destroynamesCnt)
++{
++ return EOPNOTSUPP;
++}
+Index: hurd-debian/trans/fakeroot.c
+===================================================================
+--- hurd-debian.orig/trans/fakeroot.c 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/trans/fakeroot.c 2013-06-19 23:32:37.000000000 +0000
+@@ -1,5 +1,5 @@
+ /* fakeroot -- a translator for faking actions that aren't really permitted
+- Copyright (C) 2002, 2003, 2008 Free Software Foundation, Inc.
++ Copyright (C) 2002, 2003, 2008, 2010 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
+@@ -28,6 +28,9 @@
+ #include <pthread.h>
+ #include <hurd/ihash.h>
+ #include <hurd/paths.h>
++#ifdef HAVE_FILE_EXEC_FILE_NAME
++#include <hurd/fs_experimental.h>
++#endif
+
+ #include <version.h>
+
+@@ -705,6 +708,39 @@
+ mach_port_t *destroynames,
+ size_t destroynameslen)
+ {
++ return netfs_S_file_exec_file_name (user,
++ task,
++ flags,
++ "",
++ argv, argvlen,
++ envp, envplen,
++ fds, fdslen,
++ portarray, portarraylen,
++ intarray, intarraylen,
++ deallocnames, deallocnameslen,
++ destroynames, destroynameslen);
++}
++
++kern_return_t
++netfs_S_file_exec_file_name (struct protid *user,
++ task_t task,
++ int flags,
++ char *filename,
++ char *argv,
++ size_t argvlen,
++ char *envp,
++ size_t envplen,
++ mach_port_t *fds,
++ size_t fdslen,
++ mach_port_t *portarray,
++ size_t portarraylen,
++ int *intarray,
++ size_t intarraylen,
++ mach_port_t *deallocnames,
++ size_t deallocnameslen,
++ mach_port_t *destroynames,
++ size_t destroynameslen)
++{
+ error_t err;
+ file_t file;
+
+@@ -721,13 +757,29 @@
+
+ if (!err)
+ {
++#ifdef HAVE_FILE_EXEC_FILE_NAME
+ /* We cannot use MACH_MSG_TYPE_MOVE_SEND because we might need to
+ retry an interrupted call that would have consumed the rights. */
+- err = file_exec (user->po->np->nn->file, task, flags, argv, argvlen,
+- envp, envplen, fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
+- portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
+- intarray, intarraylen, deallocnames, deallocnameslen,
+- destroynames, destroynameslen);
++ err = file_exec_file_name (user->po->np->nn->file, task, flags,
++ filename,
++ argv, argvlen,
++ envp, envplen,
++ fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
++ portarray, MACH_MSG_TYPE_COPY_SEND,
++ portarraylen,
++ intarray, intarraylen,
++ deallocnames, deallocnameslen,
++ destroynames, destroynameslen);
++ /* For backwards compatibility. Just drop it when we kill
++ file_exec. */
++ if (err == MIG_BAD_ID)
++#endif
++ err = file_exec (user->po->np->nn->file, task, flags, argv, argvlen,
++ envp, envplen, fds, MACH_MSG_TYPE_COPY_SEND, fdslen,
++ portarray, MACH_MSG_TYPE_COPY_SEND, portarraylen,
++ intarray, intarraylen, deallocnames, deallocnameslen,
++ destroynames, destroynameslen);
++
+ mach_port_deallocate (mach_task_self (), file);
+ }
+
+@@ -835,12 +887,14 @@
+ mach_msg_header_t *outp)
+ {
+ int netfs_fs_server (mach_msg_header_t *, mach_msg_header_t *);
++ int netfs_fs_experimental_server (mach_msg_header_t *, mach_msg_header_t *);
+ int netfs_io_server (mach_msg_header_t *, mach_msg_header_t *);
+ int netfs_fsys_server (mach_msg_header_t *, mach_msg_header_t *);
+ int netfs_ifsock_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ if (netfs_io_server (inp, outp)
+ || netfs_fs_server (inp, outp)
++ || netfs_fs_experimental_server (inp, outp)
+ || ports_notify_server (inp, outp)
+ || netfs_fsys_server (inp, outp)
+ /* XXX we should intercept interrupt_operation and do
+Index: hurd-debian/utils/login.c
+===================================================================
+--- hurd-debian.orig/utils/login.c 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/utils/login.c 2013-06-19 23:32:37.000000000 +0000
+@@ -1,6 +1,7 @@
+ /* Hurdish login
+
+- Copyright (C) 1995,96,97,98,99,2002 Free Software Foundation, Inc.
++ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2002, 2010
++ Free Software Foundation, Inc.
+
+ Written by Miles Bader <miles@gnu.org>
+
+@@ -46,6 +47,9 @@
+ #include <error.h>
+ #include <timefmt.h>
+ #include <hurd/lookup.h>
++#ifdef HAVE_FILE_EXEC_FILE_NAME
++#include <hurd/fs_experimental.h>
++#endif
+ #include <ugids.h>
+
+ const char *argp_program_version = STANDARD_HURD_VERSION (login);
+@@ -882,12 +886,22 @@
+ }
+ }
+
+- err = file_exec (exec, mach_task_self (), EXEC_DEFAULTS,
+- sh_args, sh_args_len, env, env_len,
+- fds, MACH_MSG_TYPE_COPY_SEND, 3,
+- ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
+- ints, INIT_INT_MAX,
+- 0, 0, 0, 0);
++#ifdef HAVE_FILE_EXEC_FILE_NAME
++ err = file_exec_file_name (exec, mach_task_self (), EXEC_DEFAULTS, shell,
++ sh_args, sh_args_len, env, env_len,
++ fds, MACH_MSG_TYPE_COPY_SEND, 3,
++ ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
++ ints, INIT_INT_MAX,
++ 0, 0, 0, 0);
++ /* Fallback in case the file server hasn't been restarted. */
++ if (err == MIG_BAD_ID)
++#endif
++ err = file_exec (exec, mach_task_self (), EXEC_DEFAULTS,
++ sh_args, sh_args_len, env, env_len,
++ fds, MACH_MSG_TYPE_COPY_SEND, 3,
++ ports, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
++ ints, INIT_INT_MAX,
++ 0, 0, 0, 0);
+ if (err)
+ error(5, err, "%s", shell);
+
+Index: hurd-debian/hurd/fs_experimental.defs
+===================================================================
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ hurd-debian/hurd/fs_experimental.defs 2013-06-19 23:32:37.000000000 +0000
+@@ -0,0 +1,51 @@
++/* Definitions for the filesystem interface.
++ Copyright (C) 1994,95,96,97,98,99,2002 Free Software Foundation, Inc.
++
++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 the GNU Hurd; see the file COPYING. If not, write to
++the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
++
++
++/* All these objects also implement the generic IO facilities. */
++
++subsystem fs_experimental 444242;
++
++#include <hurd/hurd_types.defs>
++
++#ifdef FILE_IMPORTS
++FILE_IMPORTS
++#endif
++
++/* Operations supported on all files */
++
++INTR_INTERFACE
++
++/* Overlay a task with a file. Necessary initialization, including
++ authentication changes associated with set[ug]id execution must be
++ handled by the filesystem. Filesystems normally implement this by
++ using exec_newtask or exec_loadtask as appropriate. */
++routine file_exec_file_name (
++ exec_file: file_t;
++ RPT
++ exec_task: task_t;
++ flags: int;
++ filename: string_t;
++ argv: data_t SCP;
++ envp: data_t SCP;
++ fdarray: portarray_t SCP;
++ portarray: portarray_t SCP;
++ intarray: intarray_t SCP;
++ deallocnames: mach_port_name_array_t SCP;
++ destroynames: mach_port_name_array_t SCP);
+Index: hurd-debian/libdiskfs/Makefile
+===================================================================
+--- hurd-debian.orig/libdiskfs/Makefile 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/libdiskfs/Makefile 2013-06-19 23:32:37.000000000 +0000
+@@ -55,7 +55,7 @@
+ SRCS = $(OTHERSRCS) $(FSSRCS) $(IOSRCS) $(FSYSSRCS) $(IFSOCKSRCS)
+ installhdrs = diskfs.h diskfs-pager.h
+
+-MIGSTUBS = fsServer.o ioServer.o fsysServer.o exec_startupServer.o \
++MIGSTUBS = fsServer.o fs_experimentalServer.o ioServer.o fsysServer.o exec_startupServer.o \
+ fsys_replyUser.o fs_notifyUser.o ifsockServer.o \
+ startup_notifyServer.o
+ OBJS = $(sort $(SRCS:.c=.o) $(MIGSTUBS))
+@@ -65,6 +65,7 @@
+
+ fsys-MIGSFLAGS = -imacros $(srcdir)/fsmutations.h -DREPLY_PORTS
+ fs-MIGSFLAGS = -imacros $(srcdir)/fsmutations.h
++fs_experimental-MIGSFLAGS = -imacros $(srcdir)/fsmutations.h
+ io-MIGSFLAGS = -imacros $(srcdir)/fsmutations.h
+ ifsock-MIGSFLAGS = -imacros $(srcdir)/fsmutations.h
+ MIGCOMSFLAGS = -prefix diskfs_
+Index: hurd-debian/libdiskfs/demuxer.c
+===================================================================
+--- hurd-debian.orig/libdiskfs/demuxer.c 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/libdiskfs/demuxer.c 2013-06-19 23:32:37.000000000 +0000
+@@ -22,6 +22,7 @@
+ mach_msg_header_t *outp)
+ {
+ int diskfs_fs_server (mach_msg_header_t *, mach_msg_header_t *);
++ int diskfs_fs_experimental_server (mach_msg_header_t *, mach_msg_header_t *);
+ int diskfs_io_server (mach_msg_header_t *, mach_msg_header_t *);
+ int diskfs_fsys_server (mach_msg_header_t *, mach_msg_header_t *);
+ int diskfs_exec_startup_server (mach_msg_header_t *, mach_msg_header_t *);
+@@ -31,6 +32,7 @@
+
+ return (diskfs_io_server (inp, outp)
+ || diskfs_fs_server (inp, outp)
++ || diskfs_fs_experimental_server (inp, outp)
+ || ports_notify_server (inp, outp)
+ || diskfs_fsys_server (inp, outp)
+ || diskfs_exec_startup_server (inp, outp)
+Index: hurd-debian/libnetfs/Makefile
+===================================================================
+--- hurd-debian.orig/libnetfs/Makefile 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/libnetfs/Makefile 2013-06-19 23:32:37.000000000 +0000
+@@ -58,12 +58,13 @@
+
+ installhdrs=netfs.h
+
+-MIGSTUBS= ioServer.o fsServer.o fsysServer.o fsys_replyUser.o ifsockServer.o
++MIGSTUBS= ioServer.o fsServer.o fs_experimentalServer.o fsysServer.o fsys_replyUser.o ifsockServer.o
+
+ OBJS=$(sort $(SRCS:.c=.o) $(MIGSTUBS))
+
+ fsys-MIGSFLAGS = -imacros $(srcdir)/mutations.h -DREPLY_PORTS
+ fs-MIGSFLAGS = -imacros $(srcdir)/mutations.h
++fs_experimental-MIGSFLAGS = -imacros $(srcdir)/mutations.h
+ io-MIGSFLAGS = -imacros $(srcdir)/mutations.h
+ ifsock-MIGSFLAGS = -imacros $(srcdir)/mutations.h
+ MIGCOMSFLAGS = -prefix netfs_
+Index: hurd-debian/libnetfs/demuxer.c
+===================================================================
+--- hurd-debian.orig/libnetfs/demuxer.c 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/libnetfs/demuxer.c 2013-06-19 23:32:37.000000000 +0000
+@@ -25,12 +25,14 @@
+ mach_msg_header_t *outp)
+ {
+ int netfs_fs_server (mach_msg_header_t *, mach_msg_header_t *);
++ int netfs_fs_experimental_server (mach_msg_header_t *, mach_msg_header_t *);
+ int netfs_io_server (mach_msg_header_t *, mach_msg_header_t *);
+ int netfs_fsys_server (mach_msg_header_t *, mach_msg_header_t *);
+ int netfs_ifsock_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ return (netfs_io_server (inp, outp)
+ || netfs_fs_server (inp, outp)
++ || netfs_fs_experimental_server (inp, outp)
+ || ports_notify_server (inp, outp)
+ || netfs_fsys_server (inp, outp)
+ || ports_interrupt_server (inp, outp)
+Index: hurd-debian/libtrivfs/Makefile
+===================================================================
+--- hurd-debian.orig/libtrivfs/Makefile 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/libtrivfs/Makefile 2013-06-19 23:32:37.000000000 +0000
+@@ -43,7 +43,7 @@
+
+ SRCS=$(FSSRCS) $(IOSRCS) $(FSYSSRCS) $(OTHERSRCS)
+
+-MIGSTUBS=fsServer.o ioServer.o fsysServer.o fsys_replyUser.o
++MIGSTUBS=fsServer.o fs_experimentalServer.o ioServer.o fsysServer.o fsys_replyUser.o
+
+ libname = libtrivfs
+ HURDLIBS = fshelp iohelp ports shouldbeinlibc
+@@ -53,7 +53,7 @@
+ installhdrs := trivfs.h
+ mig-sheader-prefix = trivfs_
+ ifndef no_deps
+-installhdrs += $(patsubst %,trivfs_%_S.h,fs io fsys)
++installhdrs += $(patsubst %,trivfs_%_S.h,fs fs_experimental io fsys)
+ endif
+
+ include ../Makeconf
+Index: hurd-debian/libtrivfs/demuxer.c
+===================================================================
+--- hurd-debian.orig/libtrivfs/demuxer.c 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/libtrivfs/demuxer.c 2013-06-19 23:32:37.000000000 +0000
+@@ -26,11 +26,13 @@
+ mach_msg_header_t *outp)
+ {
+ int trivfs_fs_server (mach_msg_header_t *, mach_msg_header_t *);
++ int trivfs_fs_experimental_server (mach_msg_header_t *, mach_msg_header_t *);
+ int trivfs_io_server (mach_msg_header_t *, mach_msg_header_t *);
+ int trivfs_fsys_server (mach_msg_header_t *, mach_msg_header_t *);
+
+ return (trivfs_io_server (inp, outp)
+ || trivfs_fs_server (inp, outp)
++ || trivfs_fs_experimental_server (inp, outp)
+ || ports_notify_server (inp, outp)
+ || trivfs_fsys_server (inp, outp)
+ || ports_interrupt_server (inp, outp));
+Index: hurd-debian/configure.ac
+===================================================================
+--- hurd-debian.orig/configure.ac 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/configure.ac 2013-06-19 23:32:37.000000000 +0000
+@@ -162,7 +162,7 @@
+ AC_SUBST(VERSIONING)
+
+ # Check if libc contains getgrouplist and/or uselocale.
+-AC_CHECK_FUNCS(getgrouplist uselocale)
++AC_CHECK_FUNCS(getgrouplist uselocale file_exec_file_name exec_exec_file_name)
+
+
+ # From glibc HEAD, 2007-11-07.
+Index: hurd-debian/libtrivfs/trivfs.h
+===================================================================
+--- hurd-debian.orig/libtrivfs/trivfs.h 2013-06-19 23:32:37.000000000 +0000
++++ hurd-debian/libtrivfs/trivfs.h 2013-06-19 23:32:37.000000000 +0000
+@@ -293,6 +293,7 @@
+ /* These are the MiG-generated headers that declare prototypes
+ for the server functions. */
+ #include <hurd/trivfs_fs_S.h>
++#include <hurd/trivfs_fs_experimental_S.h>
+ #include <hurd/trivfs_io_S.h>
+ #include <hurd/trivfs_fsys_S.h>
+
diff --git a/debian/patches/exec_filename_use.patch b/debian/patches/exec_filename_use.patch
new file mode 100644
index 00000000..c806aea2
--- /dev/null
+++ b/debian/patches/exec_filename_use.patch
@@ -0,0 +1,113 @@
+From bbce8439190738efc9260490fa52f9dfe9600306 Mon Sep 17 00:00:00 2001
+From: Emilio Pozuelo Monfort <pochu27@gmail.com>
+Date: Wed, 26 May 2010 23:32:16 +0200
+Subject: [PATCH 3/3] Use the new _hurd_exec_file_name function
+
+* configure.in: Check for _hurd_exec_file_name.
+* utils/fakeauth.c: Call _hurd_exec_file_name instead of
+_hurd_exec if it's available.
+* utils/rpctrace.c: Likewise.
+* utils/shd.c: Likewise.
+---
+ configure.in | 4 ++--
+ utils/fakeauth.c | 9 +++++++--
+ utils/rpctrace.c | 6 +++++-
+ utils/shd.c | 9 ++++++---
+ 4 files changed, 20 insertions(+), 8 deletions(-)
+
+Index: hurd-debian/configure.ac
+===================================================================
+--- hurd-debian.orig/configure.ac 2012-06-05 00:38:18.000000000 +0000
++++ hurd-debian/configure.ac 2012-06-05 00:38:18.000000000 +0000
+@@ -160,8 +160,8 @@
+ fi
+ AC_SUBST(VERSIONING)
+
+-# Check if libc contains getgrouplist and/or uselocale.
+-AC_CHECK_FUNCS(getgrouplist uselocale file_exec_file_name exec_exec_file_name)
++# Check if libc contains these functions.
++AC_CHECK_FUNCS(getgrouplist uselocale file_exec_file_name exec_exec_file_name _hurd_exec_file_name)
+
+
+ # From glibc HEAD, 2007-11-07.
+Index: hurd-debian/utils/fakeauth.c
+===================================================================
+--- hurd-debian.orig/utils/fakeauth.c 2012-06-05 00:35:35.000000000 +0000
++++ hurd-debian/utils/fakeauth.c 2012-06-05 01:48:00.000000000 +0000
+@@ -1,5 +1,5 @@
+ /* fakeauth -- proxy auth server to lie to users about what their IDs are
+- Copyright (C) 2002 Free Software Foundation, Inc.
++ Copyright (C) 2002, 2010 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
+@@ -388,7 +388,7 @@
+ /* We cannot use fork because it doesn't do the right thing with our send
+ rights that point to our own receive rights, i.e. the new auth port.
+ Since posix_spawn might be implemented with fork (prior to glibc 2.3),
+- we cannot use that simple interface either. We use _hurd_exec
++ we cannot use that simple interface either. We use _hurd_exec_file_name
+ directly to effect what posix_spawn does in the simple case. */
+ {
+ task_t newtask;
+@@ -413,7 +413,12 @@
+ if (err)
+ error (3, err, "proc_child");
+
++#ifdef HAVE__HURD_EXEC_FILE_NAME
++ err = _hurd_exec_file_name (newtask, execfile, argv[argi],
++ &argv[argi], environ);
++#else
+ err = _hurd_exec (newtask, execfile, &argv[argi], environ);
++#endif
+ mach_port_deallocate (mach_task_self (), newtask);
+ mach_port_deallocate (mach_task_self (), execfile);
+ if (err)
+Index: hurd-debian/utils/rpctrace.c
+===================================================================
+--- hurd-debian.orig/utils/rpctrace.c 2012-06-05 00:35:35.000000000 +0000
++++ hurd-debian/utils/rpctrace.c 2012-06-05 01:48:00.000000000 +0000
+@@ -1069,7 +1069,11 @@
+ /* Now actually run the command they told us to trace. We do the exec on
+ the actual task, so the RPCs to map in the program itself do not get
+ traced. Could have an option to use TASK_WRAPPER here instead. */
++#ifdef HAVE__HURD_EXEC_FILE_NAME
++ err = _hurd_exec_file_name (traced_task, file, *argv, argv, envp);
++#else
+ err = _hurd_exec (traced_task, file, argv, envp);
++#endif
+ if (err)
+ error (2, err, "cannot exec `%s'", argv[0]);
+
+Index: hurd-debian/utils/shd.c
+===================================================================
+--- hurd-debian.orig/utils/shd.c 2012-06-05 00:35:35.000000000 +0000
++++ hurd-debian/utils/shd.c 2012-06-05 01:48:00.000000000 +0000
+@@ -1,5 +1,5 @@
+ /*
+- Copyright (C) 1994,95,99,2002 Free Software Foundation
++ Copyright (C) 1994, 1995, 1999, 2002, 2010 Free Software Foundation
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+@@ -159,15 +159,18 @@
+ movefd (fd1, 1, &save1))
+ return -1;
+
++#ifdef HAVE__HURD_EXEC_FILE_NAME
++ err = _hurd_exec_file_name (task, file, program, argv, environ);
++#else
+ err = _hurd_exec (task, file, argv, environ);
+-
++#endif
+ if (restorefd (fd0, 0, &save0) ||
+ restorefd (fd1, 1, &save1))
+ return -1;
+
+ if (err)
+ {
+- error (0, err, "_hurd_exec");
++ error (0, err, "_hurd_exec_file_name");
+ err = task_terminate (task);
+ if (err)
+ error (0, err, "task_terminate");
diff --git a/debian/patches/ext2fs_large_stores.patch b/debian/patches/ext2fs_large_stores.patch
new file mode 100644
index 00000000..f65ec760
--- /dev/null
+++ b/debian/patches/ext2fs_large_stores.patch
@@ -0,0 +1,2274 @@
+Support for >2GB volumes
+
+XXX: this adds a parameter to pager_create and diskfs_start_disk_pager
+---
+ console/pager.c | 10
+ ext2fs/balloc.c | 57 +++--
+ ext2fs/ext2_fs.h | 3
+ ext2fs/ext2fs.c | 8
+ ext2fs/ext2fs.h | 145 +++++++++++--
+ ext2fs/getblk.c | 31 +-
+ ext2fs/hyper.c | 34 ++-
+ ext2fs/ialloc.c | 41 +++
+ ext2fs/inode.c | 58 +++--
+ ext2fs/pager.c | 497 +++++++++++++++++++++++++++++++++++++++++++----
+ ext2fs/pokel.c | 41 +++
+ ext2fs/truncate.c | 11 -
+ fatfs/pager.c | 11 -
+ isofs/pager.c | 12 -
+ libdiskfs/disk-pager.c | 6
+ libdiskfs/diskfs-pager.h | 3
+ libpager/data-request.c | 17 -
+ libpager/data-return.c | 78 +++++--
+ libpager/pager-create.c | 4
+ libpager/pager.h | 29 ++
+ libpager/priv.h | 1
+ storeio/pager.c | 9
+ tmpfs/pager-stubs.c | 8
+ ufs/pager.c | 11 -
+ 24 files changed, 940 insertions(+), 185 deletions(-)
+
+Index: hurd-debian/console/pager.c
+===================================================================
+--- hurd-debian.orig/console/pager.c 2012-07-10 01:33:10.000000000 +0000
++++ hurd-debian/console/pager.c 2012-07-10 01:39:22.000000000 +0000
+@@ -94,6 +94,14 @@
+ }
+
+
++void
++pager_notify_evict (struct user_pager_info *pager,
++ vm_offset_t page)
++{
++ assert (!"unrequested notification on eviction");
++}
++
++
+ /* Tell how big the file is. */
+ error_t
+ pager_report_extent (struct user_pager_info *upi,
+@@ -159,7 +167,7 @@
+
+ /* XXX Are the values 1 and MEMORY_OBJECT_COPY_DELAY correct? */
+ user_pager->pager = pager_create (upi, pager_bucket,
+- 1, MEMORY_OBJECT_COPY_DELAY);
++ 1, MEMORY_OBJECT_COPY_DELAY, 0);
+ if (!user_pager->pager)
+ {
+ free (upi);
+Index: hurd-debian/ext2fs/balloc.c
+===================================================================
+--- hurd-debian.orig/ext2fs/balloc.c 2012-07-10 01:36:36.000000000 +0000
++++ hurd-debian/ext2fs/balloc.c 2012-07-10 01:39:22.000000000 +0000
+@@ -92,7 +92,7 @@
+ block, count);
+ }
+ gdp = group_desc (block_group);
+- bh = bptr (gdp->bg_block_bitmap);
++ bh = disk_cache_block_ref (gdp->bg_block_bitmap);
+
+ if (in_range (gdp->bg_block_bitmap, block, gcount) ||
+ in_range (gdp->bg_inode_bitmap, block, gcount) ||
+@@ -114,6 +114,7 @@
+ }
+
+ record_global_poke (bh);
++ disk_cache_block_ref_ptr (gdp);
+ record_global_poke (gdp);
+
+ block += gcount;
+@@ -139,7 +140,7 @@
+ block_t prealloc_goal,
+ block_t *prealloc_count, block_t *prealloc_block)
+ {
+- char *bh;
++ char *bh = 0;
+ char *p, *r;
+ int i, j, k, tmp;
+ unsigned long lmap;
+@@ -164,9 +165,10 @@
+
+ ext2_debug ("goal=%u", goal);
+
+-repeat:
++ repeat:
++ assert (! bh);
+ /*
+- * First, test whether the goal block is free.
++ * First, test whether the goal block is free.
+ */
+ if (goal < sblock->s_first_data_block || goal >= sblock->s_blocks_count)
+ goal = sblock->s_first_data_block;
+@@ -179,7 +181,7 @@
+ if (j)
+ goal_attempts++;
+ #endif
+- bh = bptr (gdp->bg_block_bitmap);
++ bh = disk_cache_block_ref (gdp->bg_block_bitmap);
+
+ ext2_debug ("goal is at %d:%d", i, j);
+
+@@ -194,8 +196,8 @@
+ if (j)
+ {
+ /*
+- * The goal was occupied; search forward for a free
+- * block within the next 32 blocks
++ * The goal was occupied; search forward for a free
++ * block within the next 32 blocks
+ */
+ if ((j & 31) == 31)
+ lmap = 0;
+@@ -245,13 +247,16 @@
+ j = k;
+ goto got_block;
+ }
++
++ disk_cache_block_deref (bh);
++ bh = 0;
+ }
+
+ ext2_debug ("bit not found in block group %d", i);
+
+ /*
+- * Now search the rest of the groups. We assume that
+- * i and gdp correctly point to the last group visited.
++ * Now search the rest of the groups. We assume that
++ * i and gdp correctly point to the last group visited.
+ */
+ for (k = 0; k < groups_count; k++)
+ {
+@@ -267,7 +272,8 @@
+ pthread_spin_unlock (&global_lock);
+ return 0;
+ }
+- bh = bptr (gdp->bg_block_bitmap);
++ assert (! bh);
++ bh = disk_cache_block_ref (gdp->bg_block_bitmap);
+ r = memscan (bh, 0, sblock->s_blocks_per_group >> 3);
+ j = (r - bh) << 3;
+ if (j < sblock->s_blocks_per_group)
+@@ -277,21 +283,25 @@
+ sblock->s_blocks_per_group);
+ if (j >= sblock->s_blocks_per_group)
+ {
++ disk_cache_block_deref (bh);
++ bh = 0;
+ ext2_error ("free blocks count corrupted for block group %d", i);
+ pthread_spin_unlock (&global_lock);
+ return 0;
+ }
+
+-search_back:
++ search_back:
++ assert (bh);
+ /*
+- * We have succeeded in finding a free byte in the block
+- * bitmap. Now search backwards up to 7 bits to find the
+- * start of this group of free blocks.
++ * We have succeeded in finding a free byte in the block
++ * bitmap. Now search backwards up to 7 bits to find the
++ * start of this group of free blocks.
+ */
+ for (k = 0; k < 7 && j > 0 && !test_bit (j - 1, bh); k++, j--);
+
+-got_block:
+-
++ got_block:
++ assert (bh);
++
+ ext2_debug ("using block group %d (%d)", i, gdp->bg_free_blocks_count);
+
+ tmp = j + i * sblock->s_blocks_per_group + sblock->s_first_data_block;
+@@ -304,6 +314,8 @@
+ if (set_bit (j, bh))
+ {
+ ext2_warning ("bit already set for block %d", j);
++ disk_cache_block_deref (bh);
++ bh = 0;
+ goto repeat;
+ }
+
+@@ -320,7 +332,7 @@
+ ext2_debug ("found bit %d", j);
+
+ /*
+- * Do block preallocation now if required.
++ * Do block preallocation now if required.
+ */
+ #ifdef EXT2_PREALLOCATE
+ if (prealloc_goal)
+@@ -351,6 +363,7 @@
+ j = tmp;
+
+ record_global_poke (bh);
++ bh = 0;
+
+ if (j >= sblock->s_blocks_count)
+ {
+@@ -363,12 +376,14 @@
+ j, goal_hits, goal_attempts);
+
+ gdp->bg_free_blocks_count--;
++ disk_cache_block_ref_ptr (gdp);
+ record_global_poke (gdp);
+
+ sblock->s_free_blocks_count--;
+ sblock_dirty = 1;
+
+ sync_out:
++ assert (! bh);
+ pthread_spin_unlock (&global_lock);
+ alloc_sync (0);
+
+@@ -390,9 +405,12 @@
+ gdp = NULL;
+ for (i = 0; i < groups_count; i++)
+ {
++ void *bh;
+ gdp = group_desc (i);
+ desc_count += gdp->bg_free_blocks_count;
+- x = count_free (bptr (gdp->bg_block_bitmap), block_size);
++ bh = disk_cache_block_ref (gdp->bg_block_bitmap);
++ x = count_free (bh, block_size);
++ disk_cache_block_deref (bh);
+ printf ("group %d: stored = %d, counted = %lu",
+ i, gdp->bg_free_blocks_count, x);
+ bitmap_count += x;
+@@ -453,7 +471,7 @@
+
+ gdp = group_desc (i);
+ desc_count += gdp->bg_free_blocks_count;
+- bh = bptr (gdp->bg_block_bitmap);
++ bh = disk_cache_block_ref (gdp->bg_block_bitmap);
+
+ if (!EXT2_HAS_RO_COMPAT_FEATURE (sblock,
+ EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)
+@@ -479,6 +497,7 @@
+ ext2_error ("block #%d of the inode table in group %d is marked free", j, i);
+
+ x = count_free (bh, block_size);
++ disk_cache_block_deref (bh);
+ if (gdp->bg_free_blocks_count != x)
+ ext2_error ("wrong free blocks count for group %d,"
+ " stored = %d, counted = %lu",
+Index: hurd-debian/ext2fs/ext2_fs.h
+===================================================================
+--- hurd-debian.orig/ext2fs/ext2_fs.h 2012-07-10 01:33:10.000000000 +0000
++++ hurd-debian/ext2fs/ext2_fs.h 2012-07-10 01:39:22.000000000 +0000
+@@ -25,7 +25,8 @@
+ /*
+ * Define EXT2FS_DEBUG to produce debug messages
+ */
+-#undef EXT2FS_DEBUG
++/* #undef EXT2FS_DEBUG */
++#define EXT2FS_DEBUG
+
+ /*
+ * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
+Index: hurd-debian/ext2fs/ext2fs.c
+===================================================================
+--- hurd-debian.orig/ext2fs/ext2fs.c 2012-07-10 01:33:10.000000000 +0000
++++ hurd-debian/ext2fs/ext2fs.c 2012-07-10 01:39:22.000000000 +0000
+@@ -106,7 +106,7 @@
+ if (values == 0)
+ return ENOMEM;
+ state->hook = values;
+- bzero (values, sizeof *values);
++ memset (values, 0, sizeof *values);
+ values->sb_block = SBLOCK_BLOCK;
+ break;
+
+@@ -181,9 +181,9 @@
+ /* Map the entire disk. */
+ create_disk_pager ();
+
+- pokel_init (&global_pokel, diskfs_disk_pager, disk_image);
++ pokel_init (&global_pokel, diskfs_disk_pager, disk_cache);
+
+- get_hypermetadata();
++ map_hypermetadata ();
+
+ inode_init ();
+
+@@ -211,6 +211,8 @@
+ {
+ pokel_flush (&global_pokel);
+ pager_flush (diskfs_disk_pager, 1);
++ sblock = 0;
+ get_hypermetadata ();
++ map_hypermetadata ();
+ return 0;
+ }
+Index: hurd-debian/ext2fs/ext2fs.h
+===================================================================
+--- hurd-debian.orig/ext2fs/ext2fs.h 2012-07-10 01:33:10.000000000 +0000
++++ hurd-debian/ext2fs/ext2fs.h 2012-07-10 01:39:22.000000000 +0000
+@@ -23,7 +23,9 @@
+ #include <hurd/pager.h>
+ #include <hurd/fshelp.h>
+ #include <hurd/iohelp.h>
++#include <hurd/store.h>
+ #include <hurd/diskfs.h>
++#include <hurd/ihash.h>
+ #include <assert.h>
+ #include <pthread.h>
+ #include <sys/mman.h>
+@@ -195,6 +197,8 @@
+ /* ---------------------------------------------------------------- */
+ /* pager.c */
+
++#define DISK_CACHE_BLOCKS 65536
++
+ #include <hurd/diskfs-pager.h>
+
+ /* Set up the disk pager. */
+@@ -218,10 +222,54 @@
+ /* What the user specified. */
+ extern struct store_parsed *store_parsed;
+
+-/* Mapped image of the disk. */
+-extern void *disk_image;
++/* Mapped image of cached blocks of the disk. */
++extern void *disk_cache;
++extern store_offset_t disk_cache_size;
++extern int disk_cache_blocks;
++
++#define DC_INCORE 0x01 /* Not in core. */
++#define DC_UNTOUCHED 0x02 /* Not touched by disk_pager_read_paged
++ or disk_cache_block_ref. */
++#define DC_FIXED 0x04 /* Must not be re-associated. */
++
++/* Flags that forbid re-association of page. DC_UNTOUCHED is included
++ because this flag is used only when page is already to be
++ re-associated, so it's not good candidate for another
++ remapping. */
++#define DC_DONT_REUSE (DC_INCORE | DC_UNTOUCHED | DC_FIXED)
++
++#define DC_NO_BLOCK ((block_t) -1L)
++
++#ifndef NDEBUG
++#define DISK_CACHE_LAST_READ_XOR 0xDEADBEEF
++#endif
+
+-/* Our in-core copy of the super-block (pointer into the disk_image). */
++/* Disk cache blocks' meta info. */
++struct disk_cache_info
++{
++ block_t block;
++ uint16_t flags;
++ uint16_t ref_count;
++#ifndef NDEBUG
++ block_t last_read, last_read_xor;
++#endif
++};
++
++/* block num --> pointer to in-memory block */
++extern hurd_ihash_t disk_cache_bptr;
++/* Metadata about cached block. */
++extern struct disk_cache_info *disk_cache_info;
++/* Lock for these mappings */
++extern struct mutex disk_cache_lock;
++/* Fired when a re-association is done. */
++extern struct condition disk_cache_reassociation;
++
++void *disk_cache_block_ref (block_t block);
++void disk_cache_block_ref_ptr (void *ptr);
++void disk_cache_block_deref (void *ptr);
++int disk_cache_block_is_ref (block_t block);
++
++/* Our in-core copy of the super-block (pointer into the disk_cache). */
+ struct ext2_super_block *sblock;
+ /* True if sblock has been modified. */
+ int sblock_dirty;
+@@ -251,6 +299,9 @@
+
+ /* Get the superblock from the disk, & setup various global info from it. */
+ void get_hypermetadata ();
++
++/* Map `sblock' and `group_desc_image' pointers to disk cache. */
++void map_hypermetadata ();
+
+ /* ---------------------------------------------------------------- */
+ /* Random stuff calculated from the super block. */
+@@ -274,21 +325,51 @@
+ unsigned long next_generation;
+
+ /* ---------------------------------------------------------------- */
+-/* Functions for looking inside disk_image */
++/* Functions for looking inside disk_cache */
+
+-#define trunc_block(offs) (((offs) >> log2_block_size) << log2_block_size)
++#define trunc_block(offs) \
++ ((off_t) ((offs) >> log2_block_size) << log2_block_size)
+ #define round_block(offs) \
+- ((((offs) + block_size - 1) >> log2_block_size) << log2_block_size)
++ ((off_t) (((offs) + block_size - 1) >> log2_block_size) << log2_block_size)
+
+ /* block num --> byte offset on disk */
+-#define boffs(block) ((block) << log2_block_size)
++#define boffs(block) ((off_t) (block) << log2_block_size)
+ /* byte offset on disk --> block num */
+ #define boffs_block(offs) ((offs) >> log2_block_size)
+
++/* pointer to in-memory block -> index in disk_cache_info */
++#define bptr_index(ptr) (((char *)ptr - (char *)disk_cache) >> log2_block_size)
++
+ /* byte offset on disk --> pointer to in-memory block */
+-#define boffs_ptr(offs) (((char *)disk_image) + (offs))
++EXT2FS_EI char *
++boffs_ptr (off_t offset)
++{
++ block_t block = boffs_block (offset);
++ mutex_lock (&disk_cache_lock);
++ char *ptr = hurd_ihash_find (disk_cache_bptr, block);
++ mutex_unlock (&disk_cache_lock);
++ assert (ptr);
++ ptr += offset % block_size;
++ ext2_debug ("(%Ld) = %p", offset, ptr);
++ return ptr;
++}
++
+ /* pointer to in-memory block --> byte offset on disk */
+-#define bptr_offs(ptr) ((char *)(ptr) - ((char *)disk_image))
++EXT2FS_EI off_t
++bptr_offs (void *ptr)
++{
++ vm_offset_t mem_offset = (char *)ptr - (char *)disk_cache;
++ off_t offset;
++ assert (mem_offset < disk_cache_size);
++ mutex_lock (&disk_cache_lock);
++ offset = (off_t) disk_cache_info[boffs_block (mem_offset)].block
++ << log2_block_size;
++ assert (offset || mem_offset < block_size);
++ offset += mem_offset % block_size;
++ mutex_unlock (&disk_cache_lock);
++ ext2_debug ("(%p) = %Ld", ptr, offset);
++ return offset;
++}
+
+ /* block num --> pointer to in-memory block */
+ #define bptr(block) boffs_ptr(boffs(block))
+@@ -308,14 +389,24 @@
+ #if defined(__USE_EXTERN_INLINES) || defined(EXT2FS_DEFINE_EI)
+ /* Convert an inode number to the dinode on disk. */
+ EXT2FS_EI struct ext2_inode *
+-dino (ino_t inum)
++dino_ref (ino_t inum)
+ {
+ unsigned long inodes_per_group = sblock->s_inodes_per_group;
+ unsigned long bg_num = (inum - 1) / inodes_per_group;
+ unsigned long group_inum = (inum - 1) % inodes_per_group;
+- struct ext2_group_desc *bg = group_desc(bg_num);
++ struct ext2_group_desc *bg = group_desc (bg_num);
+ block_t block = bg->bg_inode_table + (group_inum / inodes_per_block);
+- return ((struct ext2_inode *)bptr(block)) + group_inum % inodes_per_block;
++ struct ext2_inode *inode = disk_cache_block_ref (block);
++ inode += group_inum % inodes_per_block;
++ ext2_debug ("(%qd) = %p", inum, inode);
++ return inode;
++}
++
++EXT2FS_EI void
++dino_deref (struct ext2_inode *inode)
++{
++ ext2_debug ("(%p)", inode);
++ disk_cache_block_deref (inode);
+ }
+ #endif /* Use extern inlines. */
+
+@@ -377,27 +468,38 @@
+ EXT2FS_EI void
+ record_global_poke (void *ptr)
+ {
+- int boffs = trunc_block (bptr_offs (ptr));
+- global_block_modified (boffs_block (boffs));
+- pokel_add (&global_pokel, boffs_ptr(boffs), block_size);
++ block_t block = boffs_block (bptr_offs (ptr));
++ void *block_ptr = bptr (block);
++ ext2_debug ("(%p = %p)", ptr, block_ptr);
++ assert (disk_cache_block_is_ref (block));
++ global_block_modified (block);
++ pokel_add (&global_pokel, block_ptr, block_size);
+ }
+
+ /* This syncs a modification to a non-file block. */
+ EXT2FS_EI void
+ sync_global_ptr (void *bptr, int wait)
+ {
+- vm_offset_t boffs = trunc_block (bptr_offs (bptr));
+- global_block_modified (boffs_block (boffs));
+- pager_sync_some (diskfs_disk_pager, trunc_page (boffs), vm_page_size, wait);
++ block_t block = boffs_block (bptr_offs (bptr));
++ void *block_ptr = bptr (block);
++ ext2_debug ("(%p -> %u)", bptr, (block_t)block);
++ global_block_modified (block);
++ disk_cache_block_deref (block_ptr);
++ pager_sync_some (diskfs_disk_pager,
++ block_ptr - disk_cache, block_size, wait);
++
+ }
+
+ /* This records a modification to one of a file's indirect blocks. */
+ EXT2FS_EI void
+ record_indir_poke (struct node *node, void *ptr)
+ {
+- int boffs = trunc_block (bptr_offs (ptr));
+- global_block_modified (boffs_block (boffs));
+- pokel_add (&node->dn->indir_pokel, boffs_ptr(boffs), block_size);
++ block_t block = boffs_block (bptr_offs (ptr));
++ void *block_ptr = bptr (block);
++ ext2_debug ("(%d, %p)", (int)node->cache_id, ptr);
++ assert (disk_cache_block_is_ref (block));
++ global_block_modified (block);
++ pokel_add (&node->dn->indir_pokel, block_ptr, block_size);
+ }
+
+ /* ---------------------------------------------------------------- */
+@@ -405,6 +507,7 @@
+ EXT2FS_EI void
+ sync_global (int wait)
+ {
++ ext2_debug ("%d", wait);
+ pokel_sync (&global_pokel, wait);
+ }
+
+Index: hurd-debian/ext2fs/getblk.c
+===================================================================
+--- hurd-debian.orig/ext2fs/getblk.c 2012-07-10 01:33:10.000000000 +0000
++++ hurd-debian/ext2fs/getblk.c 2012-07-10 01:39:22.000000000 +0000
+@@ -52,7 +52,7 @@
+ if (node->dn->info.i_prealloc_count)
+ {
+ int i = node->dn->info.i_prealloc_count;
+- ext2_debug ("discarding %d prealloced blocks for inode %d",
++ ext2_debug ("discarding %d prealloced blocks for inode %Ld",
+ i, node->cache_id);
+ node->dn->info.i_prealloc_count = 0;
+ ext2_free_blocks (node->dn->info.i_prealloc_block, i);
+@@ -104,8 +104,8 @@
+
+ if (result && zero)
+ {
+- char *bh = bptr (result);
+- bzero (bh, block_size);
++ char *bh = disk_cache_block_ref (result);
++ memset (bh, 0, block_size);
+ record_indir_poke (node, bh);
+ }
+
+@@ -122,6 +122,8 @@
+ block_t hint;
+ #endif
+
++ assert (0 <= nr && nr < EXT2_N_BLOCKS);
++
+ *result = node->dn->info.i_data[nr];
+ if (*result)
+ return 0;
+@@ -180,14 +182,20 @@
+ {
+ int i;
+ block_t goal = 0;
+- block_t *bh = (block_t *)bptr (block);
++ block_t *bh = (block_t *)disk_cache_block_ref (block);
+
+ *result = bh[nr];
+ if (*result)
+- return 0;
++ {
++ disk_cache_block_deref (bh);
++ return 0;
++ }
+
+ if (!create)
+- return EINVAL;
++ {
++ disk_cache_block_deref (bh);
++ return EINVAL;
++ }
+
+ if (node->dn->info.i_next_alloc_block == new_block)
+ goal = node->dn->info.i_next_alloc_goal;
+@@ -207,7 +215,10 @@
+
+ *result = ext2_alloc_block (node, goal, zero);
+ if (!*result)
+- return ENOSPC;
++ {
++ disk_cache_block_deref (bh);
++ return ENOSPC;
++ }
+
+ bh[nr] = *result;
+
+@@ -243,9 +254,9 @@
+ return EIO;
+ }
+ /*
+- * If this is a sequential block allocation, set the next_alloc_block
+- * to this block now so that all the indblock and data block
+- * allocations use the same goal zone
++ * If this is a sequential block allocation, set the next_alloc_block
++ * to this block now so that all the indblock and data block
++ * allocations use the same goal zone
+ */
+
+ ext2_debug ("block = %u, next = %u, goal = %u", block,
+Index: hurd-debian/ext2fs/hyper.c
+===================================================================
+--- hurd-debian.orig/ext2fs/hyper.c 2012-07-10 01:33:10.000000000 +0000
++++ hurd-debian/ext2fs/hyper.c 2012-07-10 01:39:22.000000000 +0000
+@@ -58,12 +58,15 @@
+ void
+ get_hypermetadata (void)
+ {
+- error_t err = diskfs_catch_exception ();
+- if (err)
+- ext2_panic ("can't read superblock: %s", strerror (err));
+-
+- sblock = (struct ext2_super_block *) boffs_ptr (SBLOCK_OFFS);
++ error_t err;
++ size_t read = 0;
+
++ assert (! sblock);
++ err = store_read (store, SBLOCK_OFFS >> store->log2_block_size,
++ SBLOCK_SIZE, (void **)&sblock, &read);
++ if (err || read != SBLOCK_SIZE)
++ ext2_panic ("Cannot read hypermetadata");
++
+ if (sblock->s_magic != EXT2_SUPER_MAGIC
+ #ifdef EXT2FS_PRE_02B_COMPAT
+ && sblock->s_magic != EXT2_PRE_02B_MAGIC
+@@ -152,15 +155,22 @@
+
+ allocate_mod_map ();
+
+- diskfs_end_catch_exception ();
++ /* A handy source of page-aligned zeros. */
++ if (zeroblock == 0)
++ zeroblock = (vm_address_t) mmap (0, block_size, PROT_READ, MAP_ANON, 0, 0);
++
++ munmap (sblock, SBLOCK_SIZE);
++ sblock = NULL;
++}
++
++void
++map_hypermetadata (void)
++{
++ sblock = (struct ext2_super_block *) boffs_ptr (SBLOCK_OFFS);
+
+ /* Cache a convenient pointer to the block group descriptors for allocation.
+ These are stored in the filesystem blocks following the superblock. */
+ group_desc_image = (struct ext2_group_desc *) bptr (bptr_block (sblock) + 1);
+-
+- /* A handy source of page-aligned zeros. */
+- if (zeroblock == 0)
+- zeroblock = (vm_address_t) mmap (0, block_size, PROT_READ, MAP_ANON, 0, 0);
+ }
+
+ error_t
+@@ -183,6 +193,7 @@
+ if (sblock_dirty)
+ {
+ sblock_dirty = 0;
++ disk_cache_block_ref_ptr (sblock);
+ record_global_poke (sblock);
+ }
+
+@@ -199,7 +210,8 @@
+
+ (*(readonly ? store_set_flags : store_clear_flags)) (store, STORE_READONLY);
+
+- mprotect (disk_image, store->size, PROT_READ | (readonly ? 0 : PROT_WRITE));
++ mprotect (disk_cache, disk_cache_size,
++ PROT_READ | (readonly ? 0 : PROT_WRITE));
+
+ if (!readonly && !(sblock->s_state & EXT2_VALID_FS))
+ ext2_warning ("UNCLEANED FILESYSTEM NOW WRITABLE");
+Index: hurd-debian/ext2fs/ialloc.c
+===================================================================
+--- hurd-debian.orig/ext2fs/ialloc.c 2012-07-10 01:33:10.000000000 +0000
++++ hurd-debian/ext2fs/ialloc.c 2012-07-10 01:39:22.000000000 +0000
+@@ -60,7 +60,7 @@
+
+ assert (!diskfs_readonly);
+
+- ext2_debug ("freeing inode %u", inum);
++ ext2_debug ("freeing inode %Lu", inum);
+
+ pthread_spin_lock (&global_lock);
+
+@@ -75,22 +75,25 @@
+ bit = (inum - 1) % sblock->s_inodes_per_group;
+
+ gdp = group_desc (block_group);
+- bh = bptr (gdp->bg_inode_bitmap);
++ bh = disk_cache_block_ref (gdp->bg_inode_bitmap);
+
+ if (!clear_bit (bit, bh))
+ ext2_warning ("bit already cleared for inode %Ld", inum);
+ else
+ {
++ disk_cache_block_ref_ptr (bh);
+ record_global_poke (bh);
+
+ gdp->bg_free_inodes_count++;
+ if (S_ISDIR (old_mode))
+ gdp->bg_used_dirs_count--;
++ disk_cache_block_ref_ptr (gdp);
+ record_global_poke (gdp);
+
+ sblock->s_free_inodes_count++;
+ }
+
++ disk_cache_block_deref (bh);
+ sblock_dirty = 1;
+ pthread_spin_unlock (&global_lock);
+ alloc_sync(0);
+@@ -111,14 +114,15 @@
+ ino_t
+ ext2_alloc_inode (ino_t dir_inum, mode_t mode)
+ {
+- char *bh;
++ char *bh = 0;
+ int i, j, inum, avefreei;
+ struct ext2_group_desc *gdp;
+ struct ext2_group_desc *tmp;
+
+ pthread_spin_lock (&global_lock);
+
+-repeat:
++ repeat:
++ assert (! bh);
+ gdp = NULL;
+ i = 0;
+
+@@ -213,7 +217,7 @@
+ return 0;
+ }
+
+- bh = bptr (gdp->bg_inode_bitmap);
++ bh = disk_cache_block_ref (gdp->bg_inode_bitmap);
+ if ((inum =
+ find_first_zero_bit ((unsigned long *) bh, sblock->s_inodes_per_group))
+ < sblock->s_inodes_per_group)
+@@ -221,12 +225,17 @@
+ if (set_bit (inum, bh))
+ {
+ ext2_warning ("bit already set for inode %d", inum);
++ disk_cache_block_deref (bh);
++ bh = 0;
+ goto repeat;
+ }
+ record_global_poke (bh);
++ bh = 0;
+ }
+ else
+ {
++ disk_cache_block_deref (bh);
++ bh = 0;
+ if (gdp->bg_free_inodes_count != 0)
+ {
+ ext2_error ("free inodes count corrupted in group %d", i);
+@@ -248,15 +257,25 @@
+ gdp->bg_free_inodes_count--;
+ if (S_ISDIR (mode))
+ gdp->bg_used_dirs_count++;
++ disk_cache_block_ref_ptr (gdp);
+ record_global_poke (gdp);
+
+ sblock->s_free_inodes_count--;
+ sblock_dirty = 1;
+
+ sync_out:
++ assert (! bh);
+ pthread_spin_unlock (&global_lock);
+ alloc_sync (0);
+
++ /* Make sure the coming read_node won't complain about bad
++ fields. */
++ {
++ struct ext2_inode *di = dino_ref (inum);
++ memset (di, 0, sizeof *di);
++ dino_deref (di);
++ }
++
+ return inum;
+ }
+
+@@ -353,10 +372,12 @@
+ gdp = NULL;
+ for (i = 0; i < groups_count; i++)
+ {
++ void *bh;
+ gdp = group_desc (i);
+ desc_count += gdp->bg_free_inodes_count;
+- x = count_free (bptr (gdp->bg_inode_bitmap),
+- sblock->s_inodes_per_group / 8);
++ bh = disk_cache_block_ref (gdp->bg_inode_bitmap);
++ x = count_free (bh, sblock->s_inodes_per_group / 8);
++ disk_cache_block_deref (bh);
+ ext2_debug ("group %d: stored = %d, counted = %lu",
+ i, gdp->bg_free_inodes_count, x);
+ bitmap_count += x;
+@@ -386,10 +407,12 @@
+ gdp = NULL;
+ for (i = 0; i < groups_count; i++)
+ {
++ void *bh;
+ gdp = group_desc (i);
+ desc_count += gdp->bg_free_inodes_count;
+- x = count_free (bptr (gdp->bg_inode_bitmap),
+- sblock->s_inodes_per_group / 8);
++ bh = disk_cache_block_ref (gdp->bg_inode_bitmap);
++ x = count_free (bh, sblock->s_inodes_per_group / 8);
++ disk_cache_block_deref (bh);
+ if (gdp->bg_free_inodes_count != x)
+ ext2_error ("wrong free inodes count in group %d, "
+ "stored = %d, counted = %lu",
+Index: hurd-debian/ext2fs/inode.c
+===================================================================
+--- hurd-debian.orig/ext2fs/inode.c 2012-11-26 00:23:28.000000000 +0000
++++ hurd-debian/ext2fs/inode.c 2012-11-26 00:24:49.000000000 +0000
+@@ -92,7 +92,7 @@
+ dn->dir_idx = 0;
+ dn->pager = 0;
+ pthread_rwlock_init (&dn->alloc_lock, NULL);
+- pokel_init (&dn->indir_pokel, diskfs_disk_pager, disk_image);
++ pokel_init (&dn->indir_pokel, diskfs_disk_pager, disk_cache);
+
+ /* Create the new node. */
+ np = diskfs_make_node (dn);
+@@ -201,13 +201,17 @@
+ error_t err;
+ struct stat *st = &np->dn_stat;
+ struct disknode *dn = np->dn;
+- struct ext2_inode *di = dino (np->cache_id);
++ struct ext2_inode *di;
+ struct ext2_inode_info *info = &dn->info;
+
++ ext2_debug ("(%d)", np->cache_id);
++
+ err = diskfs_catch_exception ();
+ if (err)
+ return err;
+
++ di = dino_ref (np->cache_id);
++
+ st->st_fstype = FSTYPE_EXT2FS;
+ st->st_fsid = getpid (); /* This call is very cheap. */
+ st->st_ino = np->cache_id;
+@@ -285,7 +289,9 @@
+ info->i_high_size = di->i_size_high;
+ if (info->i_high_size) /* XXX */
+ {
++ dino_deref (di);
+ ext2_warning ("cannot handle large file inode %Ld", np->cache_id);
++ diskfs_end_catch_exception ();
+ return EFBIG;
+ }
+ }
+@@ -307,20 +313,12 @@
+ }
+ dn->info_i_translator = di->i_translator;
+
++ dino_deref (di);
+ diskfs_end_catch_exception ();
+
+ if (S_ISREG (st->st_mode) || S_ISDIR (st->st_mode)
+ || (S_ISLNK (st->st_mode) && st->st_blocks))
+- {
+- unsigned offset;
+-
+- np->allocsize = np->dn_stat.st_size;
+-
+- /* Round up to a block multiple. */
+- offset = np->allocsize & ((1 << log2_block_size) - 1);
+- if (offset > 0)
+- np->allocsize += block_size - offset;
+- }
++ np->allocsize = round_block (np->dn_stat.st_size);
+ else
+ /* Allocsize should be zero for anything except directories, files, and
+ long symlinks. These are the only things allowed to have any blocks
+@@ -408,7 +406,9 @@
+ {
+ error_t err;
+ struct stat *st = &np->dn_stat;
+- struct ext2_inode *di = dino (np->cache_id);
++ struct ext2_inode *di;
++
++ ext2_debug ("(%d)", np->cache_id);
+
+ if (np->dn->info.i_prealloc_count)
+ ext2_discard_prealloc (np);
+@@ -419,12 +419,14 @@
+
+ assert (!diskfs_readonly);
+
+- ext2_debug ("writing inode %d to disk", np->cache_id);
++ ext2_debug ("writing inode %Ld to disk", np->cache_id);
+
+ err = diskfs_catch_exception ();
+ if (err)
+ return NULL;
+
++ di = dino_ref (np->cache_id);
++
+ di->i_generation = st->st_gen;
+
+ /* We happen to know that the stat mode bits are the same
+@@ -505,6 +507,7 @@
+ diskfs_end_catch_exception ();
+ np->dn_stat_dirty = 0;
+
++ /* Leave invoking dino_deref (di) to the caller. */
+ return di;
+ }
+ else
+@@ -674,7 +677,7 @@
+ if (err)
+ return err;
+
+- di = dino (np->cache_id);
++ di = dino_ref (np->cache_id);
+ blkno = di->i_translator;
+
+ if (namelen && !blkno)
+@@ -687,6 +690,7 @@
+ 0, 0, 0);
+ if (blkno == 0)
+ {
++ dino_deref (di);
+ diskfs_end_catch_exception ();
+ return ENOSPC;
+ }
+@@ -710,15 +714,20 @@
+ np->dn_stat.st_mode &= ~S_IPTRANS;
+ np->dn_set_ctime = 1;
+ }
++ else
++ dino_deref (di);
+
+ if (namelen)
+ {
++ void *blkptr;
++
+ buf[0] = namelen & 0xFF;
+ buf[1] = (namelen >> 8) & 0xFF;
+- bcopy (name, buf + 2, namelen);
++ memcpy (buf + 2, name, namelen);
+
+- bcopy (buf, bptr (blkno), block_size);
+- record_global_poke (bptr (blkno));
++ blkptr = disk_cache_block_ref (blkno);
++ memcpy (blkptr, buf, block_size);
++ record_global_poke (blkptr);
+
+ np->dn_stat.st_mode |= S_IPTRANS;
+ np->dn_set_ctime = 1;
+@@ -736,7 +745,7 @@
+ error_t err = 0;
+ daddr_t blkno;
+ unsigned datalen;
+- const void *transloc;
++ void *transloc;
+
+ assert (sblock->s_creator_os == EXT2_OS_HURD);
+
+@@ -744,9 +753,11 @@
+ if (err)
+ return err;
+
+- blkno = (dino (np->cache_id))->i_translator;
++ struct ext2_inode *di = dino_ref (np->cache_id);
++ blkno = di->i_translator;
++ dino_deref (di);
+ assert (blkno);
+- transloc = bptr (blkno);
++ transloc = disk_cache_block_ref (blkno);
+
+ datalen =
+ ((unsigned char *)transloc)[0] + (((unsigned char *)transloc)[1] << 8);
+@@ -761,6 +772,7 @@
+ memcpy (*namep, transloc + 2, datalen);
+ }
+
++ disk_cache_block_deref (transloc);
+ diskfs_end_catch_exception ();
+
+ *namelen = datalen;
+@@ -782,7 +794,7 @@
+
+ assert (node->dn_stat.st_blocks == 0);
+
+- bcopy (target, node->dn->info.i_data, len);
++ memcpy (node->dn->info.i_data, target, len);
+ node->dn_stat.st_size = len - 1;
+ node->dn_set_ctime = 1;
+ node->dn_set_mtime = 1;
+@@ -799,7 +811,7 @@
+
+ assert (node->dn_stat.st_size < MAX_INODE_SYMLINK);
+
+- bcopy (node->dn->info.i_data, target, node->dn_stat.st_size);
++ memcpy (target, node->dn->info.i_data, node->dn_stat.st_size);
+ return 0;
+ }
+
+Index: hurd-debian/ext2fs/pager.c
+===================================================================
+--- hurd-debian.orig/ext2fs/pager.c 2012-07-10 01:33:10.000000000 +0000
++++ hurd-debian/ext2fs/pager.c 2012-07-10 01:39:22.000000000 +0000
+@@ -18,17 +18,18 @@
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
++#include <unistd.h>
+ #include <string.h>
+ #include <errno.h>
+ #include <hurd/store.h>
+ #include "ext2fs.h"
+
++/* XXX */
++#include "../libpager/priv.h"
++
+ /* A ports bucket to hold pager ports. */
+ struct port_bucket *pager_bucket;
+
+-/* Mapped image of the disk. */
+-void *disk_image;
+-
+ pthread_spinlock_t node_to_page_lock = PTHREAD_SPINLOCK_INITIALIZER;
+
+
+@@ -165,6 +166,9 @@
+ block_t pending_blocks = 0;
+ int num_pending_blocks = 0;
+
++ ext2_debug ("reading inode %Ld page %u[%d]",
++ node->cache_id, page, vm_page_size);
++
+ /* Read the NUM_PENDING_BLOCKS blocks in PENDING_BLOCKS, into the buffer
+ pointed to by BUF (allocating it if necessary) at offset OFFS. OFFS in
+ adjusted by the amount read, and NUM_PENDING_BLOCKS is zeroed. Any read
+@@ -171,7 +175,8 @@
+ {
+ if (num_pending_blocks > 0)
+ {
+- block_t dev_block = pending_blocks << log2_dev_blocks_per_fs_block;
++ store_offset_t dev_block = (store_offset_t) pending_blocks
++ << log2_dev_blocks_per_fs_block;
+ size_t amount = num_pending_blocks << log2_block_size;
+ /* The buffer we try to read into; on the first read, we pass in a
+ size of zero, so that the read is guaranteed to allocate a new
+@@ -198,7 +203,7 @@
+ else
+ /* We've already got some buffer, so copy into it. */
+ {
+- bcopy (new_buf, *buf + offs, new_len);
++ memcpy (*buf + offs, new_buf, new_len);
+ free_page_buf (new_buf); /* Return NEW_BUF to our pool. */
+ STAT_INC (file_pagein_freed_bufs);
+ }
+@@ -254,7 +259,7 @@
+ break;
+ STAT_INC (file_pagein_alloced_bufs);
+ }
+- bzero (*buf + offs, block_size);
++ memset (*buf + offs, 0, block_size);
+ offs += block_size;
+ }
+ else
+@@ -295,16 +300,17 @@
+ if (pb->num > 0)
+ {
+ error_t err;
+- block_t dev_block = pb->block << log2_dev_blocks_per_fs_block;
++ store_offset_t dev_block = (store_offset_t) pb->block
++ << log2_dev_blocks_per_fs_block;
+ size_t length = pb->num << log2_block_size, amount;
+
+- ext2_debug ("writing block %u[%ld]", pb->block, pb->num);
++ ext2_debug ("writing block %u[%Ld]", pb->block, pb->num);
+
+ if (pb->offs > 0)
+ /* Put what we're going to write into a page-aligned buffer. */
+ {
+ void *page_buf = get_page_buf ();
+- bcopy (pb->buf + pb->offs, (void *)page_buf, length);
++ memcpy ((void *)page_buf, pb->buf + pb->offs, length);
+ err = store_write (store, dev_block, page_buf, length, &amount);
+ free_page_buf (page_buf);
+ }
+@@ -357,7 +363,7 @@
+ return 0;
+ }
+
+-/* Write one page for the pager backing NODE, at offset PAGE, into BUF. This
++/* Write one page for the pager backing NODE, at OFFSET, into BUF. This
+ may need to write several filesystem blocks to satisfy one page, and tries
+ to consolidate the i/o if possible. */
+ static error_t
+@@ -381,7 +387,7 @@
+ else if (offset + left > node->allocsize)
+ left = node->allocsize - offset;
+
+- ext2_debug ("writing inode %d page %d[%d]", node->cache_id, offset, left);
++ ext2_debug ("writing inode %Ld page %u[%d]", node->cache_id, offset, left);
+
+ STAT_INC (file_pageouts);
+
+@@ -409,16 +415,31 @@
+ {
+ error_t err;
+ size_t length = vm_page_size, read = 0;
+- vm_size_t dev_end = store->size;
++ store_offset_t offset = page, dev_end = store->size;
+
+- if (page + vm_page_size > dev_end)
+- length = dev_end - page;
++ mutex_lock (&disk_cache_lock);
++ int index = offset >> log2_block_size;
++ offset = ((store_offset_t) disk_cache_info[index].block << log2_block_size)
++ + offset % block_size;
++ disk_cache_info[index].flags |= DC_INCORE;
++ disk_cache_info[index].flags &=~ DC_UNTOUCHED;
++#ifndef NDEBUG
++ disk_cache_info[index].last_read = disk_cache_info[index].block;
++ disk_cache_info[index].last_read_xor
++ = disk_cache_info[index].block ^ DISK_CACHE_LAST_READ_XOR;
++#endif
++ ext2_debug ("(%Ld)", offset >> log2_block_size);
++ mutex_unlock (&disk_cache_lock);
++
++ if (offset + vm_page_size > dev_end)
++ length = dev_end - offset;
+
+- err = store_read (store, page >> store->log2_block_size, length, buf, &read);
++ err = store_read (store, offset >> store->log2_block_size, length,
++ buf, &read);
+ if (read != length)
+ return EIO;
+ if (!err && length != vm_page_size)
+- bzero ((void *)(*buf + length), vm_page_size - length);
++ memset ((void *)(*buf + length), 0, vm_page_size - length);
+
+ *writelock = 0;
+
+@@ -430,26 +451,38 @@
+ {
+ error_t err = 0;
+ size_t length = vm_page_size, amount;
+- vm_size_t dev_end = store->size;
++ store_offset_t offset = page, dev_end = store->size;
++
++ mutex_lock (&disk_cache_lock);
++ int index = offset >> log2_block_size;
++ assert (disk_cache_info[index].block != DC_NO_BLOCK);
++ offset = ((store_offset_t) disk_cache_info[index].block << log2_block_size)
++ + offset % block_size;
++#ifndef NDEBUG /* Not strictly needed. */
++ assert ((disk_cache_info[index].last_read ^ DISK_CACHE_LAST_READ_XOR)
++ == disk_cache_info[index].last_read_xor);
++ assert (disk_cache_info[index].last_read
++ == disk_cache_info[index].block);
++#endif
++ mutex_unlock (&disk_cache_lock);
+
+- if (page + vm_page_size > dev_end)
+- length = dev_end - page;
++ if (offset + vm_page_size > dev_end)
++ length = dev_end - offset;
+
+- ext2_debug ("writing disk page %d[%d]", page, length);
++ ext2_debug ("writing disk page %Ld[%d]", offset, length);
+
+ STAT_INC (disk_pageouts);
+
+ if (modified_global_blocks)
+ /* Be picky about which blocks in a page that we write. */
+ {
+- vm_offset_t offs = page;
+ struct pending_blocks pb;
+
+ pending_blocks_init (&pb, buf);
+
+ while (length > 0 && !err)
+ {
+- block_t block = boffs_block (offs);
++ block_t block = boffs_block (offset);
+
+ /* We don't clear the block modified bit here because this paging
+ write request may not be the same one that actually set the bit,
+@@ -467,7 +500,7 @@
+ /* Otherwise just skip it. */
+ err = pending_blocks_skip (&pb);
+
+- offs += block_size;
++ offset += block_size;
+ length -= block_size;
+ }
+
+@@ -476,7 +509,7 @@
+ }
+ else
+ {
+- err = store_write (store, page >> store->log2_block_size,
++ err = store_write (store, offset >> store->log2_block_size,
+ buf, length, &amount);
+ if (!err && length != amount)
+ err = EIO;
+@@ -484,6 +517,18 @@
+
+ return err;
+ }
++
++static void
++disk_pager_notify_evict (vm_offset_t page)
++{
++ int index = page >> log2_block_size;
++
++ ext2_debug ("(block %u)", index);
++
++ mutex_lock (&disk_cache_lock);
++ disk_cache_info[index].flags &= ~DC_INCORE;
++ mutex_unlock (&disk_cache_lock);
++}
+
+ /* Satisfy a pager read request for either the disk pager or file pager
+ PAGER, to the page at offset PAGE into BUF. WRITELOCK should be set if
+@@ -493,9 +538,11 @@
+ vm_address_t *buf, int *writelock)
+ {
+ if (pager->type == DISK)
+- return disk_pager_read_page (page, (void **)buf, writelock);
++ return disk_pager_read_page (page, (void **)buf,
++ writelock);
+ else
+- return file_pager_read_page (pager->node, page, (void **)buf, writelock);
++ return file_pager_read_page (pager->node, page, (void **)buf,
++ writelock);
+ }
+
+ /* Satisfy a pager write request for either the disk pager or file pager
+@@ -509,6 +556,14 @@
+ else
+ return file_pager_write_page (pager->node, page, (void *)buf);
+ }
++
++void
++pager_notify_evict (struct user_pager_info *pager, vm_offset_t page)
++{
++ if (pager->type == DISK)
++ disk_pager_notify_evict (page);
++}
++
+
+ /* Make page PAGE writable, at least up to ALLOCSIZE. This function and
+ diskfs_grow are the only places that blocks are actually added to the
+@@ -558,10 +613,10 @@
+
+ #ifdef EXT2FS_DEBUG
+ if (dn->last_page_partially_writable)
+- ext2_debug ("made page %u[%lu] in inode %d partially writable",
++ ext2_debug ("made page %u[%Lu] in inode %Ld partially writable",
+ page, node->allocsize - page, node->cache_id);
+ else
+- ext2_debug ("made page %u[%u] in inode %d writable",
++ ext2_debug ("made page %u[%u] in inode %Ld writable",
+ page, vm_page_size, node->cache_id);
+ #endif
+
+@@ -619,8 +674,8 @@
+ block_t old_page_end_block =
+ round_page (old_size) >> log2_block_size;
+
+- ext2_debug ("growing inode %d to %lu bytes (from %lu)", node->cache_id,
+- new_size, old_size);
++ ext2_debug ("growing inode %Ld to %Lu bytes (from %Lu)",
++ node->cache_id, new_size, old_size);
+
+ if (dn->last_page_partially_writable
+ && old_page_end_block > end_block)
+@@ -656,11 +711,11 @@
+
+ STAT_INC (file_grows);
+
+- ext2_debug ("new size: %ld%s.", new_size,
++ ext2_debug ("new size: %Lu%s.", new_size,
+ dn->last_page_partially_writable
+ ? " (last page writable)": "");
+ if (err)
+- ext2_warning ("inode=%Ld, target=%Ld: %s",
++ ext2_warning ("inode=%Ld, target=%Lu: %s",
+ node->cache_id, new_size, strerror (err));
+
+ node->allocsize = new_size;
+@@ -765,6 +820,374 @@
+ {
+ }
+
++/* Cached blocks from disk. */
++void *disk_cache;
++
++/* DISK_CACHE size in bytes and blocks. */
++store_offset_t disk_cache_size;
++int disk_cache_blocks;
++
++/* block num --> pointer to in-memory block */
++hurd_ihash_t disk_cache_bptr;
++/* Cached blocks' info. */
++struct disk_cache_info *disk_cache_info;
++/* Hint index for which cache block to reuse next. */
++int disk_cache_hint;
++/* Lock for these structures. */
++struct mutex disk_cache_lock;
++/* Fired when a re-association is done. */
++struct condition disk_cache_reassociation;
++
++/* Finish mapping initialization. */
++static void
++disk_cache_init (void)
++{
++ if (block_size != vm_page_size)
++ ext2_panic ("Block size %d != vm_page_size %d",
++ block_size, vm_page_size);
++
++ mutex_init (&disk_cache_lock);
++ condition_init (&disk_cache_reassociation);
++
++ /* Allocate space for block num -> in-memory pointer mapping. */
++ if (hurd_ihash_create (&disk_cache_bptr, HURD_IHASH_NO_LOCP))
++ ext2_panic ("Can't allocate memory for disk_pager_bptr");
++
++ /* Allocate space for disk cache blocks' info. */
++ disk_cache_info = malloc ((sizeof *disk_cache_info) * disk_cache_blocks);
++ if (!disk_cache_info)
++ ext2_panic ("Cannot allocate space for disk cache info");
++
++ /* Initialize disk_cache_info. */
++ for (int i = 0; i < disk_cache_blocks; i++)
++ {
++ disk_cache_info[i].block = DC_NO_BLOCK;
++ disk_cache_info[i].flags = 0;
++ disk_cache_info[i].ref_count = 0;
++#ifndef NDEBUG
++ disk_cache_info[i].last_read = DC_NO_BLOCK;
++ disk_cache_info[i].last_read_xor
++ = DC_NO_BLOCK ^ DISK_CACHE_LAST_READ_XOR;
++#endif
++ }
++ disk_cache_hint = 0;
++
++ /* Map the superblock and the block group descriptors. */
++ block_t fixed_first = boffs_block (SBLOCK_OFFS);
++ block_t fixed_last = fixed_first
++ + (round_block ((sizeof *group_desc_image) * groups_count)
++ >> log2_block_size);
++ ext2_debug ("%d-%d\n", fixed_first, fixed_last);
++ assert (fixed_last - fixed_first + 1 <= (block_t)disk_cache_blocks + 3);
++ for (block_t i = fixed_first; i <= fixed_last; i++)
++ {
++ disk_cache_block_ref (i);
++ assert (disk_cache_info[i-fixed_first].block == i);
++ disk_cache_info[i-fixed_first].flags |= DC_FIXED;
++ }
++}
++
++static void
++disk_cache_return_unused (void)
++{
++ int index;
++
++ /* XXX: Touch all pages. It seems that sometimes GNU Mach "forgets"
++ to notify us about evicted pages. Disk cache must be
++ unlocked. */
++ for (vm_offset_t i = 0; i < disk_cache_size; i += vm_page_size)
++ *(volatile char *)(disk_cache + i);
++
++ /* Release some references to cached blocks. */
++ pokel_sync (&global_pokel, 1);
++
++ /* Return unused pages that are in core. */
++ int pending_begin = -1, pending_end = -1;
++ mutex_lock (&disk_cache_lock);
++ for (index = 0; index < disk_cache_blocks; index++)
++ if (! (disk_cache_info[index].flags & (DC_DONT_REUSE & ~DC_INCORE))
++ && ! disk_cache_info[index].ref_count)
++ {
++ ext2_debug ("return %u -> %d",
++ disk_cache_info[index].block, index);
++ if (index != pending_end)
++ {
++ /* Return previous region, if there is such, ... */
++ if (pending_end >= 0)
++ {
++ mutex_unlock (&disk_cache_lock);
++ pager_return_some (diskfs_disk_pager,
++ pending_begin * vm_page_size,
++ (pending_end - pending_begin)
++ * vm_page_size,
++ 1);
++ mutex_lock (&disk_cache_lock);
++ }
++ /* ... and start new region. */
++ pending_begin = index;
++ }
++ pending_end = index + 1;
++ }
++
++ mutex_unlock (&disk_cache_lock);
++
++ /* Return last region, if there is such. */
++ if (pending_end >= 0)
++ pager_return_some (diskfs_disk_pager,
++ pending_begin * vm_page_size,
++ (pending_end - pending_begin) * vm_page_size,
++ 1);
++ else
++ {
++ printf ("ext2fs: disk cache is starving\n");
++
++ /* Give it some time. This should happen rarely. */
++ sleep (1);
++ }
++}
++
++/* Map block and return pointer to it. */
++void *
++disk_cache_block_ref (block_t block)
++{
++ int index;
++ void *bptr;
++
++ assert (0 <= block && block < store->size >> log2_block_size);
++
++ ext2_debug ("(%u)", block);
++
++ mutex_lock (&disk_cache_lock);
++
++ bptr = hurd_ihash_find (disk_cache_bptr, block);
++ if (bptr)
++ /* Already mapped. */
++ {
++ index = bptr_index (bptr);
++
++ /* In process of re-associating? */
++ if (disk_cache_info[index].flags & DC_UNTOUCHED)
++ {
++ /* Wait re-association to finish. */
++ condition_wait (&disk_cache_reassociation, &disk_cache_lock);
++ mutex_unlock (&disk_cache_lock);
++
++#if 0
++ printf ("Re-association -- wait finished.\n");
++#endif
++
++ /* Try again. */
++ return disk_cache_block_ref (block); /* tail recursion */
++ }
++
++ /* Just increment reference and return. */
++ assert (disk_cache_info[index].ref_count + 1
++ > disk_cache_info[index].ref_count);
++ disk_cache_info[index].ref_count++;
++
++ ext2_debug ("cached %u -> %d (ref_count = %d, flags = 0x%x, ptr = %p)",
++ disk_cache_info[index].block, index,
++ disk_cache_info[index].ref_count,
++ disk_cache_info[index].flags, bptr);
++
++ mutex_unlock (&disk_cache_lock);
++
++ return bptr;
++ }
++
++ /* Search for a block that is not in core and is not referenced. */
++ index = disk_cache_hint;
++ while ((disk_cache_info[index].flags & DC_DONT_REUSE)
++ || (disk_cache_info[index].ref_count))
++ {
++ ext2_debug ("reject %u -> %d (ref_count = %d, flags = 0x%x)",
++ disk_cache_info[index].block, index,
++ disk_cache_info[index].ref_count,
++ disk_cache_info[index].flags);
++
++ /* Just move to next block. */
++ index++;
++ if (index >= disk_cache_blocks)
++ index -= disk_cache_blocks;
++
++ /* If we return to where we started, than there is no suitable
++ block. */
++ if (index == disk_cache_hint)
++ break;
++ }
++
++ /* The next place in the disk cache becomes the current hint. */
++ disk_cache_hint = index + 1;
++ if (disk_cache_hint >= disk_cache_blocks)
++ disk_cache_hint -= disk_cache_blocks;
++
++ /* Is suitable place found? */
++ if ((disk_cache_info[index].flags & DC_DONT_REUSE)
++ || disk_cache_info[index].ref_count)
++ /* No place is found. Try to release some blocks and try
++ again. */
++ {
++ ext2_debug ("flush %u -> %d", disk_cache_info[index].block, index);
++
++ mutex_unlock (&disk_cache_lock);
++
++ disk_cache_return_unused ();
++
++ return disk_cache_block_ref (block); /* tail recursion */
++ }
++
++ /* Suitable place is found. */
++
++ /* Calculate pointer to data. */
++ bptr = (char *)disk_cache + (index << log2_block_size);
++ ext2_debug ("map %u -> %d (%p)", block, index, bptr);
++
++ /* This pager_return_some is used only to set PM_FORCEREAD for the
++ page. DC_UNTOUCHED is set so that we catch if someone has
++ referenced the block while we didn't hold disk_cache_lock. */
++ disk_cache_info[index].flags |= DC_UNTOUCHED;
++
++#if 0 /* XXX: Let's see if this is needed at all. */
++
++ mutex_unlock (&disk_cache_lock);
++ pager_return_some (diskfs_disk_pager, bptr - disk_cache, vm_page_size, 1);
++ mutex_lock (&disk_cache_lock);
++
++ /* Has someone used our bptr? Has someone mapped requested block
++ while we have unlocked disk_cache_lock? If so, environment has
++ changed and we have to restart operation. */
++ if ((! (disk_cache_info[index].flags & DC_UNTOUCHED))
++ || hurd_ihash_find (disk_cache_bptr, block))
++ {
++ mutex_unlock (&disk_cache_lock);
++ return disk_cache_block_ref (block); /* tail recursion */
++ }
++
++#elif 0
++
++ /* XXX: Use libpager internals. */
++
++ mutex_lock (&diskfs_disk_pager->interlock);
++ int page = (bptr - disk_cache) / vm_page_size;
++ assert (page >= 0);
++ int is_incore = (page < diskfs_disk_pager->pagemapsize
++ && (diskfs_disk_pager->pagemap[page] & PM_INCORE));
++ mutex_unlock (&diskfs_disk_pager->interlock);
++ if (is_incore)
++ {
++ mutex_unlock (&disk_cache_lock);
++ printf ("INCORE\n");
++ return disk_cache_block_ref (block); /* tail recursion */
++ }
++
++#endif
++
++ /* Re-associate. */
++ if (disk_cache_info[index].block != DC_NO_BLOCK)
++ /* Remove old association. */
++ hurd_ihash_remove (disk_cache_bptr, disk_cache_info[index].block);
++ /* New association. */
++ if (hurd_ihash_add (disk_cache_bptr, block, bptr))
++ ext2_panic ("Couldn't hurd_ihash_add new disk block");
++ assert (! (disk_cache_info[index].flags & DC_DONT_REUSE & ~DC_UNTOUCHED));
++ disk_cache_info[index].block = block;
++ assert (! disk_cache_info[index].ref_count);
++ disk_cache_info[index].ref_count = 1;
++
++ /* All data structures are set up. */
++ mutex_unlock (&disk_cache_lock);
++
++ /* Try to read page. */
++ *(volatile char *) bptr;
++
++ /* Check if it's actually read. */
++ mutex_lock (&disk_cache_lock);
++ if (disk_cache_info[index].flags & DC_UNTOUCHED)
++ /* It's not read. */
++ {
++ /* Remove newly created association. */
++ hurd_ihash_remove (disk_cache_bptr, block);
++ disk_cache_info[index].block = DC_NO_BLOCK;
++ disk_cache_info[index].flags &=~ DC_UNTOUCHED;
++ disk_cache_info[index].ref_count = 0;
++ mutex_unlock (&disk_cache_lock);
++
++ /* Prepare next time association of this page to succeed. */
++ pager_flush_some (diskfs_disk_pager, bptr - disk_cache,
++ vm_page_size, 0);
++
++#if 0
++ printf ("Re-association failed.\n");
++#endif
++
++ /* Try again. */
++ return disk_cache_block_ref (block); /* tail recursion */
++ }
++ mutex_unlock (&disk_cache_lock);
++
++ /* Re-association was successful. */
++ condition_broadcast (&disk_cache_reassociation);
++
++ ext2_debug ("(%u) = %p", block, bptr);
++ return bptr;
++}
++
++void
++disk_cache_block_ref_ptr (void *ptr)
++{
++ int index;
++
++ mutex_lock (&disk_cache_lock);
++ index = bptr_index (ptr);
++ assert (disk_cache_info[index].ref_count >= 1);
++ assert (disk_cache_info[index].ref_count + 1
++ > disk_cache_info[index].ref_count);
++ disk_cache_info[index].ref_count++;
++ assert (! (disk_cache_info[index].flags & DC_UNTOUCHED));
++ ext2_debug ("(%p) (ref_count = %d, flags = 0x%x)",
++ ptr,
++ disk_cache_info[index].ref_count,
++ disk_cache_info[index].flags);
++ mutex_unlock (&disk_cache_lock);
++}
++
++void
++disk_cache_block_deref (void *ptr)
++{
++ int index;
++
++ assert (disk_cache <= ptr && ptr <= disk_cache + disk_cache_size);
++
++ mutex_lock (&disk_cache_lock);
++ index = bptr_index (ptr);
++ ext2_debug ("(%p) (ref_count = %d, flags = 0x%x)",
++ ptr,
++ disk_cache_info[index].ref_count - 1,
++ disk_cache_info[index].flags);
++ assert (! (disk_cache_info[index].flags & DC_UNTOUCHED));
++ assert (disk_cache_info[index].ref_count >= 1);
++ disk_cache_info[index].ref_count--;
++ mutex_unlock (&disk_cache_lock);
++}
++
++/* Not used. */
++int
++disk_cache_block_is_ref (block_t block)
++{
++ int ref;
++ void *ptr;
++
++ mutex_lock (&disk_cache_lock);
++ ptr = hurd_ihash_find (disk_cache_bptr, block);
++ if (! ptr)
++ ref = 0;
++ else /* XXX: Should check for DC_UNTOUCHED too. */
++ ref = disk_cache_info[bptr_index (ptr)].ref_count;
++ mutex_unlock (&disk_cache_lock);
++
++ return ref;
++}
++
+ /* Create the DISK pager. */
+ void
+ create_disk_pager (void)
+@@ -774,8 +1197,12 @@
+ ext2_panic ("can't create disk pager: %s", strerror (errno));
+ upi->type = DISK;
+ pager_bucket = ports_create_bucket ();
+- diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, store->size,
+- &disk_image);
++ get_hypermetadata ();
++ disk_cache_blocks = DISK_CACHE_BLOCKS;
++ disk_cache_size = disk_cache_blocks << log2_block_size;
++ diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, 1,
++ disk_cache_size, &disk_cache);
++ disk_cache_init ();
+ }
+
+ /* Call this to create a FILE_DATA pager and return a send right.
+@@ -815,7 +1242,7 @@
+ diskfs_nref_light (node);
+ node->dn->pager =
+ pager_create (upi, pager_bucket, MAY_CACHE,
+- MEMORY_OBJECT_COPY_DELAY);
++ MEMORY_OBJECT_COPY_DELAY, 0);
+ if (node->dn->pager == 0)
+ {
+ diskfs_nrele_light (node);
+Index: hurd-debian/ext2fs/pokel.c
+===================================================================
+--- hurd-debian.orig/ext2fs/pokel.c 2012-07-10 01:33:10.000000000 +0000
++++ hurd-debian/ext2fs/pokel.c 2012-07-10 01:39:22.000000000 +0000
+@@ -67,12 +67,27 @@
+ vm_offset_t p_offs = pl->offset;
+ vm_size_t p_end = p_offs + pl->length;
+
+- if (p_offs == offset && p_end == end)
+- break;
++ if (p_offs <= offset && end <= p_end)
++ {
++ if (pokel->image == disk_cache)
++ for (vm_offset_t i = offset; i < end; i += block_size)
++ disk_cache_block_deref (disk_cache + i);
++
++ break;
++ }
+ else if (p_end >= offset && end >= p_offs)
+ {
+ pl->offset = offset < p_offs ? offset : p_offs;
+ pl->length = (end > p_end ? end : p_end) - pl->offset;
++
++ if (pokel->image == disk_cache)
++ {
++ vm_offset_t i_begin = p_offs > offset ? p_offs : offset;
++ vm_offset_t i_end = p_end < end ? p_end : end;
++ for (vm_offset_t i = i_begin; i < i_end; i += block_size)
++ disk_cache_block_deref (disk_cache + i);
++ }
++
+ ext2_debug ("extended 0x%x[%ul] to 0x%x[%ul]",
+ p_offs, p_end - p_offs, pl->offset, pl->length);
+ break;
+@@ -106,18 +121,28 @@
+ _pokel_exec (struct pokel *pokel, int sync, int wait)
+ {
+ struct poke *pl, *pokes, *last = NULL;
+-
++
+ pthread_spin_lock (&pokel->lock);
+ pokes = pokel->pokes;
+ pokel->pokes = NULL;
+ pthread_spin_unlock (&pokel->lock);
+
+ for (pl = pokes; pl; last = pl, pl = pl->next)
+- if (sync)
+- {
+- ext2_debug ("syncing 0x%x[%ul]", pl->offset, pl->length);
+- pager_sync_some (pokel->pager, pl->offset, pl->length, wait);
+- }
++ {
++ if (sync)
++ {
++ ext2_debug ("syncing 0x%x[%ul]", pl->offset, pl->length);
++ pager_sync_some (pokel->pager, pl->offset, pl->length, wait);
++ }
++
++ if (pokel->image == disk_cache)
++ {
++ vm_offset_t begin = trunc_block (pl->offset);
++ vm_offset_t end = round_block (pl->offset + pl->length);
++ for (vm_offset_t i = begin; i != end; i += block_size)
++ disk_cache_block_deref (pokel->image + i);
++ }
++ }
+
+ if (last)
+ {
+Index: hurd-debian/ext2fs/truncate.c
+===================================================================
+--- hurd-debian.orig/ext2fs/truncate.c 2012-07-10 01:33:10.000000000 +0000
++++ hurd-debian/ext2fs/truncate.c 2012-07-10 01:39:22.000000000 +0000
+@@ -124,7 +124,7 @@
+ {
+ unsigned index;
+ int modified = 0, all_freed = 1;
+- block_t *ind_bh = (block_t *)bptr (*p);
++ block_t *ind_bh = (block_t *)disk_cache_block_ref (*p);
+ unsigned first = end < offset ? 0 : end - offset;
+
+ for (index = first; index < addr_per_block; index++)
+@@ -139,11 +139,16 @@
+
+ if (first == 0 && all_freed)
+ {
+- pager_flush_some (diskfs_disk_pager, boffs (*p), block_size, 1);
++ pager_flush_some (diskfs_disk_pager,
++ bptr_index (ind_bh) << log2_block_size,
++ block_size, 1);
+ free_block_run_free_ptr (fbr, p);
++ disk_cache_block_deref (ind_bh);
+ }
+ else if (modified)
+ record_indir_poke (node, ind_bh);
++ else
++ disk_cache_block_deref (ind_bh);
+ }
+ }
+
+@@ -218,7 +223,7 @@
+ /* Flush all the data past the new size from the kernel. Also force any
+ delayed copies of this data to take place immediately. (We are implicitly
+ changing the data to zeros and doing it without the kernel's immediate
+- knowledge; accordingl we must help out the kernel thusly.) */
++ knowledge; accordingly we must help out the kernel thusly.) */
+ static void
+ force_delayed_copies (struct node *node, off_t length)
+ {
+Index: hurd-debian/fatfs/pager.c
+===================================================================
+--- hurd-debian.orig/fatfs/pager.c 2012-07-10 01:33:10.000000000 +0000
++++ hurd-debian/fatfs/pager.c 2012-07-10 01:39:22.000000000 +0000
+@@ -596,6 +596,13 @@
+ return 0;
+ }
+
++void
++pager_notify_evict (struct user_pager_info *pager,
++ vm_offset_t page)
++{
++ assert (!"unrequested notification on eviction");
++}
++
+ /* Grow the disk allocated to locked node NODE to be at least SIZE
+ bytes, and set NODE->allocsize to the actual allocated size. (If
+ the allocated size is already SIZE bytes, do nothing.) CRED
+@@ -752,7 +759,7 @@
+ struct user_pager_info *upi = malloc (sizeof (struct user_pager_info));
+ upi->type = FAT;
+ pager_bucket = ports_create_bucket ();
+- diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE,
++ diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, 0,
+ bytes_per_sector * sectors_per_fat,
+ &fat_image);
+ }
+@@ -794,7 +801,7 @@
+ diskfs_nref_light (node);
+ node->dn->pager =
+ pager_create (upi, pager_bucket, MAY_CACHE,
+- MEMORY_OBJECT_COPY_DELAY);
++ MEMORY_OBJECT_COPY_DELAY, 0);
+ if (node->dn->pager == 0)
+ {
+ diskfs_nrele_light (node);
+Index: hurd-debian/isofs/pager.c
+===================================================================
+--- hurd-debian.orig/isofs/pager.c 2012-07-10 01:33:10.000000000 +0000
++++ hurd-debian/isofs/pager.c 2012-07-10 01:39:22.000000000 +0000
+@@ -94,6 +94,13 @@
+ return EROFS;
+ }
+
++void
++pager_notify_evict (struct user_pager_info *pager,
++ vm_offset_t page)
++{
++ assert (!"unrequested notification on eviction");
++}
++
+ /* Tell how big the file is. */
+ error_t
+ pager_report_extent (struct user_pager_info *pager,
+@@ -137,7 +144,7 @@
+ upi->type = DISK;
+ upi->np = 0;
+ pager_bucket = ports_create_bucket ();
+- diskfs_start_disk_pager (upi, pager_bucket, 1, store->size, &disk_image);
++ diskfs_start_disk_pager (upi, pager_bucket, 1, 0, store->size, &disk_image);
+ upi->p = diskfs_disk_pager;
+ }
+
+@@ -168,7 +175,8 @@
+ upi->type = FILE_DATA;
+ upi->np = np;
+ diskfs_nref_light (np);
+- upi->p = pager_create (upi, pager_bucket, 1, MEMORY_OBJECT_COPY_DELAY);
++ upi->p = pager_create (upi, pager_bucket, 1,
++ MEMORY_OBJECT_COPY_DELAY, 0);
+ if (upi->p == 0)
+ {
+ diskfs_nrele_light (np);
+Index: hurd-debian/libdiskfs/disk-pager.c
+===================================================================
+--- hurd-debian.orig/libdiskfs/disk-pager.c 2012-07-10 01:33:11.000000000 +0000
++++ hurd-debian/libdiskfs/disk-pager.c 2012-07-10 01:39:22.000000000 +0000
+@@ -46,7 +46,8 @@
+
+ void
+ diskfs_start_disk_pager (struct user_pager_info *upi,
+- struct port_bucket *pager_bucket, int may_cache,
++ struct port_bucket *pager_bucket,
++ int may_cache, int notify_on_evict,
+ size_t size, void **image)
+ {
+ pthread_t thread;
+@@ -68,7 +69,8 @@
+
+ /* Create the pager. */
+ diskfs_disk_pager = pager_create (upi, pager_bucket,
+- may_cache, MEMORY_OBJECT_COPY_NONE);
++ may_cache, MEMORY_OBJECT_COPY_NONE,
++ notify_on_evict);
+ assert (diskfs_disk_pager);
+
+ /* Get a port to the disk pager. */
+Index: hurd-debian/libdiskfs/diskfs-pager.h
+===================================================================
+--- hurd-debian.orig/libdiskfs/diskfs-pager.h 2012-07-10 01:33:11.000000000 +0000
++++ hurd-debian/libdiskfs/diskfs-pager.h 2012-07-10 01:39:22.000000000 +0000
+@@ -33,7 +33,8 @@
+ mapped is returned in IMAGE. INFO, PAGER_BUCKET, & MAY_CACHE are passed
+ to `pager_create'. */
+ extern void diskfs_start_disk_pager (struct user_pager_info *info,
+- struct port_bucket *pager_bucket, int may_cache,
++ struct port_bucket *pager_bucket,
++ int may_cache, int notify_on_evict,
+ size_t size, void **image);
+
+ extern struct pager *diskfs_disk_pager;
+Index: hurd-debian/libpager/data-request.c
+===================================================================
+--- hurd-debian.orig/libpager/data-request.c 2012-11-26 00:23:28.000000000 +0000
++++ hurd-debian/libpager/data-request.c 2012-11-26 00:24:49.000000000 +0000
+@@ -40,11 +40,11 @@
+ if (!p)
+ return EOPNOTSUPP;
+
+- /* Acquire the right to meddle with the pagemap */
++ /* Acquire the right to meddle with the pagemap. */
+ pthread_mutex_lock (&p->interlock);
+ _pager_wait_for_seqno (p, seqno);
+
+- /* sanity checks -- we don't do multi-page requests yet. */
++ /* Sanity checks -- we don't do multi-page requests yet. */
+ if (control != p->memobjcntl)
+ {
+ printf ("incg data request: wrong control port\n");
+@@ -119,7 +119,8 @@
+ goto error_read;
+
+ memory_object_data_supply (p->memobjcntl, offset, page, length, 1,
+- write_lock ? VM_PROT_WRITE : VM_PROT_NONE, 0,
++ write_lock ? VM_PROT_WRITE : VM_PROT_NONE,
++ p->notify_on_evict ? 1 : 0,
+ MACH_PORT_NULL);
+ pthread_mutex_lock (&p->interlock);
+ _pager_mark_object_error (p, offset, length, 0);
+Index: hurd-debian/libpager/data-return.c
+===================================================================
+--- hurd-debian.orig/libpager/data-return.c 2012-11-26 00:23:28.000000000 +0000
++++ hurd-debian/libpager/data-return.c 2012-11-26 00:24:49.000000000 +0000
+@@ -39,6 +39,7 @@
+ struct pager *p;
+ short *pm_entries;
+ int npages, i;
++ char *notified;
+ error_t *pagerrs;
+ struct lock_request *lr;
+ struct lock_list {struct lock_request *lr;
+@@ -71,9 +72,6 @@
+ goto release_out;
+ }
+
+- if (! dirty)
+- goto release_out;
+-
+ if (p->pager_state != NORMAL)
+ {
+ printf ("pager in wrong state for write\n");
+@@ -83,6 +81,11 @@
+ npages = length / __vm_page_size;
+ pagerrs = alloca (npages * sizeof (error_t));
+
++ notified = alloca (npages * (sizeof *notified));
++#ifndef NDEBUG
++ memset (notified, -1, npages * (sizeof *notified));
++#endif
++
+ _pager_block_termination (p); /* until we are done with the pagemap
+ when the write completes. */
+
+@@ -90,6 +93,24 @@
+
+ pm_entries = &p->pagemap[offset / __vm_page_size];
+
++ if (! dirty)
++ {
++ munmap ((caddr_t) data, length);
++ if (!kcopy) {
++ /* Prepare notified array. */
++ for (i = 0; i < npages; i++)
++ notified[i] = (p->notify_on_evict
++ && ! (pm_entries[i] & PM_PAGEINWAIT));
++
++ _pager_release_seqno (p, seqno);
++ goto notify;
++ }
++ else {
++ _pager_allow_termination (p);
++ goto release_out;
++ }
++ }
++
+ /* Make sure there are no other in-progress writes for any of these
+ pages before we begin. This imposes a little more serialization
+ than we really have to require (because *all* future writes on
+@@ -120,10 +141,6 @@
+ for (i = 0; i < npages; i++)
+ pm_entries[i] |= PM_PAGINGOUT | PM_INIT;
+
+- if (!kcopy)
+- for (i = 0; i < npages; i++)
+- pm_entries[i] &= ~PM_INCORE;
+-
+ /* If this write occurs while a lock is pending, record
+ it. We have to keep this list because a lock request
+ might come in while we do the I/O; in that case there
+@@ -163,7 +180,10 @@
+ for (i = 0; i < npages; i++)
+ {
+ if (omitdata & (1 << i))
+- continue;
++ {
++ notified[i] = 0;
++ continue;
++ }
+
+ if (pm_entries[i] & PM_WRITEWAIT)
+ wakeup = 1;
+@@ -179,14 +199,22 @@
+ pm_entries[i] |= PM_INVALID;
+
+ if (pm_entries[i] & PM_PAGEINWAIT)
+- memory_object_data_supply (p->memobjcntl,
+- offset + (vm_page_size * i),
+- data + (vm_page_size * i),
+- vm_page_size, 1,
+- VM_PROT_NONE, 0, MACH_PORT_NULL);
++ {
++ memory_object_data_supply (p->memobjcntl,
++ offset + (vm_page_size * i),
++ data + (vm_page_size * i),
++ vm_page_size, 1,
++ VM_PROT_NONE, 0, MACH_PORT_NULL);
++ notified[i] = 0;
++ }
+ else
+- munmap ((caddr_t) (data + (vm_page_size * i)),
+- vm_page_size);
++ {
++ munmap ((caddr_t) (data + (vm_page_size * i)),
++ vm_page_size);
++ notified[i] = (! kcopy && p->notify_on_evict);
++ if (! kcopy)
++ pm_entries[i] &= ~PM_INCORE;
++ }
+
+ pm_entries[i] &= ~(PM_PAGINGOUT | PM_PAGEINWAIT | PM_WRITEWAIT);
+ }
+@@ -198,10 +226,29 @@
+ if (wakeup)
+ pthread_cond_broadcast (&p->wakeup);
+
++ notify:
+ _pager_allow_termination (p);
+-
+ pthread_mutex_unlock (&p->interlock);
+
++ for (i = 0; i < npages; i++)
++ {
++ assert (notified[i] == 0 || notified[i] == 1);
++ if (notified[i])
++ {
++ short *pm_entry = &pm_entries[i];
++
++ /* Do notify user. */
++ pager_notify_evict (p->upi, offset + (i * vm_page_size));
++
++ /* Clear any error that is left. Notification on eviction
++ is used only to change association of page, so any
++ error may no longer be valid. */
++ mutex_lock (&p->interlock);
++ *pm_entry = SET_PM_ERROR (SET_PM_NEXTERROR (*pm_entry, 0), 0);
++ mutex_unlock (&p->interlock);
++ }
++ }
++
+ ports_port_deref (p);
+ return 0;
+
+Index: hurd-debian/libpager/pager-create.c
+===================================================================
+--- hurd-debian.orig/libpager/pager-create.c 2012-07-10 01:33:11.000000000 +0000
++++ hurd-debian/libpager/pager-create.c 2012-07-10 01:39:22.000000000 +0000
+@@ -22,7 +22,8 @@
+ pager_create (struct user_pager_info *upi,
+ struct port_bucket *bucket,
+ boolean_t may_cache,
+- memory_object_copy_strategy_t copy_strategy)
++ memory_object_copy_strategy_t copy_strategy,
++ boolean_t notify_on_evict)
+ {
+ struct pager *p;
+
+@@ -38,6 +39,7 @@
+ p->attribute_requests = 0;
+ p->may_cache = may_cache;
+ p->copy_strategy = copy_strategy;
++ p->notify_on_evict = notify_on_evict;
+ p->memobjcntl = MACH_PORT_NULL;
+ p->memobjname = MACH_PORT_NULL;
+ p->seqno = -1;
+Index: hurd-debian/libpager/pager.h
+===================================================================
+--- hurd-debian.orig/libpager/pager.h 2012-07-10 01:33:11.000000000 +0000
++++ hurd-debian/libpager/pager.h 2012-07-10 01:39:22.000000000 +0000
+@@ -32,18 +32,21 @@
+ mach_msg_header_t *outp);
+
+ /* Create a new pager. The pager will have a port created for it
+- (using libports, in BUCKET) and will be immediately ready
+- to receive requests. U_PAGER will be provided to later calls to
++ (using libports, in BUCKET) and will be immediately ready to
++ receive requests. U_PAGER will be provided to later calls to
+ pager_find_address. The pager will have one user reference
+ created. MAY_CACHE and COPY_STRATEGY are the original values of
+- those attributes as for memory_object_ready. Users may create
+- references to pagers by use of the relevant ports library
+- functions. On errors, return null and set errno. */
++ those attributes as for memory_object_ready. If NOTIFY_ON_EVICT is
++ non-zero, pager_notify_evict user callback will be called when page
++ is evicted. Users may create references to pagers by use of the
++ relevant ports library functions. On errors, return null and set
++ errno. */
+ struct pager *
+ pager_create (struct user_pager_info *u_pager,
+ struct port_bucket *bucket,
+ boolean_t may_cache,
+- memory_object_copy_strategy_t copy_strategy);
++ memory_object_copy_strategy_t copy_strategy,
++ boolean_t notify_on_evict);
+
+ /* Return the user_pager_info struct associated with a pager. */
+ struct user_pager_info *
+@@ -110,7 +113,7 @@
+ /* Change the attributes of the memory object underlying pager PAGER.
+ Args MAY_CACHE and COPY_STRATEGY are as for
+ memory_object_change_atributes. Wait for the kernel to report completion
+- off WAIT is set.*/
++ iff WAIT is set. */
+ void
+ pager_change_attributes (struct pager *pager,
+ boolean_t may_cache,
+@@ -172,6 +175,18 @@
+ pager_unlock_page (struct user_pager_info *pager,
+ vm_offset_t address);
+
++/* The user must define this function. It is used when you want be
++ able to change association of pages to backing store. To use it,
++ pass non-zero value in NOTIFY_ON_EVICT when pager is created with
++ pager_create. You can change association of page only when
++ pager_notify_evict has been called and you haven't touched page
++ content after that. Note there is a possibility that a page is
++ evicted, but user is not notified about that. The user should be
++ able to handle this case. */
++void
++pager_notify_evict (struct user_pager_info *pager,
++ vm_offset_t page);
++
+ /* The user must define this function. It should report back (in
+ *OFFSET and *SIZE the minimum valid address the pager will accept
+ and the size of the object. */
+Index: hurd-debian/libpager/priv.h
+===================================================================
+--- hurd-debian.orig/libpager/priv.h 2012-07-10 01:33:11.000000000 +0000
++++ hurd-debian/libpager/priv.h 2012-07-10 01:39:22.000000000 +0000
+@@ -48,6 +48,7 @@
+
+ boolean_t may_cache;
+ memory_object_copy_strategy_t copy_strategy;
++ boolean_t notify_on_evict;
+
+ /* Interface ports */
+ memory_object_control_t memobjcntl;
+Index: hurd-debian/storeio/pager.c
+===================================================================
+--- hurd-debian.orig/storeio/pager.c 2012-07-10 01:33:12.000000000 +0000
++++ hurd-debian/storeio/pager.c 2012-07-10 01:39:22.000000000 +0000
+@@ -109,6 +109,13 @@
+ return 0;
+ }
+
++void
++pager_notify_evict (struct user_pager_info *pager,
++ vm_offset_t page)
++{
++ assert (!"unrequested notification on eviction");
++}
++
+ /* The user must define this function. It should report back (in
+ *OFFSET and *SIZE the minimum valid address the pager will accept
+ and the size of the object. */
+@@ -232,7 +239,7 @@
+ {
+ dev->pager =
+ pager_create ((struct user_pager_info *)dev, pager_port_bucket,
+- 1, MEMORY_OBJECT_COPY_DELAY);
++ 1, MEMORY_OBJECT_COPY_DELAY, 0);
+ if (dev->pager == NULL)
+ {
+ pthread_mutex_unlock (&dev->pager_lock);
+Index: hurd-debian/tmpfs/pager-stubs.c
+===================================================================
+--- hurd-debian.orig/tmpfs/pager-stubs.c 2012-11-26 00:23:28.000000000 +0000
++++ hurd-debian/tmpfs/pager-stubs.c 2012-11-26 00:24:49.000000000 +0000
+@@ -57,6 +57,14 @@
+ return EIEIO;
+ }
+
++void
++pager_notify_evict (struct user_pager_info *pager,
++ vm_offset_t page)
++{
++ abort();
++}
++
++
+ /* The user must define this function. It should report back (in
+ *OFFSET and *SIZE the minimum valid address the pager will accept
+ and the size of the object. */
+Index: hurd-debian/ufs/pager.c
+===================================================================
+--- hurd-debian.orig/ufs/pager.c 2012-07-10 01:33:12.000000000 +0000
++++ hurd-debian/ufs/pager.c 2012-07-10 01:39:22.000000000 +0000
+@@ -425,6 +425,13 @@
+ return err;
+ }
+
++void
++pager_notify_evict (struct user_pager_info *pager,
++ vm_offset_t page)
++{
++ assert (!"unrequested notification on eviction");
++}
++
+ /* Implement the pager_report_extent callback from the pager library. See
+ <hurd/pager.h> for the interface description. */
+ inline error_t
+@@ -477,7 +484,7 @@
+ upi->type = DISK;
+ upi->np = 0;
+ pager_bucket = ports_create_bucket ();
+- diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, store->size,
++ diskfs_start_disk_pager (upi, pager_bucket, MAY_CACHE, 0, store->size,
+ &disk_image);
+ upi->p = diskfs_disk_pager;
+ }
+@@ -570,7 +577,7 @@
+ upi->unlocked_pagein_length = 0;
+ diskfs_nref_light (np);
+ upi->p = pager_create (upi, pager_bucket,
+- MAY_CACHE, MEMORY_OBJECT_COPY_DELAY);
++ MAY_CACHE, MEMORY_OBJECT_COPY_DELAY, 0);
+ if (upi->p == 0)
+ {
+ diskfs_nrele_light (np);
diff --git a/debian/patches/ext2fs_large_stores_pthread.patch b/debian/patches/ext2fs_large_stores_pthread.patch
new file mode 100644
index 00000000..71f76a34
--- /dev/null
+++ b/debian/patches/ext2fs_large_stores_pthread.patch
@@ -0,0 +1,344 @@
+commit 93691ae1ae88c2d66d240b50e3ea5827f8a96c22
+Author: Richard Braun <rbraun@sceen.net>
+Date: Mon Sep 3 22:19:16 2012 +0200
+
+ Move large storage patch to pthreads
+
+TODO: merge into ext2fs_large_stores.patch.
+
+Index: hurd-debian/ext2fs/ext2fs.h
+===================================================================
+--- hurd-debian.orig/ext2fs/ext2fs.h 2012-11-26 00:24:49.000000000 +0000
++++ hurd-debian/ext2fs/ext2fs.h 2012-11-26 00:24:58.000000000 +0000
+@@ -260,9 +260,9 @@
+ /* Metadata about cached block. */
+ extern struct disk_cache_info *disk_cache_info;
+ /* Lock for these mappings */
+-extern struct mutex disk_cache_lock;
++extern pthread_mutex_t disk_cache_lock;
+ /* Fired when a re-association is done. */
+-extern struct condition disk_cache_reassociation;
++extern pthread_cond_t disk_cache_reassociation;
+
+ void *disk_cache_block_ref (block_t block);
+ void disk_cache_block_ref_ptr (void *ptr);
+@@ -345,9 +345,9 @@
+ boffs_ptr (off_t offset)
+ {
+ block_t block = boffs_block (offset);
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+ char *ptr = hurd_ihash_find (disk_cache_bptr, block);
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+ assert (ptr);
+ ptr += offset % block_size;
+ ext2_debug ("(%Ld) = %p", offset, ptr);
+@@ -361,12 +361,12 @@ bptr_offs (void *ptr)
+ vm_offset_t mem_offset = (char *)ptr - (char *)disk_cache;
+ off_t offset;
+ assert (mem_offset < disk_cache_size);
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+ offset = (off_t) disk_cache_info[boffs_block (mem_offset)].block
+ << log2_block_size;
+ assert (offset || mem_offset < block_size);
+ offset += mem_offset % block_size;
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+ ext2_debug ("(%p) = %Ld", ptr, offset);
+ return offset;
+ }
+diff --git a/ext2fs/pager.c b/ext2fs/pager.c
+index 2bec88d..67c9922 100644
+--- a/ext2fs/pager.c
++++ b/ext2fs/pager.c
+@@ -418,7 +418,7 @@ disk_pager_read_page (vm_offset_t page, void **buf, int *writelock)
+ size_t length = vm_page_size, read = 0;
+ store_offset_t offset = page, dev_end = store->size;
+
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+ int index = offset >> log2_block_size;
+ offset = ((store_offset_t) disk_cache_info[index].block << log2_block_size)
+ + offset % block_size;
+@@ -430,7 +430,7 @@ disk_pager_read_page (vm_offset_t page, void **buf, int *writelock)
+ = disk_cache_info[index].block ^ DISK_CACHE_LAST_READ_XOR;
+ #endif
+ ext2_debug ("(%Ld)", offset >> log2_block_size);
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+
+ if (offset + vm_page_size > dev_end)
+ length = dev_end - offset;
+@@ -454,7 +454,7 @@ disk_pager_write_page (vm_offset_t page, void *buf)
+ size_t length = vm_page_size, amount;
+ store_offset_t offset = page, dev_end = store->size;
+
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+ int index = offset >> log2_block_size;
+ assert (disk_cache_info[index].block != DC_NO_BLOCK);
+ offset = ((store_offset_t) disk_cache_info[index].block << log2_block_size)
+@@ -465,7 +465,7 @@ disk_pager_write_page (vm_offset_t page, void *buf)
+ assert (disk_cache_info[index].last_read
+ == disk_cache_info[index].block);
+ #endif
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+
+ if (offset + vm_page_size > dev_end)
+ length = dev_end - offset;
+@@ -526,9 +526,9 @@ disk_pager_notify_evict (vm_offset_t page)
+
+ ext2_debug ("(block %u)", index);
+
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+ disk_cache_info[index].flags &= ~DC_INCORE;
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+ }
+
+ /* Satisfy a pager read request for either the disk pager or file pager
+@@ -836,9 +836,9 @@
+ /* Hint index for which cache block to reuse next. */
+ int disk_cache_hint;
+ /* Lock for these structures. */
+-struct mutex disk_cache_lock;
++pthread_mutex_t disk_cache_lock;
+ /* Fired when a re-association is done. */
+-struct condition disk_cache_reassociation;
++pthread_cond_t disk_cache_reassociation;
+
+ /* Finish mapping initialization. */
+ static void
+@@ -848,8 +848,8 @@
+ ext2_panic ("Block size %d != vm_page_size %d",
+ block_size, vm_page_size);
+
+- mutex_init (&disk_cache_lock);
+- condition_init (&disk_cache_reassociation);
++ pthread_mutex_init (&disk_cache_lock, NULL);
++ pthread_cond_init (&disk_cache_reassociation, NULL);
+
+ /* Allocate space for block num -> in-memory pointer mapping. */
+ if (hurd_ihash_create (&disk_cache_bptr, HURD_IHASH_NO_LOCP))
+@@ -905,7 +905,7 @@
+
+ /* Return unused pages that are in core. */
+ int pending_begin = -1, pending_end = -1;
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+ for (index = 0; index < disk_cache_blocks; index++)
+ if (! (disk_cache_info[index].flags & (DC_DONT_REUSE & ~DC_INCORE))
+ && ! disk_cache_info[index].ref_count)
+@@ -916,13 +916,13 @@ disk_cache_return_unused (void)
+ /* Return previous region, if there is such, ... */
+ if (pending_end >= 0)
+ {
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+ pager_return_some (diskfs_disk_pager,
+ pending_begin * vm_page_size,
+ (pending_end - pending_begin)
+ * vm_page_size,
+ 1);
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+ }
+ /* ... and start new region. */
+ pending_begin = index;
+@@ -930,7 +930,7 @@ disk_cache_return_unused (void)
+ pending_end = index + 1;
+ }
+
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+
+ /* Return last region, if there is such. */
+ if (pending_end >= 0)
+@@ -958,7 +958,7 @@ disk_cache_block_ref (block_t block)
+
+ ext2_debug ("(%u)", block);
+
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+
+ bptr = hurd_ihash_find (disk_cache_bptr, block);
+ if (bptr)
+@@ -971,8 +971,8 @@
+ if (disk_cache_info[index].flags & DC_UNTOUCHED)
+ {
+ /* Wait re-association to finish. */
+- condition_wait (&disk_cache_reassociation, &disk_cache_lock);
+- mutex_unlock (&disk_cache_lock);
++ pthread_cond_wait (&disk_cache_reassociation, &disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+
+ #if 0
+ printf ("Re-association -- wait finished.\n");
+@@ -992,7 +992,7 @@
+ disk_cache_info[index].ref_count,
+ disk_cache_info[index].flags, bptr);
+
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+
+ return bptr;
+ }
+@@ -1030,7 +1030,7 @@ disk_cache_block_ref (block_t block)
+ {
+ ext2_debug ("flush %u -> %d", disk_cache_info[index].block, index);
+
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+
+ disk_cache_return_unused ();
+
+@@ -1050,9 +1050,9 @@ disk_cache_block_ref (block_t block)
+
+ #if 0 /* XXX: Let's see if this is needed at all. */
+
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+ pager_return_some (diskfs_disk_pager, bptr - disk_cache, vm_page_size, 1);
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+
+ /* Has someone used our bptr? Has someone mapped requested block
+ while we have unlocked disk_cache_lock? If so, environment has
+@@ -1060,7 +1060,7 @@ disk_cache_block_ref (block_t block)
+ if ((! (disk_cache_info[index].flags & DC_UNTOUCHED))
+ || hurd_ihash_find (disk_cache_bptr, block))
+ {
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+ return disk_cache_block_ref (block); /* tail recursion */
+ }
+
+@@ -1068,15 +1068,15 @@ disk_cache_block_ref (block_t block)
+
+ /* XXX: Use libpager internals. */
+
+- mutex_lock (&diskfs_disk_pager->interlock);
++ pthread_mutex_lock (&diskfs_disk_pager->interlock);
+ int page = (bptr - disk_cache) / vm_page_size;
+ assert (page >= 0);
+ int is_incore = (page < diskfs_disk_pager->pagemapsize
+ && (diskfs_disk_pager->pagemap[page] & PM_INCORE));
+- mutex_unlock (&diskfs_disk_pager->interlock);
++ pthread_mutex_unlock (&diskfs_disk_pager->interlock);
+ if (is_incore)
+ {
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+ printf ("INCORE\n");
+ return disk_cache_block_ref (block); /* tail recursion */
+ }
+@@ -1096,13 +1096,13 @@ disk_cache_block_ref (block_t block)
+ disk_cache_info[index].ref_count = 1;
+
+ /* All data structures are set up. */
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+
+ /* Try to read page. */
+ *(volatile char *) bptr;
+
+ /* Check if it's actually read. */
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+ if (disk_cache_info[index].flags & DC_UNTOUCHED)
+ /* It's not read. */
+ {
+@@ -1111,7 +1111,7 @@ disk_cache_block_ref (block_t block)
+ disk_cache_info[index].block = DC_NO_BLOCK;
+ disk_cache_info[index].flags &=~ DC_UNTOUCHED;
+ disk_cache_info[index].ref_count = 0;
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+
+ /* Prepare next time association of this page to succeed. */
+ pager_flush_some (diskfs_disk_pager, bptr - disk_cache,
+@@ -1124,10 +1124,10 @@ disk_cache_block_ref (block_t block)
+ /* Try again. */
+ return disk_cache_block_ref (block); /* tail recursion */
+ }
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+
+ /* Re-association was successful. */
+- condition_broadcast (&disk_cache_reassociation);
++ pthread_cond_broadcast (&disk_cache_reassociation);
+
+ ext2_debug ("(%u) = %p", block, bptr);
+ return bptr;
+@@ -1139,7 +1139,7 @@
+ {
+ int index;
+
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+ index = bptr_index (ptr);
+ assert (disk_cache_info[index].ref_count >= 1);
+ assert (disk_cache_info[index].ref_count + 1
+@@ -1149,7 +1149,7 @@ disk_cache_block_ref_ptr (void *ptr)
+ ptr,
+ disk_cache_info[index].ref_count,
+ disk_cache_info[index].flags);
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+ }
+
+ void
+@@ -1159,7 +1159,7 @@ disk_cache_block_deref (void *ptr)
+
+ assert (disk_cache <= ptr && ptr <= disk_cache + disk_cache_size);
+
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+ index = bptr_index (ptr);
+ ext2_debug ("(%p) (ref_count = %d, flags = 0x%x)",
+ ptr,
+@@ -1168,7 +1168,7 @@ disk_cache_block_deref (void *ptr)
+ assert (! (disk_cache_info[index].flags & DC_UNTOUCHED));
+ assert (disk_cache_info[index].ref_count >= 1);
+ disk_cache_info[index].ref_count--;
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+ }
+
+ /* Not used. */
+@@ -1179,13 +1179,13 @@ disk_cache_block_is_ref (block_t block)
+ int ref;
+ void *ptr;
+
+- mutex_lock (&disk_cache_lock);
++ pthread_mutex_lock (&disk_cache_lock);
+ ptr = hurd_ihash_find (disk_cache_bptr, block);
+ if (! ptr)
+ ref = 0;
+ else /* XXX: Should check for DC_UNTOUCHED too. */
+ ref = disk_cache_info[bptr_index (ptr)].ref_count;
+- mutex_unlock (&disk_cache_lock);
++ pthread_mutex_unlock (&disk_cache_lock);
+
+ return ref;
+ }
+diff --git a/libpager/data-return.c b/libpager/data-return.c
+index 24533e7..0d71db7 100644
+--- a/libpager/data-return.c
++++ b/libpager/data-return.c
+@@ -243,9 +243,9 @@ _pager_do_write_request (mach_port_t object,
+ /* Clear any error that is left. Notification on eviction
+ is used only to change association of page, so any
+ error may no longer be valid. */
+- mutex_lock (&p->interlock);
++ pthread_mutex_lock (&p->interlock);
+ *pm_entry = SET_PM_ERROR (SET_PM_NEXTERROR (*pm_entry, 0), 0);
+- mutex_unlock (&p->interlock);
++ pthread_mutex_unlock (&p->interlock);
+ }
+ }
+
diff --git a/debian/patches/external.patch b/debian/patches/external.patch
new file mode 100644
index 00000000..9cc2f088
--- /dev/null
+++ b/debian/patches/external.patch
@@ -0,0 +1,114 @@
+Include procfs, random, and DDE in the build
+
+Index: hurd-debian/Makefile
+===================================================================
+--- hurd-debian.orig/Makefile 2010-09-27 19:42:53.000000000 +0000
++++ hurd-debian/Makefile 2010-09-27 19:45:57.000000000 +0000
+@@ -31,7 +31,8 @@
+ # Hurd libraries
+ lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \
+ libpager libfshelp libdiskfs libtrivfs libps \
+- libnetfs libpipe libstore libhurdbugaddr libftpconn libcons
++ libnetfs libpipe libstore libhurdbugaddr libftpconn libcons \
++ libmachdev libbpf libddekit libhurd-slab
+
+ # Hurd programs
+ prog-subdirs = auth proc exec init term \
+@@ -40,7 +41,7 @@
+ login daemons boot console \
+ hostmux usermux ftpfs trans \
+ console-client utils sutils ufs-fsck ufs-utils \
+- benchmarks fstests
++ benchmarks fstests procfs random devnode
+
+ ifeq ($(HAVE_SUN_RPC),yes)
+ prog-subdirs += nfs nfsd
+--- hurd-debian.orig/Makeconf
++++ hurd-debian/Makeconf
+@@ -548,7 +548,7 @@ vpath %.defs $(top_srcdir)/hurd
+ # These we want to find in the libc include directory...
+ mach_defs_names = bootstrap exc mach mach4 \
+ mach_host mach_port mach_timer_reply memory_object \
+- memory_object_default notify
++ memory_object_default notify experimental
+ device_defs_names = dev_forward device device_reply device_request
+
+ mach_defs = $(addsuffix .defs,$(mach_defs_names))
+diff --git a/configure.ac b/configure.ac
+index 05b959b..68ec159 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -227,6 +227,12 @@ AC_SUBST(boot_store_types)dnl
+ AC_MSG_CHECKING(boot store types)
+ AC_MSG_RESULT($boot_store_types)
+
++AC_CHECK_LIB(pciaccess, pci_system_init, LIBPCIACCESS=-lpciaccess, LIBPCIACCESS=no)
++AC_SUBST(LIBPCIACCESS)
++if test "$LIBPCIACCESS" = "no"; then
++ AC_MSG_ERROR([libpciaccess must be install in order to use libddekit])
++fi
++
+ # Check for ncursesw, which is needed for the console-curses client.
+ hurd_LIB_NCURSESW
+
+Index: hurd-debian/procfs/Makefile
+===================================================================
+--- hurd-debian.orig/procfs/Makefile 2012-11-26 00:23:22.000000000 +0000
++++ hurd-debian/procfs/Makefile 2012-11-26 00:25:35.000000000 +0000
+@@ -1,26 +1,31 @@
+-TARGET = procfs
+-OBJS = procfs.o netfs.o procfs_dir.o \
+- process.o proclist.o rootdir.o dircat.o main.o
+-LIBS = -lnetfs -lps -lfshelp
++# Makefile - for procfs
++#
++# Copyright (C) 2008 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
++# published by the Free Software Foundation; either version 2, or (at
++# your option) any later version.
++#
++# This program 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.
++
++dir := procfs
++makemode := server
++
++target = procfs
++
++SRCS = procfs.c netfs.c procfs_dir.c process.c proclist.c rootdir.c dircat.c main.c
++LCLHDRS = dircat.h main.h process.h procfs.h procfs_dir.h proclist.h rootdir.h
++
++OBJS = $(SRCS:.c=.o)
++HURDLIBS = netfs fshelp iohelp ps ports ihash shouldbeinlibc
++OTHERLIBS = -lpthread
+
+-CC = gcc
+-CFLAGS = -Wall -g
+-CPPFLAGS =
+-LDFLAGS =
+-
+-ifdef PROFILE
+-CFLAGS= -g -pg
+-CPPFLAGS= -DPROFILE
+-LDFLAGS= -static
+-LIBS= -lnetfs -lfshelp -liohelp -lps -lports -lthreads -lihash -lshouldbeinlibc
+-endif
+-
+-CPPFLAGS += -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
+-
+-all: $(TARGET)
+-
+-$(TARGET): $(OBJS)
+- $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+-
+-clean:
+- $(RM) $(TARGET) $(OBJS)
++include ../Makeconf
diff --git a/debian/patches/hurd_console_startup.patch b/debian/patches/hurd_console_startup.patch
new file mode 100644
index 00000000..8e9301c8
--- /dev/null
+++ b/debian/patches/hurd_console_startup.patch
@@ -0,0 +1,32 @@
+Automatically startup the hurd console when enabled.
+---
+ daemons/runsystem.sh | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/daemons/runsystem.sh
++++ b/daemons/runsystem.sh
+@@ -127,10 +127,24 @@ while : ; do
+ trap "kill -$sig \${runttys_pid}" $sig
+ done
+
++ # Touch the first tty so that the Hurd console is certain to pick it
++ # and not some random other tty.
++ touch /dev/tty1
++
+ # This program reads /etc/ttys and starts the programs it says to.
+ ${RUNTTYS} &
+ runttys_pid=$!
+
++ # Startup the Hurd console if configured.
++ if [ -e /etc/default/hurd-console ]; then
++ unset DISPLAY KBD KBD_REPEAT MOUSE MOUSE_REPEAT SPEAKER
++ . /etc/default/hurd-console
++ fi
++ if [ "$ENABLE" = "true" ]; then
++ console ${DISPLAY} ${KBD} ${KBD_REPEAT} \
++ ${SPEAKER} ${MOUSE} ${MOUSE_REPEAT} -d current_vcs -c /dev/vcs
++ fi
++
+ # Wait for runttys to die, meanwhile handling trapped signals.
+ wait
+
diff --git a/debian/patches/init_try_runsystem.gnu.patch b/debian/patches/init_try_runsystem.gnu.patch
new file mode 100644
index 00000000..a8389b23
--- /dev/null
+++ b/debian/patches/init_try_runsystem.gnu.patch
@@ -0,0 +1,19 @@
+Also try runsystem.gnu
+
+---
+ daemons/console-run.c | 7 +++++++
+ init/init.c | 24 ++++++++++++++++++++----
+ 2 files changed, 27 insertions(+), 4 deletions(-)
+
+Index: hurd-debian/init/init.c
+===================================================================
+--- hurd-debian.orig/init/init.c 2012-11-26 00:23:25.000000000 +0000
++++ hurd-debian/init/init.c 2012-11-26 00:25:06.000000000 +0000
+@@ -1087,6 +1087,7 @@
+ static const char *const tries[] =
+ {
+ "/libexec/runsystem",
++ "/libexec/runsystem.gnu",
+ _PATH_BSHELL,
+ "/bin/shd", /* XXX */
+ };
diff --git a/debian/patches/libdde_addr_fix.patch b/debian/patches/libdde_addr_fix.patch
new file mode 100644
index 00000000..7d6af794
--- /dev/null
+++ b/debian/patches/libdde_addr_fix.patch
@@ -0,0 +1,37 @@
+commit 0c27922e4933ceb86644f4a9b1af212ffe5aad75
+Author: Eric Dumazet <eric.dumazet@gmail.com>
+Date: Mon Jun 8 03:49:24 2009 +0000
+
+ net: dev_addr_init() fix
+
+ commit f001fde5eadd915f4858d22ed70d7040f48767cf
+ (net: introduce a list of device addresses dev_addr_list (v6))
+ added one regression Vegard Nossum found in its testings.
+
+ With kmemcheck help, Vegard found some uninitialized memory
+ was read and reported to user, potentialy leaking kernel data.
+ ( thread can be found on http://lkml.org/lkml/2009/5/30/177 )
+
+ dev_addr_init() incorrectly uses sizeof() operator. We were
+ initializing one byte instead of MAX_ADDR_LEN bytes.
+
+ Reported-by: Vegard Nossum <vegard.nossum@gmail.com>
+ Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
+ Acked-by: Jiri Pirko <jpirko@redhat.com>
+ Signed-off-by: David S. Miller <davem@davemloft.net>
+
+diff --git a/net/core/dev.c b/net/core/dev.c
+index 4913089..81b392e 100644
+--- a/libdde_linux26/lib/src/net/core/dev.c
++++ b/libdde_linux26/lib/src/net/core/dev.c
+@@ -3577,8 +3577,8 @@ static int dev_addr_init(struct net_device *dev)
+ /* rtnl_mutex must be held here */
+
+ INIT_LIST_HEAD(&dev->dev_addr_list);
+- memset(addr, 0, sizeof(*addr));
+- err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, sizeof(*addr),
++ memset(addr, 0, sizeof(addr));
++ err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, sizeof(addr),
+ NETDEV_HW_ADDR_T_LAN);
+ if (!err) {
+ /*
diff --git a/debian/patches/libdde_addr_list.patch b/debian/patches/libdde_addr_list.patch
new file mode 100644
index 00000000..c1b4d96d
--- /dev/null
+++ b/debian/patches/libdde_addr_list.patch
@@ -0,0 +1,423 @@
+commit f001fde5eadd915f4858d22ed70d7040f48767cf
+Author: Jiri Pirko <jpirko@redhat.com>
+Date: Tue May 5 02:48:28 2009 +0000
+
+ net: introduce a list of device addresses dev_addr_list (v6)
+
+ v5 -> v6 (current):
+ -removed so far unused static functions
+ -corrected dev_addr_del_multiple to call del instead of add
+
+ v4 -> v5:
+ -added device address type (suggested by davem)
+ -removed refcounting (better to have simplier code then safe potentially few
+ bytes)
+
+ v3 -> v4:
+ -changed kzalloc to kmalloc in __hw_addr_add_ii()
+ -ASSERT_RTNL() avoided in dev_addr_flush() and dev_addr_init()
+
+ v2 -> v3:
+ -removed unnecessary rcu read locking
+ -moved dev_addr_flush() calling to ensure no null dereference of dev_addr
+
+ v1 -> v2:
+ -added forgotten ASSERT_RTNL to dev_addr_init and dev_addr_flush
+ -removed unnecessary rcu_read locking in dev_addr_init
+ -use compare_ether_addr_64bits instead of compare_ether_addr
+ -use L1_CACHE_BYTES as size for allocating struct netdev_hw_addr
+ -use call_rcu instead of rcu_synchronize
+ -moved is_etherdev_addr into __KERNEL__ ifdef
+
+ This patch introduces a new list in struct net_device and brings a set of
+ functions to handle the work with device address list. The list is a replacement
+ for the original dev_addr field and because in some situations there is need to
+ carry several device addresses with the net device. To be backward compatible,
+ dev_addr is made to point to the first member of the list so original drivers
+ sees no difference.
+
+ Signed-off-by: Jiri Pirko <jpirko@redhat.com>
+ Signed-off-by: David S. Miller <davem@davemloft.net>
+
+Index: hurd-debian/libdde_linux26/contrib/include/linux/etherdevice.h
+===================================================================
+--- hurd-debian.orig/libdde_linux26/contrib/include/linux/etherdevice.h 2012-04-16 00:26:43.000000000 +0000
++++ hurd-debian/libdde_linux26/contrib/include/linux/etherdevice.h 2012-04-16 00:34:43.000000000 +0000
+@@ -182,6 +182,33 @@
+ return compare_ether_addr(addr1, addr2);
+ #endif
+ }
++
++/**
++ * is_etherdev_addr - Tell if given Ethernet address belongs to the device.
++ * @dev: Pointer to a device structure
++ * @addr: Pointer to a six-byte array containing the Ethernet address
++ *
++ * Compare passed address with all addresses of the device. Return true if the
++ * address if one of the device addresses.
++ *
++ * Note that this function calls compare_ether_addr_64bits() so take care of
++ * the right padding.
++ */
++static inline bool is_etherdev_addr(const struct net_device *dev,
++ const u8 addr[6 + 2])
++{
++ struct netdev_hw_addr *ha;
++ int res = 1;
++
++ rcu_read_lock();
++ for_each_dev_addr(dev, ha) {
++ res = compare_ether_addr_64bits(addr, ha->addr);
++ if (!res)
++ break;
++ }
++ rcu_read_unlock();
++ return !res;
++}
+ #endif /* __KERNEL__ */
+
+ #endif /* _LINUX_ETHERDEVICE_H */
+Index: hurd-debian/libdde_linux26/contrib/include/linux/netdevice.h
+===================================================================
+--- hurd-debian.orig/libdde_linux26/contrib/include/linux/netdevice.h 2012-04-16 00:33:34.000000000 +0000
++++ hurd-debian/libdde_linux26/contrib/include/linux/netdevice.h 2012-04-16 00:34:43.000000000 +0000
+@@ -211,6 +211,16 @@
+ #define dmi_users da_users
+ #define dmi_gusers da_gusers
+
++struct netdev_hw_addr {
++ struct list_head list;
++ unsigned char addr[MAX_ADDR_LEN];
++ unsigned char type;
++#define NETDEV_HW_ADDR_T_LAN 1
++#define NETDEV_HW_ADDR_T_SAN 2
++#define NETDEV_HW_ADDR_T_SLAVE 3
++ struct rcu_head rcu_head;
++};
++
+ struct hh_cache
+ {
+ struct hh_cache *hh_next; /* Next entry */
+@@ -757,8 +767,11 @@
+ */
+ unsigned long last_rx; /* Time of last Rx */
+ /* Interface address info used in eth_type_trans() */
+- unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address, (before bcast
+- because most packets are unicast) */
++ unsigned char *dev_addr; /* hw address, (before bcast
++ because most packets are
++ unicast) */
++
++ struct list_head dev_addr_list; /* list of device hw addresses */
+
+ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
+
+@@ -1768,6 +1781,13 @@
+ spin_unlock_bh(&dev->addr_list_lock);
+ }
+
++/*
++ * dev_addr_list walker. Should be used only for read access. Call with
++ * rcu_read_lock held.
++ */
++#define for_each_dev_addr(dev, ha) \
++ list_for_each_entry_rcu(ha, &dev->dev_addr_list, list)
++
+ /* These functions live elsewhere (drivers/net/net_init.c, but related) */
+
+ extern void ether_setup(struct net_device *dev);
+@@ -1780,6 +1800,19 @@
+ alloc_netdev_mq(sizeof_priv, name, setup, 1)
+ extern int register_netdev(struct net_device *dev);
+ extern void unregister_netdev(struct net_device *dev);
++
++/* Functions used for device addresses handling */
++extern int dev_addr_add(struct net_device *dev, unsigned char *addr,
++ unsigned char addr_type);
++extern int dev_addr_del(struct net_device *dev, unsigned char *addr,
++ unsigned char addr_type);
++extern int dev_addr_add_multiple(struct net_device *to_dev,
++ struct net_device *from_dev,
++ unsigned char addr_type);
++extern int dev_addr_del_multiple(struct net_device *to_dev,
++ struct net_device *from_dev,
++ unsigned char addr_type);
++
+ /* Functions used for secondary unicast and multicast support */
+ extern void dev_set_rx_mode(struct net_device *dev);
+ extern void __dev_set_rx_mode(struct net_device *dev);
+Index: hurd-debian/libdde_linux26/lib/src/net/core/dev.c
+===================================================================
+--- hurd-debian.orig/libdde_linux26/lib/src/net/core/dev.c 2012-04-16 00:26:43.000000000 +0000
++++ hurd-debian/libdde_linux26/lib/src/net/core/dev.c 2012-04-16 00:34:43.000000000 +0000
+@@ -3397,6 +3397,252 @@
+ netif_addr_unlock_bh(dev);
+ }
+
++/* hw addresses list handling functions */
++
++static int __hw_addr_add(struct list_head *list, unsigned char *addr,
++ int addr_len, unsigned char addr_type)
++{
++ struct netdev_hw_addr *ha;
++ int alloc_size;
++
++ if (addr_len > MAX_ADDR_LEN)
++ return -EINVAL;
++
++ alloc_size = sizeof(*ha);
++ if (alloc_size < L1_CACHE_BYTES)
++ alloc_size = L1_CACHE_BYTES;
++ ha = kmalloc(alloc_size, GFP_ATOMIC);
++ if (!ha)
++ return -ENOMEM;
++ memcpy(ha->addr, addr, addr_len);
++ ha->type = addr_type;
++ list_add_tail_rcu(&ha->list, list);
++ return 0;
++}
++
++static void ha_rcu_free(struct rcu_head *head)
++{
++ struct netdev_hw_addr *ha;
++
++ ha = container_of(head, struct netdev_hw_addr, rcu_head);
++ kfree(ha);
++}
++
++static int __hw_addr_del_ii(struct list_head *list, unsigned char *addr,
++ int addr_len, unsigned char addr_type,
++ int ignore_index)
++{
++ struct netdev_hw_addr *ha;
++ int i = 0;
++
++ list_for_each_entry(ha, list, list) {
++ if (i++ != ignore_index &&
++ !memcmp(ha->addr, addr, addr_len) &&
++ (ha->type == addr_type || !addr_type)) {
++ list_del_rcu(&ha->list);
++ call_rcu(&ha->rcu_head, ha_rcu_free);
++ return 0;
++ }
++ }
++ return -ENOENT;
++}
++
++static int __hw_addr_add_multiple_ii(struct list_head *to_list,
++ struct list_head *from_list,
++ int addr_len, unsigned char addr_type,
++ int ignore_index)
++{
++ int err;
++ struct netdev_hw_addr *ha, *ha2;
++ unsigned char type;
++
++ list_for_each_entry(ha, from_list, list) {
++ type = addr_type ? addr_type : ha->type;
++ err = __hw_addr_add(to_list, ha->addr, addr_len, type);
++ if (err)
++ goto unroll;
++ }
++ return 0;
++
++unroll:
++ list_for_each_entry(ha2, from_list, list) {
++ if (ha2 == ha)
++ break;
++ type = addr_type ? addr_type : ha2->type;
++ __hw_addr_del_ii(to_list, ha2->addr, addr_len, type,
++ ignore_index);
++ }
++ return err;
++}
++
++static void __hw_addr_del_multiple_ii(struct list_head *to_list,
++ struct list_head *from_list,
++ int addr_len, unsigned char addr_type,
++ int ignore_index)
++{
++ struct netdev_hw_addr *ha;
++ unsigned char type;
++
++ list_for_each_entry(ha, from_list, list) {
++ type = addr_type ? addr_type : ha->type;
++ __hw_addr_del_ii(to_list, ha->addr, addr_len, addr_type,
++ ignore_index);
++ }
++}
++
++static void __hw_addr_flush(struct list_head *list)
++{
++ struct netdev_hw_addr *ha, *tmp;
++
++ list_for_each_entry_safe(ha, tmp, list, list) {
++ list_del_rcu(&ha->list);
++ call_rcu(&ha->rcu_head, ha_rcu_free);
++ }
++}
++
++/* Device addresses handling functions */
++
++static void dev_addr_flush(struct net_device *dev)
++{
++ /* rtnl_mutex must be held here */
++
++ __hw_addr_flush(&dev->dev_addr_list);
++ dev->dev_addr = NULL;
++}
++
++static int dev_addr_init(struct net_device *dev)
++{
++ unsigned char addr[MAX_ADDR_LEN];
++ struct netdev_hw_addr *ha;
++ int err;
++
++ /* rtnl_mutex must be held here */
++
++ INIT_LIST_HEAD(&dev->dev_addr_list);
++ memset(addr, 0, sizeof(*addr));
++ err = __hw_addr_add(&dev->dev_addr_list, addr, sizeof(*addr),
++ NETDEV_HW_ADDR_T_LAN);
++ if (!err) {
++ /*
++ * Get the first (previously created) address from the list
++ * and set dev_addr pointer to this location.
++ */
++ ha = list_first_entry(&dev->dev_addr_list,
++ struct netdev_hw_addr, list);
++ dev->dev_addr = ha->addr;
++ }
++ return err;
++}
++
++/**
++ * dev_addr_add - Add a device address
++ * @dev: device
++ * @addr: address to add
++ * @addr_type: address type
++ *
++ * Add a device address to the device or increase the reference count if
++ * it already exists.
++ *
++ * The caller must hold the rtnl_mutex.
++ */
++int dev_addr_add(struct net_device *dev, unsigned char *addr,
++ unsigned char addr_type)
++{
++ int err;
++
++ ASSERT_RTNL();
++
++ err = __hw_addr_add(&dev->dev_addr_list, addr, dev->addr_len,
++ addr_type);
++ if (!err)
++ call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
++ return err;
++}
++EXPORT_SYMBOL(dev_addr_add);
++
++/**
++ * dev_addr_del - Release a device address.
++ * @dev: device
++ * @addr: address to delete
++ * @addr_type: address type
++ *
++ * Release reference to a device address and remove it from the device
++ * if the reference count drops to zero.
++ *
++ * The caller must hold the rtnl_mutex.
++ */
++int dev_addr_del(struct net_device *dev, unsigned char *addr,
++ unsigned char addr_type)
++{
++ int err;
++
++ ASSERT_RTNL();
++
++ err = __hw_addr_del_ii(&dev->dev_addr_list, addr, dev->addr_len,
++ addr_type, 0);
++ if (!err)
++ call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
++ return err;
++}
++EXPORT_SYMBOL(dev_addr_del);
++
++/**
++ * dev_addr_add_multiple - Add device addresses from another device
++ * @to_dev: device to which addresses will be added
++ * @from_dev: device from which addresses will be added
++ * @addr_type: address type - 0 means type will be used from from_dev
++ *
++ * Add device addresses of the one device to another.
++ **
++ * The caller must hold the rtnl_mutex.
++ */
++int dev_addr_add_multiple(struct net_device *to_dev,
++ struct net_device *from_dev,
++ unsigned char addr_type)
++{
++ int err;
++
++ ASSERT_RTNL();
++
++ if (from_dev->addr_len != to_dev->addr_len)
++ return -EINVAL;
++ err = __hw_addr_add_multiple_ii(&to_dev->dev_addr_list,
++ &from_dev->dev_addr_list,
++ to_dev->addr_len, addr_type, 0);
++ if (!err)
++ call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
++ return err;
++}
++EXPORT_SYMBOL(dev_addr_add_multiple);
++
++/**
++ * dev_addr_del_multiple - Delete device addresses by another device
++ * @to_dev: device where the addresses will be deleted
++ * @from_dev: device by which addresses the addresses will be deleted
++ * @addr_type: address type - 0 means type will used from from_dev
++ *
++ * Deletes addresses in to device by the list of addresses in from device.
++ *
++ * The caller must hold the rtnl_mutex.
++ */
++int dev_addr_del_multiple(struct net_device *to_dev,
++ struct net_device *from_dev,
++ unsigned char addr_type)
++{
++ ASSERT_RTNL();
++
++ if (from_dev->addr_len != to_dev->addr_len)
++ return -EINVAL;
++ __hw_addr_del_multiple_ii(&to_dev->dev_addr_list,
++ &from_dev->dev_addr_list,
++ to_dev->addr_len, addr_type, 0);
++ call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
++ return 0;
++}
++EXPORT_SYMBOL(dev_addr_del_multiple);
++
++/* unicast and multicast addresses handling functions */
++
+ int __dev_addr_delete(struct dev_addr_list **list, int *count,
+ void *addr, int alen, int glbl)
+ {
+@@ -4737,6 +4983,7 @@
+
+ dev->gso_max_size = GSO_MAX_SIZE;
+
++ dev_addr_init(dev);
+ netdev_init_queues(dev);
+
+ INIT_LIST_HEAD(&dev->napi_list);
+@@ -4762,6 +5009,9 @@
+
+ kfree(dev->_tx);
+
++ /* Flush device addresses */
++ dev_addr_flush(dev);
++
+ list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
+ netif_napi_del(p);
+
diff --git a/debian/patches/libdde_devres.patch b/debian/patches/libdde_devres.patch
new file mode 100644
index 00000000..6c41cea1
--- /dev/null
+++ b/debian/patches/libdde_devres.patch
@@ -0,0 +1,366 @@
+--- /dev/null 2011-08-03 18:03:30.000000000 +0000
++++ b/libdde_linux26/contrib/lib/devres.c 2012-04-15 23:14:01.000000000 +0000
+@@ -0,0 +1,351 @@
++#include <linux/pci.h>
++#include <linux/io.h>
++#include <linux/module.h>
++
++void devm_ioremap_release(struct device *dev, void *res)
++{
++ iounmap(*(void __iomem **)res);
++}
++
++static int devm_ioremap_match(struct device *dev, void *res, void *match_data)
++{
++ return *(void **)res == match_data;
++}
++
++/**
++ * devm_ioremap - Managed ioremap()
++ * @dev: Generic device to remap IO address for
++ * @offset: BUS offset to map
++ * @size: Size of map
++ *
++ * Managed ioremap(). Map is automatically unmapped on driver detach.
++ */
++void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
++ unsigned long size)
++{
++ void __iomem **ptr, *addr;
++
++ ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
++ if (!ptr)
++ return NULL;
++
++ addr = ioremap(offset, size);
++ if (addr) {
++ *ptr = addr;
++ devres_add(dev, ptr);
++ } else
++ devres_free(ptr);
++
++ return addr;
++}
++EXPORT_SYMBOL(devm_ioremap);
++
++/**
++ * devm_ioremap_nocache - Managed ioremap_nocache()
++ * @dev: Generic device to remap IO address for
++ * @offset: BUS offset to map
++ * @size: Size of map
++ *
++ * Managed ioremap_nocache(). Map is automatically unmapped on driver
++ * detach.
++ */
++void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
++ unsigned long size)
++{
++ void __iomem **ptr, *addr;
++
++ ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
++ if (!ptr)
++ return NULL;
++
++ addr = ioremap_nocache(offset, size);
++ if (addr) {
++ *ptr = addr;
++ devres_add(dev, ptr);
++ } else
++ devres_free(ptr);
++
++ return addr;
++}
++EXPORT_SYMBOL(devm_ioremap_nocache);
++
++/**
++ * devm_iounmap - Managed iounmap()
++ * @dev: Generic device to unmap for
++ * @addr: Address to unmap
++ *
++ * Managed iounmap(). @addr must have been mapped using devm_ioremap*().
++ */
++void devm_iounmap(struct device *dev, void __iomem *addr)
++{
++ iounmap(addr);
++ WARN_ON(devres_destroy(dev, devm_ioremap_release, devm_ioremap_match,
++ (void *)addr));
++}
++EXPORT_SYMBOL(devm_iounmap);
++
++#ifdef CONFIG_HAS_IOPORT
++/*
++ * Generic iomap devres
++ */
++static void devm_ioport_map_release(struct device *dev, void *res)
++{
++ ioport_unmap(*(void __iomem **)res);
++}
++
++static int devm_ioport_map_match(struct device *dev, void *res,
++ void *match_data)
++{
++ return *(void **)res == match_data;
++}
++
++/**
++ * devm_ioport_map - Managed ioport_map()
++ * @dev: Generic device to map ioport for
++ * @port: Port to map
++ * @nr: Number of ports to map
++ *
++ * Managed ioport_map(). Map is automatically unmapped on driver
++ * detach.
++ */
++void __iomem * devm_ioport_map(struct device *dev, unsigned long port,
++ unsigned int nr)
++{
++ void __iomem **ptr, *addr;
++
++ ptr = devres_alloc(devm_ioport_map_release, sizeof(*ptr), GFP_KERNEL);
++ if (!ptr)
++ return NULL;
++
++ addr = ioport_map(port, nr);
++ if (addr) {
++ *ptr = addr;
++ devres_add(dev, ptr);
++ } else
++ devres_free(ptr);
++
++ return addr;
++}
++EXPORT_SYMBOL(devm_ioport_map);
++
++/**
++ * devm_ioport_unmap - Managed ioport_unmap()
++ * @dev: Generic device to unmap for
++ * @addr: Address to unmap
++ *
++ * Managed ioport_unmap(). @addr must have been mapped using
++ * devm_ioport_map().
++ */
++void devm_ioport_unmap(struct device *dev, void __iomem *addr)
++{
++ ioport_unmap(addr);
++ WARN_ON(devres_destroy(dev, devm_ioport_map_release,
++ devm_ioport_map_match, (void *)addr));
++}
++EXPORT_SYMBOL(devm_ioport_unmap);
++
++#ifdef CONFIG_PCI
++/*
++ * PCI iomap devres
++ */
++#define PCIM_IOMAP_MAX PCI_ROM_RESOURCE
++
++struct pcim_iomap_devres {
++ void __iomem *table[PCIM_IOMAP_MAX];
++};
++
++static void pcim_iomap_release(struct device *gendev, void *res)
++{
++ struct pci_dev *dev = container_of(gendev, struct pci_dev, dev);
++ struct pcim_iomap_devres *this = res;
++ int i;
++
++ for (i = 0; i < PCIM_IOMAP_MAX; i++)
++ if (this->table[i])
++ pci_iounmap(dev, this->table[i]);
++}
++
++/**
++ * pcim_iomap_table - access iomap allocation table
++ * @pdev: PCI device to access iomap table for
++ *
++ * Access iomap allocation table for @dev. If iomap table doesn't
++ * exist and @pdev is managed, it will be allocated. All iomaps
++ * recorded in the iomap table are automatically unmapped on driver
++ * detach.
++ *
++ * This function might sleep when the table is first allocated but can
++ * be safely called without context and guaranteed to succed once
++ * allocated.
++ */
++void __iomem * const * pcim_iomap_table(struct pci_dev *pdev)
++{
++ struct pcim_iomap_devres *dr, *new_dr;
++
++ dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL);
++ if (dr)
++ return dr->table;
++
++ new_dr = devres_alloc(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL);
++ if (!new_dr)
++ return NULL;
++ dr = devres_get(&pdev->dev, new_dr, NULL, NULL);
++ return dr->table;
++}
++EXPORT_SYMBOL(pcim_iomap_table);
++
++/**
++ * pcim_iomap - Managed pcim_iomap()
++ * @pdev: PCI device to iomap for
++ * @bar: BAR to iomap
++ * @maxlen: Maximum length of iomap
++ *
++ * Managed pci_iomap(). Map is automatically unmapped on driver
++ * detach.
++ */
++void __iomem * pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
++{
++ void __iomem **tbl;
++
++ BUG_ON(bar >= PCIM_IOMAP_MAX);
++
++ tbl = (void __iomem **)pcim_iomap_table(pdev);
++ if (!tbl || tbl[bar]) /* duplicate mappings not allowed */
++ return NULL;
++
++ tbl[bar] = pci_iomap(pdev, bar, maxlen);
++ return tbl[bar];
++}
++EXPORT_SYMBOL(pcim_iomap);
++
++/**
++ * pcim_iounmap - Managed pci_iounmap()
++ * @pdev: PCI device to iounmap for
++ * @addr: Address to unmap
++ *
++ * Managed pci_iounmap(). @addr must have been mapped using pcim_iomap().
++ */
++void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr)
++{
++ void __iomem **tbl;
++ int i;
++
++ pci_iounmap(pdev, addr);
++
++ tbl = (void __iomem **)pcim_iomap_table(pdev);
++ BUG_ON(!tbl);
++
++ for (i = 0; i < PCIM_IOMAP_MAX; i++)
++ if (tbl[i] == addr) {
++ tbl[i] = NULL;
++ return;
++ }
++ WARN_ON(1);
++}
++EXPORT_SYMBOL(pcim_iounmap);
++
++/**
++ * pcim_iomap_regions - Request and iomap PCI BARs
++ * @pdev: PCI device to map IO resources for
++ * @mask: Mask of BARs to request and iomap
++ * @name: Name used when requesting regions
++ *
++ * Request and iomap regions specified by @mask.
++ */
++int pcim_iomap_regions(struct pci_dev *pdev, u16 mask, const char *name)
++{
++ void __iomem * const *iomap;
++ int i, rc;
++
++ iomap = pcim_iomap_table(pdev);
++ if (!iomap)
++ return -ENOMEM;
++
++ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
++ unsigned long len;
++
++ if (!(mask & (1 << i)))
++ continue;
++
++ rc = -EINVAL;
++ len = pci_resource_len(pdev, i);
++ if (!len)
++ goto err_inval;
++
++ rc = pci_request_region(pdev, i, name);
++ if (rc)
++ goto err_inval;
++
++ rc = -ENOMEM;
++ if (!pcim_iomap(pdev, i, 0))
++ goto err_region;
++ }
++
++ return 0;
++
++ err_region:
++ pci_release_region(pdev, i);
++ err_inval:
++ while (--i >= 0) {
++ if (!(mask & (1 << i)))
++ continue;
++ pcim_iounmap(pdev, iomap[i]);
++ pci_release_region(pdev, i);
++ }
++
++ return rc;
++}
++EXPORT_SYMBOL(pcim_iomap_regions);
++
++/**
++ * pcim_iomap_regions_request_all - Request all BARs and iomap specified ones
++ * @pdev: PCI device to map IO resources for
++ * @mask: Mask of BARs to iomap
++ * @name: Name used when requesting regions
++ *
++ * Request all PCI BARs and iomap regions specified by @mask.
++ */
++int pcim_iomap_regions_request_all(struct pci_dev *pdev, u16 mask,
++ const char *name)
++{
++ int request_mask = ((1 << 6) - 1) & ~mask;
++ int rc;
++
++ rc = pci_request_selected_regions(pdev, request_mask, name);
++ if (rc)
++ return rc;
++
++ rc = pcim_iomap_regions(pdev, mask, name);
++ if (rc)
++ pci_release_selected_regions(pdev, request_mask);
++ return rc;
++}
++EXPORT_SYMBOL(pcim_iomap_regions_request_all);
++
++/**
++ * pcim_iounmap_regions - Unmap and release PCI BARs
++ * @pdev: PCI device to map IO resources for
++ * @mask: Mask of BARs to unmap and release
++ *
++ * Unamp and release regions specified by @mask.
++ */
++void pcim_iounmap_regions(struct pci_dev *pdev, u16 mask)
++{
++ void __iomem * const *iomap;
++ int i;
++
++ iomap = pcim_iomap_table(pdev);
++ if (!iomap)
++ return;
++
++ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
++ if (!(mask & (1 << i)))
++ continue;
++
++ pcim_iounmap(pdev, iomap[i]);
++ pci_release_region(pdev, i);
++ }
++}
++EXPORT_SYMBOL(pcim_iounmap_regions);
++#endif
++#endif
+diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile
+index 358196b..f7a64da 100644
+--- a/libdde_linux26/lib/src/Makefile
++++ b/libdde_linux26/lib/src/Makefile
+@@ -103,6 +103,7 @@ SRC_C_libdde_linux26.o.a += \
+ lib/crc32.c \
+ lib/ctype.c \
+ lib/cpumask.c \
++ lib/devres.c \
+ lib/find_next_bit.c \
+ lib/hexdump.c \
+ lib/idr.c \
diff --git a/debian/patches/libdde_dma_head.patch b/debian/patches/libdde_dma_head.patch
new file mode 100644
index 00000000..1a1c75fd
--- /dev/null
+++ b/debian/patches/libdde_dma_head.patch
@@ -0,0 +1,93 @@
+commit 042a53a9e437feaf2230dd2cadcecfae9c7bfe05
+Author: Eric Dumazet <eric.dumazet@gmail.com>
+Date: Fri Jun 5 04:04:16 2009 +0000
+
+ net: skb_shared_info optimization
+
+ skb_dma_unmap() is quite expensive for small packets,
+ because we use two different cache lines from skb_shared_info.
+
+ One to access nr_frags, one to access dma_maps[0]
+
+ Instead of dma_maps being an array of MAX_SKB_FRAGS + 1 elements,
+ let dma_head alone in a new dma_head field, close to nr_frags,
+ to reduce cache lines misses.
+
+ Tested on my dev machine (bnx2 & tg3 adapters), nice speedup !
+
+ Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
+ Signed-off-by: David S. Miller <davem@davemloft.net>
+
+Index: hurd-debian/libdde_linux26/contrib/include/linux/skbuff.h
+===================================================================
+--- hurd-debian.orig/libdde_linux26/contrib/include/linux/skbuff.h 2012-04-16 00:26:40.000000000 +0000
++++ hurd-debian/libdde_linux26/contrib/include/linux/skbuff.h 2012-04-16 00:34:56.000000000 +0000
+@@ -142,6 +142,9 @@
+ atomic_t dataref;
+ unsigned short nr_frags;
+ unsigned short gso_size;
++#ifdef CONFIG_HAS_DMA
++ dma_addr_t dma_head;
++#endif
+ /* Warning: this field is not always filled in (UFO)! */
+ unsigned short gso_segs;
+ unsigned short gso_type;
+@@ -152,7 +155,7 @@
+ struct sk_buff *frag_list;
+ skb_frag_t frags[MAX_SKB_FRAGS];
+ #ifdef CONFIG_HAS_DMA
+- dma_addr_t dma_maps[MAX_SKB_FRAGS + 1];
++ dma_addr_t dma_maps[MAX_SKB_FRAGS];
+ #endif
+ };
+
+Index: hurd-debian/libdde_linux26/contrib/net/core/skb_dma_map.c
+===================================================================
+--- hurd-debian.orig/libdde_linux26/contrib/net/core/skb_dma_map.c 2012-04-16 00:26:40.000000000 +0000
++++ hurd-debian/libdde_linux26/contrib/net/core/skb_dma_map.c 2012-04-16 00:34:56.000000000 +0000
+@@ -20,7 +20,7 @@
+ if (dma_mapping_error(dev, map))
+ goto out_err;
+
+- sp->dma_maps[0] = map;
++ sp->dma_head = map;
+ for (i = 0; i < sp->nr_frags; i++) {
+ skb_frag_t *fp = &sp->frags[i];
+
+@@ -28,7 +28,7 @@
+ fp->size, dir);
+ if (dma_mapping_error(dev, map))
+ goto unwind;
+- sp->dma_maps[i + 1] = map;
++ sp->dma_maps[i] = map;
+ }
+ sp->num_dma_maps = i + 1;
+
+@@ -38,10 +38,10 @@
+ while (--i >= 0) {
+ skb_frag_t *fp = &sp->frags[i];
+
+- dma_unmap_page(dev, sp->dma_maps[i + 1],
++ dma_unmap_page(dev, sp->dma_maps[i],
+ fp->size, dir);
+ }
+- dma_unmap_single(dev, sp->dma_maps[0],
++ dma_unmap_single(dev, sp->dma_head,
+ skb_headlen(skb), dir);
+ out_err:
+ return -ENOMEM;
+@@ -54,12 +54,12 @@
+ struct skb_shared_info *sp = skb_shinfo(skb);
+ int i;
+
+- dma_unmap_single(dev, sp->dma_maps[0],
++ dma_unmap_single(dev, sp->dma_head,
+ skb_headlen(skb), dir);
+ for (i = 0; i < sp->nr_frags; i++) {
+ skb_frag_t *fp = &sp->frags[i];
+
+- dma_unmap_page(dev, sp->dma_maps[i + 1],
++ dma_unmap_page(dev, sp->dma_maps[i],
+ fp->size, dir);
+ }
+ }
diff --git a/debian/patches/libdde_ethoc.patch b/debian/patches/libdde_ethoc.patch
new file mode 100644
index 00000000..eba5cdf5
--- /dev/null
+++ b/debian/patches/libdde_ethoc.patch
@@ -0,0 +1,25 @@
+--- /dev/null 2011-08-03 18:03:30.000000000 +0000
++++ b/libdde_linux26/contrib/include/net/ethoc.h 2012-04-15 22:19:57.000000000 +0000
+@@ -0,0 +1,22 @@
++/*
++ * linux/include/net/ethoc.h
++ *
++ * Copyright (C) 2008-2009 Avionic Design GmbH
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Written by Thierry Reding <thierry.reding@avionic-design.de>
++ */
++
++#ifndef LINUX_NET_ETHOC_H
++#define LINUX_NET_ETHOC_H 1
++
++struct ethoc_platform_data {
++ u8 hwaddr[IFHWADDRLEN];
++ s8 phy_id;
++};
++
++#endif /* !LINUX_NET_ETHOC_H */
++
diff --git a/debian/patches/libdde_ethtool.patch b/debian/patches/libdde_ethtool.patch
new file mode 100644
index 00000000..9e52d1b5
--- /dev/null
+++ b/debian/patches/libdde_ethtool.patch
@@ -0,0 +1,98 @@
+diff --git a/libdde_linux26/contrib/include/linux/ethtool.h b/libdde_linux26/contrib/include/linux/ethtool.h
+index 27c67a5..45f34dc 100644
+--- a/libdde_linux26/contrib/include/linux/ethtool.h
++++ b/libdde_linux26/contrib/include/linux/ethtool.h
+@@ -25,11 +25,14 @@ struct ethtool_cmd {
+ __u8 phy_address;
+ __u8 transceiver; /* Which transceiver to use */
+ __u8 autoneg; /* Enable or disable autonegotiation */
++ __u8 mdio_support;
+ __u32 maxtxpkt; /* Tx pkts before generating tx int */
+ __u32 maxrxpkt; /* Rx pkts before generating rx int */
+ __u16 speed_hi;
+- __u16 reserved2;
+- __u32 reserved[3];
++ __u8 eth_tp_mdix;
++ __u8 reserved2;
++ __u32 lp_advertising; /* Features the link partner advertises */
++ __u32 reserved[2];
+ };
+
+ static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep,
+@@ -469,6 +472,13 @@ struct ethtool_ops {
+ #define ETHTOOL_SRXFH 0x0000002a /* Set RX flow hash configuration */
+ #define ETHTOOL_GGRO 0x0000002b /* Get GRO enable (ethtool_value) */
+ #define ETHTOOL_SGRO 0x0000002c /* Set GRO enable (ethtool_value) */
++#define ETHTOOL_GRXRINGS 0x0000002d /* Get RX rings available for LB */
++#define ETHTOOL_GRXCLSRLCNT 0x0000002e /* Get RX class rule count */
++#define ETHTOOL_GRXCLSRULE 0x0000002f /* Get RX classification rule */
++#define ETHTOOL_GRXCLSRLALL 0x00000030 /* Get all RX classification rule */
++#define ETHTOOL_SRXCLSRLDEL 0x00000031 /* Delete RX classification rule */
++#define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */
++#define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */
+
+ /* compatibility with older code */
+ #define SPARC_ETH_GSET ETHTOOL_GSET
+@@ -491,6 +501,11 @@ struct ethtool_ops {
+ #define SUPPORTED_Pause (1 << 13)
+ #define SUPPORTED_Asym_Pause (1 << 14)
+ #define SUPPORTED_2500baseX_Full (1 << 15)
++#define SUPPORTED_Backplane (1 << 16)
++#define SUPPORTED_1000baseKX_Full (1 << 17)
++#define SUPPORTED_10000baseKX4_Full (1 << 18)
++#define SUPPORTED_10000baseKR_Full (1 << 19)
++#define SUPPORTED_10000baseR_FEC (1 << 20)
+
+ /* Indicates what features are advertised by the interface. */
+ #define ADVERTISED_10baseT_Half (1 << 0)
+@@ -509,6 +524,11 @@ struct ethtool_ops {
+ #define ADVERTISED_Pause (1 << 13)
+ #define ADVERTISED_Asym_Pause (1 << 14)
+ #define ADVERTISED_2500baseX_Full (1 << 15)
++#define ADVERTISED_Backplane (1 << 16)
++#define ADVERTISED_1000baseKX_Full (1 << 17)
++#define ADVERTISED_10000baseKX4_Full (1 << 18)
++#define ADVERTISED_10000baseKR_Full (1 << 19)
++#define ADVERTISED_10000baseR_FEC (1 << 20)
+
+ /* The following are all involved in forcing a particular link
+ * mode for the device for setting things. When getting the
+@@ -533,6 +553,7 @@ struct ethtool_ops {
+ #define PORT_MII 0x02
+ #define PORT_FIBRE 0x03
+ #define PORT_BNC 0x04
++#define PORT_OTHER 0xff
+
+ /* Which transceiver to use. */
+ #define XCVR_INTERNAL 0x00
+@@ -547,6 +568,11 @@ struct ethtool_ops {
+ #define AUTONEG_DISABLE 0x00
+ #define AUTONEG_ENABLE 0x01
+
++/* Mode MDI or MDI-X */
++#define ETH_TP_MDI_INVALID 0x00
++#define ETH_TP_MDI 0x01
++#define ETH_TP_MDI_X 0x02
++
+ /* Wake-On-Lan options. */
+ #define WAKE_PHY (1 << 0)
+ #define WAKE_UCAST (1 << 1)
+@@ -565,6 +591,11 @@ struct ethtool_ops {
+ #define UDP_V6_FLOW 0x06
+ #define SCTP_V6_FLOW 0x07
+ #define AH_ESP_V6_FLOW 0x08
++#define AH_V4_FLOW 0x09
++#define ESP_V4_FLOW 0x0a
++#define AH_V6_FLOW 0x0b
++#define ESP_V6_FLOW 0x0c
++#define IP_USER_FLOW 0x0d
+
+ /* L3-L4 network traffic flow hash options */
+ #define RXH_DEV_PORT (1 << 0)
+@@ -577,5 +608,6 @@ struct ethtool_ops {
+ #define RXH_L4_B_2_3 (1 << 7) /* dst port in case of TCP/UDP/SCTP */
+ #define RXH_DISCARD (1 << 31)
+
++#define RX_CLS_FLOW_DISC 0xffffffffffffffffULL
+
+ #endif /* _LINUX_ETHTOOL_H */
diff --git a/debian/patches/libdde_group_addr.patch b/debian/patches/libdde_group_addr.patch
new file mode 100644
index 00000000..2ea72715
--- /dev/null
+++ b/debian/patches/libdde_group_addr.patch
@@ -0,0 +1,429 @@
+commit 31278e71471399beaff9280737e52b47db4dc345
+Author: Jiri Pirko <jpirko@redhat.com>
+Date: Wed Jun 17 01:12:19 2009 +0000
+
+ net: group address list and its count
+
+ This patch is inspired by patch recently posted by Johannes Berg. Basically what
+ my patch does is to group list and a count of addresses into newly introduced
+ structure netdev_hw_addr_list. This brings us two benefits:
+ 1) struct net_device becames a bit nicer.
+ 2) in the future there will be a possibility to operate with lists independently
+ on netdevices (with exporting right functions).
+ I wanted to introduce this patch before I'll post a multicast lists conversion.
+
+ Signed-off-by: Jiri Pirko <jpirko@redhat.com>
+
+ drivers/net/bnx2.c | 4 +-
+ drivers/net/e1000/e1000_main.c | 4 +-
+ drivers/net/ixgbe/ixgbe_main.c | 6 +-
+ drivers/net/mv643xx_eth.c | 2 +-
+ drivers/net/niu.c | 4 +-
+ drivers/net/virtio_net.c | 10 ++--
+ drivers/s390/net/qeth_l2_main.c | 2 +-
+ include/linux/netdevice.h | 17 +++--
+ net/core/dev.c | 130 ++++++++++++++++++--------------------
+ 9 files changed, 89 insertions(+), 90 deletions(-)
+ Signed-off-by: David S. Miller <davem@davemloft.net>
+
+Index: hurd-debian/libdde_linux26/contrib/include/linux/netdevice.h
+===================================================================
+--- hurd-debian.orig/libdde_linux26/contrib/include/linux/netdevice.h 2012-04-16 00:34:46.000000000 +0000
++++ hurd-debian/libdde_linux26/contrib/include/linux/netdevice.h 2012-04-16 00:34:51.000000000 +0000
+@@ -224,6 +224,11 @@
+ struct rcu_head rcu_head;
+ };
+
++struct netdev_hw_addr_list {
++ struct list_head list;
++ int count;
++};
++
+ struct hh_cache
+ {
+ struct hh_cache *hh_next; /* Next entry */
+@@ -741,9 +746,8 @@
+ unsigned char addr_len; /* hardware address length */
+ unsigned short dev_id; /* for shared network cards */
+
+- struct list_head uc_list; /* Secondary unicast mac
+- addresses */
+- int uc_count; /* Number of installed ucasts */
++ struct netdev_hw_addr_list uc; /* Secondary unicast
++ mac addresses */
+ int uc_promisc;
+ spinlock_t addr_list_lock;
+ struct dev_addr_list *mc_list; /* Multicast mac addresses */
+@@ -775,7 +779,8 @@
+ because most packets are
+ unicast) */
+
+- struct list_head dev_addr_list; /* list of device hw addresses */
++ struct netdev_hw_addr_list dev_addrs; /* list of device
++ hw addresses */
+
+ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */
+
+@@ -1786,11 +1791,11 @@
+ }
+
+ /*
+- * dev_addr_list walker. Should be used only for read access. Call with
++ * dev_addrs walker. Should be used only for read access. Call with
+ * rcu_read_lock held.
+ */
+ #define for_each_dev_addr(dev, ha) \
+- list_for_each_entry_rcu(ha, &dev->dev_addr_list, list)
++ list_for_each_entry_rcu(ha, &dev->dev_addrs.list, list)
+
+ /* These functions live elsewhere (drivers/net/net_init.c, but related) */
+
+Index: hurd-debian/libdde_linux26/lib/src/net/core/dev.c
+===================================================================
+--- hurd-debian.orig/libdde_linux26/lib/src/net/core/dev.c 2012-04-16 00:34:49.000000000 +0000
++++ hurd-debian/libdde_linux26/lib/src/net/core/dev.c 2012-04-16 00:34:51.000000000 +0000
+@@ -3377,10 +3377,10 @@
+ /* Unicast addresses changes may only happen under the rtnl,
+ * therefore calling __dev_set_promiscuity here is safe.
+ */
+- if (dev->uc_count > 0 && !dev->uc_promisc) {
++ if (dev->uc.count > 0 && !dev->uc_promisc) {
+ __dev_set_promiscuity(dev, 1);
+ dev->uc_promisc = 1;
+- } else if (dev->uc_count == 0 && dev->uc_promisc) {
++ } else if (dev->uc.count == 0 && dev->uc_promisc) {
+ __dev_set_promiscuity(dev, -1);
+ dev->uc_promisc = 0;
+ }
+@@ -3399,9 +3399,8 @@
+
+ /* hw addresses list handling functions */
+
+-static int __hw_addr_add(struct list_head *list, int *delta,
+- unsigned char *addr, int addr_len,
+- unsigned char addr_type)
++static int __hw_addr_add(struct netdev_hw_addr_list *list, unsigned char *addr,
++ int addr_len, unsigned char addr_type)
+ {
+ struct netdev_hw_addr *ha;
+ int alloc_size;
+@@ -3409,7 +3408,7 @@
+ if (addr_len > MAX_ADDR_LEN)
+ return -EINVAL;
+
+- list_for_each_entry(ha, list, list) {
++ list_for_each_entry(ha, &list->list, list) {
+ if (!memcmp(ha->addr, addr, addr_len) &&
+ ha->type == addr_type) {
+ ha->refcount++;
+@@ -3428,9 +3427,8 @@
+ ha->type = addr_type;
+ ha->refcount = 1;
+ ha->synced = false;
+- list_add_tail_rcu(&ha->list, list);
+- if (delta)
+- (*delta)++;
++ list_add_tail_rcu(&ha->list, &list->list);
++ list->count++;
+ return 0;
+ }
+
+@@ -3442,120 +3440,121 @@
+ kfree(ha);
+ }
+
+-static int __hw_addr_del(struct list_head *list, int *delta,
+- unsigned char *addr, int addr_len,
+- unsigned char addr_type)
++static int __hw_addr_del(struct netdev_hw_addr_list *list, unsigned char *addr,
++ int addr_len, unsigned char addr_type)
+ {
+ struct netdev_hw_addr *ha;
+
+- list_for_each_entry(ha, list, list) {
++ list_for_each_entry(ha, &list->list, list) {
+ if (!memcmp(ha->addr, addr, addr_len) &&
+ (ha->type == addr_type || !addr_type)) {
+ if (--ha->refcount)
+ return 0;
+ list_del_rcu(&ha->list);
+ call_rcu(&ha->rcu_head, ha_rcu_free);
+- if (delta)
+- (*delta)--;
++ list->count--;
+ return 0;
+ }
+ }
+ return -ENOENT;
+ }
+
+-static int __hw_addr_add_multiple(struct list_head *to_list, int *to_delta,
+- struct list_head *from_list, int addr_len,
++static int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list,
++ struct netdev_hw_addr_list *from_list,
++ int addr_len,
+ unsigned char addr_type)
+ {
+ int err;
+ struct netdev_hw_addr *ha, *ha2;
+ unsigned char type;
+
+- list_for_each_entry(ha, from_list, list) {
++ list_for_each_entry(ha, &from_list->list, list) {
+ type = addr_type ? addr_type : ha->type;
+- err = __hw_addr_add(to_list, to_delta, ha->addr,
+- addr_len, type);
++ err = __hw_addr_add(to_list, ha->addr, addr_len, type);
+ if (err)
+ goto unroll;
+ }
+ return 0;
+
+ unroll:
+- list_for_each_entry(ha2, from_list, list) {
++ list_for_each_entry(ha2, &from_list->list, list) {
+ if (ha2 == ha)
+ break;
+ type = addr_type ? addr_type : ha2->type;
+- __hw_addr_del(to_list, to_delta, ha2->addr,
+- addr_len, type);
++ __hw_addr_del(to_list, ha2->addr, addr_len, type);
+ }
+ return err;
+ }
+
+-static void __hw_addr_del_multiple(struct list_head *to_list, int *to_delta,
+- struct list_head *from_list, int addr_len,
++static void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list,
++ struct netdev_hw_addr_list *from_list,
++ int addr_len,
+ unsigned char addr_type)
+ {
+ struct netdev_hw_addr *ha;
+ unsigned char type;
+
+- list_for_each_entry(ha, from_list, list) {
++ list_for_each_entry(ha, &from_list->list, list) {
+ type = addr_type ? addr_type : ha->type;
+- __hw_addr_del(to_list, to_delta, ha->addr,
+- addr_len, addr_type);
++ __hw_addr_del(to_list, ha->addr, addr_len, addr_type);
+ }
+ }
+
+-static int __hw_addr_sync(struct list_head *to_list, int *to_delta,
+- struct list_head *from_list, int *from_delta,
++static int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
++ struct netdev_hw_addr_list *from_list,
+ int addr_len)
+ {
+ int err = 0;
+ struct netdev_hw_addr *ha, *tmp;
+
+- list_for_each_entry_safe(ha, tmp, from_list, list) {
++ list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
+ if (!ha->synced) {
+- err = __hw_addr_add(to_list, to_delta, ha->addr,
++ err = __hw_addr_add(to_list, ha->addr,
+ addr_len, ha->type);
+ if (err)
+ break;
+ ha->synced = true;
+ ha->refcount++;
+ } else if (ha->refcount == 1) {
+- __hw_addr_del(to_list, to_delta, ha->addr,
+- addr_len, ha->type);
+- __hw_addr_del(from_list, from_delta, ha->addr,
+- addr_len, ha->type);
++ __hw_addr_del(to_list, ha->addr, addr_len, ha->type);
++ __hw_addr_del(from_list, ha->addr, addr_len, ha->type);
+ }
+ }
+ return err;
+ }
+
+-static void __hw_addr_unsync(struct list_head *to_list, int *to_delta,
+- struct list_head *from_list, int *from_delta,
++static void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
++ struct netdev_hw_addr_list *from_list,
+ int addr_len)
+ {
+ struct netdev_hw_addr *ha, *tmp;
+
+- list_for_each_entry_safe(ha, tmp, from_list, list) {
++ list_for_each_entry_safe(ha, tmp, &from_list->list, list) {
+ if (ha->synced) {
+- __hw_addr_del(to_list, to_delta, ha->addr,
++ __hw_addr_del(to_list, ha->addr,
+ addr_len, ha->type);
+ ha->synced = false;
+- __hw_addr_del(from_list, from_delta, ha->addr,
++ __hw_addr_del(from_list, ha->addr,
+ addr_len, ha->type);
+ }
+ }
+ }
+
+-
+-static void __hw_addr_flush(struct list_head *list)
++static void __hw_addr_flush(struct netdev_hw_addr_list *list)
+ {
+ struct netdev_hw_addr *ha, *tmp;
+
+- list_for_each_entry_safe(ha, tmp, list, list) {
++ list_for_each_entry_safe(ha, tmp, &list->list, list) {
+ list_del_rcu(&ha->list);
+ call_rcu(&ha->rcu_head, ha_rcu_free);
+ }
++ list->count = 0;
++}
++
++static void __hw_addr_init(struct netdev_hw_addr_list *list)
++{
++ INIT_LIST_HEAD(&list->list);
++ list->count = 0;
+ }
+
+ /* Device addresses handling functions */
+@@ -3564,7 +3563,7 @@
+ {
+ /* rtnl_mutex must be held here */
+
+- __hw_addr_flush(&dev->dev_addr_list);
++ __hw_addr_flush(&dev->dev_addrs);
+ dev->dev_addr = NULL;
+ }
+
+@@ -3576,16 +3575,16 @@
+
+ /* rtnl_mutex must be held here */
+
+- INIT_LIST_HEAD(&dev->dev_addr_list);
++ __hw_addr_init(&dev->dev_addrs);
+ memset(addr, 0, sizeof(addr));
+- err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, sizeof(addr),
++ err = __hw_addr_add(&dev->dev_addrs, addr, sizeof(addr),
+ NETDEV_HW_ADDR_T_LAN);
+ if (!err) {
+ /*
+ * Get the first (previously created) address from the list
+ * and set dev_addr pointer to this location.
+ */
+- ha = list_first_entry(&dev->dev_addr_list,
++ ha = list_first_entry(&dev->dev_addrs.list,
+ struct netdev_hw_addr, list);
+ dev->dev_addr = ha->addr;
+ }
+@@ -3610,8 +3609,7 @@
+
+ ASSERT_RTNL();
+
+- err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, dev->addr_len,
+- addr_type);
++ err = __hw_addr_add(&dev->dev_addrs, addr, dev->addr_len, addr_type);
+ if (!err)
+ call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+ return err;
+@@ -3641,11 +3639,12 @@
+ * We can not remove the first address from the list because
+ * dev->dev_addr points to that.
+ */
+- ha = list_first_entry(&dev->dev_addr_list, struct netdev_hw_addr, list);
++ ha = list_first_entry(&dev->dev_addrs.list,
++ struct netdev_hw_addr, list);
+ if (ha->addr == dev->dev_addr && ha->refcount == 1)
+ return -ENOENT;
+
+- err = __hw_addr_del(&dev->dev_addr_list, NULL, addr, dev->addr_len,
++ err = __hw_addr_del(&dev->dev_addrs, addr, dev->addr_len,
+ addr_type);
+ if (!err)
+ call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+@@ -3673,8 +3672,7 @@
+
+ if (from_dev->addr_len != to_dev->addr_len)
+ return -EINVAL;
+- err = __hw_addr_add_multiple(&to_dev->dev_addr_list, NULL,
+- &from_dev->dev_addr_list,
++ err = __hw_addr_add_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs,
+ to_dev->addr_len, addr_type);
+ if (!err)
+ call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
+@@ -3700,15 +3698,14 @@
+
+ if (from_dev->addr_len != to_dev->addr_len)
+ return -EINVAL;
+- __hw_addr_del_multiple(&to_dev->dev_addr_list, NULL,
+- &from_dev->dev_addr_list,
++ __hw_addr_del_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs,
+ to_dev->addr_len, addr_type);
+ call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
+ return 0;
+ }
+ EXPORT_SYMBOL(dev_addr_del_multiple);
+
+-/* unicast and multicast addresses handling functions */
++/* multicast addresses handling functions */
+
+ int __dev_addr_delete(struct dev_addr_list **list, int *count,
+ void *addr, int alen, int glbl)
+@@ -3784,8 +3781,8 @@
+
+ ASSERT_RTNL();
+
+- err = __hw_addr_del(&dev->uc_list, &dev->uc_count, addr,
+- dev->addr_len, NETDEV_HW_ADDR_T_UNICAST);
++ err = __hw_addr_del(&dev->uc, addr, dev->addr_len,
++ NETDEV_HW_ADDR_T_UNICAST);
+ if (!err)
+ __dev_set_rx_mode(dev);
+ return err;
+@@ -3808,8 +3805,8 @@
+
+ ASSERT_RTNL();
+
+- err = __hw_addr_add(&dev->uc_list, &dev->uc_count, addr,
+- dev->addr_len, NETDEV_HW_ADDR_T_UNICAST);
++ err = __hw_addr_add(&dev->uc, addr, dev->addr_len,
++ NETDEV_HW_ADDR_T_UNICAST);
+ if (!err)
+ __dev_set_rx_mode(dev);
+ return err;
+@@ -3882,8 +3879,7 @@
+ if (to->addr_len != from->addr_len)
+ return -EINVAL;
+
+- err = __hw_addr_sync(&to->uc_list, &to->uc_count,
+- &from->uc_list, &from->uc_count, to->addr_len);
++ err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len);
+ if (!err)
+ __dev_set_rx_mode(to);
+ return err;
+@@ -3906,8 +3902,7 @@
+ if (to->addr_len != from->addr_len)
+ return;
+
+- __hw_addr_unsync(&to->uc_list, &to->uc_count,
+- &from->uc_list, &from->uc_count, to->addr_len);
++ __hw_addr_unsync(&to->uc, &from->uc, to->addr_len);
+ __dev_set_rx_mode(to);
+ }
+ EXPORT_SYMBOL(dev_unicast_unsync);
+@@ -3916,15 +3911,14 @@
+ {
+ /* rtnl_mutex must be held here */
+
+- __hw_addr_flush(&dev->uc_list);
+- dev->uc_count = 0;
++ __hw_addr_flush(&dev->uc);
+ }
+
+ static void dev_unicast_init(struct net_device *dev)
+ {
+ /* rtnl_mutex must be held here */
+
+- INIT_LIST_HEAD(&dev->uc_list);
++ __hw_addr_init(&dev->uc);
+ }
+
+
diff --git a/debian/patches/libdde_mdio.patch b/debian/patches/libdde_mdio.patch
new file mode 100644
index 00000000..6c9b0c29
--- /dev/null
+++ b/debian/patches/libdde_mdio.patch
@@ -0,0 +1,359 @@
+--- /dev/null 2011-08-03 18:03:30.000000000 +0000
++++ b/libdde_linux26/contrib/include/linux/mdio.h 2012-04-15 22:16:31.000000000 +0000
+@@ -0,0 +1,356 @@
++/*
++ * linux/mdio.h: definitions for MDIO (clause 45) transceivers
++ * Copyright 2006-2009 Solarflare Communications Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ */
++
++#ifndef __LINUX_MDIO_H__
++#define __LINUX_MDIO_H__
++
++#include <linux/mii.h>
++
++/* MDIO Manageable Devices (MMDs). */
++#define MDIO_MMD_PMAPMD 1 /* Physical Medium Attachment/
++ * Physical Medium Dependent */
++#define MDIO_MMD_WIS 2 /* WAN Interface Sublayer */
++#define MDIO_MMD_PCS 3 /* Physical Coding Sublayer */
++#define MDIO_MMD_PHYXS 4 /* PHY Extender Sublayer */
++#define MDIO_MMD_DTEXS 5 /* DTE Extender Sublayer */
++#define MDIO_MMD_TC 6 /* Transmission Convergence */
++#define MDIO_MMD_AN 7 /* Auto-Negotiation */
++#define MDIO_MMD_C22EXT 29 /* Clause 22 extension */
++#define MDIO_MMD_VEND1 30 /* Vendor specific 1 */
++#define MDIO_MMD_VEND2 31 /* Vendor specific 2 */
++
++/* Generic MDIO registers. */
++#define MDIO_CTRL1 MII_BMCR
++#define MDIO_STAT1 MII_BMSR
++#define MDIO_DEVID1 MII_PHYSID1
++#define MDIO_DEVID2 MII_PHYSID2
++#define MDIO_SPEED 4 /* Speed ability */
++#define MDIO_DEVS1 5 /* Devices in package */
++#define MDIO_DEVS2 6
++#define MDIO_CTRL2 7 /* 10G control 2 */
++#define MDIO_STAT2 8 /* 10G status 2 */
++#define MDIO_PMA_TXDIS 9 /* 10G PMA/PMD transmit disable */
++#define MDIO_PMA_RXDET 10 /* 10G PMA/PMD receive signal detect */
++#define MDIO_PMA_EXTABLE 11 /* 10G PMA/PMD extended ability */
++#define MDIO_PKGID1 14 /* Package identifier */
++#define MDIO_PKGID2 15
++#define MDIO_AN_ADVERTISE 16 /* AN advertising (base page) */
++#define MDIO_AN_LPA 19 /* AN LP abilities (base page) */
++#define MDIO_PHYXS_LNSTAT 24 /* PHY XGXS lane state */
++
++/* Media-dependent registers. */
++#define MDIO_PMA_10GBT_SWAPPOL 130 /* 10GBASE-T pair swap & polarity */
++#define MDIO_PMA_10GBT_TXPWR 131 /* 10GBASE-T TX power control */
++#define MDIO_PMA_10GBT_SNR 133 /* 10GBASE-T SNR margin, lane A.
++ * Lanes B-D are numbered 134-136. */
++#define MDIO_PMA_10GBR_FECABLE 170 /* 10GBASE-R FEC ability */
++#define MDIO_PCS_10GBX_STAT1 24 /* 10GBASE-X PCS status 1 */
++#define MDIO_PCS_10GBRT_STAT1 32 /* 10GBASE-R/-T PCS status 1 */
++#define MDIO_PCS_10GBRT_STAT2 33 /* 10GBASE-R/-T PCS status 2 */
++#define MDIO_AN_10GBT_CTRL 32 /* 10GBASE-T auto-negotiation control */
++#define MDIO_AN_10GBT_STAT 33 /* 10GBASE-T auto-negotiation status */
++
++/* LASI (Link Alarm Status Interrupt) registers, defined by XENPAK MSA. */
++#define MDIO_PMA_LASI_RXCTRL 0x9000 /* RX_ALARM control */
++#define MDIO_PMA_LASI_TXCTRL 0x9001 /* TX_ALARM control */
++#define MDIO_PMA_LASI_CTRL 0x9002 /* LASI control */
++#define MDIO_PMA_LASI_RXSTAT 0x9003 /* RX_ALARM status */
++#define MDIO_PMA_LASI_TXSTAT 0x9004 /* TX_ALARM status */
++#define MDIO_PMA_LASI_STAT 0x9005 /* LASI status */
++
++/* Control register 1. */
++/* Enable extended speed selection */
++#define MDIO_CTRL1_SPEEDSELEXT (BMCR_SPEED1000 | BMCR_SPEED100)
++/* All speed selection bits */
++#define MDIO_CTRL1_SPEEDSEL (MDIO_CTRL1_SPEEDSELEXT | 0x003c)
++#define MDIO_CTRL1_FULLDPLX BMCR_FULLDPLX
++#define MDIO_CTRL1_LPOWER BMCR_PDOWN
++#define MDIO_CTRL1_RESET BMCR_RESET
++#define MDIO_PMA_CTRL1_LOOPBACK 0x0001
++#define MDIO_PMA_CTRL1_SPEED1000 BMCR_SPEED1000
++#define MDIO_PMA_CTRL1_SPEED100 BMCR_SPEED100
++#define MDIO_PCS_CTRL1_LOOPBACK BMCR_LOOPBACK
++#define MDIO_PHYXS_CTRL1_LOOPBACK BMCR_LOOPBACK
++#define MDIO_AN_CTRL1_RESTART BMCR_ANRESTART
++#define MDIO_AN_CTRL1_ENABLE BMCR_ANENABLE
++#define MDIO_AN_CTRL1_XNP 0x2000 /* Enable extended next page */
++
++/* 10 Gb/s */
++#define MDIO_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00)
++/* 10PASS-TS/2BASE-TL */
++#define MDIO_CTRL1_SPEED10P2B (MDIO_CTRL1_SPEEDSELEXT | 0x04)
++
++/* Status register 1. */
++#define MDIO_STAT1_LPOWERABLE 0x0002 /* Low-power ability */
++#define MDIO_STAT1_LSTATUS BMSR_LSTATUS
++#define MDIO_STAT1_FAULT 0x0080 /* Fault */
++#define MDIO_AN_STAT1_LPABLE 0x0001 /* Link partner AN ability */
++#define MDIO_AN_STAT1_ABLE BMSR_ANEGCAPABLE
++#define MDIO_AN_STAT1_RFAULT BMSR_RFAULT
++#define MDIO_AN_STAT1_COMPLETE BMSR_ANEGCOMPLETE
++#define MDIO_AN_STAT1_PAGE 0x0040 /* Page received */
++#define MDIO_AN_STAT1_XNP 0x0080 /* Extended next page status */
++
++/* Speed register. */
++#define MDIO_SPEED_10G 0x0001 /* 10G capable */
++#define MDIO_PMA_SPEED_2B 0x0002 /* 2BASE-TL capable */
++#define MDIO_PMA_SPEED_10P 0x0004 /* 10PASS-TS capable */
++#define MDIO_PMA_SPEED_1000 0x0010 /* 1000M capable */
++#define MDIO_PMA_SPEED_100 0x0020 /* 100M capable */
++#define MDIO_PMA_SPEED_10 0x0040 /* 10M capable */
++#define MDIO_PCS_SPEED_10P2B 0x0002 /* 10PASS-TS/2BASE-TL capable */
++
++/* Device present registers. */
++#define MDIO_DEVS_PRESENT(devad) (1 << (devad))
++#define MDIO_DEVS_PMAPMD MDIO_DEVS_PRESENT(MDIO_MMD_PMAPMD)
++#define MDIO_DEVS_WIS MDIO_DEVS_PRESENT(MDIO_MMD_WIS)
++#define MDIO_DEVS_PCS MDIO_DEVS_PRESENT(MDIO_MMD_PCS)
++#define MDIO_DEVS_PHYXS MDIO_DEVS_PRESENT(MDIO_MMD_PHYXS)
++#define MDIO_DEVS_DTEXS MDIO_DEVS_PRESENT(MDIO_MMD_DTEXS)
++#define MDIO_DEVS_TC MDIO_DEVS_PRESENT(MDIO_MMD_TC)
++#define MDIO_DEVS_AN MDIO_DEVS_PRESENT(MDIO_MMD_AN)
++#define MDIO_DEVS_C22EXT MDIO_DEVS_PRESENT(MDIO_MMD_C22EXT)
++
++/* Control register 2. */
++#define MDIO_PMA_CTRL2_TYPE 0x000f /* PMA/PMD type selection */
++#define MDIO_PMA_CTRL2_10GBCX4 0x0000 /* 10GBASE-CX4 type */
++#define MDIO_PMA_CTRL2_10GBEW 0x0001 /* 10GBASE-EW type */
++#define MDIO_PMA_CTRL2_10GBLW 0x0002 /* 10GBASE-LW type */
++#define MDIO_PMA_CTRL2_10GBSW 0x0003 /* 10GBASE-SW type */
++#define MDIO_PMA_CTRL2_10GBLX4 0x0004 /* 10GBASE-LX4 type */
++#define MDIO_PMA_CTRL2_10GBER 0x0005 /* 10GBASE-ER type */
++#define MDIO_PMA_CTRL2_10GBLR 0x0006 /* 10GBASE-LR type */
++#define MDIO_PMA_CTRL2_10GBSR 0x0007 /* 10GBASE-SR type */
++#define MDIO_PMA_CTRL2_10GBLRM 0x0008 /* 10GBASE-LRM type */
++#define MDIO_PMA_CTRL2_10GBT 0x0009 /* 10GBASE-T type */
++#define MDIO_PMA_CTRL2_10GBKX4 0x000a /* 10GBASE-KX4 type */
++#define MDIO_PMA_CTRL2_10GBKR 0x000b /* 10GBASE-KR type */
++#define MDIO_PMA_CTRL2_1000BT 0x000c /* 1000BASE-T type */
++#define MDIO_PMA_CTRL2_1000BKX 0x000d /* 1000BASE-KX type */
++#define MDIO_PMA_CTRL2_100BTX 0x000e /* 100BASE-TX type */
++#define MDIO_PMA_CTRL2_10BT 0x000f /* 10BASE-T type */
++#define MDIO_PCS_CTRL2_TYPE 0x0003 /* PCS type selection */
++#define MDIO_PCS_CTRL2_10GBR 0x0000 /* 10GBASE-R type */
++#define MDIO_PCS_CTRL2_10GBX 0x0001 /* 10GBASE-X type */
++#define MDIO_PCS_CTRL2_10GBW 0x0002 /* 10GBASE-W type */
++#define MDIO_PCS_CTRL2_10GBT 0x0003 /* 10GBASE-T type */
++
++/* Status register 2. */
++#define MDIO_STAT2_RXFAULT 0x0400 /* Receive fault */
++#define MDIO_STAT2_TXFAULT 0x0800 /* Transmit fault */
++#define MDIO_STAT2_DEVPRST 0xc000 /* Device present */
++#define MDIO_STAT2_DEVPRST_VAL 0x8000 /* Device present value */
++#define MDIO_PMA_STAT2_LBABLE 0x0001 /* PMA loopback ability */
++#define MDIO_PMA_STAT2_10GBEW 0x0002 /* 10GBASE-EW ability */
++#define MDIO_PMA_STAT2_10GBLW 0x0004 /* 10GBASE-LW ability */
++#define MDIO_PMA_STAT2_10GBSW 0x0008 /* 10GBASE-SW ability */
++#define MDIO_PMA_STAT2_10GBLX4 0x0010 /* 10GBASE-LX4 ability */
++#define MDIO_PMA_STAT2_10GBER 0x0020 /* 10GBASE-ER ability */
++#define MDIO_PMA_STAT2_10GBLR 0x0040 /* 10GBASE-LR ability */
++#define MDIO_PMA_STAT2_10GBSR 0x0080 /* 10GBASE-SR ability */
++#define MDIO_PMD_STAT2_TXDISAB 0x0100 /* PMD TX disable ability */
++#define MDIO_PMA_STAT2_EXTABLE 0x0200 /* Extended abilities */
++#define MDIO_PMA_STAT2_RXFLTABLE 0x1000 /* Receive fault ability */
++#define MDIO_PMA_STAT2_TXFLTABLE 0x2000 /* Transmit fault ability */
++#define MDIO_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R capable */
++#define MDIO_PCS_STAT2_10GBX 0x0002 /* 10GBASE-X capable */
++#define MDIO_PCS_STAT2_10GBW 0x0004 /* 10GBASE-W capable */
++#define MDIO_PCS_STAT2_RXFLTABLE 0x1000 /* Receive fault ability */
++#define MDIO_PCS_STAT2_TXFLTABLE 0x2000 /* Transmit fault ability */
++
++/* Transmit disable register. */
++#define MDIO_PMD_TXDIS_GLOBAL 0x0001 /* Global PMD TX disable */
++#define MDIO_PMD_TXDIS_0 0x0002 /* PMD TX disable 0 */
++#define MDIO_PMD_TXDIS_1 0x0004 /* PMD TX disable 1 */
++#define MDIO_PMD_TXDIS_2 0x0008 /* PMD TX disable 2 */
++#define MDIO_PMD_TXDIS_3 0x0010 /* PMD TX disable 3 */
++
++/* Receive signal detect register. */
++#define MDIO_PMD_RXDET_GLOBAL 0x0001 /* Global PMD RX signal detect */
++#define MDIO_PMD_RXDET_0 0x0002 /* PMD RX signal detect 0 */
++#define MDIO_PMD_RXDET_1 0x0004 /* PMD RX signal detect 1 */
++#define MDIO_PMD_RXDET_2 0x0008 /* PMD RX signal detect 2 */
++#define MDIO_PMD_RXDET_3 0x0010 /* PMD RX signal detect 3 */
++
++/* Extended abilities register. */
++#define MDIO_PMA_EXTABLE_10GCX4 0x0001 /* 10GBASE-CX4 ability */
++#define MDIO_PMA_EXTABLE_10GBLRM 0x0002 /* 10GBASE-LRM ability */
++#define MDIO_PMA_EXTABLE_10GBT 0x0004 /* 10GBASE-T ability */
++#define MDIO_PMA_EXTABLE_10GBKX4 0x0008 /* 10GBASE-KX4 ability */
++#define MDIO_PMA_EXTABLE_10GBKR 0x0010 /* 10GBASE-KR ability */
++#define MDIO_PMA_EXTABLE_1000BT 0x0020 /* 1000BASE-T ability */
++#define MDIO_PMA_EXTABLE_1000BKX 0x0040 /* 1000BASE-KX ability */
++#define MDIO_PMA_EXTABLE_100BTX 0x0080 /* 100BASE-TX ability */
++#define MDIO_PMA_EXTABLE_10BT 0x0100 /* 10BASE-T ability */
++
++/* PHY XGXS lane state register. */
++#define MDIO_PHYXS_LNSTAT_SYNC0 0x0001
++#define MDIO_PHYXS_LNSTAT_SYNC1 0x0002
++#define MDIO_PHYXS_LNSTAT_SYNC2 0x0004
++#define MDIO_PHYXS_LNSTAT_SYNC3 0x0008
++#define MDIO_PHYXS_LNSTAT_ALIGN 0x1000
++
++/* PMA 10GBASE-T pair swap & polarity */
++#define MDIO_PMA_10GBT_SWAPPOL_ABNX 0x0001 /* Pair A/B uncrossed */
++#define MDIO_PMA_10GBT_SWAPPOL_CDNX 0x0002 /* Pair C/D uncrossed */
++#define MDIO_PMA_10GBT_SWAPPOL_AREV 0x0100 /* Pair A polarity reversed */
++#define MDIO_PMA_10GBT_SWAPPOL_BREV 0x0200 /* Pair B polarity reversed */
++#define MDIO_PMA_10GBT_SWAPPOL_CREV 0x0400 /* Pair C polarity reversed */
++#define MDIO_PMA_10GBT_SWAPPOL_DREV 0x0800 /* Pair D polarity reversed */
++
++/* PMA 10GBASE-T TX power register. */
++#define MDIO_PMA_10GBT_TXPWR_SHORT 0x0001 /* Short-reach mode */
++
++/* PMA 10GBASE-T SNR registers. */
++/* Value is SNR margin in dB, clamped to range [-127, 127], plus 0x8000. */
++#define MDIO_PMA_10GBT_SNR_BIAS 0x8000
++#define MDIO_PMA_10GBT_SNR_MAX 127
++
++/* PMA 10GBASE-R FEC ability register. */
++#define MDIO_PMA_10GBR_FECABLE_ABLE 0x0001 /* FEC ability */
++#define MDIO_PMA_10GBR_FECABLE_ERRABLE 0x0002 /* FEC error indic. ability */
++
++/* PCS 10GBASE-R/-T status register 1. */
++#define MDIO_PCS_10GBRT_STAT1_BLKLK 0x0001 /* Block lock attained */
++
++/* PCS 10GBASE-R/-T status register 2. */
++#define MDIO_PCS_10GBRT_STAT2_ERR 0x00ff
++#define MDIO_PCS_10GBRT_STAT2_BER 0x3f00
++
++/* AN 10GBASE-T control register. */
++#define MDIO_AN_10GBT_CTRL_ADV10G 0x1000 /* Advertise 10GBASE-T */
++
++/* AN 10GBASE-T status register. */
++#define MDIO_AN_10GBT_STAT_LPTRR 0x0200 /* LP training reset req. */
++#define MDIO_AN_10GBT_STAT_LPLTABLE 0x0400 /* LP loop timing ability */
++#define MDIO_AN_10GBT_STAT_LP10G 0x0800 /* LP is 10GBT capable */
++#define MDIO_AN_10GBT_STAT_REMOK 0x1000 /* Remote OK */
++#define MDIO_AN_10GBT_STAT_LOCOK 0x2000 /* Local OK */
++#define MDIO_AN_10GBT_STAT_MS 0x4000 /* Master/slave config */
++#define MDIO_AN_10GBT_STAT_MSFLT 0x8000 /* Master/slave config fault */
++
++/* LASI RX_ALARM control/status registers. */
++#define MDIO_PMA_LASI_RX_PHYXSLFLT 0x0001 /* PHY XS RX local fault */
++#define MDIO_PMA_LASI_RX_PCSLFLT 0x0008 /* PCS RX local fault */
++#define MDIO_PMA_LASI_RX_PMALFLT 0x0010 /* PMA/PMD RX local fault */
++#define MDIO_PMA_LASI_RX_OPTICPOWERFLT 0x0020 /* RX optical power fault */
++#define MDIO_PMA_LASI_RX_WISLFLT 0x0200 /* WIS local fault */
++
++/* LASI TX_ALARM control/status registers. */
++#define MDIO_PMA_LASI_TX_PHYXSLFLT 0x0001 /* PHY XS TX local fault */
++#define MDIO_PMA_LASI_TX_PCSLFLT 0x0008 /* PCS TX local fault */
++#define MDIO_PMA_LASI_TX_PMALFLT 0x0010 /* PMA/PMD TX local fault */
++#define MDIO_PMA_LASI_TX_LASERPOWERFLT 0x0080 /* Laser output power fault */
++#define MDIO_PMA_LASI_TX_LASERTEMPFLT 0x0100 /* Laser temperature fault */
++#define MDIO_PMA_LASI_TX_LASERBICURRFLT 0x0200 /* Laser bias current fault */
++
++/* LASI control/status registers. */
++#define MDIO_PMA_LASI_LSALARM 0x0001 /* LS_ALARM enable/status */
++#define MDIO_PMA_LASI_TXALARM 0x0002 /* TX_ALARM enable/status */
++#define MDIO_PMA_LASI_RXALARM 0x0004 /* RX_ALARM enable/status */
++
++/* Mapping between MDIO PRTAD/DEVAD and mii_ioctl_data::phy_id */
++
++#define MDIO_PHY_ID_C45 0x8000
++#define MDIO_PHY_ID_PRTAD 0x03e0
++#define MDIO_PHY_ID_DEVAD 0x001f
++#define MDIO_PHY_ID_C45_MASK \
++ (MDIO_PHY_ID_C45 | MDIO_PHY_ID_PRTAD | MDIO_PHY_ID_DEVAD)
++
++static inline __u16 mdio_phy_id_c45(int prtad, int devad)
++{
++ return MDIO_PHY_ID_C45 | (prtad << 5) | devad;
++}
++
++static inline bool mdio_phy_id_is_c45(int phy_id)
++{
++ return (phy_id & MDIO_PHY_ID_C45) && !(phy_id & ~MDIO_PHY_ID_C45_MASK);
++}
++
++static inline __u16 mdio_phy_id_prtad(int phy_id)
++{
++ return (phy_id & MDIO_PHY_ID_PRTAD) >> 5;
++}
++
++static inline __u16 mdio_phy_id_devad(int phy_id)
++{
++ return phy_id & MDIO_PHY_ID_DEVAD;
++}
++
++#define MDIO_SUPPORTS_C22 1
++#define MDIO_SUPPORTS_C45 2
++
++#ifdef __KERNEL__
++
++/**
++ * struct mdio_if_info - Ethernet controller MDIO interface
++ * @prtad: PRTAD of the PHY (%MDIO_PRTAD_NONE if not present/unknown)
++ * @mmds: Mask of MMDs expected to be present in the PHY. This must be
++ * non-zero unless @prtad = %MDIO_PRTAD_NONE.
++ * @mode_support: MDIO modes supported. If %MDIO_SUPPORTS_C22 is set then
++ * MII register access will be passed through with @devad =
++ * %MDIO_DEVAD_NONE. If %MDIO_EMULATE_C22 is set then access to
++ * commonly used clause 22 registers will be translated into
++ * clause 45 registers.
++ * @dev: Net device structure
++ * @mdio_read: Register read function; returns value or negative error code
++ * @mdio_write: Register write function; returns 0 or negative error code
++ */
++struct mdio_if_info {
++ int prtad;
++ u32 mmds;
++ unsigned mode_support;
++
++ struct net_device *dev;
++ int (*mdio_read)(struct net_device *dev, int prtad, int devad,
++ u16 addr);
++ int (*mdio_write)(struct net_device *dev, int prtad, int devad,
++ u16 addr, u16 val);
++};
++
++#define MDIO_PRTAD_NONE (-1)
++#define MDIO_DEVAD_NONE (-1)
++#define MDIO_EMULATE_C22 4
++
++struct ethtool_cmd;
++struct ethtool_pauseparam;
++extern int mdio45_probe(struct mdio_if_info *mdio, int prtad);
++extern int mdio_set_flag(const struct mdio_if_info *mdio,
++ int prtad, int devad, u16 addr, int mask,
++ bool sense);
++extern int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmds);
++extern int mdio45_nway_restart(const struct mdio_if_info *mdio);
++extern void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
++ struct ethtool_cmd *ecmd,
++ u32 npage_adv, u32 npage_lpa);
++extern void
++mdio45_ethtool_spauseparam_an(const struct mdio_if_info *mdio,
++ const struct ethtool_pauseparam *ecmd);
++
++/**
++ * mdio45_ethtool_gset - get settings for ETHTOOL_GSET
++ * @mdio: MDIO interface
++ * @ecmd: Ethtool request structure
++ *
++ * Since the CSRs for auto-negotiation using next pages are not fully
++ * standardised, this function does not attempt to decode them. Use
++ * mdio45_ethtool_gset_npage() to specify advertisement bits from next
++ * pages.
++ */
++static inline void mdio45_ethtool_gset(const struct mdio_if_info *mdio,
++ struct ethtool_cmd *ecmd)
++{
++ mdio45_ethtool_gset_npage(mdio, ecmd, 0, 0);
++}
++
++extern int mdio_mii_ioctl(const struct mdio_if_info *mdio,
++ struct mii_ioctl_data *mii_data, int cmd);
++
++#endif /* __KERNEL__ */
++#endif /* __LINUX_MDIO_H__ */
diff --git a/debian/patches/libdde_netdev_tx_t.patch b/debian/patches/libdde_netdev_tx_t.patch
new file mode 100644
index 00000000..73ff710c
--- /dev/null
+++ b/debian/patches/libdde_netdev_tx_t.patch
@@ -0,0 +1,66 @@
+commit dc1f8bf68b311b1537cb65893430b6796118498a
+Author: Stephen Hemminger <shemminger@vyatta.com>
+Date: Mon Aug 31 19:50:40 2009 +0000
+
+ netdev: change transmit to limited range type
+
+ The transmit function should only return one of three possible values,
+ some drivers got confused and returned errno's or other values.
+ This changes the definition so that this can be caught at compile time.
+
+ Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
+ Signed-off-by: David S. Miller <davem@davemloft.net>
+
+diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
+index 60d3aac..376a2e1 100644
+--- a/libdde_linux26/contrib/include/linux/netdevice.h
++++ b/libdde_linux26/contrib/include/linux/netdevice.h
+@@ -79,17 +79,19 @@ struct wireless_dev;
+ #define net_xmit_eval(e) ((e) == NET_XMIT_CN? 0 : (e))
+ #define net_xmit_errno(e) ((e) != NET_XMIT_CN ? -ENOBUFS : 0)
+
++/* Driver transmit return codes */
++enum netdev_tx {
++ NETDEV_TX_OK = 0, /* driver took care of packet */
++ NETDEV_TX_BUSY, /* driver tx path was busy*/
++ NETDEV_TX_LOCKED = -1, /* driver tx lock was already taken */
++};
++typedef enum netdev_tx netdev_tx_t;
++
+ #endif
+
+ #define MAX_ADDR_LEN 32 /* Largest hardware address length */
+
+-/* Driver transmit return codes */
+-#define NETDEV_TX_OK 0 /* driver took care of packet */
+-#define NETDEV_TX_BUSY 1 /* driver tx path was busy*/
+-#define NETDEV_TX_LOCKED -1 /* driver tx lock was already taken */
+-
+ #ifdef __KERNEL__
+-
+ /*
+ * Compute the worst case header length according to the protocols
+ * used.
+@@ -507,9 +509,11 @@ struct netdev_queue {
+ * This function is called when network device transistions to the down
+ * state.
+ *
+- * int (*ndo_start_xmit)(struct sk_buff *skb, struct net_device *dev);
++ * netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb,
++ * struct net_device *dev);
+ * Called when a packet needs to be transmitted.
+- * Must return NETDEV_TX_OK , NETDEV_TX_BUSY, or NETDEV_TX_LOCKED,
++ * Must return NETDEV_TX_OK , NETDEV_TX_BUSY.
++ * (can also return NETDEV_TX_LOCKED iff NETIF_F_LLTX)
+ * Required can not be NULL.
+ *
+ * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb);
+@@ -580,7 +584,7 @@ struct net_device_ops {
+ void (*ndo_uninit)(struct net_device *dev);
+ int (*ndo_open)(struct net_device *dev);
+ int (*ndo_stop)(struct net_device *dev);
+- int (*ndo_start_xmit) (struct sk_buff *skb,
++ netdev_tx_t (*ndo_start_xmit) (struct sk_buff *skb,
+ struct net_device *dev);
+ u16 (*ndo_select_queue)(struct net_device *dev,
+ struct sk_buff *skb);
diff --git a/debian/patches/libdde_pci-needs_freset.patch b/debian/patches/libdde_pci-needs_freset.patch
new file mode 100644
index 00000000..cc1f6aed
--- /dev/null
+++ b/debian/patches/libdde_pci-needs_freset.patch
@@ -0,0 +1,39 @@
+commit 260d703adc5f275e3ba7ddff6e2e0217bc613b35
+Author: Mike Mason <mmlnx@us.ibm.com>
+Date: Thu Jul 30 15:33:21 2009 -0700
+
+ PCI: support for PCI Express fundamental reset
+
+ This is the first of three patches that implement a bit field that PCI
+ Express device drivers can use to indicate they need a fundamental reset
+ during error recovery.
+
+ By default, the EEH framework on powerpc does what's known as a "hot
+ reset" during recovery of a PCI Express device. We've found a case
+ where the device needs a "fundamental reset" to recover properly. The
+ current PCI error recovery and EEH frameworks do not support this
+ distinction.
+
+ The attached patch (courtesy of Richard Lary) adds a bit field to
+ pci_dev that indicates whether the device requires a fundamental reset
+ during recovery.
+
+ These patches supersede the previously submitted patch that implemented
+ a fundamental reset bit field.
+
+ Signed-off-by: Mike Mason <mmlnx@us.ibm.com>
+ Signed-off-by: Richard Lary <rlary@us.ibm.com>
+ Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
+
+Index: hurd-debian/libdde_linux26/contrib/include/linux/pci.h
+===================================================================
+--- hurd-debian.orig/libdde_linux26/contrib/include/linux/pci.h 2012-04-16 00:26:44.000000000 +0000
++++ hurd-debian/libdde_linux26/contrib/include/linux/pci.h 2012-04-16 00:34:37.000000000 +0000
+@@ -256,6 +256,7 @@
+ unsigned int ari_enabled:1; /* ARI forwarding */
+ unsigned int is_managed:1;
+ unsigned int is_pcie:1;
++ unsigned int needs_freset:1; /* Dev requires fundamental reset */
+ unsigned int state_saved:1;
+ pci_dev_flags_t dev_flags;
+ atomic_t enable_cnt; /* pci_enable_device has been called */
diff --git a/debian/patches/libdde_pci_ids.h.patch b/debian/patches/libdde_pci_ids.h.patch
new file mode 100644
index 00000000..df63d98d
--- /dev/null
+++ b/debian/patches/libdde_pci_ids.h.patch
@@ -0,0 +1,515 @@
+--- a/libdde_linux26/contrib/include/linux/pci_ids.h 2012-04-15 20:31:32.000000000 +0000
++++ b/libdde_linux26/contrib/include/linux/pci_ids.h 2012-03-17 10:14:52.000000000 +0000
+@@ -2,6 +2,9 @@
+ * PCI Class, Vendor and Device IDs
+ *
+ * Please keep sorted.
++ *
++ * Do not add new entries to this file unless the definitions
++ * are shared between multiple drivers.
+ */
+
+ /* Device classes and subclasses */
+@@ -104,6 +107,7 @@
+ #define PCI_CLASS_SERIAL_USB_UHCI 0x0c0300
+ #define PCI_CLASS_SERIAL_USB_OHCI 0x0c0310
+ #define PCI_CLASS_SERIAL_USB_EHCI 0x0c0320
++#define PCI_CLASS_SERIAL_USB_XHCI 0x0c0330
+ #define PCI_CLASS_SERIAL_FIBER 0x0c04
+ #define PCI_CLASS_SERIAL_SMBUS 0x0c05
+
+@@ -389,6 +393,9 @@
+ #define PCI_DEVICE_ID_VLSI_82C147 0x0105
+ #define PCI_DEVICE_ID_VLSI_VAS96011 0x0702
+
++/* AMD RD890 Chipset */
++#define PCI_DEVICE_ID_RD890_IOMMU 0x5a23
++
+ #define PCI_VENDOR_ID_ADL 0x1005
+ #define PCI_DEVICE_ID_ADL_2301 0x2301
+
+@@ -478,6 +485,9 @@
+ #define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE 0x0361
+ #define PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL 0x252
+
++#define PCI_SUBVENDOR_ID_IBM 0x1014
++#define PCI_SUBDEVICE_ID_IBM_SATURN_SERIAL_ONE_PORT 0x03d4
++
+ #define PCI_VENDOR_ID_UNISYS 0x1018
+ #define PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR 0x001C
+
+@@ -526,6 +536,7 @@
+ #define PCI_DEVICE_ID_AMD_OPUS_7443 0x7443
+ #define PCI_DEVICE_ID_AMD_VIPER_7443 0x7443
+ #define PCI_DEVICE_ID_AMD_OPUS_7445 0x7445
++#define PCI_DEVICE_ID_AMD_8111_PCI 0x7460
+ #define PCI_DEVICE_ID_AMD_8111_LPC 0x7468
+ #define PCI_DEVICE_ID_AMD_8111_IDE 0x7469
+ #define PCI_DEVICE_ID_AMD_8111_SMBUS2 0x746a
+@@ -535,6 +546,8 @@
+ #define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450
+ #define PCI_DEVICE_ID_AMD_8131_APIC 0x7451
+ #define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458
++#define PCI_DEVICE_ID_AMD_HUDSON2_SMBUS 0x780b
++#define PCI_DEVICE_ID_AMD_CS5535_IDE 0x208F
+ #define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090
+ #define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091
+ #define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093
+@@ -543,9 +556,10 @@
+ #define PCI_DEVICE_ID_AMD_CS5536_UDC 0x2096
+ #define PCI_DEVICE_ID_AMD_CS5536_UOC 0x2097
+ #define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A
+-
+ #define PCI_DEVICE_ID_AMD_LX_VIDEO 0x2081
+ #define PCI_DEVICE_ID_AMD_LX_AES 0x2082
++#define PCI_DEVICE_ID_AMD_HUDSON2_IDE 0x780c
++#define PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE 0x7800
+
+ #define PCI_VENDOR_ID_TRIDENT 0x1023
+ #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000
+@@ -591,6 +605,8 @@
+ #define PCI_DEVICE_ID_MATROX_G550 0x2527
+ #define PCI_DEVICE_ID_MATROX_VIA 0x4536
+
++#define PCI_VENDOR_ID_MOBILITY_ELECTRONICS 0x14f2
++
+ #define PCI_VENDOR_ID_CT 0x102c
+ #define PCI_DEVICE_ID_CT_69000 0x00c0
+ #define PCI_DEVICE_ID_CT_65545 0x00d8
+@@ -766,6 +782,7 @@
+ #define PCI_DEVICE_ID_TI_X515 0x8036
+ #define PCI_DEVICE_ID_TI_XX12 0x8039
+ #define PCI_DEVICE_ID_TI_XX12_FM 0x803b
++#define PCI_DEVICE_ID_TI_XIO2000A 0x8231
+ #define PCI_DEVICE_ID_TI_1130 0xac12
+ #define PCI_DEVICE_ID_TI_1031 0xac13
+ #define PCI_DEVICE_ID_TI_1131 0xac15
+@@ -834,6 +851,8 @@
+ #define PCI_DEVICE_ID_PROMISE_20276 0x5275
+ #define PCI_DEVICE_ID_PROMISE_20277 0x7275
+
++#define PCI_VENDOR_ID_FOXCONN 0x105b
++
+ #define PCI_VENDOR_ID_UMC 0x1060
+ #define PCI_DEVICE_ID_UMC_UM8673F 0x0101
+ #define PCI_DEVICE_ID_UMC_UM8886BF 0x673a
+@@ -873,6 +892,7 @@
+ #define PCI_DEVICE_ID_APPLE_SH_SUNGEM 0x0051
+ #define PCI_DEVICE_ID_APPLE_U3L_AGP 0x0058
+ #define PCI_DEVICE_ID_APPLE_U3H_AGP 0x0059
++#define PCI_DEVICE_ID_APPLE_U4_PCIE 0x005b
+ #define PCI_DEVICE_ID_APPLE_IPID2_AGP 0x0066
+ #define PCI_DEVICE_ID_APPLE_IPID2_ATA 0x0069
+ #define PCI_DEVICE_ID_APPLE_IPID2_FW 0x006a
+@@ -941,6 +961,32 @@
+ #define PCI_DEVICE_ID_SUN_TOMATILLO 0xa801
+ #define PCI_DEVICE_ID_SUN_CASSINI 0xabba
+
++#define PCI_VENDOR_ID_NI 0x1093
++#define PCI_DEVICE_ID_NI_PCI2322 0xd130
++#define PCI_DEVICE_ID_NI_PCI2324 0xd140
++#define PCI_DEVICE_ID_NI_PCI2328 0xd150
++#define PCI_DEVICE_ID_NI_PXI8422_2322 0xd190
++#define PCI_DEVICE_ID_NI_PXI8422_2324 0xd1a0
++#define PCI_DEVICE_ID_NI_PXI8420_2322 0xd1d0
++#define PCI_DEVICE_ID_NI_PXI8420_2324 0xd1e0
++#define PCI_DEVICE_ID_NI_PXI8420_2328 0xd1f0
++#define PCI_DEVICE_ID_NI_PXI8420_23216 0xd1f1
++#define PCI_DEVICE_ID_NI_PCI2322I 0xd250
++#define PCI_DEVICE_ID_NI_PCI2324I 0xd270
++#define PCI_DEVICE_ID_NI_PCI23216 0xd2b0
++#define PCI_DEVICE_ID_NI_PXI8430_2322 0x7080
++#define PCI_DEVICE_ID_NI_PCI8430_2322 0x70db
++#define PCI_DEVICE_ID_NI_PXI8430_2324 0x70dd
++#define PCI_DEVICE_ID_NI_PCI8430_2324 0x70df
++#define PCI_DEVICE_ID_NI_PXI8430_2328 0x70e2
++#define PCI_DEVICE_ID_NI_PCI8430_2328 0x70e4
++#define PCI_DEVICE_ID_NI_PXI8430_23216 0x70e6
++#define PCI_DEVICE_ID_NI_PCI8430_23216 0x70e7
++#define PCI_DEVICE_ID_NI_PXI8432_2322 0x70e8
++#define PCI_DEVICE_ID_NI_PCI8432_2322 0x70ea
++#define PCI_DEVICE_ID_NI_PXI8432_2324 0x70ec
++#define PCI_DEVICE_ID_NI_PCI8432_2324 0x70ee
++
+ #define PCI_VENDOR_ID_CMD 0x1095
+ #define PCI_DEVICE_ID_CMD_643 0x0643
+ #define PCI_DEVICE_ID_CMD_646 0x0646
+@@ -976,6 +1022,7 @@
+ #define PCI_DEVICE_ID_PLX_PCI200SYN 0x3196
+ #define PCI_DEVICE_ID_PLX_9030 0x9030
+ #define PCI_DEVICE_ID_PLX_9050 0x9050
++#define PCI_DEVICE_ID_PLX_9056 0x9056
+ #define PCI_DEVICE_ID_PLX_9080 0x9080
+ #define PCI_DEVICE_ID_PLX_GTEK_SERIAL2 0xa001
+
+@@ -1037,8 +1084,6 @@
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS 0x0034
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE 0x0035
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA 0x0036
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_10 0x0037
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_11 0x0038
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2 0x003e
+ #define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA 0x0040
+ #define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800 0x0041
+@@ -1049,21 +1094,16 @@
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE 0x0053
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2 0x0055
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_8 0x0056
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_9 0x0057
+ #define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059
+ #define PCI_DEVICE_ID_NVIDIA_CK804_PCIE 0x005d
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066
+ #define PCI_DEVICE_ID_NVIDIA_MCP2_MODEM 0x0069
+ #define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS 0x0084
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_4 0x0086
+ #define PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM 0x0089
+ #define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO 0x008a
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_5 0x008c
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e
+ #define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT 0x0090
+ #define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX 0x0091
+@@ -1079,15 +1119,12 @@
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE3 0x00d1
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS 0x00d4
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_3 0x00d6
+ #define PCI_DEVICE_ID_NVIDIA_MCP3_MODEM 0x00d9
+ #define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_7 0x00df
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA 0x00e3
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS 0x00e4
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_6 0x00e6
+ #define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2 0x00ee
+ #define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1 0x00f0
+@@ -1147,7 +1184,6 @@
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01b4
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc
+ #define PCI_DEVICE_ID_NVIDIA_MCP1_MODEM 0x01c1
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_1 0x01c3
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0
+ #define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200
+ #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201
+@@ -1170,8 +1206,6 @@
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_12 0x0268
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_13 0x0269
+ #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800 0x0280
+ #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X 0x0281
+ #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE 0x0282
+@@ -1218,42 +1252,22 @@
+ #define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2 0x0348
+ #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000 0x034C
+ #define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100 0x034E
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_14 0x0372
+ #define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_16 0x03E5
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_17 0x03E6
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA 0x03E7
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS 0x03EB
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE 0x03EC
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_18 0x03EE
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_19 0x03EF
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2 0x03F6
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3 0x03F7
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS 0x0446
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE 0x0448
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_20 0x0450
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_22 0x0452
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_23 0x0453
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_24 0x054C
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_25 0x054D
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_26 0x054E
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_27 0x054F
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_28 0x07DC
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_29 0x07DD
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_30 0x07DE
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_31 0x07DF
++#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_SMBUS 0x0542
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE 0x0560
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE 0x056C
++#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP78S_SMBUS 0x0752
+ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE 0x0759
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_32 0x0760
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_33 0x0761
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_34 0x0762
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_35 0x0763
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_36 0x0AB0
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_37 0x0AB1
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_38 0x0AB2
+-#define PCI_DEVICE_ID_NVIDIA_NVENET_39 0x0AB3
++#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_SMBUS 0x07D8
++#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS 0x0AA2
++#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA 0x0D85
+
+ #define PCI_VENDOR_ID_IMS 0x10e0
+ #define PCI_DEVICE_ID_IMS_TT128 0x9128
+@@ -1281,6 +1295,13 @@
+
+ #define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */
+ #define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
++#define PCI_DEVICE_ID_CREATIVE_20K1 0x0005
++#define PCI_DEVICE_ID_CREATIVE_20K2 0x000b
++#define PCI_SUBDEVICE_ID_CREATIVE_SB0760 0x0024
++#define PCI_SUBDEVICE_ID_CREATIVE_SB08801 0x0041
++#define PCI_SUBDEVICE_ID_CREATIVE_SB08802 0x0042
++#define PCI_SUBDEVICE_ID_CREATIVE_SB08803 0x0043
++#define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX 0x6000
+
+ #define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */
+ #define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938
+@@ -1373,7 +1394,7 @@
+ #define PCI_DEVICE_ID_VIA_82C598_1 0x8598
+ #define PCI_DEVICE_ID_VIA_838X_1 0xB188
+ #define PCI_DEVICE_ID_VIA_83_87XX_1 0xB198
+-#define PCI_DEVICE_ID_VIA_C409_IDE 0XC409
++#define PCI_DEVICE_ID_VIA_VX855_IDE 0xC409
+ #define PCI_DEVICE_ID_VIA_ANON 0xFFFF
+
+ #define PCI_VENDOR_ID_SIEMENS 0x110A
+@@ -1473,6 +1494,7 @@
+ #define PCI_DEVICE_ID_SERVERWORKS_HT1000IDE 0x0214
+ #define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217
+ #define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227
++#define PCI_DEVICE_ID_SERVERWORKS_HT1100LD 0x0408
+
+ #define PCI_VENDOR_ID_SBE 0x1176
+ #define PCI_DEVICE_ID_SBE_WANXL100 0x0301
+@@ -1516,6 +1538,8 @@
+ #define PCI_DEVICE_ID_ARTOP_ATP860R 0x0007
+ #define PCI_DEVICE_ID_ARTOP_ATP865 0x0008
+ #define PCI_DEVICE_ID_ARTOP_ATP865R 0x0009
++#define PCI_DEVICE_ID_ARTOP_ATP867A 0x000A
++#define PCI_DEVICE_ID_ARTOP_ATP867B 0x000B
+ #define PCI_DEVICE_ID_ARTOP_AEC7610 0x8002
+ #define PCI_DEVICE_ID_ARTOP_AEC7612UW 0x8010
+ #define PCI_DEVICE_ID_ARTOP_AEC7612U 0x8020
+@@ -1813,6 +1837,10 @@
+ #define PCI_SUBDEVICE_ID_HYPERCOPE_METRO 0x0107
+ #define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 0x0108
+
++#define PCI_VENDOR_ID_DIGIGRAM 0x1369
++#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM 0xc001
++#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM 0xc002
++
+ #define PCI_VENDOR_ID_KAWASAKI 0x136b
+ #define PCI_DEVICE_ID_MCHIP_KL5A72002 0xff01
+
+@@ -1880,6 +1908,8 @@
+ #define PCI_SUBDEVICE_ID_CCD_SWYX4S 0xB540
+ #define PCI_SUBDEVICE_ID_CCD_JH4S20 0xB550
+ #define PCI_SUBDEVICE_ID_CCD_IOB8ST_1 0xB552
++#define PCI_SUBDEVICE_ID_CCD_JHSE1 0xB553
++#define PCI_SUBDEVICE_ID_CCD_JH8S 0xB55B
+ #define PCI_SUBDEVICE_ID_CCD_BN4S 0xB560
+ #define PCI_SUBDEVICE_ID_CCD_BN8S 0xB562
+ #define PCI_SUBDEVICE_ID_CCD_BNE1 0xB563
+@@ -1932,6 +1962,8 @@
+ #define PCI_DEVICE_ID_LAVA_DSERIAL 0x0100 /* 2x 16550 */
+ #define PCI_DEVICE_ID_LAVA_QUATRO_A 0x0101 /* 2x 16550, half of 4 port */
+ #define PCI_DEVICE_ID_LAVA_QUATRO_B 0x0102 /* 2x 16550, half of 4 port */
++#define PCI_DEVICE_ID_LAVA_QUATTRO_A 0x0120 /* 2x 16550A, half of 4 port */
++#define PCI_DEVICE_ID_LAVA_QUATTRO_B 0x0121 /* 2x 16550A, half of 4 port */
+ #define PCI_DEVICE_ID_LAVA_OCTO_A 0x0180 /* 4x 16550A, half of 8 port */
+ #define PCI_DEVICE_ID_LAVA_OCTO_B 0x0181 /* 4x 16550A, half of 8 port */
+ #define PCI_DEVICE_ID_LAVA_PORT_PLUS 0x0200 /* 2x 16650 */
+@@ -1962,15 +1994,21 @@
+ #define PCI_DEVICE_ID_OXSEMI_PCIe952_1_U 0xC118
+ #define PCI_DEVICE_ID_OXSEMI_PCIe952_1_GU 0xC11C
+ #define PCI_DEVICE_ID_OXSEMI_16PCI954 0x9501
++#define PCI_DEVICE_ID_OXSEMI_C950 0x950B
+ #define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511
+ #define PCI_DEVICE_ID_OXSEMI_16PCI954PP 0x9513
+ #define PCI_DEVICE_ID_OXSEMI_16PCI952 0x9521
+ #define PCI_DEVICE_ID_OXSEMI_16PCI952PP 0x9523
++#define PCI_SUBDEVICE_ID_OXSEMI_C950 0x0001
+
+ #define PCI_VENDOR_ID_CHELSIO 0x1425
+
+ #define PCI_VENDOR_ID_SAMSUNG 0x144d
+
++#define PCI_VENDOR_ID_GIGABYTE 0x1458
++
++#define PCI_VENDOR_ID_AMBIT 0x1468
++
+ #define PCI_VENDOR_ID_MYRICOM 0x14c1
+
+ #define PCI_VENDOR_ID_TITAN 0x14D2
+@@ -1998,6 +2036,7 @@
+ #define PCI_DEVICE_ID_AFAVLAB_P030 0x2182
+ #define PCI_SUBDEVICE_ID_AFAVLAB_P061 0x2150
+
++#define PCI_VENDOR_ID_BCM_GVC 0x14a4
+ #define PCI_VENDOR_ID_BROADCOM 0x14e4
+ #define PCI_DEVICE_ID_TIGON3_5752 0x1600
+ #define PCI_DEVICE_ID_TIGON3_5752M 0x1601
+@@ -2047,7 +2086,6 @@
+ #define PCI_DEVICE_ID_TIGON3_5787M 0x1693
+ #define PCI_DEVICE_ID_TIGON3_5782 0x1696
+ #define PCI_DEVICE_ID_TIGON3_5784 0x1698
+-#define PCI_DEVICE_ID_TIGON3_5785 0x1699
+ #define PCI_DEVICE_ID_TIGON3_5786 0x169a
+ #define PCI_DEVICE_ID_TIGON3_5787 0x169b
+ #define PCI_DEVICE_ID_TIGON3_5788 0x169c
+@@ -2077,6 +2115,7 @@
+ #define PCI_VENDOR_ID_MAINPINE 0x1522
+ #define PCI_DEVICE_ID_MAINPINE_PBRIDGE 0x0100
+ #define PCI_VENDOR_ID_ENE 0x1524
++#define PCI_DEVICE_ID_ENE_CB710_FLASH 0x0510
+ #define PCI_DEVICE_ID_ENE_CB712_SD 0x0550
+ #define PCI_DEVICE_ID_ENE_CB712_SD_2 0x0551
+ #define PCI_DEVICE_ID_ENE_CB714_SD 0x0750
+@@ -2112,6 +2151,8 @@
+ #define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
+ #define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274
+
++#define PCI_VENDOR_ID_DFI 0x15bd
++
+ #define PCI_VENDOR_ID_QUICKNET 0x15e2
+ #define PCI_DEVICE_ID_QUICKNET_XJ 0x0500
+
+@@ -2131,6 +2172,10 @@
+ #define PCI_DEVICE_ID_ADDIDATA_APCI7420_3 0x700D
+ #define PCI_DEVICE_ID_ADDIDATA_APCI7300_3 0x700E
+ #define PCI_DEVICE_ID_ADDIDATA_APCI7800_3 0x700F
++#define PCI_DEVICE_ID_ADDIDATA_APCIe7300 0x7010
++#define PCI_DEVICE_ID_ADDIDATA_APCIe7420 0x7011
++#define PCI_DEVICE_ID_ADDIDATA_APCIe7500 0x7012
++#define PCI_DEVICE_ID_ADDIDATA_APCIe7800 0x7013
+
+ #define PCI_VENDOR_ID_PDC 0x15e9
+
+@@ -2215,10 +2260,20 @@
+
+ #define PCI_VENDOR_ID_TOPSPIN 0x1867
+
++#define PCI_VENDOR_ID_SILAN 0x1904
++
+ #define PCI_VENDOR_ID_TDI 0x192E
+ #define PCI_DEVICE_ID_TDI_EHCI 0x0101
+
+ #define PCI_VENDOR_ID_FREESCALE 0x1957
++#define PCI_DEVICE_ID_MPC8315E 0x00b4
++#define PCI_DEVICE_ID_MPC8315 0x00b5
++#define PCI_DEVICE_ID_MPC8314E 0x00b6
++#define PCI_DEVICE_ID_MPC8314 0x00b7
++#define PCI_DEVICE_ID_MPC8378E 0x00c4
++#define PCI_DEVICE_ID_MPC8378 0x00c5
++#define PCI_DEVICE_ID_MPC8377E 0x00c6
++#define PCI_DEVICE_ID_MPC8377 0x00c7
+ #define PCI_DEVICE_ID_MPC8548E 0x0012
+ #define PCI_DEVICE_ID_MPC8548 0x0013
+ #define PCI_DEVICE_ID_MPC8543E 0x0014
+@@ -2226,6 +2281,8 @@
+ #define PCI_DEVICE_ID_MPC8547E 0x0018
+ #define PCI_DEVICE_ID_MPC8545E 0x0019
+ #define PCI_DEVICE_ID_MPC8545 0x001a
++#define PCI_DEVICE_ID_MPC8569E 0x0061
++#define PCI_DEVICE_ID_MPC8569 0x0060
+ #define PCI_DEVICE_ID_MPC8568E 0x0020
+ #define PCI_DEVICE_ID_MPC8568 0x0021
+ #define PCI_DEVICE_ID_MPC8567E 0x0022
+@@ -2238,6 +2295,22 @@
+ #define PCI_DEVICE_ID_MPC8572 0x0041
+ #define PCI_DEVICE_ID_MPC8536E 0x0050
+ #define PCI_DEVICE_ID_MPC8536 0x0051
++#define PCI_DEVICE_ID_P2020E 0x0070
++#define PCI_DEVICE_ID_P2020 0x0071
++#define PCI_DEVICE_ID_P2010E 0x0078
++#define PCI_DEVICE_ID_P2010 0x0079
++#define PCI_DEVICE_ID_P1020E 0x0100
++#define PCI_DEVICE_ID_P1020 0x0101
++#define PCI_DEVICE_ID_P1011E 0x0108
++#define PCI_DEVICE_ID_P1011 0x0109
++#define PCI_DEVICE_ID_P1022E 0x0110
++#define PCI_DEVICE_ID_P1022 0x0111
++#define PCI_DEVICE_ID_P1013E 0x0118
++#define PCI_DEVICE_ID_P1013 0x0119
++#define PCI_DEVICE_ID_P4080E 0x0400
++#define PCI_DEVICE_ID_P4080 0x0401
++#define PCI_DEVICE_ID_P4040E 0x0408
++#define PCI_DEVICE_ID_P4040 0x0409
+ #define PCI_DEVICE_ID_MPC8641 0x7010
+ #define PCI_DEVICE_ID_MPC8641D 0x7011
+ #define PCI_DEVICE_ID_MPC8610 0x7018
+@@ -2251,6 +2324,7 @@
+ #define PCI_VENDOR_ID_JMICRON 0x197B
+ #define PCI_DEVICE_ID_JMICRON_JMB360 0x2360
+ #define PCI_DEVICE_ID_JMICRON_JMB361 0x2361
++#define PCI_DEVICE_ID_JMICRON_JMB362 0x2362
+ #define PCI_DEVICE_ID_JMICRON_JMB363 0x2363
+ #define PCI_DEVICE_ID_JMICRON_JMB365 0x2365
+ #define PCI_DEVICE_ID_JMICRON_JMB366 0x2366
+@@ -2263,6 +2337,10 @@
+ #define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600
+ #define PCI_DEVICE_ID_KORENIX_JETCARDF1 0x16ff
+
++#define PCI_VENDOR_ID_QMI 0x1a32
++
++#define PCI_VENDOR_ID_AZWAVE 0x1a3b
++
+ #define PCI_VENDOR_ID_TEKRAM 0x1de1
+ #define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29
+
+@@ -2342,6 +2420,9 @@
+ #define PCI_DEVICE_ID_INTEL_82840_HB 0x1a21
+ #define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30
+ #define PCI_DEVICE_ID_INTEL_IOAT 0x1a38
++#define PCI_DEVICE_ID_INTEL_CPT_SMBUS 0x1c22
++#define PCI_DEVICE_ID_INTEL_CPT_LPC1 0x1c42
++#define PCI_DEVICE_ID_INTEL_CPT_LPC2 0x1c43
+ #define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410
+ #define PCI_DEVICE_ID_INTEL_82801AA_1 0x2411
+ #define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413
+@@ -2373,6 +2454,7 @@
+ #define PCI_DEVICE_ID_INTEL_82801CA_12 0x248c
+ #define PCI_DEVICE_ID_INTEL_82801DB_0 0x24c0
+ #define PCI_DEVICE_ID_INTEL_82801DB_1 0x24c1
++#define PCI_DEVICE_ID_INTEL_82801DB_2 0x24c2
+ #define PCI_DEVICE_ID_INTEL_82801DB_3 0x24c3
+ #define PCI_DEVICE_ID_INTEL_82801DB_5 0x24c5
+ #define PCI_DEVICE_ID_INTEL_82801DB_6 0x24c6
+@@ -2463,6 +2545,8 @@
+ #define PCI_DEVICE_ID_INTEL_IOAT_TBG3 0x3433
+ #define PCI_DEVICE_ID_INTEL_82830_HB 0x3575
+ #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577
++#define PCI_DEVICE_ID_INTEL_82854_HB 0x358c
++#define PCI_DEVICE_ID_INTEL_82854_IG 0x358e
+ #define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580
+ #define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582
+ #define PCI_DEVICE_ID_INTEL_E7520_MCH 0x3590
+@@ -2476,6 +2560,16 @@
+ #define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e
+ #define PCI_DEVICE_ID_INTEL_IOAT_CNB 0x360b
+ #define PCI_DEVICE_ID_INTEL_FBD_CNB 0x360c
++#define PCI_DEVICE_ID_INTEL_IOAT_JSF0 0x3710
++#define PCI_DEVICE_ID_INTEL_IOAT_JSF1 0x3711
++#define PCI_DEVICE_ID_INTEL_IOAT_JSF2 0x3712
++#define PCI_DEVICE_ID_INTEL_IOAT_JSF3 0x3713
++#define PCI_DEVICE_ID_INTEL_IOAT_JSF4 0x3714
++#define PCI_DEVICE_ID_INTEL_IOAT_JSF5 0x3715
++#define PCI_DEVICE_ID_INTEL_IOAT_JSF6 0x3716
++#define PCI_DEVICE_ID_INTEL_IOAT_JSF7 0x3717
++#define PCI_DEVICE_ID_INTEL_IOAT_JSF8 0x3718
++#define PCI_DEVICE_ID_INTEL_IOAT_JSF9 0x3719
+ #define PCI_DEVICE_ID_INTEL_ICH10_0 0x3a14
+ #define PCI_DEVICE_ID_INTEL_ICH10_1 0x3a16
+ #define PCI_DEVICE_ID_INTEL_ICH10_2 0x3a18
+@@ -2606,6 +2700,7 @@
+ #define PCI_DEVICE_ID_NETMOS_9835 0x9835
+ #define PCI_DEVICE_ID_NETMOS_9845 0x9845
+ #define PCI_DEVICE_ID_NETMOS_9855 0x9855
++#define PCI_DEVICE_ID_NETMOS_9901 0x9901
+
+ #define PCI_VENDOR_ID_3COM_2 0xa727
+
diff --git a/debian/patches/libdde_phy.patch b/debian/patches/libdde_phy.patch
new file mode 100644
index 00000000..b7385122
--- /dev/null
+++ b/debian/patches/libdde_phy.patch
@@ -0,0 +1,60 @@
+--- a/libdde_linux26/contrib/include/linux/phy.h 2012-04-15 20:31:32.000000000 +0000
++++ b/libdde_linux26/contrib/include/linux/phy.h 2012-03-17 10:14:52.000000000 +0000
+@@ -79,7 +79,7 @@
+ * Need to be a little smaller than phydev->dev.bus_id to leave room
+ * for the ":%02x"
+ */
+-#define MII_BUS_ID_SIZE (BUS_ID_SIZE - 3)
++#define MII_BUS_ID_SIZE (20 - 3)
+
+ /*
+ * The Bus class for PHYs. Devices which provide access to
+@@ -315,8 +315,7 @@
+
+ /* Interrupt and Polling infrastructure */
+ struct work_struct phy_queue;
+- struct work_struct state_queue;
+- struct timer_list phy_timer;
++ struct delayed_work state_queue;
+ atomic_t irq_disable;
+
+ struct mutex lock;
+@@ -389,6 +388,12 @@
+ /* Enables or disables interrupts */
+ int (*config_intr)(struct phy_device *phydev);
+
++ /*
++ * Checks if the PHY generated an interrupt.
++ * For multi-PHY devices with shared PHY interrupt pin
++ */
++ int (*did_interrupt)(struct phy_device *phydev);
++
+ /* Clears up any memory if needed */
+ void (*remove)(struct phy_device *phydev);
+
+@@ -402,7 +407,7 @@
+ /* A Structure for boards to register fixups with the PHY Lib */
+ struct phy_fixup {
+ struct list_head list;
+- char bus_id[BUS_ID_SIZE];
++ char bus_id[20];
+ u32 phy_uid;
+ u32 phy_uid_mask;
+ int (*run)(struct phy_device *phydev);
+@@ -439,10 +444,16 @@
+
+ int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id);
+ struct phy_device* get_phy_device(struct mii_bus *bus, int addr);
++int phy_device_register(struct phy_device *phy);
+ int phy_clear_interrupt(struct phy_device *phydev);
+ int phy_config_interrupt(struct phy_device *phydev, u32 interrupts);
++int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
++ u32 flags, phy_interface_t interface);
+ struct phy_device * phy_attach(struct net_device *dev,
+ const char *bus_id, u32 flags, phy_interface_t interface);
++int phy_connect_direct(struct net_device *dev, struct phy_device *phydev,
++ void (*handler)(struct net_device *), u32 flags,
++ phy_interface_t interface);
+ struct phy_device * phy_connect(struct net_device *dev, const char *bus_id,
+ void (*handler)(struct net_device *), u32 flags,
+ phy_interface_t interface);
diff --git a/debian/patches/libdde_pr_cont.patch b/debian/patches/libdde_pr_cont.patch
new file mode 100644
index 00000000..74b88a2a
--- /dev/null
+++ b/debian/patches/libdde_pr_cont.patch
@@ -0,0 +1,26 @@
+diff --git a/libdde_linux26/include/linux/kernel.h b/libdde_linux26/include/linux/kernel.h
+index 573ed07..6354939 100644
+--- a/libdde_linux26/include/linux/kernel.h
++++ b/libdde_linux26/include/linux/kernel.h
+@@ -363,6 +363,8 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
+ printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
+ #define pr_info(fmt, ...) \
+ printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
++#define pr_cont(fmt, ...) \
++ printk(KERN_CONT fmt, ##__VA_ARGS__)
+
+ #if defined(DEBUG)
+ #ifndef DDE_LINUX
+diff --git a/libdde_linux26/contrib/include/linux/kernel.h b/libdde_linux26/contrib/include/linux/kernel.h
+index 7fa3718..0bded10 100644
+--- a/libdde_linux26/contrib/include/linux/kernel.h
++++ b/libdde_linux26/contrib/include/linux/kernel.h
+@@ -353,6 +353,8 @@ static inline char *pack_hex_byte(char *buf, u8 byte)
+ printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
+ #define pr_info(fmt, ...) \
+ printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
++#define pr_cont(fmt, ...) \
++ printk(KERN_CONT fmt, ##__VA_ARGS__)
+
+ /* If you are writing a driver, please use dev_dbg instead */
+ #if defined(DEBUG)
diff --git a/debian/patches/libdde_rcu.patch b/debian/patches/libdde_rcu.patch
new file mode 100644
index 00000000..25f8a395
--- /dev/null
+++ b/debian/patches/libdde_rcu.patch
@@ -0,0 +1,816 @@
+--- /dev/null 2011-08-03 18:03:30.000000000 +0000
++++ b/libdde_linux26/contrib/kernel/rcuclassic.c 2012-04-15 23:40:54.000000000 +0000
+@@ -0,0 +1,788 @@
++/*
++ * Read-Copy Update mechanism for mutual exclusion
++ *
++ * This program 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 of the License, or
++ * (at your option) any later version.
++ *
++ * This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Copyright IBM Corporation, 2001
++ *
++ * Authors: Dipankar Sarma <dipankar@in.ibm.com>
++ * Manfred Spraul <manfred@colorfullife.com>
++ *
++ * Based on the original work by Paul McKenney <paulmck@us.ibm.com>
++ * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
++ * Papers:
++ * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
++ * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001)
++ *
++ * For detailed explanation of Read-Copy Update mechanism see -
++ * Documentation/RCU
++ *
++ */
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/spinlock.h>
++#include <linux/smp.h>
++#include <linux/rcupdate.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <asm/atomic.h>
++#include <linux/bitops.h>
++#include <linux/module.h>
++#include <linux/completion.h>
++#include <linux/moduleparam.h>
++#include <linux/percpu.h>
++#include <linux/notifier.h>
++#include <linux/cpu.h>
++#include <linux/mutex.h>
++#include <linux/time.h>
++
++#ifdef CONFIG_DEBUG_LOCK_ALLOC
++static struct lock_class_key rcu_lock_key;
++struct lockdep_map rcu_lock_map =
++ STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key);
++EXPORT_SYMBOL_GPL(rcu_lock_map);
++#endif
++
++
++/* Definition for rcupdate control block. */
++static struct rcu_ctrlblk rcu_ctrlblk = {
++ .cur = -300,
++ .completed = -300,
++ .pending = -300,
++ .lock = __SPIN_LOCK_UNLOCKED(&rcu_ctrlblk.lock),
++ .cpumask = CPU_BITS_NONE,
++};
++static struct rcu_ctrlblk rcu_bh_ctrlblk = {
++ .cur = -300,
++ .completed = -300,
++ .pending = -300,
++ .lock = __SPIN_LOCK_UNLOCKED(&rcu_bh_ctrlblk.lock),
++ .cpumask = CPU_BITS_NONE,
++};
++
++DEFINE_PER_CPU(struct rcu_data, rcu_data) = { 0L };
++DEFINE_PER_CPU(struct rcu_data, rcu_bh_data) = { 0L };
++
++static int blimit = 10;
++static int qhimark = 10000;
++static int qlowmark = 100;
++
++#ifdef CONFIG_SMP
++static void force_quiescent_state(struct rcu_data *rdp,
++ struct rcu_ctrlblk *rcp)
++{
++ int cpu;
++ unsigned long flags;
++
++ set_need_resched();
++ spin_lock_irqsave(&rcp->lock, flags);
++ if (unlikely(!rcp->signaled)) {
++ rcp->signaled = 1;
++ /*
++ * Don't send IPI to itself. With irqs disabled,
++ * rdp->cpu is the current cpu.
++ *
++ * cpu_online_mask is updated by the _cpu_down()
++ * using __stop_machine(). Since we're in irqs disabled
++ * section, __stop_machine() is not exectuting, hence
++ * the cpu_online_mask is stable.
++ *
++ * However, a cpu might have been offlined _just_ before
++ * we disabled irqs while entering here.
++ * And rcu subsystem might not yet have handled the CPU_DEAD
++ * notification, leading to the offlined cpu's bit
++ * being set in the rcp->cpumask.
++ *
++ * Hence cpumask = (rcp->cpumask & cpu_online_mask) to prevent
++ * sending smp_reschedule() to an offlined CPU.
++ */
++ for_each_cpu_and(cpu,
++ to_cpumask(rcp->cpumask), cpu_online_mask) {
++ if (cpu != rdp->cpu)
++ smp_send_reschedule(cpu);
++ }
++ }
++ spin_unlock_irqrestore(&rcp->lock, flags);
++}
++#else
++static inline void force_quiescent_state(struct rcu_data *rdp,
++ struct rcu_ctrlblk *rcp)
++{
++ set_need_resched();
++}
++#endif
++
++static void __call_rcu(struct rcu_head *head, struct rcu_ctrlblk *rcp,
++ struct rcu_data *rdp)
++{
++ long batch;
++
++ head->next = NULL;
++ smp_mb(); /* Read of rcu->cur must happen after any change by caller. */
++
++ /*
++ * Determine the batch number of this callback.
++ *
++ * Using ACCESS_ONCE to avoid the following error when gcc eliminates
++ * local variable "batch" and emits codes like this:
++ * 1) rdp->batch = rcp->cur + 1 # gets old value
++ * ......
++ * 2)rcu_batch_after(rcp->cur + 1, rdp->batch) # gets new value
++ * then [*nxttail[0], *nxttail[1]) may contain callbacks
++ * that batch# = rdp->batch, see the comment of struct rcu_data.
++ */
++ batch = ACCESS_ONCE(rcp->cur) + 1;
++
++ if (rdp->nxtlist && rcu_batch_after(batch, rdp->batch)) {
++ /* process callbacks */
++ rdp->nxttail[0] = rdp->nxttail[1];
++ rdp->nxttail[1] = rdp->nxttail[2];
++ if (rcu_batch_after(batch - 1, rdp->batch))
++ rdp->nxttail[0] = rdp->nxttail[2];
++ }
++
++ rdp->batch = batch;
++ *rdp->nxttail[2] = head;
++ rdp->nxttail[2] = &head->next;
++
++ if (unlikely(++rdp->qlen > qhimark)) {
++ rdp->blimit = INT_MAX;
++ force_quiescent_state(rdp, &rcu_ctrlblk);
++ }
++}
++
++#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
++
++static void record_gp_stall_check_time(struct rcu_ctrlblk *rcp)
++{
++ rcp->gp_start = jiffies;
++ rcp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_CHECK;
++}
++
++static void print_other_cpu_stall(struct rcu_ctrlblk *rcp)
++{
++ int cpu;
++ long delta;
++ unsigned long flags;
++
++ /* Only let one CPU complain about others per time interval. */
++
++ spin_lock_irqsave(&rcp->lock, flags);
++ delta = jiffies - rcp->jiffies_stall;
++ if (delta < 2 || rcp->cur != rcp->completed) {
++ spin_unlock_irqrestore(&rcp->lock, flags);
++ return;
++ }
++ rcp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_RECHECK;
++ spin_unlock_irqrestore(&rcp->lock, flags);
++
++ /* OK, time to rat on our buddy... */
++
++ printk(KERN_ERR "INFO: RCU detected CPU stalls:");
++ for_each_possible_cpu(cpu) {
++ if (cpumask_test_cpu(cpu, to_cpumask(rcp->cpumask)))
++ printk(" %d", cpu);
++ }
++ printk(" (detected by %d, t=%ld jiffies)\n",
++ smp_processor_id(), (long)(jiffies - rcp->gp_start));
++}
++
++static void print_cpu_stall(struct rcu_ctrlblk *rcp)
++{
++ unsigned long flags;
++
++ printk(KERN_ERR "INFO: RCU detected CPU %d stall (t=%lu/%lu jiffies)\n",
++ smp_processor_id(), jiffies,
++ jiffies - rcp->gp_start);
++ dump_stack();
++ spin_lock_irqsave(&rcp->lock, flags);
++ if ((long)(jiffies - rcp->jiffies_stall) >= 0)
++ rcp->jiffies_stall =
++ jiffies + RCU_SECONDS_TILL_STALL_RECHECK;
++ spin_unlock_irqrestore(&rcp->lock, flags);
++ set_need_resched(); /* kick ourselves to get things going. */
++}
++
++static void check_cpu_stall(struct rcu_ctrlblk *rcp)
++{
++ long delta;
++
++ delta = jiffies - rcp->jiffies_stall;
++ if (cpumask_test_cpu(smp_processor_id(), to_cpumask(rcp->cpumask)) &&
++ delta >= 0) {
++
++ /* We haven't checked in, so go dump stack. */
++ print_cpu_stall(rcp);
++
++ } else if (rcp->cur != rcp->completed && delta >= 2) {
++
++ /* They had two seconds to dump stack, so complain. */
++ print_other_cpu_stall(rcp);
++ }
++}
++
++#else /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
++
++static void record_gp_stall_check_time(struct rcu_ctrlblk *rcp)
++{
++}
++
++static inline void check_cpu_stall(struct rcu_ctrlblk *rcp)
++{
++}
++
++#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
++
++/**
++ * call_rcu - Queue an RCU callback for invocation after a grace period.
++ * @head: structure to be used for queueing the RCU updates.
++ * @func: actual update function to be invoked after the grace period
++ *
++ * The update function will be invoked some time after a full grace
++ * period elapses, in other words after all currently executing RCU
++ * read-side critical sections have completed. RCU read-side critical
++ * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
++ * and may be nested.
++ */
++void call_rcu(struct rcu_head *head,
++ void (*func)(struct rcu_head *rcu))
++{
++ unsigned long flags;
++
++ head->func = func;
++ local_irq_save(flags);
++ __call_rcu(head, &rcu_ctrlblk, &__get_cpu_var(rcu_data));
++ local_irq_restore(flags);
++}
++EXPORT_SYMBOL_GPL(call_rcu);
++
++/**
++ * call_rcu_bh - Queue an RCU for invocation after a quicker grace period.
++ * @head: structure to be used for queueing the RCU updates.
++ * @func: actual update function to be invoked after the grace period
++ *
++ * The update function will be invoked some time after a full grace
++ * period elapses, in other words after all currently executing RCU
++ * read-side critical sections have completed. call_rcu_bh() assumes
++ * that the read-side critical sections end on completion of a softirq
++ * handler. This means that read-side critical sections in process
++ * context must not be interrupted by softirqs. This interface is to be
++ * used when most of the read-side critical sections are in softirq context.
++ * RCU read-side critical sections are delimited by rcu_read_lock() and
++ * rcu_read_unlock(), * if in interrupt context or rcu_read_lock_bh()
++ * and rcu_read_unlock_bh(), if in process context. These may be nested.
++ */
++void call_rcu_bh(struct rcu_head *head,
++ void (*func)(struct rcu_head *rcu))
++{
++ unsigned long flags;
++
++ head->func = func;
++ local_irq_save(flags);
++ __call_rcu(head, &rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data));
++ local_irq_restore(flags);
++}
++EXPORT_SYMBOL_GPL(call_rcu_bh);
++
++/*
++ * Return the number of RCU batches processed thus far. Useful
++ * for debug and statistics.
++ */
++long rcu_batches_completed(void)
++{
++ return rcu_ctrlblk.completed;
++}
++EXPORT_SYMBOL_GPL(rcu_batches_completed);
++
++/*
++ * Return the number of RCU batches processed thus far. Useful
++ * for debug and statistics.
++ */
++long rcu_batches_completed_bh(void)
++{
++ return rcu_bh_ctrlblk.completed;
++}
++EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
++
++/* Raises the softirq for processing rcu_callbacks. */
++static inline void raise_rcu_softirq(void)
++{
++ raise_softirq(RCU_SOFTIRQ);
++}
++
++/*
++ * Invoke the completed RCU callbacks. They are expected to be in
++ * a per-cpu list.
++ */
++static void rcu_do_batch(struct rcu_data *rdp)
++{
++ unsigned long flags;
++ struct rcu_head *next, *list;
++ int count = 0;
++
++ list = rdp->donelist;
++ while (list) {
++ next = list->next;
++ prefetch(next);
++ list->func(list);
++ list = next;
++ if (++count >= rdp->blimit)
++ break;
++ }
++ rdp->donelist = list;
++
++ local_irq_save(flags);
++ rdp->qlen -= count;
++ local_irq_restore(flags);
++ if (rdp->blimit == INT_MAX && rdp->qlen <= qlowmark)
++ rdp->blimit = blimit;
++
++ if (!rdp->donelist)
++ rdp->donetail = &rdp->donelist;
++ else
++ raise_rcu_softirq();
++}
++
++/*
++ * Grace period handling:
++ * The grace period handling consists out of two steps:
++ * - A new grace period is started.
++ * This is done by rcu_start_batch. The start is not broadcasted to
++ * all cpus, they must pick this up by comparing rcp->cur with
++ * rdp->quiescbatch. All cpus are recorded in the
++ * rcu_ctrlblk.cpumask bitmap.
++ * - All cpus must go through a quiescent state.
++ * Since the start of the grace period is not broadcasted, at least two
++ * calls to rcu_check_quiescent_state are required:
++ * The first call just notices that a new grace period is running. The
++ * following calls check if there was a quiescent state since the beginning
++ * of the grace period. If so, it updates rcu_ctrlblk.cpumask. If
++ * the bitmap is empty, then the grace period is completed.
++ * rcu_check_quiescent_state calls rcu_start_batch(0) to start the next grace
++ * period (if necessary).
++ */
++
++/*
++ * Register a new batch of callbacks, and start it up if there is currently no
++ * active batch and the batch to be registered has not already occurred.
++ * Caller must hold rcu_ctrlblk.lock.
++ */
++static void rcu_start_batch(struct rcu_ctrlblk *rcp)
++{
++ if (rcp->cur != rcp->pending &&
++ rcp->completed == rcp->cur) {
++ rcp->cur++;
++ record_gp_stall_check_time(rcp);
++
++ /*
++ * Accessing nohz_cpu_mask before incrementing rcp->cur needs a
++ * Barrier Otherwise it can cause tickless idle CPUs to be
++ * included in rcp->cpumask, which will extend graceperiods
++ * unnecessarily.
++ */
++ smp_mb();
++ cpumask_andnot(to_cpumask(rcp->cpumask),
++ cpu_online_mask, nohz_cpu_mask);
++
++ rcp->signaled = 0;
++ }
++}
++
++/*
++ * cpu went through a quiescent state since the beginning of the grace period.
++ * Clear it from the cpu mask and complete the grace period if it was the last
++ * cpu. Start another grace period if someone has further entries pending
++ */
++static void cpu_quiet(int cpu, struct rcu_ctrlblk *rcp)
++{
++ cpumask_clear_cpu(cpu, to_cpumask(rcp->cpumask));
++ if (cpumask_empty(to_cpumask(rcp->cpumask))) {
++ /* batch completed ! */
++ rcp->completed = rcp->cur;
++ rcu_start_batch(rcp);
++ }
++}
++
++/*
++ * Check if the cpu has gone through a quiescent state (say context
++ * switch). If so and if it already hasn't done so in this RCU
++ * quiescent cycle, then indicate that it has done so.
++ */
++static void rcu_check_quiescent_state(struct rcu_ctrlblk *rcp,
++ struct rcu_data *rdp)
++{
++ unsigned long flags;
++
++ if (rdp->quiescbatch != rcp->cur) {
++ /* start new grace period: */
++ rdp->qs_pending = 1;
++ rdp->passed_quiesc = 0;
++ rdp->quiescbatch = rcp->cur;
++ return;
++ }
++
++ /* Grace period already completed for this cpu?
++ * qs_pending is checked instead of the actual bitmap to avoid
++ * cacheline trashing.
++ */
++ if (!rdp->qs_pending)
++ return;
++
++ /*
++ * Was there a quiescent state since the beginning of the grace
++ * period? If no, then exit and wait for the next call.
++ */
++ if (!rdp->passed_quiesc)
++ return;
++ rdp->qs_pending = 0;
++
++ spin_lock_irqsave(&rcp->lock, flags);
++ /*
++ * rdp->quiescbatch/rcp->cur and the cpu bitmap can come out of sync
++ * during cpu startup. Ignore the quiescent state.
++ */
++ if (likely(rdp->quiescbatch == rcp->cur))
++ cpu_quiet(rdp->cpu, rcp);
++
++ spin_unlock_irqrestore(&rcp->lock, flags);
++}
++
++
++#ifdef CONFIG_HOTPLUG_CPU
++
++/* warning! helper for rcu_offline_cpu. do not use elsewhere without reviewing
++ * locking requirements, the list it's pulling from has to belong to a cpu
++ * which is dead and hence not processing interrupts.
++ */
++static void rcu_move_batch(struct rcu_data *this_rdp, struct rcu_head *list,
++ struct rcu_head **tail, long batch)
++{
++ unsigned long flags;
++
++ if (list) {
++ local_irq_save(flags);
++ this_rdp->batch = batch;
++ *this_rdp->nxttail[2] = list;
++ this_rdp->nxttail[2] = tail;
++ local_irq_restore(flags);
++ }
++}
++
++static void __rcu_offline_cpu(struct rcu_data *this_rdp,
++ struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
++{
++ unsigned long flags;
++
++ /*
++ * if the cpu going offline owns the grace period
++ * we can block indefinitely waiting for it, so flush
++ * it here
++ */
++ spin_lock_irqsave(&rcp->lock, flags);
++ if (rcp->cur != rcp->completed)
++ cpu_quiet(rdp->cpu, rcp);
++ rcu_move_batch(this_rdp, rdp->donelist, rdp->donetail, rcp->cur + 1);
++ rcu_move_batch(this_rdp, rdp->nxtlist, rdp->nxttail[2], rcp->cur + 1);
++ spin_unlock(&rcp->lock);
++
++ this_rdp->qlen += rdp->qlen;
++ local_irq_restore(flags);
++}
++
++static void rcu_offline_cpu(int cpu)
++{
++ struct rcu_data *this_rdp = &get_cpu_var(rcu_data);
++ struct rcu_data *this_bh_rdp = &get_cpu_var(rcu_bh_data);
++
++ __rcu_offline_cpu(this_rdp, &rcu_ctrlblk,
++ &per_cpu(rcu_data, cpu));
++ __rcu_offline_cpu(this_bh_rdp, &rcu_bh_ctrlblk,
++ &per_cpu(rcu_bh_data, cpu));
++ put_cpu_var(rcu_data);
++ put_cpu_var(rcu_bh_data);
++}
++
++#else
++
++static void rcu_offline_cpu(int cpu)
++{
++}
++
++#endif
++
++/*
++ * This does the RCU processing work from softirq context.
++ */
++static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp,
++ struct rcu_data *rdp)
++{
++ unsigned long flags;
++ long completed_snap;
++
++ if (rdp->nxtlist) {
++ local_irq_save(flags);
++ completed_snap = ACCESS_ONCE(rcp->completed);
++
++ /*
++ * move the other grace-period-completed entries to
++ * [rdp->nxtlist, *rdp->nxttail[0]) temporarily
++ */
++ if (!rcu_batch_before(completed_snap, rdp->batch))
++ rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2];
++ else if (!rcu_batch_before(completed_snap, rdp->batch - 1))
++ rdp->nxttail[0] = rdp->nxttail[1];
++
++ /*
++ * the grace period for entries in
++ * [rdp->nxtlist, *rdp->nxttail[0]) has completed and
++ * move these entries to donelist
++ */
++ if (rdp->nxttail[0] != &rdp->nxtlist) {
++ *rdp->donetail = rdp->nxtlist;
++ rdp->donetail = rdp->nxttail[0];
++ rdp->nxtlist = *rdp->nxttail[0];
++ *rdp->donetail = NULL;
++
++ if (rdp->nxttail[1] == rdp->nxttail[0])
++ rdp->nxttail[1] = &rdp->nxtlist;
++ if (rdp->nxttail[2] == rdp->nxttail[0])
++ rdp->nxttail[2] = &rdp->nxtlist;
++ rdp->nxttail[0] = &rdp->nxtlist;
++ }
++
++ local_irq_restore(flags);
++
++ if (rcu_batch_after(rdp->batch, rcp->pending)) {
++ unsigned long flags2;
++
++ /* and start it/schedule start if it's a new batch */
++ spin_lock_irqsave(&rcp->lock, flags2);
++ if (rcu_batch_after(rdp->batch, rcp->pending)) {
++ rcp->pending = rdp->batch;
++ rcu_start_batch(rcp);
++ }
++ spin_unlock_irqrestore(&rcp->lock, flags2);
++ }
++ }
++
++ rcu_check_quiescent_state(rcp, rdp);
++ if (rdp->donelist)
++ rcu_do_batch(rdp);
++}
++
++static void rcu_process_callbacks(struct softirq_action *unused)
++{
++ /*
++ * Memory references from any prior RCU read-side critical sections
++ * executed by the interrupted code must be see before any RCU
++ * grace-period manupulations below.
++ */
++
++ smp_mb(); /* See above block comment. */
++
++ __rcu_process_callbacks(&rcu_ctrlblk, &__get_cpu_var(rcu_data));
++ __rcu_process_callbacks(&rcu_bh_ctrlblk, &__get_cpu_var(rcu_bh_data));
++
++ /*
++ * Memory references from any later RCU read-side critical sections
++ * executed by the interrupted code must be see after any RCU
++ * grace-period manupulations above.
++ */
++
++ smp_mb(); /* See above block comment. */
++}
++
++static int __rcu_pending(struct rcu_ctrlblk *rcp, struct rcu_data *rdp)
++{
++ /* Check for CPU stalls, if enabled. */
++ check_cpu_stall(rcp);
++
++ if (rdp->nxtlist) {
++ long completed_snap = ACCESS_ONCE(rcp->completed);
++
++ /*
++ * This cpu has pending rcu entries and the grace period
++ * for them has completed.
++ */
++ if (!rcu_batch_before(completed_snap, rdp->batch))
++ return 1;
++ if (!rcu_batch_before(completed_snap, rdp->batch - 1) &&
++ rdp->nxttail[0] != rdp->nxttail[1])
++ return 1;
++ if (rdp->nxttail[0] != &rdp->nxtlist)
++ return 1;
++
++ /*
++ * This cpu has pending rcu entries and the new batch
++ * for then hasn't been started nor scheduled start
++ */
++ if (rcu_batch_after(rdp->batch, rcp->pending))
++ return 1;
++ }
++
++ /* This cpu has finished callbacks to invoke */
++ if (rdp->donelist)
++ return 1;
++
++ /* The rcu core waits for a quiescent state from the cpu */
++ if (rdp->quiescbatch != rcp->cur || rdp->qs_pending)
++ return 1;
++
++ /* nothing to do */
++ return 0;
++}
++
++/*
++ * Check to see if there is any immediate RCU-related work to be done
++ * by the current CPU, returning 1 if so. This function is part of the
++ * RCU implementation; it is -not- an exported member of the RCU API.
++ */
++int rcu_pending(int cpu)
++{
++ return __rcu_pending(&rcu_ctrlblk, &per_cpu(rcu_data, cpu)) ||
++ __rcu_pending(&rcu_bh_ctrlblk, &per_cpu(rcu_bh_data, cpu));
++}
++
++/*
++ * Check to see if any future RCU-related work will need to be done
++ * by the current CPU, even if none need be done immediately, returning
++ * 1 if so. This function is part of the RCU implementation; it is -not-
++ * an exported member of the RCU API.
++ */
++int rcu_needs_cpu(int cpu)
++{
++ struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
++ struct rcu_data *rdp_bh = &per_cpu(rcu_bh_data, cpu);
++
++ return !!rdp->nxtlist || !!rdp_bh->nxtlist || rcu_pending(cpu);
++}
++
++/*
++ * Top-level function driving RCU grace-period detection, normally
++ * invoked from the scheduler-clock interrupt. This function simply
++ * increments counters that are read only from softirq by this same
++ * CPU, so there are no memory barriers required.
++ */
++void rcu_check_callbacks(int cpu, int user)
++{
++ if (user ||
++ (idle_cpu(cpu) && rcu_scheduler_active &&
++ !in_softirq() && hardirq_count() <= (1 << HARDIRQ_SHIFT))) {
++
++ /*
++ * Get here if this CPU took its interrupt from user
++ * mode or from the idle loop, and if this is not a
++ * nested interrupt. In this case, the CPU is in
++ * a quiescent state, so count it.
++ *
++ * Also do a memory barrier. This is needed to handle
++ * the case where writes from a preempt-disable section
++ * of code get reordered into schedule() by this CPU's
++ * write buffer. The memory barrier makes sure that
++ * the rcu_qsctr_inc() and rcu_bh_qsctr_inc() are see
++ * by other CPUs to happen after any such write.
++ */
++
++ smp_mb(); /* See above block comment. */
++ rcu_qsctr_inc(cpu);
++ rcu_bh_qsctr_inc(cpu);
++
++ } else if (!in_softirq()) {
++
++ /*
++ * Get here if this CPU did not take its interrupt from
++ * softirq, in other words, if it is not interrupting
++ * a rcu_bh read-side critical section. This is an _bh
++ * critical section, so count it. The memory barrier
++ * is needed for the same reason as is the above one.
++ */
++
++ smp_mb(); /* See above block comment. */
++ rcu_bh_qsctr_inc(cpu);
++ }
++ raise_rcu_softirq();
++}
++
++static void __cpuinit rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp,
++ struct rcu_data *rdp)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&rcp->lock, flags);
++ memset(rdp, 0, sizeof(*rdp));
++ rdp->nxttail[0] = rdp->nxttail[1] = rdp->nxttail[2] = &rdp->nxtlist;
++ rdp->donetail = &rdp->donelist;
++ rdp->quiescbatch = rcp->completed;
++ rdp->qs_pending = 0;
++ rdp->cpu = cpu;
++ rdp->blimit = blimit;
++ spin_unlock_irqrestore(&rcp->lock, flags);
++}
++
++static void __cpuinit rcu_online_cpu(int cpu)
++{
++ struct rcu_data *rdp = &per_cpu(rcu_data, cpu);
++ struct rcu_data *bh_rdp = &per_cpu(rcu_bh_data, cpu);
++
++ rcu_init_percpu_data(cpu, &rcu_ctrlblk, rdp);
++ rcu_init_percpu_data(cpu, &rcu_bh_ctrlblk, bh_rdp);
++ open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
++}
++
++static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
++ unsigned long action, void *hcpu)
++{
++ long cpu = (long)hcpu;
++
++ switch (action) {
++ case CPU_UP_PREPARE:
++ case CPU_UP_PREPARE_FROZEN:
++ rcu_online_cpu(cpu);
++ break;
++ case CPU_DEAD:
++ case CPU_DEAD_FROZEN:
++ rcu_offline_cpu(cpu);
++ break;
++ default:
++ break;
++ }
++ return NOTIFY_OK;
++}
++
++static struct notifier_block __cpuinitdata rcu_nb = {
++ .notifier_call = rcu_cpu_notify,
++};
++
++/*
++ * Initializes rcu mechanism. Assumed to be called early.
++ * That is before local timer(SMP) or jiffie timer (uniproc) is setup.
++ * Note that rcu_qsctr and friends are implicitly
++ * initialized due to the choice of ``0'' for RCU_CTR_INVALID.
++ */
++void __init __rcu_init(void)
++{
++#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
++ printk(KERN_INFO "RCU-based detection of stalled CPUs is enabled.\n");
++#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
++ rcu_cpu_notify(&rcu_nb, CPU_UP_PREPARE,
++ (void *)(long)smp_processor_id());
++ /* Register notifier for non-boot CPUs */
++ register_cpu_notifier(&rcu_nb);
++}
++
++module_param(blimit, int, 0);
++module_param(qhimark, int, 0);
++module_param(qlowmark, int, 0);
+diff --git a/libdde_linux26/contrib/kernel/rcupdate.c b/libdde_linux26/contrib/kernel/rcupdate.c
+index cae8a05..c6bfa1a 100644
+--- a/libdde_linux26/contrib/kernel/rcupdate.c
++++ b/libdde_linux26/contrib/kernel/rcupdate.c
+@@ -180,6 +180,7 @@ void __init rcu_init(void)
+ {
+ __rcu_init();
+ }
++core_initcall(rcu_init);
+
+ void rcu_scheduler_starting(void)
+ {
+diff --git a/libdde_linux26/lib/src/Makefile b/libdde_linux26/lib/src/Makefile
+index 358196b..450c4e6 100644
+--- a/libdde_linux26/lib/src/Makefile
++++ b/libdde_linux26/lib/src/Makefile
+@@ -89,6 +89,8 @@ SRC_C_libdde_linux26.o.a += \
+ kernel/kthread.c \
+ kernel/mutex.c \
+ kernel/notifier.c \
++ kernel/rcupdate.c \
++ kernel/rcuclassic.c \
+ kernel/resource.c \
+ kernel/rwsem.c \
+ kernel/sched.c \
diff --git a/debian/patches/libdde_rculist.patch b/debian/patches/libdde_rculist.patch
new file mode 100644
index 00000000..19e512a6
--- /dev/null
+++ b/debian/patches/libdde_rculist.patch
@@ -0,0 +1,12 @@
+diff --git a/libdde_linux26/contrib/include/linux/netdevice.h b/libdde_linux26/contrib/include/linux/netdevice.h
+index 6593667..bb4fca1 100644
+--- a/libdde_linux26/contrib/include/linux/netdevice.h
++++ b/libdde_linux26/contrib/include/linux/netdevice.h
+@@ -37,6 +37,7 @@
+ #include <asm/byteorder.h>
+
+ #include <linux/device.h>
++#include <linux/rculist.h>
+ #include <linux/percpu.h>
+ #include <linux/dmaengine.h>
+ #include <linux/workqueue.h>
diff --git a/debian/patches/libdde_rx_queue.patch b/debian/patches/libdde_rx_queue.patch
new file mode 100644
index 00000000..0d962647
--- /dev/null
+++ b/debian/patches/libdde_rx_queue.patch
@@ -0,0 +1,70 @@
+commit d5a9e24afb4ab38110ebb777588ea0bd0eacbd0a
+Author: David S. Miller <davem@davemloft.net>
+Date: Tue Jan 27 16:22:11 2009 -0800
+
+ net: Allow RX queue selection to seed TX queue hashing.
+
+ The idea is that drivers which implement multiqueue RX
+ pre-seed the SKB by recording the RX queue selected by
+ the hardware.
+
+ If such a seed is found on TX, we'll use that to select
+ the outgoing TX queue.
+
+ This helps get more consistent load balancing on router
+ and firewall loads.
+
+ Signed-off-by: David S. Miller <davem@davemloft.net>
+
+Index: hurd-debian/libdde_linux26/contrib/include/linux/skbuff.h
+===================================================================
+--- hurd-debian.orig/libdde_linux26/contrib/include/linux/skbuff.h 2012-04-16 00:34:56.000000000 +0000
++++ hurd-debian/libdde_linux26/contrib/include/linux/skbuff.h 2012-04-16 00:35:11.000000000 +0000
+@@ -1903,6 +1903,21 @@
+ to->queue_mapping = from->queue_mapping;
+ }
+
++static inline void skb_record_rx_queue(struct sk_buff *skb, u16 rx_queue)
++{
++ skb->queue_mapping = rx_queue + 1;
++}
++
++static inline u16 skb_get_rx_queue(struct sk_buff *skb)
++{
++ return skb->queue_mapping - 1;
++}
++
++static inline bool skb_rx_queue_recorded(struct sk_buff *skb)
++{
++ return (skb->queue_mapping != 0);
++}
++
+ #ifdef CONFIG_XFRM
+ static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
+ {
+Index: hurd-debian/libdde_linux26/lib/src/net/core/dev.c
+===================================================================
+--- hurd-debian.orig/libdde_linux26/lib/src/net/core/dev.c 2012-04-16 00:34:51.000000000 +0000
++++ hurd-debian/libdde_linux26/lib/src/net/core/dev.c 2012-04-16 00:35:11.000000000 +0000
+@@ -1731,6 +1731,13 @@
+ simple_tx_hashrnd_initialized = 1;
+ }
+
++ if (skb_rx_queue_recorded(skb)) {
++ u32 val = skb_get_rx_queue(skb);
++
++ hash = jhash_1word(val, simple_tx_hashrnd);
++ goto out;
++ }
++
+ switch (skb->protocol) {
+ case htons(ETH_P_IP):
+ if (!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)))
+@@ -1768,6 +1775,7 @@
+
+ hash = jhash_3words(addr1, addr2, ports, simple_tx_hashrnd);
+
++out:
+ return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32);
+ }
+
diff --git a/debian/patches/libdde_trans_start.patch b/debian/patches/libdde_trans_start.patch
new file mode 100644
index 00000000..07acc6dd
--- /dev/null
+++ b/debian/patches/libdde_trans_start.patch
@@ -0,0 +1,138 @@
+commit 9d21493b4beb8f918ba248032fefa393074a5e2b
+Author: Eric Dumazet <dada1@cosmosbay.com>
+Date: Sun May 17 20:55:16 2009 -0700
+
+ net: tx scalability works : trans_start
+
+ struct net_device trans_start field is a hot spot on SMP and high performance
+ devices, particularly multi queues ones, because every transmitter dirties
+ it. Is main use is tx watchdog and bonding alive checks.
+
+ But as most devices dont use NETIF_F_LLTX, we have to lock
+ a netdev_queue before calling their ndo_start_xmit(). So it makes
+ sense to move trans_start from net_device to netdev_queue. Its update
+ will occur on a already present (and in exclusive state) cache line, for
+ free.
+
+ We can do this transition smoothly. An old driver continue to
+ update dev->trans_start, while an updated one updates txq->trans_start.
+
+ Further patches could also put tx_bytes/tx_packets counters in
+ netdev_queue to avoid dirtying dev->stats (vlan device comes to mind)
+
+ Signed-off-by: Eric Dumazet <dada1@cosmosbay.com>
+ Signed-off-by: David S. Miller <davem@davemloft.net>
+
+Index: hurd-debian/libdde_linux26/contrib/include/linux/netdevice.h
+===================================================================
+--- hurd-debian.orig/libdde_linux26/contrib/include/linux/netdevice.h 2012-04-16 00:34:54.000000000 +0000
++++ hurd-debian/libdde_linux26/contrib/include/linux/netdevice.h 2012-04-16 00:35:04.000000000 +0000
+@@ -462,6 +462,10 @@
+ spinlock_t _xmit_lock;
+ int xmit_lock_owner;
+ struct Qdisc *qdisc_sleeping;
++ /*
++ * please use this field instead of dev->trans_start
++ */
++ unsigned long trans_start;
+ } ____cacheline_aligned_in_smp;
+
+
+@@ -801,6 +805,11 @@
+ * One part is mostly used on xmit path (device)
+ */
+ /* These may be needed for future network-power-down code. */
++
++ /*
++ * trans_start here is expensive for high speed devices on SMP,
++ * please use netdev_queue->trans_start instead.
++ */
+ unsigned long trans_start; /* Time (in jiffies) of last Tx */
+
+ int watchdog_timeo; /* used by dev_watchdog() */
+@@ -1477,6 +1486,8 @@
+ return !test_bit(__LINK_STATE_NOCARRIER, &dev->state);
+ }
+
++extern unsigned long dev_trans_start(struct net_device *dev);
++
+ extern void __netdev_watchdog_up(struct net_device *dev);
+
+ extern void netif_carrier_on(struct net_device *dev);
+Index: hurd-debian/libdde_linux26/lib/src/net/sched/sch_generic.c
+===================================================================
+--- hurd-debian.orig/libdde_linux26/lib/src/net/sched/sch_generic.c 2012-04-16 00:26:38.000000000 +0000
++++ hurd-debian/libdde_linux26/lib/src/net/sched/sch_generic.c 2012-04-16 00:35:04.000000000 +0000
+@@ -200,6 +200,21 @@
+ clear_bit(__QDISC_STATE_RUNNING, &q->state);
+ }
+
++unsigned long dev_trans_start(struct net_device *dev)
++{
++ unsigned long val, res = dev->trans_start;
++ unsigned int i;
++
++ for (i = 0; i < dev->num_tx_queues; i++) {
++ val = netdev_get_tx_queue(dev, i)->trans_start;
++ if (val && time_after(val, res))
++ res = val;
++ }
++ dev->trans_start = res;
++ return res;
++}
++EXPORT_SYMBOL(dev_trans_start);
++
+ static void dev_watchdog(unsigned long arg)
+ {
+ struct net_device *dev = (struct net_device *)arg;
+@@ -209,25 +224,30 @@
+ if (netif_device_present(dev) &&
+ netif_running(dev) &&
+ netif_carrier_ok(dev)) {
+- int some_queue_stopped = 0;
++ int some_queue_timedout = 0;
+ unsigned int i;
++ unsigned long trans_start;
+
+ for (i = 0; i < dev->num_tx_queues; i++) {
+ struct netdev_queue *txq;
+
+ txq = netdev_get_tx_queue(dev, i);
+- if (netif_tx_queue_stopped(txq)) {
+- some_queue_stopped = 1;
++ /*
++ * old device drivers set dev->trans_start
++ */
++ trans_start = txq->trans_start ? : dev->trans_start;
++ if (netif_tx_queue_stopped(txq) &&
++ time_after(jiffies, (trans_start +
++ dev->watchdog_timeo))) {
++ some_queue_timedout = 1;
+ break;
+ }
+ }
+
+- if (some_queue_stopped &&
+- time_after(jiffies, (dev->trans_start +
+- dev->watchdog_timeo))) {
++ if (some_queue_timedout) {
+ char drivername[64];
+- WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n",
+- dev->name, netdev_drivername(dev, drivername, 64));
++ WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out\n",
++ dev->name, netdev_drivername(dev, drivername, 64), i);
+ dev->netdev_ops->ndo_tx_timeout(dev);
+ }
+ if (!mod_timer(&dev->watchdog_timer,
+@@ -612,8 +632,10 @@
+ clear_bit(__QDISC_STATE_DEACTIVATED, &new_qdisc->state);
+
+ rcu_assign_pointer(dev_queue->qdisc, new_qdisc);
+- if (need_watchdog_p && new_qdisc != &noqueue_qdisc)
++ if (need_watchdog_p && new_qdisc != &noqueue_qdisc) {
++ dev_queue->trans_start = 0;
+ *need_watchdog_p = 1;
++ }
+ }
+
+ void dev_activate(struct net_device *dev)
diff --git a/debian/patches/libdde_ucast_list.patch b/debian/patches/libdde_ucast_list.patch
new file mode 100644
index 00000000..5abd3443
--- /dev/null
+++ b/debian/patches/libdde_ucast_list.patch
@@ -0,0 +1,488 @@
+commit ccffad25b5136958d4769ed6de5e87992dd9c65c
+Author: Jiri Pirko <jpirko@redhat.com>
+Date: Fri May 22 23:22:17 2009 +0000
+
+ net: convert unicast addr list
+
+ This patch converts unicast address list to standard list_head using
+ previously introduced struct netdev_hw_addr. It also relaxes the
+ locking. Original spinlock (still used for multicast addresses) is not
+ needed and is no longer used for a protection of this list. All
+ reading and writing takes place under rtnl (with no changes).
+
+ I also removed a possibility to specify the length of the address
+ while adding or deleting unicast address. It's always dev->addr_len.
+
+ The convertion touched especially e1000 and ixgbe codes when the
+ change is not so trivial.
+
+ Signed-off-by: Jiri Pirko <jpirko@redhat.com>
+
+ drivers/net/bnx2.c | 13 +--
+ drivers/net/e1000/e1000_main.c | 24 +++--
+ drivers/net/ixgbe/ixgbe_common.c | 14 ++--
+ drivers/net/ixgbe/ixgbe_common.h | 4 +-
+ drivers/net/ixgbe/ixgbe_main.c | 6 +-
+ drivers/net/ixgbe/ixgbe_type.h | 4 +-
+ drivers/net/macvlan.c | 11 +-
+ drivers/net/mv643xx_eth.c | 11 +-
+ drivers/net/niu.c | 7 +-
+ drivers/net/virtio_net.c | 7 +-
+ drivers/s390/net/qeth_l2_main.c | 6 +-
+ drivers/scsi/fcoe/fcoe.c | 16 ++--
+ include/linux/netdevice.h | 18 ++--
+ net/8021q/vlan.c | 4 +-
+ net/8021q/vlan_dev.c | 10 +-
+ net/core/dev.c | 195 +++++++++++++++++++++++++++-----------
+ net/dsa/slave.c | 10 +-
+ net/packet/af_packet.c | 4 +-
+ 18 files changed, 227 insertions(+), 137 deletions(-)
+ Signed-off-by: David S. Miller <davem@davemloft.net>
+
+Index: hurd-debian/libdde_linux26/contrib/include/linux/netdevice.h
+===================================================================
+--- hurd-debian.orig/libdde_linux26/contrib/include/linux/netdevice.h 2012-04-16 00:34:43.000000000 +0000
++++ hurd-debian/libdde_linux26/contrib/include/linux/netdevice.h 2012-04-16 00:34:46.000000000 +0000
+@@ -215,9 +215,12 @@
+ struct list_head list;
+ unsigned char addr[MAX_ADDR_LEN];
+ unsigned char type;
+-#define NETDEV_HW_ADDR_T_LAN 1
+-#define NETDEV_HW_ADDR_T_SAN 2
+-#define NETDEV_HW_ADDR_T_SLAVE 3
++#define NETDEV_HW_ADDR_T_LAN 1
++#define NETDEV_HW_ADDR_T_SAN 2
++#define NETDEV_HW_ADDR_T_SLAVE 3
++#define NETDEV_HW_ADDR_T_UNICAST 4
++ int refcount;
++ bool synced;
+ struct rcu_head rcu_head;
+ };
+
+@@ -738,10 +741,11 @@
+ unsigned char addr_len; /* hardware address length */
+ unsigned short dev_id; /* for shared network cards */
+
+- spinlock_t addr_list_lock;
+- struct dev_addr_list *uc_list; /* Secondary unicast mac addresses */
++ struct list_head uc_list; /* Secondary unicast mac
++ addresses */
+ int uc_count; /* Number of installed ucasts */
+ int uc_promisc;
++ spinlock_t addr_list_lock;
+ struct dev_addr_list *mc_list; /* Multicast mac addresses */
+ int mc_count; /* Number of installed mcasts */
+ unsigned int promiscuity;
+@@ -1816,8 +1820,8 @@
+ /* Functions used for secondary unicast and multicast support */
+ extern void dev_set_rx_mode(struct net_device *dev);
+ extern void __dev_set_rx_mode(struct net_device *dev);
+-extern int dev_unicast_delete(struct net_device *dev, void *addr, int alen);
+-extern int dev_unicast_add(struct net_device *dev, void *addr, int alen);
++extern int dev_unicast_delete(struct net_device *dev, void *addr);
++extern int dev_unicast_add(struct net_device *dev, void *addr);
+ extern int dev_unicast_sync(struct net_device *to, struct net_device *from);
+ extern void dev_unicast_unsync(struct net_device *to, struct net_device *from);
+ extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
+Index: hurd-debian/libdde_linux26/lib/src/net/core/dev.c
+===================================================================
+--- hurd-debian.orig/libdde_linux26/lib/src/net/core/dev.c 2012-04-16 00:34:43.000000000 +0000
++++ hurd-debian/libdde_linux26/lib/src/net/core/dev.c 2012-04-16 00:34:46.000000000 +0000
+@@ -3399,8 +3399,9 @@
+
+ /* hw addresses list handling functions */
+
+-static int __hw_addr_add(struct list_head *list, unsigned char *addr,
+- int addr_len, unsigned char addr_type)
++static int __hw_addr_add(struct list_head *list, int *delta,
++ unsigned char *addr, int addr_len,
++ unsigned char addr_type)
+ {
+ struct netdev_hw_addr *ha;
+ int alloc_size;
+@@ -3408,6 +3409,15 @@
+ if (addr_len > MAX_ADDR_LEN)
+ return -EINVAL;
+
++ list_for_each_entry(ha, list, list) {
++ if (!memcmp(ha->addr, addr, addr_len) &&
++ ha->type == addr_type) {
++ ha->refcount++;
++ return 0;
++ }
++ }
++
++
+ alloc_size = sizeof(*ha);
+ if (alloc_size < L1_CACHE_BYTES)
+ alloc_size = L1_CACHE_BYTES;
+@@ -3416,7 +3426,11 @@
+ return -ENOMEM;
+ memcpy(ha->addr, addr, addr_len);
+ ha->type = addr_type;
++ ha->refcount = 1;
++ ha->synced = false;
+ list_add_tail_rcu(&ha->list, list);
++ if (delta)
++ (*delta)++;
+ return 0;
+ }
+
+@@ -3428,29 +3442,30 @@
+ kfree(ha);
+ }
+
+-static int __hw_addr_del_ii(struct list_head *list, unsigned char *addr,
+- int addr_len, unsigned char addr_type,
+- int ignore_index)
++static int __hw_addr_del(struct list_head *list, int *delta,
++ unsigned char *addr, int addr_len,
++ unsigned char addr_type)
+ {
+ struct netdev_hw_addr *ha;
+- int i = 0;
+
+ list_for_each_entry(ha, list, list) {
+- if (i++ != ignore_index &&
+- !memcmp(ha->addr, addr, addr_len) &&
++ if (!memcmp(ha->addr, addr, addr_len) &&
+ (ha->type == addr_type || !addr_type)) {
++ if (--ha->refcount)
++ return 0;
+ list_del_rcu(&ha->list);
+ call_rcu(&ha->rcu_head, ha_rcu_free);
++ if (delta)
++ (*delta)--;
+ return 0;
+ }
+ }
+ return -ENOENT;
+ }
+
+-static int __hw_addr_add_multiple_ii(struct list_head *to_list,
+- struct list_head *from_list,
+- int addr_len, unsigned char addr_type,
+- int ignore_index)
++static int __hw_addr_add_multiple(struct list_head *to_list, int *to_delta,
++ struct list_head *from_list, int addr_len,
++ unsigned char addr_type)
+ {
+ int err;
+ struct netdev_hw_addr *ha, *ha2;
+@@ -3458,7 +3473,8 @@
+
+ list_for_each_entry(ha, from_list, list) {
+ type = addr_type ? addr_type : ha->type;
+- err = __hw_addr_add(to_list, ha->addr, addr_len, type);
++ err = __hw_addr_add(to_list, to_delta, ha->addr,
++ addr_len, type);
+ if (err)
+ goto unroll;
+ }
+@@ -3469,27 +3485,69 @@
+ if (ha2 == ha)
+ break;
+ type = addr_type ? addr_type : ha2->type;
+- __hw_addr_del_ii(to_list, ha2->addr, addr_len, type,
+- ignore_index);
++ __hw_addr_del(to_list, to_delta, ha2->addr,
++ addr_len, type);
+ }
+ return err;
+ }
+
+-static void __hw_addr_del_multiple_ii(struct list_head *to_list,
+- struct list_head *from_list,
+- int addr_len, unsigned char addr_type,
+- int ignore_index)
++static void __hw_addr_del_multiple(struct list_head *to_list, int *to_delta,
++ struct list_head *from_list, int addr_len,
++ unsigned char addr_type)
+ {
+ struct netdev_hw_addr *ha;
+ unsigned char type;
+
+ list_for_each_entry(ha, from_list, list) {
+ type = addr_type ? addr_type : ha->type;
+- __hw_addr_del_ii(to_list, ha->addr, addr_len, addr_type,
+- ignore_index);
++ __hw_addr_del(to_list, to_delta, ha->addr,
++ addr_len, addr_type);
+ }
+ }
+
++static int __hw_addr_sync(struct list_head *to_list, int *to_delta,
++ struct list_head *from_list, int *from_delta,
++ int addr_len)
++{
++ int err = 0;
++ struct netdev_hw_addr *ha, *tmp;
++
++ list_for_each_entry_safe(ha, tmp, from_list, list) {
++ if (!ha->synced) {
++ err = __hw_addr_add(to_list, to_delta, ha->addr,
++ addr_len, ha->type);
++ if (err)
++ break;
++ ha->synced = true;
++ ha->refcount++;
++ } else if (ha->refcount == 1) {
++ __hw_addr_del(to_list, to_delta, ha->addr,
++ addr_len, ha->type);
++ __hw_addr_del(from_list, from_delta, ha->addr,
++ addr_len, ha->type);
++ }
++ }
++ return err;
++}
++
++static void __hw_addr_unsync(struct list_head *to_list, int *to_delta,
++ struct list_head *from_list, int *from_delta,
++ int addr_len)
++{
++ struct netdev_hw_addr *ha, *tmp;
++
++ list_for_each_entry_safe(ha, tmp, from_list, list) {
++ if (ha->synced) {
++ __hw_addr_del(to_list, to_delta, ha->addr,
++ addr_len, ha->type);
++ ha->synced = false;
++ __hw_addr_del(from_list, from_delta, ha->addr,
++ addr_len, ha->type);
++ }
++ }
++}
++
++
+ static void __hw_addr_flush(struct list_head *list)
+ {
+ struct netdev_hw_addr *ha, *tmp;
+@@ -3520,7 +3578,7 @@
+
+ INIT_LIST_HEAD(&dev->dev_addr_list);
+ memset(addr, 0, sizeof(*addr));
+- err = __hw_addr_add(&dev->dev_addr_list, addr, sizeof(*addr),
++ err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, sizeof(*addr),
+ NETDEV_HW_ADDR_T_LAN);
+ if (!err) {
+ /*
+@@ -3552,7 +3610,7 @@
+
+ ASSERT_RTNL();
+
+- err = __hw_addr_add(&dev->dev_addr_list, addr, dev->addr_len,
++ err = __hw_addr_add(&dev->dev_addr_list, NULL, addr, dev->addr_len,
+ addr_type);
+ if (!err)
+ call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+@@ -3575,11 +3633,20 @@
+ unsigned char addr_type)
+ {
+ int err;
++ struct netdev_hw_addr *ha;
+
+ ASSERT_RTNL();
+
+- err = __hw_addr_del_ii(&dev->dev_addr_list, addr, dev->addr_len,
+- addr_type, 0);
++ /*
++ * We can not remove the first address from the list because
++ * dev->dev_addr points to that.
++ */
++ ha = list_first_entry(&dev->dev_addr_list, struct netdev_hw_addr, list);
++ if (ha->addr == dev->dev_addr && ha->refcount == 1)
++ return -ENOENT;
++
++ err = __hw_addr_del(&dev->dev_addr_list, NULL, addr, dev->addr_len,
++ addr_type);
+ if (!err)
+ call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+ return err;
+@@ -3606,9 +3673,9 @@
+
+ if (from_dev->addr_len != to_dev->addr_len)
+ return -EINVAL;
+- err = __hw_addr_add_multiple_ii(&to_dev->dev_addr_list,
+- &from_dev->dev_addr_list,
+- to_dev->addr_len, addr_type, 0);
++ err = __hw_addr_add_multiple(&to_dev->dev_addr_list, NULL,
++ &from_dev->dev_addr_list,
++ to_dev->addr_len, addr_type);
+ if (!err)
+ call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
+ return err;
+@@ -3633,9 +3700,9 @@
+
+ if (from_dev->addr_len != to_dev->addr_len)
+ return -EINVAL;
+- __hw_addr_del_multiple_ii(&to_dev->dev_addr_list,
+- &from_dev->dev_addr_list,
+- to_dev->addr_len, addr_type, 0);
++ __hw_addr_del_multiple(&to_dev->dev_addr_list, NULL,
++ &from_dev->dev_addr_list,
++ to_dev->addr_len, addr_type);
+ call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev);
+ return 0;
+ }
+@@ -3705,24 +3772,22 @@
+ * dev_unicast_delete - Release secondary unicast address.
+ * @dev: device
+ * @addr: address to delete
+- * @alen: length of @addr
+ *
+ * Release reference to a secondary unicast address and remove it
+ * from the device if the reference count drops to zero.
+ *
+ * The caller must hold the rtnl_mutex.
+ */
+-int dev_unicast_delete(struct net_device *dev, void *addr, int alen)
++int dev_unicast_delete(struct net_device *dev, void *addr)
+ {
+ int err;
+
+ ASSERT_RTNL();
+
+- netif_addr_lock_bh(dev);
+- err = __dev_addr_delete(&dev->uc_list, &dev->uc_count, addr, alen, 0);
++ err = __hw_addr_del(&dev->uc_list, &dev->uc_count, addr,
++ dev->addr_len, NETDEV_HW_ADDR_T_UNICAST);
+ if (!err)
+ __dev_set_rx_mode(dev);
+- netif_addr_unlock_bh(dev);
+ return err;
+ }
+ EXPORT_SYMBOL(dev_unicast_delete);
+@@ -3731,24 +3796,22 @@
+ * dev_unicast_add - add a secondary unicast address
+ * @dev: device
+ * @addr: address to add
+- * @alen: length of @addr
+ *
+ * Add a secondary unicast address to the device or increase
+ * the reference count if it already exists.
+ *
+ * The caller must hold the rtnl_mutex.
+ */
+-int dev_unicast_add(struct net_device *dev, void *addr, int alen)
++int dev_unicast_add(struct net_device *dev, void *addr)
+ {
+ int err;
+
+ ASSERT_RTNL();
+
+- netif_addr_lock_bh(dev);
+- err = __dev_addr_add(&dev->uc_list, &dev->uc_count, addr, alen, 0);
++ err = __hw_addr_add(&dev->uc_list, &dev->uc_count, addr,
++ dev->addr_len, NETDEV_HW_ADDR_T_UNICAST);
+ if (!err)
+ __dev_set_rx_mode(dev);
+- netif_addr_unlock_bh(dev);
+ return err;
+ }
+ EXPORT_SYMBOL(dev_unicast_add);
+@@ -3805,8 +3868,7 @@
+ * @from: source device
+ *
+ * Add newly added addresses to the destination device and release
+- * addresses that have no users left. The source device must be
+- * locked by netif_addr_lock_bh.
++ * addresses that have no users left.
+ *
+ * This function is intended to be called from the dev->set_rx_mode
+ * function of layered software devices.
+@@ -3815,12 +3877,15 @@
+ {
+ int err = 0;
+
+- netif_addr_lock_bh(to);
+- err = __dev_addr_sync(&to->uc_list, &to->uc_count,
+- &from->uc_list, &from->uc_count);
++ ASSERT_RTNL();
++
++ if (to->addr_len != from->addr_len)
++ return -EINVAL;
++
++ err = __hw_addr_sync(&to->uc_list, &to->uc_count,
++ &from->uc_list, &from->uc_count, to->addr_len);
+ if (!err)
+ __dev_set_rx_mode(to);
+- netif_addr_unlock_bh(to);
+ return err;
+ }
+ EXPORT_SYMBOL(dev_unicast_sync);
+@@ -3836,18 +3901,33 @@
+ */
+ void dev_unicast_unsync(struct net_device *to, struct net_device *from)
+ {
+- netif_addr_lock_bh(from);
+- netif_addr_lock(to);
++ ASSERT_RTNL();
+
+- __dev_addr_unsync(&to->uc_list, &to->uc_count,
+- &from->uc_list, &from->uc_count);
+- __dev_set_rx_mode(to);
++ if (to->addr_len != from->addr_len)
++ return;
+
+- netif_addr_unlock(to);
+- netif_addr_unlock_bh(from);
++ __hw_addr_unsync(&to->uc_list, &to->uc_count,
++ &from->uc_list, &from->uc_count, to->addr_len);
++ __dev_set_rx_mode(to);
+ }
+ EXPORT_SYMBOL(dev_unicast_unsync);
+
++static void dev_unicast_flush(struct net_device *dev)
++{
++ /* rtnl_mutex must be held here */
++
++ __hw_addr_flush(&dev->uc_list);
++ dev->uc_count = 0;
++}
++
++static void dev_unicast_init(struct net_device *dev)
++{
++ /* rtnl_mutex must be held here */
++
++ INIT_LIST_HEAD(&dev->uc_list);
++}
++
++
+ static void __dev_addr_discard(struct dev_addr_list **list)
+ {
+ struct dev_addr_list *tmp;
+@@ -3866,9 +3946,6 @@
+ {
+ netif_addr_lock_bh(dev);
+
+- __dev_addr_discard(&dev->uc_list);
+- dev->uc_count = 0;
+-
+ __dev_addr_discard(&dev->mc_list);
+ dev->mc_count = 0;
+
+@@ -4459,6 +4536,7 @@
+ /*
+ * Flush the unicast and multicast chains
+ */
++ dev_unicast_flush(dev);
+ dev_addr_discard(dev);
+
+ if (dev->netdev_ops->ndo_uninit)
+@@ -4975,6 +5053,8 @@
+ dev = (struct net_device *)
+ (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
+ dev->padded = (char *)dev - (char *)p;
++ dev_unicast_init(dev);
++
+ dev_net_set(dev, &init_net);
+
+ dev->_tx = tx;
+@@ -5173,6 +5253,7 @@
+ /*
+ * Flush the unicast and multicast chains
+ */
++ dev_unicast_flush(dev);
+ dev_addr_discard(dev);
+
+ netdev_unregister_kobject(dev);
diff --git a/debian/patches/libdde_workqueue.patch b/debian/patches/libdde_workqueue.patch
new file mode 100644
index 00000000..5ea9b612
--- /dev/null
+++ b/debian/patches/libdde_workqueue.patch
@@ -0,0 +1,55 @@
+diff --git a/libdde_linux26/contrib/include/linux/workqueue.h b/libdde_linux26/contrib/include/linux/workqueue.h
+index 3cd51e5..cf24c20 100644
+--- a/libdde_linux26/contrib/include/linux/workqueue.h
++++ b/libdde_linux26/contrib/include/linux/workqueue.h
+@@ -41,6 +41,11 @@ struct delayed_work {
+ struct timer_list timer;
+ };
+
++static inline struct delayed_work *to_delayed_work(struct work_struct *work)
++{
++ return container_of(work, struct delayed_work, work);
++}
++
+ struct execute_work {
+ struct work_struct work;
+ };
+@@ -89,7 +94,7 @@ struct execute_work {
+ /*
+ * initialize all of a work item in one go
+ *
+- * NOTE! No point in using "atomic_long_set()": useing a direct
++ * NOTE! No point in using "atomic_long_set()": using a direct
+ * assignment of the work data initializer allows the compiler
+ * to generate better code.
+ */
+@@ -202,6 +207,7 @@
+
+ extern void flush_workqueue(struct workqueue_struct *wq);
+ extern void flush_scheduled_work(void);
++extern void flush_delayed_work(struct delayed_work *work);
+
+ extern int schedule_work(struct work_struct *work);
+ extern int schedule_work_on(int cpu, struct work_struct *work);
+@@ -233,6 +239,21 @@
+ if (ret)
+ work_clear_pending(&work->work);
+ return ret;
++}
++
++/*
++ * Like above, but uses del_timer() instead of del_timer_sync(). This means,
++ * if it returns 0 the timer function may be running and the queueing is in
++ * progress.
++ */
++static inline int __cancel_delayed_work(struct delayed_work *work)
++{
++ int ret;
++
++ ret = del_timer(&work->timer);
++ if (ret)
++ work_clear_pending(&work->work);
++ return ret;
+ }
+
+ extern int cancel_delayed_work_sync(struct delayed_work *work);
diff --git a/debian/patches/libexec.patch b/debian/patches/libexec.patch
new file mode 100644
index 00000000..12b5a01d
--- /dev/null
+++ b/debian/patches/libexec.patch
@@ -0,0 +1,103 @@
+diff --git a/config/ttys b/config/ttys
+index 6a548d5..d10bfcc 100644
+--- a/config/ttys
++++ b/config/ttys
+@@ -4,11 +4,11 @@
+
+ # name program type status comments
+
+-console "/libexec/getty 9600" mach-gnu-color on secure trusted console
+-tty1 "/libexec/getty 38400" hurd on secure trusted console
+-tty2 "/libexec/getty 38400" hurd on secure trusted console
+-tty3 "/libexec/getty 38400" hurd on secure trusted console
+-tty4 "/libexec/getty 38400" hurd on secure trusted console
+-tty5 "/libexec/getty 38400" hurd on secure trusted console
+-tty6 "/libexec/getty 38400" hurd on secure trusted console
+-#com0 "/libexec/getty 9600" dialup on secure
++console "/sbin/getty 9600" mach-gnu-color on secure trusted console
++tty1 "/sbin/getty 38400" hurd on secure trusted console
++tty2 "/sbin/getty 38400" hurd on secure trusted console
++tty3 "/sbin/getty 38400" hurd on secure trusted console
++tty4 "/sbin/getty 38400" hurd on secure trusted console
++tty5 "/sbin/getty 38400" hurd on secure trusted console
++tty6 "/sbin/getty 38400" hurd on secure trusted console
++#com0 "/sbin/getty 9600" dialup on secure
+diff --git a/daemons/runsystem.sh b/daemons/runsystem.sh
+index c3cb2d6..0ce4f59 100644
+--- a/daemons/runsystem.sh
++++ b/daemons/runsystem.sh
+@@ -23,8 +23,8 @@ fallback_shells='/bin/sh /bin/bash /bin/csh /bin/ash /bin/shd'
+ SHELL=/bin/sh
+
+ # Programs that do multi-user startup.
+-RUNCOM=/libexec/rc
+-RUNTTYS=/libexec/runttys
++RUNCOM=/etc/hurd/rc
++RUNTTYS=/sbin/runttys
+ # Signals that we should pass down to runttys.
+ runttys_sigs='TERM INT HUP TSTP'
+
+diff --git a/doc/hurd.texi b/doc/hurd.texi
+index ea73a4c..7d7af39 100644
+--- a/doc/hurd.texi
++++ b/doc/hurd.texi
+@@ -570,7 +570,7 @@ The @option{--multiboot-command-line} option tells the file system server that
+ it is a root filesystem, which triggers it to run @command{/hurd/init} as PID
+ 1. @command{/hurd/init} starts the @command{/hurd/proc} and
+ @command{/hurd/auth} servers. After the servers are launched
+-@command{/hurd/init} starts the @command{/libexec/runsystem.sh} script to
++@command{/hurd/init} starts the @command{/etc/hurd/runsystem.sh} script to
+ finish booting.
+
+ After the Hurd has been booted, other sets of core Hurd servers can be
+diff --git a/init/init.c b/init/init.c
+index d66bee0..14d822e 100644
+--- a/init/init.c
++++ b/init/init.c
+@@ -888,7 +888,7 @@ frob_kernel_process (void)
+ /** Running userland. **/
+
+ /* In the "split-init" setup, we just run a single program (usually
+- /libexec/runsystem) that is not expected to ever exit (or stop).
++ /etc/hurd/runsystem) that is not expected to ever exit (or stop).
+ If it does exit (or can't be started), we go to an emergency single-user
+ shell as a fallback. */
+
+@@ -1004,7 +1004,7 @@ process_signal (int signo)
+ }
+ }
+
+-/* Start the child program PROG. It is run via /libexec/console-run
++/* Start the child program PROG. It is run via /sbin/console-run
+ with the given additional arguments. */
+ static int
+ start_child (const char *prog, char **progargs)
+@@ -1016,7 +1016,7 @@ start_child (const char *prog, char **progargs)
+
+ if (progargs == 0)
+ {
+- const char *argv[] = { "/libexec/console-run", prog, 0 };
++ const char *argv[] = { "/sbin/console-run", prog, 0 };
+ err = argz_create ((char **) argv, &args, &arglen);
+ }
+ else
+@@ -1026,7 +1026,7 @@ start_child (const char *prog, char **progargs)
+ ++argc;
+ {
+ const char *argv[2 + argc + 1];
+- argv[0] = "/libexec/console-run";
++ argv[0] = "/sbin/console-run";
+ argv[1] = prog;
+ argv[2 + argc] = 0;
+ while (argc-- > 0)
+@@ -1086,8 +1086,8 @@ launch_something (const char *why)
+ static unsigned int try;
+ static const char *const tries[] =
+ {
+- "/libexec/runsystem",
+- "/libexec/runsystem.gnu",
++ "/etc/hurd/runsystem",
++ "/etc/hurd/runsystem.gnu",
+ _PATH_BSHELL,
+ "/bin/shd", /* XXX */
+ };
diff --git a/debian/patches/libmachdev.patch b/debian/patches/libmachdev.patch
new file mode 100644
index 00000000..3bca9ff3
--- /dev/null
+++ b/debian/patches/libmachdev.patch
@@ -0,0 +1,35 @@
+diff --git a/libmachdev/net.c b/libmachdev/net.c
+index 606765f..766d9b4 100644
+--- a/libmachdev/net.c
++++ b/libmachdev/net.c
+@@ -212,7 +212,7 @@ deliver_msg(struct net_rcv_msg *msg, if_filter_list_t *ifp)
+ MACH_SEND_MSG|MACH_SEND_TIMEOUT,
+ msg->msg_hdr.msgh_size, 0, MACH_PORT_NULL,
+ 0, MACH_PORT_NULL);
+- if (err != MACH_MSG_SUCCESS)
++ if (0 && err != MACH_MSG_SUCCESS)
+ {
+ /* TODO: remove from filter */
+ }
+@@ -377,7 +377,7 @@ device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
+ }
+
+ *devp = ports_get_right (nd);
+- *devicePoly = MACH_MSG_TYPE_COPY_SEND;
++ *devicePoly = MACH_MSG_TYPE_MAKE_SEND;
+ return D_SUCCESS;
+ }
+
+diff --git a/libmachdev/ds_routines.c b/libmachdev/ds_routines.c
+index 6b8d1d4..f0c034f 100644
+--- a/libmachdev/ds_routines.c
++++ b/libmachdev/ds_routines.c
+@@ -206,7 +206,7 @@ ds_device_close (device_t dev)
+ ret = (device->emul_ops->close
+ ? (*device->emul_ops->close) (device->emul_data)
+ : D_SUCCESS);
+- mach_device_deallocate (device_to_pi (device));
++ //mach_device_deallocate (device_to_pi (device));
+
+ ports_port_deref (device_to_pi (device));
+ return ret;
diff --git a/debian/patches/libports_stability.patch b/debian/patches/libports_stability.patch
new file mode 100644
index 00000000..4452807c
--- /dev/null
+++ b/debian/patches/libports_stability.patch
@@ -0,0 +1,20 @@
+Ideally we should be able to time out and see translators go away automatically,
+however it makes all threads often wake at the same time and overload Mach.
+
+---
+ libports/manage-multithread.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+Index: hurd-debian/libports/manage-multithread.c
+===================================================================
+--- hurd-debian.orig/libports/manage-multithread.c 2012-11-26 00:23:22.000000000 +0000
++++ hurd-debian/libports/manage-multithread.c 2012-11-26 00:25:28.000000000 +0000
+@@ -243,6 +243,8 @@
+ return NULL;
+ }
+
++ thread_timeout = global_timeout = 0; /* XXX */
++
+ nreqthreads = 1;
+ totalthreads = 1;
+ thread_function ((void *) 1);
diff --git a/debian/patches/makedev.diff b/debian/patches/makedev.diff
new file mode 100644
index 00000000..f53320c5
--- /dev/null
+++ b/debian/patches/makedev.diff
@@ -0,0 +1,17 @@
+Do not create the shm node since Marcus' SHM implementation uses a directory
+there.
+---
+ sutils/MAKEDEV.sh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sutils/MAKEDEV.sh
++++ b/sutils/MAKEDEV.sh
+@@ -86,7 +86,7 @@ function mkdev {
+ ;;
+
+ std)
+- mkdev console tty null zero full fd time mem klog shm
++ mkdev console tty null zero full fd time mem klog
+ ;;
+ console|com[0-9])
+ st $I root 600 /hurd/term ${DEVDIR}/$I device $I;;
diff --git a/debian/patches/pfinet_dhcp.patch b/debian/patches/pfinet_dhcp.patch
new file mode 100644
index 00000000..92446267
--- /dev/null
+++ b/debian/patches/pfinet_dhcp.patch
@@ -0,0 +1,560 @@
+2007-10-14 Christian Dietrich <stettberger@dokucode.de>
+
+ * options.c (options): Marked -a, -g -m, -p, -A, -G
+ OPTION_ARG_OPTIONAL. Adding -d option.
+ (parse_interface_copy_device): New function.
+ (parse_opt): When selecting another interface with -i
+ set the options from e.g. a prior fsysopts call as default
+ values. For -a, -g, -p, -g, -A, -G set the optional
+ argument as value. When there is no argument, delete the
+ value (e.g. unset default gateway). Delete delete default gateways
+ only if the set gateway is on an interface modified in this call.
+ Add always an route for dhcp packages on all devices. By doing
+ this we can send dhcp renew packages.
+ (trivfs_append_args): Add --gateway only once.
+
+2007-10-14 Marco Gerards <metgerards@student.han.nl>
+
+ * options.c (options): Add the option `dhcp'.
+ (parse_hook_add_interface): Initialize the `dhcp' member for the
+ parse hook.
+ (parse_opt): In case pfinet is started with the argument `--dhcp',
+ set the address to `0.0.0.0', the netmask to `255.0.0.0' and add
+ the route for `0.0.0.0' so broadcasting works.
+
+ * linux-src/net/ipv4/devinet.c (inet_insert_ifa) [_HURD_]: Don't
+ fail when the address is `0.0.0.0'.
+
+---
+ pfinet/linux-src/net/ipv4/devinet.c | 2
+ pfinet/options.c | 381 ++++++++++++++++++++++++++----------
+ 2 files changed, 278 insertions(+), 105 deletions(-)
+
+--- a/pfinet/options.c
++++ b/pfinet/options.c
+@@ -60,23 +60,26 @@ extern struct inet6_dev *ipv6_find_idev
+ extern int inet6_addr_add (int ifindex, struct in6_addr *pfx, int plen);
+ extern int inet6_addr_del (int ifindex, struct in6_addr *pfx, int plen);
+
++#ifdef CONFIG_IPV6
++static struct rt6_info * ipv6_get_dflt_router (void);
++#endif
++
+
+ /* Pfinet options. Used for both startup and runtime. */
+ static const struct argp_option options[] =
+ {
+- {"interface", 'i', "DEVICE", 0, "Network interface to use", 1},
++ {"interface", 'i', "DEVICE", 0, "Network interface to use", 1},
+ {0,0,0,0,"These apply to a given interface:", 2},
+- {"address", 'a', "ADDRESS", 0, "Set the network address"},
+- {"netmask", 'm', "MASK", 0, "Set the netmask"},
+- {"peer", 'p', "ADDRESS", 0, "Set the peer address"},
+- {"gateway", 'g', "ADDRESS", 0, "Set the default gateway"},
+- {"ipv4", '4', "NAME", 0, "Put active IPv4 translator on NAME"},
++ {"address", 'a', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the network address"},
++ {"netmask", 'm', "MASK", OPTION_ARG_OPTIONAL, "Set the netmask"},
++ {"peer", 'p', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the peer address"},
++ {"gateway", 'g', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the default gateway"},
++ {"ipv4", '4', "NAME", 0, "Put active IPv4 translator on NAME"},
+ #ifdef CONFIG_IPV6
+- {"ipv6", '6', "NAME", 0, "Put active IPv6 translator on NAME"},
+- {"address6", 'A', "ADDR/LEN",0, "Set the global IPv6 address"},
+- {"gateway6", 'G', "ADDRESS", 0, "Set the IPv6 default gateway"},
++ {"ipv6", '6', "NAME", 0, "Put active IPv6 translator on NAME"},
++ {"address6", 'A', "ADDR/LEN", OPTION_ARG_OPTIONAL, "Set the global IPv6 address"},
++ {"gateway6", 'G', "ADDRESS", OPTION_ARG_OPTIONAL, "Set the IPv6 default gateway"},
+ #endif
+- {"shutdown", 's', 0, 0, "Shut it down"},
+ {0}
+ };
+
+@@ -112,6 +115,50 @@ struct parse_hook
+ struct parse_interface *curint;
+ };
+
++static void
++parse_interface_copy_device(struct device *src,
++ struct parse_interface *dst)
++{
++ uint32_t broad;
++ struct rt_key key = { 0 };
++ struct inet6_dev *idev = NULL;
++ struct fib_result res;
++
++ inquire_device (src, &dst->address, &dst->netmask,
++ &dst->peer, &broad);
++ /* Get gateway */
++ dst->gateway = INADDR_NONE;
++ key.oif = src->ifindex;
++ if (! main_table->tb_lookup (main_table, &key, &res)
++ && FIB_RES_GW(res) != INADDR_ANY)
++ dst->gateway = FIB_RES_GW (res);
++#ifdef CONFIG_IPV6
++ if (trivfs_protid_portclasses[PORTCLASS_INET6] != MACH_PORT_NULL)
++ idev = ipv6_find_idev(src);
++
++ if (idev)
++ {
++ struct inet6_ifaddr *ifa = idev->addr_list;
++
++ /* Look for IPv6 default router and add it to the interface,
++ * if it belongs to it.
++ */
++ struct rt6_info *rt6i = ipv6_get_dflt_router();
++ if (rt6i->rt6i_dev == src)
++ memcpy (&dst->gateway6, &rt6i->rt6i_gateway, sizeof (struct in6_addr));
++ /* Search for global address and set it in dst */
++ do
++ {
++ if (!IN6_IS_ADDR_LINKLOCAL (&ifa->addr)) {
++ memcpy (&dst->address6, ifa, sizeof (struct inet6_ifaddr));
++ break;
++ }
++ }
++ while ((ifa = ifa->if_next));
++ }
++#endif
++}
++
+ /* Adds an empty interface slot to H, and sets H's current interface to it, or
+ returns an error. */
+ static error_t
+@@ -122,6 +169,7 @@ parse_hook_add_interface (struct parse_h
+ (h->num_interfaces + 1) * sizeof (struct parse_interface));
+ if (! new)
+ return ENOMEM;
++
+ h->interfaces = new;
+ h->num_interfaces++;
+ h->curint = new + h->num_interfaces - 1;
+@@ -183,10 +231,16 @@ parse_opt (int opt, char *arg, struct ar
+ if (addr == INADDR_NONE) PERR (EINVAL, "Malformed %s", type); \
+ addr; })
+
++ if (!arg && state->next < state->argc
++ && (*state->argv[state->next] != '-'))
++ {
++ arg = state->argv[state->next];
++ state->next ++;
++ }
++
+ switch (opt)
+ {
+- struct parse_interface *in;
+- uint32_t gateway;
++ struct parse_interface *in, *gw4_in;
+ #ifdef CONFIG_IPV6
+ struct parse_interface *gw6_in;
+ char *ptr;
+@@ -217,29 +271,59 @@ parse_opt (int opt, char *arg, struct ar
+ if (err)
+ FAIL (err, 10, err, "%s", arg);
+
++ /* Set old interface values */
++ parse_interface_copy_device (in->device, in);
+ break;
+
+ case 'a':
+- h->curint->address = ADDR (arg, "address");
+- if (!IN_CLASSA (ntohl (h->curint->address))
+- && !IN_CLASSB (ntohl (h->curint->address))
+- && !IN_CLASSC (ntohl (h->curint->address)))
+- {
+- if (IN_MULTICAST (ntohl (h->curint->address)))
+- FAIL (EINVAL, 1, 0,
+- "%s: Cannot set interface address to multicast address",
+- arg);
+- else
+- FAIL (EINVAL, 1, 0,
+- "%s: Illegal or undefined network address", arg);
+- }
++ if (arg)
++ {
++ h->curint->address = ADDR (arg, "address");
++ if (!IN_CLASSA (ntohl (h->curint->address))
++ && !IN_CLASSB (ntohl (h->curint->address))
++ && !IN_CLASSC (ntohl (h->curint->address)))
++ {
++ if (IN_MULTICAST (ntohl (h->curint->address)))
++ FAIL (EINVAL, 1, 0,
++ "%s: Cannot set interface address to multicast address",
++ arg);
++ else
++ FAIL (EINVAL, 1, 0,
++ "%s: Illegal or undefined network address", arg);
++ }
++ } else {
++ h->curint->address = ADDR ("0.0.0.0", "address");
++ h->curint->netmask = ADDR ("255.0.0.0", "netmask");
++ h->curint->gateway = INADDR_NONE;
++ }
+ break;
++
+ case 'm':
+- h->curint->netmask = ADDR (arg, "netmask"); break;
++ if (arg)
++ h->curint->netmask = ADDR (arg, "netmask");
++ else
++ h->curint->netmask = INADDR_NONE;
++ break;
++
+ case 'p':
+- h->curint->peer = ADDR (arg, "peer"); break;
++ if (arg)
++ h->curint->peer = ADDR (arg, "peer");
++ else
++ h->curint->peer = INADDR_NONE;
++ break;
++
+ case 'g':
+- h->curint->gateway = ADDR (arg, "gateway"); break;
++ if (arg)
++ {
++ /* Remove an possible other default gateway */
++ for (in = h->interfaces; in < h->interfaces + h->num_interfaces;
++ in++)
++ in->gateway = INADDR_NONE;
++ h->curint->gateway = ADDR (arg, "gateway");
++ }
++ else
++ h->curint->gateway = INADDR_NONE;
++ break;
+
+ case '4':
+ pfinet_bind (PORTCLASS_INET, arg);
+@@ -254,36 +338,46 @@ parse_opt (int opt, char *arg, struct ar
+ break;
+
+ case 'A':
+- if ((ptr = strchr (arg, '/')))
++ if (arg)
+ {
+- h->curint->address6.prefix_len = atoi (ptr + 1);
+- if (h->curint->address6.prefix_len > 128)
+- FAIL (EINVAL, 1, 0, "%s: The prefix-length is invalid", arg);
++ if ((ptr = strchr (arg, '/')))
++ {
++ h->curint->address6.prefix_len = atoi (ptr + 1);
++ if (h->curint->address6.prefix_len > 128)
++ FAIL (EINVAL, 1, 0, "%s: The prefix-length is invalid", arg);
++
++ *ptr = 0;
++ }
++ else
++ {
++ h->curint->address6.prefix_len = 64;
++ fprintf (stderr, "No prefix-length given, "
++ "defaulting to %s/64.\n", arg);
++ }
++
++ if (inet_pton (AF_INET6, arg, &h->curint->address6.addr) <= 0)
++ PERR (EINVAL, "Malformed address");
+
+- *ptr = 0;
++ if (IN6_IS_ADDR_MULTICAST (&h->curint->address6.addr))
++ FAIL (EINVAL, 1, 0, "%s: Cannot set interface address to "
++ "multicast address", arg);
+ }
+ else
+- {
+- h->curint->address6.prefix_len = 64;
+- fprintf (stderr, "No prefix-length given, defaulting to %s/64.\n",
+- arg);
+- }
+-
+- if (inet_pton (AF_INET6, arg, &h->curint->address6.addr) <= 0)
+- PERR (EINVAL, "Malformed address");
+-
+- if (IN6_IS_ADDR_MULTICAST (&h->curint->address6.addr))
+- FAIL (EINVAL, 1, 0, "%s: Cannot set interface address to "
+- "multicast address", arg);
++ memset (&h->curint->address6, 0, sizeof (struct inet6_ifaddr));
+ break;
+
+ case 'G':
+- if (inet_pton (AF_INET6, arg, &h->curint->gateway6) <= 0)
+- PERR (EINVAL, "Malformed gateway");
++ if (arg)
++ {
++ if (inet_pton (AF_INET6, arg, &h->curint->gateway6) <= 0)
++ PERR (EINVAL, "Malformed gateway");
+
+- if (IN6_IS_ADDR_MULTICAST (&h->curint->gateway6))
+- FAIL (EINVAL, 1, 0, "%s: Cannot set gateway to "
+- "multicast address", arg);
++ if (IN6_IS_ADDR_MULTICAST (&h->curint->gateway6))
++ FAIL (EINVAL, 1, 0, "%s: Cannot set gateway to "
++ "multicast address", arg);
++ }
++ else
++ memset (&h->curint->gateway6, 0, sizeof (struct in6_addr));
+ break;
+ #endif /* CONFIG_IPV6 */
+
+@@ -323,20 +417,19 @@ parse_opt (int opt, char *arg, struct ar
+ /* Specifying a netmask for an address-less interface is a no-no. */
+ FAIL (EDESTADDRREQ, 14, 0, "Cannot set netmask");
+ #endif
+-
+- gateway = INADDR_NONE;
+ #ifdef CONFIG_IPV6
+ gw6_in = NULL;
+ #endif
++ gw4_in = NULL;
+ for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++)
+ {
++ /* delete interface if it doesn't match the actual netmask */
++ if (! ( (h->curint->address & h->curint->netmask)
++ == (h->curint->gateway & h->curint->netmask)))
++ h->curint->gateway = INADDR_NONE;
++
+ if (in->gateway != INADDR_NONE)
+- {
+- if (gateway != INADDR_NONE)
+- FAIL (err, 15, 0, "Cannot have multiple default gateways");
+- gateway = in->gateway;
+- in->gateway = INADDR_NONE;
+- }
++ gw4_in = in;
+
+ #ifdef CONFIG_IPV6
+ if (!IN6_IS_ADDR_UNSPECIFIED (&in->gateway6))
+@@ -361,15 +454,20 @@
+ idev = ipv6_find_idev(in->device);
+ #endif
+
+- if (in->address != INADDR_NONE || in->netmask != INADDR_NONE)
++ if (in->address == INADDR_NONE && in->netmask == INADDR_NONE)
+ {
+- err = configure_device (in->device, in->address, in->netmask,
+- in->peer, INADDR_NONE);
+- if (err)
+- {
+- pthread_mutex_unlock (&global_lock);
+- FAIL (err, 16, 0, "cannot configure interface");
+- }
++ h->curint->address = ADDR ("0.0.0.0", "address");
++ h->curint->netmask = ADDR ("255.0.0.0", "netmask");
++ }
++
++ if (in->device)
++ err = configure_device (in->device, in->address, in->netmask,
++ in->peer, INADDR_NONE);
++
++ if (err)
++ {
++ pthread_mutex_unlock (&global_lock);
++ FAIL (err, 16, 0, "cannot configure interface");
+ }
+
+ #ifdef CONFIG_IPV6
+@@ -377,24 +475,25 @@
+ continue;
+
+ /* First let's remove all non-local addresses. */
+- struct inet6_ifaddr *ifa = idev->addr_list;
+-
+- while (ifa)
+- {
+- struct inet6_ifaddr *c_ifa = ifa;
+- ifa = ifa->if_next;
+-
+- if (IN6_ARE_ADDR_EQUAL (&c_ifa->addr, &in->address6.addr))
+- memset (&in->address6, 0, sizeof (struct inet6_ifaddr));
+-
+- else if (!IN6_IS_ADDR_LINKLOCAL (&c_ifa->addr)
+- && !IN6_IS_ADDR_SITELOCAL (&c_ifa->addr))
+- inet6_addr_del (in->device->ifindex, &c_ifa->addr,
+- c_ifa->prefix_len);
+- }
+-
+- if (!IN6_IS_ADDR_UNSPECIFIED (&in->address6.addr))
+- {
++ struct inet6_ifaddr *ifa = idev->addr_list;
++
++ while (ifa)
++ {
++ struct inet6_ifaddr *c_ifa = ifa;
++ ifa = ifa->if_next;
++
++ if (!IN6_IS_ADDR_UNSPECIFIED (&in->address6.addr)
++ && IN6_ARE_ADDR_EQUAL (&c_ifa->addr, &in->address6.addr))
++ memset (&in->address6, 0, sizeof (struct inet6_ifaddr));
++
++ else if (!IN6_IS_ADDR_LINKLOCAL (&c_ifa->addr)
++ && !IN6_IS_ADDR_SITELOCAL (&c_ifa->addr))
++ inet6_addr_del (in->device->ifindex, &c_ifa->addr,
++ c_ifa->prefix_len);
++ }
++
++ if (!IN6_IS_ADDR_UNSPECIFIED (&in->address6.addr))
++ {
+ /* Now assign the new address */
+ inet6_addr_add (in->device->ifindex, &in->address6.addr,
+ in->address6.prefix_len);
+@@ -418,33 +517,40 @@
+ req.nlh.nlmsg_seq = 0;
+ req.nlh.nlmsg_len = NLMSG_LENGTH (sizeof req.rtm);
+
+- bzero (&req.rtm, sizeof req.rtm);
+- bzero (&rta, sizeof rta);
++ memset (&req.rtm, 0, sizeof req.rtm);
++ memset (&rta, 0, sizeof rta);
+ req.rtm.rtm_scope = RT_SCOPE_UNIVERSE;
+ req.rtm.rtm_type = RTN_UNICAST;
+ req.rtm.rtm_protocol = RTPROT_STATIC;
+- rta.rta_gw = &gateway;
+
+- if (gateway == INADDR_NONE)
++ if (!gw4_in)
+ {
+- /* Delete any existing default route. */
+- req.nlh.nlmsg_type = RTM_DELROUTE;
+- req.nlh.nlmsg_flags = 0;
+- tb = fib_get_table (req.rtm.rtm_table);
+- if (tb)
+- {
+- err = - (*tb->tb_delete) (tb, &req.rtm, &rta, &req.nlh, 0);
+- if (err && err != ESRCH)
+- {
+- pthread_mutex_unlock (&global_lock);
+- FAIL (err, 17, 0, "cannot remove old default gateway");
+- }
+- err = 0;
+- }
++ /* Delete any existing default route on configured devices */
++ for (in = h->interfaces; in < h->interfaces + h->num_interfaces;
++ in++) {
++ req.nlh.nlmsg_type = RTM_DELROUTE;
++ req.nlh.nlmsg_flags = 0;
++ rta.rta_oif = &in->device->ifindex;
++ tb = fib_get_table (req.rtm.rtm_table);
++ if (tb)
++ {
++ err = - (*tb->tb_delete)
++ (tb, &req.rtm, &rta, &req.nlh, 0);
++ if (err && err != ESRCH)
++ {
++ pthread_mutex_unlock (&global_lock);
++ FAIL (err, 17, 0,
++ "cannot remove old default gateway");
++ }
++ err = 0;
++ }
++ }
+ }
+ else
+ {
+ /* Add a default route, replacing any existing one. */
++ rta.rta_oif = &gw4_in->device->ifindex;
++ rta.rta_gw = &gw4_in->gateway;
+ req.nlh.nlmsg_type = RTM_NEWROUTE;
+ req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE;
+ tb = fib_new_table (req.rtm.rtm_table);
+@@ -467,13 +573,77 @@
+ if (!gw6_in || rt6i->rt6i_dev != gw6_in->device
+ || !IN6_ARE_ADDR_EQUAL (&rt6i->rt6i_gateway, &gw6_in->gateway6))
+ {
+- rt6_purge_dflt_routers (0);
++ /* Delete any existing default route on configured devices */
++ for (in = h->interfaces; in < h->interfaces
++ + h->num_interfaces; in++)
++ if (rt6i->rt6i_dev == in->device || gw6_in )
++ rt6_purge_dflt_routers (0);
++
+ if (gw6_in)
+ rt6_add_dflt_router (&gw6_in->gateway6, gw6_in->device);
+ }
+ }
+ #endif
+
++ /* Setup the routing required for DHCP. */
++ for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++)
++ {
++ struct kern_rta rta;
++ struct
++ {
++ struct nlmsghdr nlh;
++ struct rtmsg rtm;
++ } req;
++ struct fib_table *tb;
++ struct rtentry route;
++ struct sockaddr_in *dst;
++ struct device *dev;
++
++ if (!in->device)
++ continue;
++
++ dst = (struct sockaddr_in *) &route.rt_dst;
++ if (!in->device->name)
++ {
++ pthread_mutex_unlock (&global_lock);
++ FAIL (ENODEV, 17, 0, "unknown device");
++ }
++ dev = dev_get (in->device->name);
++ if (!dev)
++ {
++ pthread_mutex_unlock (&global_lock);
++ FAIL (ENODEV, 17, 0, "unknown device");
++ }
++
++ /* Simulate the SIOCADDRT behavior. */
++ memset (&route, 0, sizeof (struct rtentry));
++ memset (&req.rtm, 0, sizeof req.rtm);
++ memset (&rta, 0, sizeof rta);
++ req.nlh.nlmsg_type = RTM_NEWROUTE;
++
++ /* Append this routing for 0.0.0.0. By this way we can send always
++ dhcp messages (e.g dhcp renew). */
++ req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE
++ | NLM_F_APPEND;
++ req.rtm.rtm_protocol = RTPROT_BOOT;
++ req.rtm.rtm_scope = RT_SCOPE_LINK;
++ req.rtm.rtm_type = RTN_UNICAST;
++ rta.rta_dst = &dst->sin_addr.s_addr;
++ rta.rta_oif = &dev->ifindex;
++
++ tb = fib_new_table (req.rtm.rtm_table);
++ if (tb)
++ err = tb->tb_insert (tb, &req.rtm, &rta, &req.nlh, NULL);
++ else
++ err = ENOBUFS;
++
++ if (err)
++ {
++ pthread_mutex_unlock (&global_lock);
++ FAIL (err, 17, 0, "cannot add route");
++ }
++ }
++
+ pthread_mutex_unlock (&global_lock);
+
+ /* Fall through to free hook. */
+@@ -526,8 +696,9 @@
+ ADD_ADDR_OPT ("netmask", mask);
+ if (peer != addr)
+ ADD_ADDR_OPT ("peer", peer);
+- key.iif = dev->ifindex;
+- if (! main_table->tb_lookup (main_table, &key, &res))
++ key.oif = dev->ifindex;
++ if (! main_table->tb_lookup (main_table, &key, &res)
++ && FIB_RES_GW(res) != INADDR_ANY)
+ ADD_ADDR_OPT ("gateway", FIB_RES_GW (res));
+
+ #undef ADD_ADDR_OPT
+--- a/pfinet/linux-src/net/ipv4/devinet.c
++++ b/pfinet/linux-src/net/ipv4/devinet.c
+@@ -214,10 +214,12 @@ inet_insert_ifa(struct in_device *in_dev
+ {
+ struct in_ifaddr *ifa1, **ifap, **last_primary;
+
++#ifndef _HURD_
+ if (ifa->ifa_local == 0) {
+ inet_free_ifa(ifa);
+ return 0;
+ }
++#endif
+
+ ifa->ifa_flags &= ~IFA_F_SECONDARY;
+ last_primary = &in_dev->ifa_list;
diff --git a/debian/patches/posix-sigcodes.patch b/debian/patches/posix-sigcodes.patch
new file mode 100644
index 00000000..8efb886a
--- /dev/null
+++ b/debian/patches/posix-sigcodes.patch
@@ -0,0 +1,270 @@
+commit 2a54ebafd46a26d537ac38d46dc82568f751cc42
+Author: Jeremie Koenig <jk@jk.fr.eu.org>
+Date: Wed Jun 8 03:00:37 2011 +0000
+
+ proc: send signals with POSIX sigcodes
+
+ * proc/stubs.c (send_signal): Add a sigcode argument.
+ * proc/proc.h (send_signal): Declare the sigcode argument.
+ * proc/pgrp.c (leave_pgrp): Specify a null sigcode.
+ * proc/wait.c (alert_parent): Use CLD_EXITED for SIGCHLD on exit.
+ (S_proc_mark_stop): Use CLD_STOPPED for SIGCHLD on stop.
+
+diff --git a/proc/pgrp.c b/proc/pgrp.c
+index 2d6ca93..72c09ba 100644
+--- a/proc/pgrp.c
++++ b/proc/pgrp.c
+@@ -399,42 +399,42 @@ leave_pgrp (struct proc *p)
+ else if (p->p_parent->p_pgrp != pg
+ && p->p_parent->p_pgrp->pg_session == pg->pg_session
+ && !--pg->pg_orphcnt)
+ {
+ /* We were the last process keeping this from being
+ an orphaned process group -- do the orphaning gook */
+ struct proc *ip;
+ int dosignal = 0;
+
+ for (ip = pg->pg_plist; ip; ip = ip->p_gnext)
+ {
+ if (ip->p_stopped)
+ dosignal = 1;
+ if (ip->p_msgport != MACH_PORT_NULL)
+ nowait_msg_proc_newids (ip->p_msgport, ip->p_task, ip->p_parent->p_pid,
+ ip->p_pid, 1);
+ }
+ if (dosignal)
+ for (ip = pg->pg_plist; ip; ip = ip->p_gnext)
+ {
+- send_signal (ip->p_msgport, SIGHUP, ip->p_task);
+- send_signal (ip->p_msgport, SIGCONT, ip->p_task);
++ send_signal (ip->p_msgport, SIGHUP, 0, ip->p_task);
++ send_signal (ip->p_msgport, SIGCONT, 0, ip->p_task);
+ }
+ }
+ }
+
+ /* Cause process P to join its process group. */
+ void
+ join_pgrp (struct proc *p)
+ {
+ struct pgrp *pg = p->p_pgrp;
+ struct proc *tp;
+ int origorphcnt;
+
+ p->p_gnext = pg->pg_plist;
+ p->p_gprevp = &pg->pg_plist;
+ if (pg->pg_plist)
+ pg->pg_plist->p_gprevp = &p->p_gnext;
+ pg->pg_plist = p;
+
+ origorphcnt = !!pg->pg_orphcnt;
+ if (p->p_parent->p_pgrp != pg
+diff --git a/proc/proc.h b/proc/proc.h
+index 7943e0b..b52ca1d 100644
+--- a/proc/proc.h
++++ b/proc/proc.h
+@@ -192,24 +192,24 @@ void exc_clean (void *);
+
+ struct proc *add_tasks (task_t);
+ int pidfree (pid_t);
+
+ struct proc *create_startup_proc (void);
+ struct proc *allocate_proc (task_t);
+ void proc_death_notify (struct proc *);
+ void complete_proc (struct proc *, pid_t);
+
+ void leave_pgrp (struct proc *);
+ void join_pgrp (struct proc *);
+ void boot_setsid (struct proc *);
+
+ void process_has_exited (struct proc *);
+ void alert_parent (struct proc *);
+ void reparent_zombies (struct proc *);
+ void complete_exit (struct proc *);
+
+ void initialize_version_info (void);
+
+-void send_signal (mach_port_t, int, mach_port_t);
++void send_signal (mach_port_t, int, int, mach_port_t);
+
+
+ #endif
+diff --git a/proc/stubs.c b/proc/stubs.c
+index de3a9b1..ee8e578 100644
+--- a/proc/stubs.c
++++ b/proc/stubs.c
+@@ -59,40 +59,41 @@ blocking_message_send (any_t arg)
+ case MACH_SEND_INTERRUPTED:
+ case MACH_SEND_INVALID_NOTIFY:
+ case MACH_SEND_NO_NOTIFY:
+ case MACH_SEND_NOTIFY_IN_PROGRESS:
+ assert_perror (err);
+ break;
+
+ default: /* Other errors are safe to ignore. */
+ break;
+ }
+
+
+ return 0;
+ }
+
+ /* Send signal SIGNO to MSGPORT with REFPORT as reference. Don't
+ block in any fashion. */
+ void
+ send_signal (mach_port_t msgport,
+ int signal,
++ int sigcode,
+ mach_port_t refport)
+ {
+ error_t err;
+
+ /* This message buffer might be modified by mach_msg in some error cases,
+ so we cannot safely use a shared static buffer. */
+ struct msg_sig_post_request message =
+ {
+ {
+ /* Message header: */
+ (MACH_MSGH_BITS_COMPLEX
+ | MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE)), /* msgh_bits */
+ sizeof message, /* msgh_size */
+ msgport, /* msgh_remote_port */
+ MACH_PORT_NULL, /* msgh_local_port */
+ 0, /* msgh_seqno */
+ RPCID_SIG_POST, /* msgh_id */
+ },
+ {
+@@ -101,41 +102,41 @@ send_signal (mach_port_t msgport,
+ 32, /* msgt_size */
+ 1, /* msgt_number */
+ 1, /* msgt_inline */
+ 0, /* msgt_longform */
+ 0, /* msgt_deallocate */
+ 0, /* msgt_unused */
+ },
+ /* Signal number */
+ signal,
+ /* Type descriptor for sigcode */
+ {
+ MACH_MSG_TYPE_INTEGER_32, /* msgt_name */
+ 32, /* msgt_size */
+ 1, /* msgt_number */
+ 1, /* msgt_inline */
+ 0, /* msgt_longform */
+ 0, /* msgt_deallocate */
+ 0, /* msgt_unused */
+ },
+ /* Sigcode */
+- 0,
++ sigcode,
+ {
+ /* Type descriptor for refport */
+ MACH_MSG_TYPE_COPY_SEND, /* msgt_name */
+ 32, /* msgt_size */
+ 1, /* msgt_number */
+ 1, /* msgt_inline */
+ 0, /* msgt_longform */
+ 0, /* msgt_deallocate */
+ 0, /* msgt_unused */
+ },
+ refport
+ };
+
+ err = mach_msg ((mach_msg_header_t *)&message,
+ MACH_SEND_MSG|MACH_SEND_TIMEOUT, sizeof message, 0,
+ MACH_PORT_NULL, 0, MACH_PORT_NULL);
+ switch (err)
+ {
+ case MACH_SEND_TIMED_OUT:
+ /* The send could not complete immediately, and we do not want to
+diff --git a/proc/wait.c b/proc/wait.c
+index 6fc94e8..332aaf6 100644
+--- a/proc/wait.c
++++ b/proc/wait.c
+@@ -127,41 +127,41 @@ sample_rusage (struct proc *p)
+ /* Return nonzero if a `waitpid' on WAIT_PID by a process
+ in MYPGRP cares about the death of PID/PGRP. */
+ static inline int
+ waiter_cares (pid_t wait_pid, pid_t mypgrp,
+ pid_t pid, pid_t pgrp)
+ {
+ return (wait_pid == pid ||
+ wait_pid == -pgrp ||
+ wait_pid == WAIT_ANY ||
+ (wait_pid == WAIT_MYPGRP && pgrp == mypgrp));
+ }
+
+ /* A process is dying. Send SIGCHLD to the parent.
+ Wake the parent if it is waiting for us to exit. */
+ void
+ alert_parent (struct proc *p)
+ {
+ /* We accumulate the aggregate usage stats of all our dead children. */
+ rusage_add (&p->p_parent->p_child_rusage, &p->p_rusage);
+
+- send_signal (p->p_parent->p_msgport, SIGCHLD, p->p_parent->p_task);
++ send_signal (p->p_parent->p_msgport, SIGCHLD, CLD_EXITED, p->p_parent->p_task);
+
+ if (!p->p_exiting)
+ {
+ p->p_status = W_EXITCODE (0, SIGKILL);
+ p->p_sigcode = -1;
+ }
+
+ if (p->p_parent->p_waiting)
+ {
+ pthread_cond_broadcast (&p->p_parent->p_wakeup);
+ p->p_parent->p_waiting = 0;
+ }
+ }
+
+ kern_return_t
+ S_proc_wait (struct proc *p,
+ mach_port_t reply_port,
+ mach_msg_type_name_t reply_port_type,
+ pid_t pid,
+ int options,
+@@ -240,41 +240,41 @@ S_proc_wait (struct proc *p,
+ kern_return_t
+ S_proc_mark_stop (struct proc *p,
+ int signo,
+ int sigcode)
+ {
+ if (!p)
+ return EOPNOTSUPP;
+
+ p->p_stopped = 1;
+ p->p_status = W_STOPCODE (signo);
+ p->p_sigcode = sigcode;
+ p->p_waited = 0;
+
+ if (p->p_parent->p_waiting)
+ {
+ pthread_cond_broadcast (&p->p_parent->p_wakeup);
+ p->p_parent->p_waiting = 0;
+ }
+
+ if (!p->p_parent->p_nostopcld)
+- send_signal (p->p_parent->p_msgport, SIGCHLD, p->p_parent->p_task);
++ send_signal (p->p_parent->p_msgport, SIGCHLD, CLD_STOPPED, p->p_parent->p_task);
+
+ return 0;
+ }
+
+ /* Implement proc_mark_exit as described in <hurd/process.defs>. */
+ kern_return_t
+ S_proc_mark_exit (struct proc *p,
+ int status,
+ int sigcode)
+ {
+ if (!p)
+ return EOPNOTSUPP;
+
+ if (WIFSTOPPED (status))
+ return EINVAL;
+
+ sample_rusage (p); /* See comments above sample_rusage. */
+
+ if (p->p_exiting)
+ return EBUSY;
diff --git a/debian/patches/proxy-defpager.diff b/debian/patches/proxy-defpager.diff
new file mode 100644
index 00000000..db9604ad
--- /dev/null
+++ b/debian/patches/proxy-defpager.diff
@@ -0,0 +1,62 @@
+https://savannah.gnu.org/bugs/?26751
+
+2009-06-07 Zheng Da <zhengda1936@gmail.com>
+
+ * Makefile: Use customized default_pager.defs.
+
+ * proxy-defpager.c: Include customized default_pager header.
+
+---
+ Makefile | 7 +++++--
+ proxy-defpager.c | 5 +++--
+ 2 files changed, 8 insertions(+), 4 deletions(-)
+
+Index: hurd-debian/trans/Makefile
+===================================================================
+--- hurd-debian.orig/trans/Makefile 2012-11-26 00:23:22.000000000 +0000
++++ hurd-debian/trans/Makefile 2012-11-26 00:25:32.000000000 +0000
+@@ -26,7 +26,7 @@
+ fakeroot.c proxy-defpager.c remap.c
+ OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \
+ crashServer.o crash_replyUser.o msgServer.o \
+- default_pagerServer.o default_pagerUser.o \
++ ourdefault_pagerServer.o ourdefault_pagerUser.o \
+ device_replyServer.o elfcore.o
+ HURDLIBS = ports netfs trivfs iohelp fshelp pipe ihash shouldbeinlibc
+ LDLIBS += -lpthread
+@@ -34,6 +34,9 @@
+
+ include ../Makeconf
+
++ourdefault_pager.defs: default_pager.defs
++ $(CPP) $(CPPFLAGS) -x c $< | sed -e '/MACH_MSG_TYPE_MAKE_SEND;/s/MAKE/COPY/' | sed -e '/subsystem/iserverprefix S_;' > $@
++
+ vpath elfcore.c $(top_srcdir)/exec
+
+ symlink: fsysServer.o
+@@ -41,7 +44,7 @@
+ crash: crashServer.o crash_replyUser.o msgServer.o elfcore.o
+ password: passwordServer.o
+ streamio: device_replyServer.o
+-proxy-defpager: default_pagerServer.o default_pagerUser.o
++proxy-defpager: ourdefault_pagerServer.o ourdefault_pagerUser.o
+
+ proxy-defpager crash password streamio: ../libports/libports.a ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a
+ fifo new-fifo: ../libpipe/libpipe.a
+Index: hurd-debian/trans/proxy-defpager.c
+===================================================================
+--- hurd-debian.orig/trans/proxy-defpager.c 2012-11-26 00:23:22.000000000 +0000
++++ hurd-debian/trans/proxy-defpager.c 2012-11-26 00:25:32.000000000 +0000
+@@ -23,9 +23,10 @@
+ #include <error.h>
+ #include <version.h>
+ #include <hurd/paths.h>
++#include <string.h>
+
+-#include "default_pager_S.h"
+-#include "default_pager_U.h"
++#include "ourdefault_pager_S.h"
++#include "ourdefault_pager_U.h"
+
+ static mach_port_t real_defpager, dev_master;
+
diff --git a/debian/patches/random-default-fast.patch b/debian/patches/random-default-fast.patch
new file mode 100644
index 00000000..555b3045
--- /dev/null
+++ b/debian/patches/random-default-fast.patch
@@ -0,0 +1,13 @@
+diff --git a/random/random.c b/random/random.c
+index 0ae31f5..c732356 100644
+--- a/random/random.c
++++ b/random/random.c
+@@ -50,7 +50,7 @@ struct condition select_alert; /* For read and select. */
+ numbers.
+ 2: Strong random numbers with a somewhat guaranteed entropy.
+ */
+-#define DEFAULT_LEVEL 2
++#define DEFAULT_LEVEL 1
+ static int level = DEFAULT_LEVEL;
+
+ /* Name of file to use as seed. */
diff --git a/debian/patches/rc.patch b/debian/patches/rc.patch
new file mode 100644
index 00000000..228bb349
--- /dev/null
+++ b/debian/patches/rc.patch
@@ -0,0 +1,78 @@
+More debianish rc scripts
+---
+ daemons/rc.sh | 43 ++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 32 insertions(+), 11 deletions(-)
+
+--- a/daemons/rc.sh
++++ b/daemons/rc.sh
+@@ -19,14 +19,17 @@ then
+ echo Automatic boot in progress...
+ date
+
+- /sbin/fsck --preen --writable
++ fsysopts / --update --readonly
++ /sbin/fsck -p -A
+
+ case $? in
+ # Successful completion
+ 0)
++ fsysopts / --update --writable
+ ;;
+ # Filesystem modified (but ok now)
+ 1 | 2)
++ fsysopts / --update --writable
+ ;;
+ # Fsck couldn't fix it.
+ 4 | 8)
+@@ -85,7 +88,15 @@ if test -d /tmp; then
+
+ fi
+ if test -d /var/run; then
+- (cd /var/run && { rm -rf -- *; cp /dev/null utmp; chmod 644 utmp; })
++ (cd /var/run && {
++ find . ! -type d ! -name utmp ! -name innd.pid \
++ -exec rm -f -- {} \;
++ cp /dev/null utmp
++ if grep -q ^utmp: /etc/group
++ then
++ chmod 664 utmp
++ chgrp utmp utmp
++ fi; })
+ fi
+ echo done
+
+@@ -104,15 +115,25 @@ touch /var/run/mtab
+
+ chmod 664 /etc/motd
+
+-echo -n starting daemons:
++(
++ trap ":" INT QUIT TSTP
+
+-/sbin/syslogd && echo -n ' syslogd'
+-/sbin/inetd && echo -n ' inetd'
+-
+-if test -x /sbin/sendmail -a -r /etc/sendmail.cf; then
+- /sbin/sendmail -bd -q30m && echo -n ' sendmail'
+-fi
+-
+-echo .
++ if [ -d /etc/rc.boot ]
++ then
++ for i in /etc/rc.boot/S*
++ do
++ [ ! -f $i ] && continue
++ $i start
++ done
++ fi
++ if [ -d /etc/rc2.d ]
++ then
++ for i in /etc/rc2.d/S*
++ do
++ [ ! -f $i ] && continue
++ $i start
++ done
++ fi
++)
+
+ date
diff --git a/debian/patches/run.patch b/debian/patches/run.patch
new file mode 100644
index 00000000..50f584fb
--- /dev/null
+++ b/debian/patches/run.patch
@@ -0,0 +1,18 @@
+Index: hurd/daemons/rc.sh
+===================================================================
+--- hurd.orig/daemons/rc.sh 2011-12-06 02:51:32.000000000 +0100
++++ hurd/daemons/rc.sh 2011-12-06 02:52:16.000000000 +0100
+@@ -98,6 +98,13 @@
+ chgrp utmp utmp
+ fi; })
+ fi
++
++# until we properly start /etc/rcS.d
++rm -fr /run/*
++mkdir -p /run/lock /run/shm
++chmod 1777 /run/lock /run/shm
++: > /run/utmp
++
+ echo done
+
+ # This file must exist for e2fsck to work. XXX
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 00000000..299b9452
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,43 @@
+diskfs_no_inherit_dir_group.patch
+ext2fs_large_stores.patch
+ext2fs_large_stores_pthread.patch
+hurd_console_startup.patch
+init_try_runsystem.gnu.patch
+makedev.diff
+pfinet_dhcp.patch
+rc.patch
+startup-usr-support.patch
+tmp_exec_startup.patch
+uptime_w_path_fix.patch
+stat_round.patch
+libports_stability.patch
+proxy-defpager.diff
+external.patch
+console_ignore_bdf_err.patch
+posix-sigcodes.patch
+random-default-fast.patch
+libexec.patch
+run.patch
+libdde_netdev_tx_t.patch
+libdde_pci-needs_freset.patch
+libdde_addr_list.patch
+libdde_ucast_list.patch
+libdde_addr_fix.patch
+libdde_group_addr.patch
+libdde_rculist.patch
+libdde_dma_head.patch
+libdde_mdio.patch
+libdde_ethoc.patch
+libdde_phy.patch
+libdde_pci_ids.h.patch
+libdde_ethtool.patch
+libdde_workqueue.patch
+libdde_trans_start.patch
+libdde_devres.patch
+libdde_pr_cont.patch
+libdde_rx_queue.patch
+libdde_rcu.patch
+libmachdev.patch
+exec_filename_exec.patch
+exec_filename_fs.patch
+exec_filename_use.patch
diff --git a/debian/patches/startup-usr-support.patch b/debian/patches/startup-usr-support.patch
new file mode 100644
index 00000000..1d705fc9
--- /dev/null
+++ b/debian/patches/startup-usr-support.patch
@@ -0,0 +1,27 @@
+Debian GNU/Hurd has a real /usr
+---
+ daemons/rc.sh | 2 +-
+ daemons/runsystem.sh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/daemons/rc.sh
++++ b/daemons/rc.sh
+@@ -1,6 +1,6 @@
+ #!/bin/bash
+
+-PATH=/bin:/sbin
++PATH=/bin:/sbin:/usr/bin:/usr/sbin
+
+ # Start the default pager. It will bail if there is already one running.
+ /hurd/mach-defpager
+--- a/daemons/runsystem.sh
++++ b/daemons/runsystem.sh
+@@ -11,7 +11,7 @@
+ ### Where to find programs, etc.
+ ###
+
+-PATH=/bin:/sbin
++PATH=/bin:/sbin:/usr/bin:/usr/sbin
+ export PATH
+
+ umask 022
diff --git a/debian/patches/stat_round.patch b/debian/patches/stat_round.patch
new file mode 100644
index 00000000..9c821865
--- /dev/null
+++ b/debian/patches/stat_round.patch
@@ -0,0 +1,57 @@
+This is not a proper fix, discussed on
+http://lists.gnu.org/archive/html/bug-hurd/2009-02/msg00002.html
+but not finished, last mail on
+http://lists.gnu.org/archive/html/bug-hurd/2009-04/msg00006.html
+
+---
+ libdiskfs/file-utimes.c | 4 ++--
+ libdiskfs/node-times.c | 6 +++---
+ 2 files changed, 5 insertions(+), 5 deletions(-)
+
+--- a/libdiskfs/file-utimes.c
++++ b/libdiskfs/file-utimes.c
+@@ -33,7 +33,7 @@ diskfs_S_file_utimes (struct protid *cre
+ else
+ {
+ np->dn_stat.st_atim.tv_sec = atime.seconds;
+- np->dn_stat.st_atim.tv_nsec = atime.microseconds * 1000;
++ np->dn_stat.st_atim.tv_nsec = 0;
+ np->dn_set_atime = 0;
+ }
+
+@@ -42,7 +42,7 @@ diskfs_S_file_utimes (struct protid *cre
+ else
+ {
+ np->dn_stat.st_mtim.tv_sec = mtime.seconds;
+- np->dn_stat.st_mtim.tv_nsec = mtime.microseconds * 1000;
++ np->dn_stat.st_mtim.tv_nsec = 0;
+ np->dn_set_mtime = 0;
+ }
+
+--- a/libdiskfs/node-times.c
++++ b/libdiskfs/node-times.c
+@@ -53,21 +53,21 @@ diskfs_set_node_times (struct node *np)
+ if (np->dn_set_mtime)
+ {
+ np->dn_stat.st_mtim.tv_sec = t.tv_sec;
+- np->dn_stat.st_mtim.tv_nsec = t.tv_usec * 1000;
++ np->dn_stat.st_mtim.tv_nsec = 0;
+ np->dn_stat_dirty = 1;
+ np->dn_set_mtime = 0;
+ }
+ if (np->dn_set_atime)
+ {
+ np->dn_stat.st_atim.tv_sec = t.tv_sec;
+- np->dn_stat.st_atim.tv_nsec = t.tv_usec * 1000;
++ np->dn_stat.st_atim.tv_nsec = 0;
+ np->dn_stat_dirty = 1;
+ np->dn_set_atime = 0;
+ }
+ if (np->dn_set_ctime)
+ {
+ np->dn_stat.st_ctim.tv_sec = t.tv_sec;
+- np->dn_stat.st_ctim.tv_nsec = t.tv_usec * 1000;
++ np->dn_stat.st_ctim.tv_nsec = 0;
+ np->dn_stat_dirty = 1;
+ np->dn_set_ctime = 0;
+ }
diff --git a/debian/patches/tmp_exec_startup.patch b/debian/patches/tmp_exec_startup.patch
new file mode 100644
index 00000000..bd605718
--- /dev/null
+++ b/debian/patches/tmp_exec_startup.patch
@@ -0,0 +1,54 @@
+Also try /tmp/exec as it's used for installation.
+
+TODO: not used by d-i. Is it used by crosshurd?
+---
+ libdiskfs/boot-start.c | 24 ++++++++++++++++++++----
+ 1 file changed, 20 insertions(+), 4 deletions(-)
+
+--- a/libdiskfs/boot-start.c
++++ b/libdiskfs/boot-start.c
+@@ -126,8 +126,13 @@ diskfs_start_bootstrap ()
+ assert (_hurd_ports);
+ assert (_hurd_ports[INIT_PORT_CRDIR].port != MACH_PORT_NULL);
+ diskfs_exec = file_name_lookup (_SERVERS_EXEC, 0, 0);
+- if (diskfs_exec == MACH_PORT_NULL)
+- error (1, errno, "%s", _SERVERS_EXEC);
++ if (diskfs_exec == MACH_PORT_NULL)
++ {
++ /* Debian specifc work-around for install bootstrapping. */
++ diskfs_exec = file_name_lookup ("/tmp/exec", 0, 0);
++ if (diskfs_exec == MACH_PORT_NULL)
++ error (1, errno, "%s", _SERVERS_EXEC);
++ }
+ else
+ {
+ #ifndef NDEBUG
+@@ -177,8 +182,15 @@ diskfs_start_bootstrap ()
+ &retry, pathbuf, &execnode);
+ if (err)
+ {
+- error (0, err, "cannot set translator on %s", _SERVERS_EXEC);
+- mach_port_deallocate (mach_task_self (), diskfs_exec_ctl);
++ /* If /servers/exec is not available (which is the case during
++ installation, try /tmp/exec as well. */
++ err = dir_lookup (root_pt, "/tmp/exec", O_NOTRANS, 0,
++ &retry, pathbuf, &execnode);
++ if (err)
++ {
++ error (0, err, "cannot set translator on %s", _SERVERS_EXEC);
++ mach_port_deallocate (mach_task_self (), diskfs_exec_ctl);
++ }
+ }
+ else
+ {
+@@ -393,6 +405,10 @@ diskfs_execboot_fsys_startup (mach_port_
+
+ err = dir_lookup (rootport, _SERVERS_EXEC, flags|O_NOTRANS, 0,
+ &retry, pathbuf, real);
++ if (err)
++ /* Try /tmp/exec as well, in case we're installing. */
++ err = dir_lookup (rootport, "/tmp/exec", flags|O_NOTRANS|O_CREAT, 0,
++ &retry, pathbuf, real);
+ assert_perror (err);
+ assert (retry == FS_RETRY_NORMAL);
+ assert (pathbuf[0] == '\0');
diff --git a/debian/patches/uptime_w_path_fix.patch b/debian/patches/uptime_w_path_fix.patch
new file mode 100644
index 00000000..a2e595ef
--- /dev/null
+++ b/debian/patches/uptime_w_path_fix.patch
@@ -0,0 +1,16 @@
+Debian has a real /usr and uses w-hurd file name
+---
+ utils/uptime.sh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/utils/uptime.sh
++++ b/utils/uptime.sh
+@@ -25,7 +25,7 @@
+ USAGE="Usage: $0 [OPTION...]"
+ DOC="Show system uptime, number of users, and load"
+
+-W=${W-/bin/w}
++W=${W-/usr/bin/w-hurd}
+
+ while :; do
+ case "$1" in