Whamcloud - gitweb
- series for uml on 2.6.0
authoralex <alex>
Tue, 3 Feb 2004 18:21:47 +0000 (18:21 +0000)
committeralex <alex>
Tue, 3 Feb 2004 18:21:47 +0000 (18:21 +0000)
NOTE: subsytem initialize order problem is to be solved yet

lustre/kernel_patches/patches/uml-patch-2.6.0-1-fix1.patch [new file with mode: 0644]
lustre/kernel_patches/patches/uml-patch-2.6.0-1.patch [new file with mode: 0644]
lustre/kernel_patches/patches/vfs_nointent_2.6.0-uml1.patch [new file with mode: 0644]
lustre/kernel_patches/series/uml_2.6.0 [new file with mode: 0644]

diff --git a/lustre/kernel_patches/patches/uml-patch-2.6.0-1-fix1.patch b/lustre/kernel_patches/patches/uml-patch-2.6.0-1-fix1.patch
new file mode 100644 (file)
index 0000000..997cd49
--- /dev/null
@@ -0,0 +1,15 @@
+Index: linux-2.6.0/include/asm-um/unistd.h
+===================================================================
+--- linux-2.6.0.orig/include/asm-um/unistd.h   2004-02-03 18:07:34.000000000 +0300
++++ linux-2.6.0/include/asm-um/unistd.h        2004-02-03 20:29:49.000000000 +0300
+@@ -6,8 +6,10 @@
+ #ifndef _UM_UNISTD_H_
+ #define _UM_UNISTD_H_
++#ifdef __KERNEL__
+ #include "linux/resource.h"
+ #include "asm/uaccess.h"
++#endif
+ extern long sys_open(const char *filename, int flags, int mode);
+ extern long sys_dup(unsigned int fildes);
diff --git a/lustre/kernel_patches/patches/uml-patch-2.6.0-1.patch b/lustre/kernel_patches/patches/uml-patch-2.6.0-1.patch
new file mode 100644 (file)
index 0000000..8bfe6a2
--- /dev/null
@@ -0,0 +1,18163 @@
+diff -Naur a/arch/um/config.release b/arch/um/config.release
+--- a/arch/um/config.release   2004-01-08 22:31:37.000000000 -0500
++++ b/arch/um/config.release   2004-01-08 22:36:18.000000000 -0500
+@@ -228,7 +228,6 @@
+ CONFIG_EXT2_FS=y
+ CONFIG_SYSV_FS=m
+ CONFIG_UDF_FS=m
+-# CONFIG_UDF_RW is not set
+ CONFIG_UFS_FS=m
+ # CONFIG_UFS_FS_WRITE is not set
+diff -Naur a/arch/um/defconfig b/arch/um/defconfig
+--- a/arch/um/defconfig        2004-01-08 22:24:41.000000000 -0500
++++ b/arch/um/defconfig        2004-01-08 22:32:17.000000000 -0500
+@@ -3,29 +3,19 @@
+ #
+ CONFIG_USERMODE=y
+ CONFIG_MMU=y
+-CONFIG_SWAP=y
+ CONFIG_UID16=y
+ CONFIG_RWSEM_GENERIC_SPINLOCK=y
+-CONFIG_CONFIG_LOG_BUF_SHIFT=14
+ #
+-# Code maturity level options
+-#
+-CONFIG_EXPERIMENTAL=y
+-
+-#
+-# General Setup
++# UML-specific options
+ #
+ CONFIG_MODE_TT=y
+ CONFIG_MODE_SKAS=y
+ CONFIG_NET=y
+-CONFIG_SYSVIPC=y
+-CONFIG_BSD_PROCESS_ACCT=y
+-CONFIG_SYSCTL=y
+-CONFIG_BINFMT_AOUT=y
+ CONFIG_BINFMT_ELF=y
+ CONFIG_BINFMT_MISC=y
+ CONFIG_HOSTFS=y
++CONFIG_HPPFS=y
+ CONFIG_MCONSOLE=y
+ CONFIG_MAGIC_SYSRQ=y
+ # CONFIG_HOST_2G_2G is not set
+@@ -36,12 +26,41 @@
+ # CONFIG_HIGHMEM is not set
+ CONFIG_PROC_MM=y
+ CONFIG_KERNEL_STACK_ORDER=2
++CONFIG_UML_REAL_TIME_CLOCK=y
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_CLEAN_COMPILE=y
++CONFIG_STANDALONE=y
++CONFIG_BROKEN_ON_SMP=y
++
++#
++# General setup
++#
++CONFIG_SWAP=y
++CONFIG_SYSVIPC=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_SYSCTL=y
++CONFIG_LOG_BUF_SHIFT=14
++# CONFIG_IKCONFIG is not set
++# CONFIG_EMBEDDED is not set
++CONFIG_KALLSYMS=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
+ #
+ # Loadable module support
+ #
+-CONFIG_MODULES=y
+-# CONFIG_KMOD is not set
++# CONFIG_MODULES is not set
++
++#
++# Generic Driver Options
++#
+ #
+ # Character Devices
+@@ -69,6 +88,7 @@
+ #
+ CONFIG_BLK_DEV_UBD=y
+ # CONFIG_BLK_DEV_UBD_SYNC is not set
++CONFIG_BLK_DEV_COW_COMMON=y
+ CONFIG_BLK_DEV_LOOP=y
+ CONFIG_BLK_DEV_NBD=y
+ CONFIG_BLK_DEV_RAM=y
+@@ -78,7 +98,7 @@
+ CONFIG_NETDEVICES=y
+ #
+-# Network Devices
++# UML Network Devices
+ #
+ CONFIG_UML_NET=y
+ CONFIG_UML_NET_ETHERTAP=y
+@@ -88,22 +108,6 @@
+ CONFIG_UML_NET_MCAST=y
+ # CONFIG_UML_NET_PCAP is not set
+ CONFIG_UML_NET_SLIRP=y
+-CONFIG_DUMMY=y
+-# CONFIG_BONDING is not set
+-# CONFIG_EQUALIZER is not set
+-CONFIG_TUN=y
+-# CONFIG_ETHERTAP is not set
+-CONFIG_PPP=y
+-# CONFIG_PPP_MULTILINK is not set
+-# CONFIG_PPP_ASYNC is not set
+-# CONFIG_PPP_SYNC_TTY is not set
+-# CONFIG_PPP_DEFLATE is not set
+-# CONFIG_PPP_BSDCOMP is not set
+-# CONFIG_PPPOE is not set
+-CONFIG_SLIP=y
+-# CONFIG_SLIP_COMPRESSED is not set
+-# CONFIG_SLIP_SMART is not set
+-# CONFIG_SLIP_MODE_SLIP6 is not set
+ #
+ # Networking support
+@@ -115,8 +119,6 @@
+ CONFIG_PACKET=y
+ CONFIG_PACKET_MMAP=y
+ # CONFIG_NETLINK_DEV is not set
+-# CONFIG_NETFILTER is not set
+-# CONFIG_FILTER is not set
+ CONFIG_UNIX=y
+ # CONFIG_NET_KEY is not set
+ CONFIG_INET=y
+@@ -130,8 +132,11 @@
+ # CONFIG_SYN_COOKIES is not set
+ # CONFIG_INET_AH is not set
+ # CONFIG_INET_ESP is not set
+-# CONFIG_XFRM_USER is not set
++# CONFIG_INET_IPCOMP is not set
+ # CONFIG_IPV6 is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NETFILTER is not set
+ #
+ # SCTP Configuration (EXPERIMENTAL)
+@@ -140,9 +145,9 @@
+ # CONFIG_IP_SCTP is not set
+ # CONFIG_ATM is not set
+ # CONFIG_VLAN_8021Q is not set
+-# CONFIG_LLC is not set
+-# CONFIG_DECNET is not set
+-# CONFIG_BRIDGE is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
+ # CONFIG_X25 is not set
+ # CONFIG_LAPB is not set
+ # CONFIG_NET_DIVERT is not set
+@@ -160,6 +165,10 @@
+ # Network testing
+ #
+ # CONFIG_NET_PKTGEN is not set
++CONFIG_DUMMY=y
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_TUN=y
+ #
+ # Ethernet (10 or 100Mbit)
+@@ -171,12 +180,28 @@
+ #
+ #
++# Ethernet (10000 Mbit)
++#
++CONFIG_PPP=y
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPP_FILTER is not set
++# CONFIG_PPP_ASYNC is not set
++# CONFIG_PPP_SYNC_TTY is not set
++# CONFIG_PPP_DEFLATE is not set
++# CONFIG_PPP_BSDCOMP is not set
++# CONFIG_PPPOE is not set
++CONFIG_SLIP=y
++# CONFIG_SLIP_COMPRESSED is not set
++# CONFIG_SLIP_SMART is not set
++# CONFIG_SLIP_MODE_SLIP6 is not set
++
++#
+ # Wireless LAN (non-hamradio)
+ #
+ # CONFIG_NET_RADIO is not set
+ #
+-# Token Ring devices (depends on LLC=y)
++# Token Ring devices
+ #
+ # CONFIG_SHAPER is not set
+@@ -186,68 +211,101 @@
+ # CONFIG_WAN is not set
+ #
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BT is not set
++
++#
+ # File systems
+ #
++CONFIG_EXT2_FS=y
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++CONFIG_REISERFS_FS=y
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_XFS_FS is not set
++CONFIG_MINIX_FS=y
++# CONFIG_ROMFS_FS is not set
+ CONFIG_QUOTA=y
+ # CONFIG_QFMT_V1 is not set
+ # CONFIG_QFMT_V2 is not set
+ CONFIG_QUOTACTL=y
+-CONFIG_AUTOFS_FS=m
+-CONFIG_AUTOFS4_FS=m
+-CONFIG_REISERFS_FS=m
+-# CONFIG_REISERFS_CHECK is not set
+-# CONFIG_REISERFS_PROC_INFO is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++
++#
++# CD-ROM/DVD Filesystems
++#
++CONFIG_ISO9660_FS=y
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_KCORE=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_DEVPTS_FS_XATTR is not set
++# CONFIG_TMPFS is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_RAMFS=y
++
++#
++# Miscellaneous filesystems
++#
+ # CONFIG_ADFS_FS is not set
+ # CONFIG_AFFS_FS is not set
+ # CONFIG_HFS_FS is not set
+ # CONFIG_BEFS_FS is not set
+ # CONFIG_BFS_FS is not set
+-# CONFIG_EXT3_FS is not set
+-# CONFIG_JBD is not set
+-CONFIG_FAT_FS=m
+-CONFIG_MSDOS_FS=m
+-CONFIG_VFAT_FS=m
+ # CONFIG_EFS_FS is not set
+ CONFIG_JFFS_FS=y
+ CONFIG_JFFS_FS_VERBOSE=0
+-CONFIG_JFFS_PROC_FS=y
+ # CONFIG_JFFS2_FS is not set
+ # CONFIG_CRAMFS is not set
+-# CONFIG_TMPFS is not set
+-CONFIG_RAMFS=y
+-CONFIG_ISO9660_FS=m
+-# CONFIG_JOLIET is not set
+-# CONFIG_ZISOFS is not set
+-# CONFIG_JFS_FS is not set
+-CONFIG_MINIX_FS=m
+ # CONFIG_VXFS_FS is not set
+-# CONFIG_NTFS_FS is not set
+ # CONFIG_HPFS_FS is not set
+-CONFIG_PROC_FS=y
+-CONFIG_DEVFS_FS=y
+-CONFIG_DEVFS_MOUNT=y
+-# CONFIG_DEVFS_DEBUG is not set
+-CONFIG_DEVPTS_FS=y
+ # CONFIG_QNX4FS_FS is not set
+-# CONFIG_ROMFS_FS is not set
+-CONFIG_EXT2_FS=y
+-# CONFIG_EXT2_FS_XATTR is not set
+ # CONFIG_SYSV_FS is not set
+-# CONFIG_UDF_FS is not set
+ # CONFIG_UFS_FS is not set
+-# CONFIG_XFS_FS is not set
+ #
+ # Network File Systems
+ #
+-# CONFIG_CODA_FS is not set
+-# CONFIG_INTERMEZZO_FS is not set
+ # CONFIG_NFS_FS is not set
+ # CONFIG_NFSD is not set
+ # CONFIG_EXPORTFS is not set
+-# CONFIG_CIFS is not set
+ # CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
+ # CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
+ # CONFIG_AFS_FS is not set
+ #
+@@ -317,28 +375,7 @@
+ #
+ # SCSI support
+ #
+-CONFIG_SCSI=y
+-CONFIG_GENERIC_ISA_DMA=y
+-
+-#
+-# SCSI support type (disk, tape, CD-ROM)
+-#
+-CONFIG_BLK_DEV_SD=y
+-CONFIG_SD_EXTRA_DEVS=40
+-CONFIG_CHR_DEV_ST=y
+-CONFIG_BLK_DEV_SR=y
+-CONFIG_BLK_DEV_SR_VENDOR=y
+-CONFIG_SR_EXTRA_DEVS=2
+-CONFIG_CHR_DEV_SG=y
+-
+-#
+-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+-#
+-CONFIG_SCSI_DEBUG_QUEUES=y
+-CONFIG_SCSI_MULTI_LUN=y
+-CONFIG_SCSI_CONSTANTS=y
+-CONFIG_SCSI_LOGGING=y
+-CONFIG_SCSI_DEBUG=y
++# CONFIG_SCSI is not set
+ #
+ # Multi-device support (RAID and LVM)
+@@ -360,6 +397,7 @@
+ CONFIG_MTD_BLOCK=y
+ # CONFIG_FTL is not set
+ # CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
+ #
+ # RAM/ROM/Flash chip drivers
+@@ -374,20 +412,21 @@
+ #
+ # Mapping drivers for chip access
+ #
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+ #
+ # Self-contained MTD device drivers
+ #
+ # CONFIG_MTD_SLRAM is not set
+ # CONFIG_MTD_MTDRAM is not set
+-CONFIG_MTD_BLKMTD=m
++CONFIG_MTD_BLKMTD=y
+ #
+ # Disk-On-Chip Device Drivers
+ #
+-# CONFIG_MTD_DOC1000 is not set
+ # CONFIG_MTD_DOC2000 is not set
+ # CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
+ #
+ # NAND Flash Device Drivers
+diff -Naur a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
+--- a/arch/um/drivers/chan_kern.c      2004-01-08 22:32:12.000000000 -0500
++++ b/arch/um/drivers/chan_kern.c      2004-01-08 22:36:26.000000000 -0500
+@@ -8,6 +8,7 @@
+ #include <linux/list.h>
+ #include <linux/slab.h>
+ #include <linux/tty.h>
++#include <linux/string.h>
+ #include <linux/tty_flip.h>
+ #include <asm/irq.h>
+ #include "chan_kern.h"
+@@ -265,6 +266,11 @@
+ {
+       int n = 0;
++      if(chan == NULL){
++              CONFIG_CHUNK(str, size, n, "none", 1);
++              return(n);
++      }
++
+       CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
+       if(chan->dev == NULL){
+@@ -420,7 +426,8 @@
+               INIT_LIST_HEAD(chans);
+       }
+-      if((out = strchr(str, ',')) != NULL){
++      out = strchr(str, ',');
++      if(out != NULL){
+               in = str;
+               *out = '\0';
+               out++;
+@@ -475,12 +482,15 @@
+                               goto out;
+                       }
+                       err = chan->ops->read(chan->fd, &c, chan->data);
+-                      if(err > 0) tty_receive_char(tty, c);
++                      if(err > 0) 
++                              tty_receive_char(tty, c);
+               } while(err > 0);
++
+               if(err == 0) reactivate_fd(chan->fd, irq);
+               if(err == -EIO){
+                       if(chan->primary){
+-                              if(tty != NULL) tty_hangup(tty);
++                              if(tty != NULL) 
++                                      tty_hangup(tty);
+                               line_disable(dev, irq);
+                               close_chan(chans);
+                               free_chan(chans);
+diff -Naur a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
+--- a/arch/um/drivers/chan_user.c      2004-01-08 22:13:40.000000000 -0500
++++ b/arch/um/drivers/chan_user.c      2004-01-08 22:17:53.000000000 -0500
+@@ -1,5 +1,5 @@
+ /* 
+- * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+@@ -7,7 +7,6 @@
+ #include <stdlib.h>
+ #include <errno.h>
+ #include <termios.h>
+-#include <fcntl.h>
+ #include <string.h>
+ #include <signal.h>
+ #include <sys/stat.h>
+@@ -24,29 +23,27 @@
+ void generic_close(int fd, void *unused)
+ {
+-      close(fd);
++      os_close_file(fd);
+ }
+ int generic_read(int fd, char *c_out, void *unused)
+ {
+       int n;
+-      n = read(fd, c_out, sizeof(*c_out));
+-      if(n < 0){
+-              if(errno == EAGAIN) return(0);
+-              return(-errno);
+-      }
+-      else if(n == 0) return(-EIO);
+-      return(1);
++      n = os_read_file(fd, c_out, sizeof(*c_out));
++
++      if(n == -EAGAIN) 
++              return(0);
++      else if(n == 0) 
++              return(-EIO);
++      return(n);
+ }
++/* XXX Trivial wrapper around os_write_file */
++
+ int generic_write(int fd, const char *buf, int n, void *unused)
+ {
+-      int count;
+-
+-      count = write(fd, buf, n);
+-      if(count < 0) return(-errno);
+-      return(count);
++      return(os_write_file(fd, buf, n));
+ }
+ int generic_console_write(int fd, const char *buf, int n, void *unused)
+@@ -68,15 +65,18 @@
+ int generic_window_size(int fd, void *unused, unsigned short *rows_out,
+                       unsigned short *cols_out)
+ {
+-      struct winsize size;
+-      int ret = 0;
++      int rows, cols;
++      int ret;
++
++      ret = os_window_size(fd, &rows, &cols);
++      if(ret < 0)
++              return(ret);
++
++      ret = ((*rows_out != rows) || (*cols_out != cols));
++
++      *rows_out = rows;
++      *cols_out = cols;
+-      if(ioctl(fd, TIOCGWINSZ, &size) == 0){
+-              ret = ((*rows_out != size.ws_row) || 
+-                     (*cols_out != size.ws_col));
+-              *rows_out = size.ws_row;
+-              *cols_out = size.ws_col;
+-      }
+       return(ret);
+ }
+@@ -100,14 +100,16 @@
+       struct winch_data *data = arg;
+       sigset_t sigs;
+       int pty_fd, pipe_fd;
++      int count, err;
+       char c = 1;
+-      close(data->close_me);
++      os_close_file(data->close_me);
+       pty_fd = data->pty_fd;
+       pipe_fd = data->pipe_fd;
+-      if(write(pipe_fd, &c, sizeof(c)) != sizeof(c))
++      count = os_write_file(pipe_fd, &c, sizeof(c));
++      if(count != sizeof(c))
+               printk("winch_thread : failed to write synchronization "
+-                     "byte, errno = %d\n", errno);
++                     "byte, err = %d\n", -count);
+       signal(SIGWINCH, winch_handler);
+       sigfillset(&sigs);
+@@ -123,26 +125,24 @@
+               exit(1);
+       }
+-      if(ioctl(pty_fd, TIOCSCTTY, 0) < 0){
+-              printk("winch_thread : TIOCSCTTY failed, errno = %d\n", errno);
+-              exit(1);
+-      }
+-      if(tcsetpgrp(pty_fd, os_getpid()) < 0){
+-              printk("winch_thread : tcsetpgrp failed, errno = %d\n", errno);
++      err = os_new_tty_pgrp(pty_fd, os_getpid());
++      if(err < 0){
++              printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err);
+               exit(1);
+       }
+-      if(read(pipe_fd, &c, sizeof(c)) != sizeof(c))
++      count = os_read_file(pipe_fd, &c, sizeof(c));
++      if(count != sizeof(c))
+               printk("winch_thread : failed to read synchronization byte, "
+-                     "errno = %d\n", errno);
++                     "err = %d\n", -count);
+       while(1){
+               pause();
+-              if(write(pipe_fd, &c, sizeof(c)) != sizeof(c)){
+-                      printk("winch_thread : write failed, errno = %d\n",
+-                             errno);
+-              }
++              count = os_write_file(pipe_fd, &c, sizeof(c));
++              if(count != sizeof(c))
++                      printk("winch_thread : write failed, err = %d\n",
++                             -count);
+       }
+ }
+@@ -154,8 +154,8 @@
+       char c;
+       err = os_pipe(fds, 1, 1);
+-      if(err){
+-              printk("winch_tramp : os_pipe failed, errno = %d\n", -err);
++      if(err < 0){
++              printk("winch_tramp : os_pipe failed, err = %d\n", -err);
+               return(err);
+       }
+@@ -168,12 +168,12 @@
+               return(pid);
+       }
+-      close(fds[1]);
++      os_close_file(fds[1]);
+       *fd_out = fds[0];
+-      n = read(fds[0], &c, sizeof(c));
++      n = os_read_file(fds[0], &c, sizeof(c));
+       if(n != sizeof(c)){
+               printk("winch_tramp : failed to read synchronization byte\n");
+-              printk("read returned %d, errno = %d\n", n, errno);
++              printk("read failed, err = %d\n", -n);
+               printk("fd %d will not support SIGWINCH\n", fd);
+               *fd_out = -1;
+       }
+@@ -183,20 +183,24 @@
+ void register_winch(int fd, void *device_data)
+ {
+       int pid, thread, thread_fd;
++      int count;
+       char c = 1;
+-      if(!isatty(fd)) return;
++      if(!isatty(fd)) 
++              return;
+       pid = tcgetpgrp(fd);
+-      if(!CHOOSE_MODE(is_tracer_winch(pid, fd, device_data), 0) && 
+-         (pid == -1)){
++      if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, 
++                           device_data) && (pid == -1)){
+               thread = winch_tramp(fd, device_data, &thread_fd);
+               if(fd != -1){
+                       register_winch_irq(thread_fd, fd, thread, device_data);
+-                      if(write(thread_fd, &c, sizeof(c)) != sizeof(c))
++                      count = os_write_file(thread_fd, &c, sizeof(c));
++                      if(count != sizeof(c))
+                               printk("register_winch : failed to write "
+-                                     "synchronization byte\n");
++                                     "synchronization byte, err = %d\n",
++                                      -count);
+               }
+       }
+ }
+diff -Naur a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h
+--- a/arch/um/drivers/cow.h    1969-12-31 19:00:00.000000000 -0500
++++ b/arch/um/drivers/cow.h    2004-01-08 22:20:48.000000000 -0500
+@@ -0,0 +1,41 @@
++#ifndef __COW_H__
++#define __COW_H__
++
++#include <asm/types.h>
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++# define ntohll(x) (x)
++# define htonll(x) (x)
++#elif __BYTE_ORDER == __LITTLE_ENDIAN
++# define ntohll(x)  bswap_64(x)
++# define htonll(x)  bswap_64(x)
++#else
++#error "__BYTE_ORDER not defined"
++#endif
++
++extern int init_cow_file(int fd, char *cow_file, char *backing_file, 
++                       int sectorsize, int alignment, int *bitmap_offset_out, 
++                       unsigned long *bitmap_len_out, int *data_offset_out);
++
++extern int file_reader(__u64 offset, char *buf, int len, void *arg);
++extern int read_cow_header(int (*reader)(__u64, char *, int, void *), 
++                         void *arg, __u32 *version_out, 
++                         char **backing_file_out, time_t *mtime_out, 
++                         __u64 *size_out, int *sectorsize_out, 
++                         __u32 *align_out, int *bitmap_offset_out);
++
++extern int write_cow_header(char *cow_file, int fd, char *backing_file, 
++                          int sectorsize, int alignment, long long *size);
++
++extern void cow_sizes(int version, __u64 size, int sectorsize, int align,
++                    int bitmap_offset, unsigned long *bitmap_len_out, 
++                    int *data_offset_out);
++
++#endif
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/arch/um/drivers/cow_kern.c b/arch/um/drivers/cow_kern.c
+--- a/arch/um/drivers/cow_kern.c       1969-12-31 19:00:00.000000000 -0500
++++ b/arch/um/drivers/cow_kern.c       2004-01-08 22:36:26.000000000 -0500
+@@ -0,0 +1,630 @@
++#define COW_MAJOR 60
++#define MAJOR_NR COW_MAJOR
++
++#include <linux/stddef.h>
++#include <linux/kernel.h>
++#include <linux/ctype.h>
++#include <linux/stat.h>
++#include <linux/vmalloc.h>
++#include <linux/blkdev.h>
++#include <linux/blk.h>
++#include <linux/fs.h>
++#include <linux/genhd.h>
++#include <linux/devfs_fs.h>
++#include <asm/uaccess.h>
++#include "2_5compat.h"
++#include "cow.h"
++#include "ubd_user.h"
++
++#define COW_SHIFT 4
++
++struct cow {
++      int count;
++      char *cow_path;
++      dev_t cow_dev;
++      struct block_device *cow_bdev;
++      char *backing_path;
++      dev_t backing_dev;
++      struct block_device *backing_bdev;
++      int sectorsize;
++      unsigned long *bitmap;
++      unsigned long bitmap_len;
++      int bitmap_offset;
++      int data_offset;
++      devfs_handle_t devfs;
++      struct semaphore sem;
++      struct semaphore io_sem;
++      atomic_t working;
++      spinlock_t io_lock;
++      struct buffer_head *bh;
++      struct buffer_head *bhtail;
++      void *end_io;
++};
++
++#define DEFAULT_COW { \
++      .count                  = 0, \
++      .cow_path               = NULL, \
++      .cow_dev                = 0, \
++      .backing_path           = NULL, \
++      .backing_dev            = 0, \
++        .bitmap                       = NULL, \
++      .bitmap_len             = 0, \
++      .bitmap_offset          = 0, \
++        .data_offset          = 0, \
++      .devfs                  = NULL, \
++      .working                = ATOMIC_INIT(0), \
++      .io_lock                = SPIN_LOCK_UNLOCKED, \
++}
++
++#define MAX_DEV (8)
++#define MAX_MINOR (MAX_DEV << COW_SHIFT)
++
++struct cow cow_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_COW };
++
++/* Not modified by this driver */
++static int blk_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = BLOCK_SIZE };
++static int hardsect_sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 512 };
++
++/* Protected by cow_lock */
++static int sizes[MAX_MINOR] = { [ 0 ... MAX_MINOR - 1 ] = 0 };
++
++static struct hd_struct       cow_part[MAX_MINOR] =
++      { [ 0 ... MAX_MINOR - 1 ] = { 0, 0, 0 } };
++
++/* Protected by io_request_lock */
++static request_queue_t *cow_queue;
++
++static int cow_open(struct inode *inode, struct file *filp);
++static int cow_release(struct inode * inode, struct file * file);
++static int cow_ioctl(struct inode * inode, struct file * file,
++                   unsigned int cmd, unsigned long arg);
++static int cow_revalidate(kdev_t rdev);
++
++static struct block_device_operations cow_blops = {
++       .open          = cow_open,
++       .release       = cow_release,
++       .ioctl         = cow_ioctl,
++       .revalidate    = cow_revalidate,
++};
++
++/* Initialized in an initcall, and unchanged thereafter */
++devfs_handle_t cow_dir_handle;
++
++#define INIT_GENDISK(maj, name, parts, shift, bsizes, max, blops) \
++{ \
++      .major          = maj, \
++      .major_name     = name, \
++      .minor_shift    = shift, \
++      .max_p          = 1 << shift, \
++      .part           = parts, \
++      .sizes          = bsizes, \
++      .nr_real        = max, \
++      .real_devices   = NULL, \
++      .next           = NULL, \
++      .fops           = blops, \
++      .de_arr         = NULL, \
++      .flags          = 0 \
++}
++
++static spinlock_t cow_lock = SPIN_LOCK_UNLOCKED;
++
++static struct gendisk cow_gendisk = INIT_GENDISK(MAJOR_NR, "cow", cow_part,
++                                               COW_SHIFT, sizes, MAX_DEV, 
++                                               &cow_blops);
++
++static int cow_add(int n)
++{
++      struct cow *dev = &cow_dev[n];
++      char name[sizeof("nnnnnn\0")];
++      int err = -ENODEV;
++
++      if(dev->cow_path == NULL)
++              goto out;
++
++      sprintf(name, "%d", n);
++      dev->devfs = devfs_register(cow_dir_handle, name, DEVFS_FL_REMOVABLE,
++                                  MAJOR_NR, n << COW_SHIFT, S_IFBLK | 
++                                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
++                                  &cow_blops, NULL);
++
++      init_MUTEX_LOCKED(&dev->sem);
++      init_MUTEX(&dev->io_sem);
++
++      return(0);
++
++out:
++      return(err);
++}
++
++/*
++* Add buffer_head to back of pending list
++*/
++static void cow_add_bh(struct cow *cow, struct buffer_head *bh)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&cow->io_lock, flags);
++      if(cow->bhtail != NULL){
++              cow->bhtail->b_reqnext = bh;
++              cow->bhtail = bh;
++      }
++      else {
++              cow->bh = bh;
++              cow->bhtail = bh;
++      }
++      spin_unlock_irqrestore(&cow->io_lock, flags);
++}
++
++/*
++* Grab first pending buffer
++*/
++static struct buffer_head *cow_get_bh(struct cow *cow)
++{
++      struct buffer_head *bh;
++
++      spin_lock_irq(&cow->io_lock);
++      bh = cow->bh;
++      if(bh != NULL){
++              if(bh == cow->bhtail)
++                      cow->bhtail = NULL;
++              cow->bh = bh->b_reqnext;
++              bh->b_reqnext = NULL;
++      }
++      spin_unlock_irq(&cow->io_lock);
++
++      return(bh);
++}
++
++static void cow_handle_bh(struct cow *cow, struct buffer_head *bh, 
++                        struct buffer_head **cow_bh, int ncow_bh)
++{
++      int i;
++
++      if(ncow_bh > 0)
++              ll_rw_block(WRITE, ncow_bh, cow_bh);
++
++      for(i = 0; i < ncow_bh ; i++){
++              wait_on_buffer(cow_bh[i]);
++              brelse(cow_bh[i]);
++      }
++
++      ll_rw_block(WRITE, 1, &bh);
++      brelse(bh);
++}
++
++static struct buffer_head *cow_new_bh(struct cow *dev, int sector)
++{
++      struct buffer_head *bh;
++
++      sector = (dev->bitmap_offset + sector / 8) / dev->sectorsize;
++      bh = getblk(dev->cow_dev, sector, dev->sectorsize);
++      memcpy(bh->b_data, dev->bitmap + sector / (8 * sizeof(dev->bitmap[0])),
++             dev->sectorsize);
++      return(bh);
++}
++
++/* Copied from loop.c, needed to avoid deadlocking in make_request. */
++
++static int cow_thread(void *data)
++{
++      struct cow *dev = data;
++      struct buffer_head *bh;
++
++      daemonize();
++      exit_files(current);
++
++      sprintf(current->comm, "cow%d", dev - cow_dev);
++
++      spin_lock_irq(&current->sigmask_lock);
++      sigfillset(&current->blocked);
++      flush_signals(current);
++      spin_unlock_irq(&current->sigmask_lock);
++
++      atomic_inc(&dev->working);
++
++      current->policy = SCHED_OTHER;
++      current->nice = -20;
++
++      current->flags |= PF_NOIO;
++
++      /*
++       * up sem, we are running
++       */
++      up(&dev->sem);
++
++      for(;;){
++              int start, len, nbh, i, update_bitmap = 0;
++              struct buffer_head *cow_bh[2];
++
++              down_interruptible(&dev->io_sem);
++              /*
++               * could be upped because of tear-down, not because of
++               * pending work
++               */
++              if(!atomic_read(&dev->working))
++                      break;
++
++              bh = cow_get_bh(dev);
++              if(bh == NULL){
++                      printk(KERN_ERR "cow: missing bh\n");
++                      continue;
++              }
++
++              start = bh->b_blocknr * bh->b_size / dev->sectorsize;
++              len = bh->b_size / dev->sectorsize;
++              for(i = 0; i < len ; i++){
++                      if(ubd_test_bit(start +ni, 
++                                      (unsigned char *) dev->bitmap))
++                              continue;
++
++                      update_bitmap = 1;
++                      ubd_set_bit(start + i, (unsigned char *) dev->bitmap);
++              }
++
++              cow_bh[0] = NULL;
++              cow_bh[1] = NULL;
++              nbh = 0;
++              if(update_bitmap){
++                      cow_bh[0] = cow_new_bh(dev, start);
++                      nbh++;
++                      if(start / dev->sectorsize != 
++                         (start + len) / dev->sectorsize){
++                              cow_bh[1] = cow_new_bh(dev, start + len);
++                              nbh++;
++                      }
++              }
++              
++              bh->b_dev = dev->cow_dev;
++              bh->b_blocknr += dev->data_offset / dev->sectorsize;
++
++              cow_handle_bh(dev, bh, cow_bh, nbh);
++
++              /*
++               * upped both for pending work and tear-down, lo_pending
++               * will hit zero then
++               */
++              if(atomic_dec_and_test(&dev->working))
++                      break;
++      }
++
++      up(&dev->sem);
++      return(0);
++}
++
++static int cow_make_request(request_queue_t *q, int rw, struct buffer_head *bh)
++{
++      struct cow *dev;
++      int n, minor;
++
++      minor = MINOR(bh->b_rdev);
++      n = minor >> COW_SHIFT;
++      dev = &cow_dev[n];
++
++      dev->end_io = NULL;
++      if(ubd_test_bit(bh->b_rsector, (unsigned char *) dev->bitmap)){
++              bh->b_rdev = dev->cow_dev;
++              bh->b_rsector += dev->data_offset / dev->sectorsize;
++      }
++      else if(rw == WRITE){
++              bh->b_dev = dev->cow_dev;
++              bh->b_blocknr += dev->data_offset / dev->sectorsize;
++
++              cow_add_bh(dev, bh);
++              up(&dev->io_sem);
++              return(0);
++      }
++      else {
++              bh->b_rdev = dev->backing_dev;
++      }
++
++      return(1);
++}
++
++int cow_init(void)
++{
++      int i;
++
++      cow_dir_handle = devfs_mk_dir (NULL, "cow", NULL);
++      if (devfs_register_blkdev(MAJOR_NR, "cow", &cow_blops)) {
++              printk(KERN_ERR "cow: unable to get major %d\n", MAJOR_NR);
++              return -1;
++      }
++      read_ahead[MAJOR_NR] = 8;               /* 8 sector (4kB) read-ahead */
++      blksize_size[MAJOR_NR] = blk_sizes;
++      blk_size[MAJOR_NR] = sizes;
++      INIT_HARDSECT(hardsect_size, MAJOR_NR, hardsect_sizes);
++
++      cow_queue = BLK_DEFAULT_QUEUE(MAJOR_NR);
++      blk_init_queue(cow_queue, NULL);
++      INIT_ELV(cow_queue, &cow_queue->elevator);
++      blk_queue_make_request(cow_queue, cow_make_request);
++
++       add_gendisk(&cow_gendisk);
++
++      for(i=0;i<MAX_DEV;i++) 
++              cow_add(i);
++
++      return(0);
++}
++
++__initcall(cow_init);
++
++static int reader(__u64 start, char *buf, int count, void *arg)
++{
++      dev_t dev = *((dev_t *) arg);
++      struct buffer_head *bh;
++      __u64 block;
++      int cur, offset, left, n, blocksize = get_hardsect_size(dev);
++
++      if(blocksize == 0)
++              panic("Zero blocksize");
++
++      block = start / blocksize;
++      offset = start % blocksize;
++      left = count;
++      cur = 0;
++      while(left > 0){
++              n = (left > blocksize) ? blocksize : left;
++
++              bh = bread(dev, block, (n < 512) ? 512 : n);
++              if(bh == NULL)
++                      return(-EIO);
++
++              n -= offset;
++              memcpy(&buf[cur], bh->b_data + offset, n);
++              block++;
++              left -= n;
++              cur += n;
++              offset = 0;
++              brelse(bh);
++      }
++
++      return(count);
++}
++
++static int cow_open(struct inode *inode, struct file *filp)
++{
++      int (*dev_ioctl)(struct inode *, struct file *, unsigned int, 
++                       unsigned long);
++      mm_segment_t fs;
++      struct cow *dev;
++      __u64 size;
++      __u32 version, align;
++      time_t mtime;
++      char *backing_file;
++      int n, offset, err = 0;
++
++      n = DEVICE_NR(inode->i_rdev);
++      if(n >= MAX_DEV)
++              return(-ENODEV);
++      dev = &cow_dev[n];
++      offset = n << COW_SHIFT;
++
++      spin_lock(&cow_lock);
++
++      if(dev->count == 0){
++              dev->cow_dev = name_to_kdev_t(dev->cow_path);
++              if(dev->cow_dev == 0){
++                      printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") "
++                             "failed\n", dev->cow_path);
++                      err = -ENODEV;
++              }
++
++              dev->backing_dev = name_to_kdev_t(dev->backing_path);
++              if(dev->backing_dev == 0){
++                      printk(KERN_ERR "cow_open - name_to_kdev_t(\"%s\") "
++                             "failed\n", dev->backing_path);
++                      err = -ENODEV;
++              }
++
++              if(err) 
++                      goto out;
++
++              dev->cow_bdev = bdget(dev->cow_dev);
++              if(dev->cow_bdev == NULL){
++                      printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n", 
++                             dev->cow_path);
++                      err = -ENOMEM;
++              }
++              dev->backing_bdev = bdget(dev->backing_dev);
++              if(dev->backing_bdev == NULL){
++                      printk(KERN_ERR "cow_open - bdget(\"%s\") failed\n", 
++                             dev->backing_path);
++                      err = -ENOMEM;
++              }
++
++              if(err) 
++                      goto out;
++
++              err = blkdev_get(dev->cow_bdev, FMODE_READ|FMODE_WRITE, 0, 
++                               BDEV_RAW);
++              if(err){
++                      printk("cow_open - blkdev_get of COW device failed, "
++                             "error = %d\n", err);
++                      goto out;
++              }
++              
++              err = blkdev_get(dev->backing_bdev, FMODE_READ, 0, BDEV_RAW);
++              if(err){
++                      printk("cow_open - blkdev_get of backing device "
++                             "failed, error = %d\n", err);
++                      goto out;
++              }
++              
++              err = read_cow_header(reader, &dev->cow_dev, &version, 
++                                    &backing_file, &mtime, &size,
++                                    &dev->sectorsize, &align, 
++                                    &dev->bitmap_offset);
++              if(err){
++                      printk(KERN_ERR "cow_open - read_cow_header failed, "
++                             "err = %d\n", err);
++                      goto out;
++              }
++
++              cow_sizes(version, size, dev->sectorsize, align, 
++                        dev->bitmap_offset, &dev->bitmap_len, 
++                        &dev->data_offset);
++              dev->bitmap = (void *) vmalloc(dev->bitmap_len);
++              if(dev->bitmap == NULL){
++                      err = -ENOMEM;
++                      printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
++                      goto out;
++              }
++              flush_tlb_kernel_vm();
++              
++              err = reader(dev->bitmap_offset, (char *) dev->bitmap, 
++                           dev->bitmap_len, &dev->cow_dev);
++              if(err < 0){
++                      printk(KERN_ERR "Failed to read COW bitmap\n");
++                      vfree(dev->bitmap);
++                      goto out;
++              }
++
++              dev_ioctl = dev->backing_bdev->bd_op->ioctl;
++              fs = get_fs();
++              set_fs(KERNEL_DS);
++              err = (*dev_ioctl)(inode, filp, BLKGETSIZE, 
++                                 (unsigned long) &sizes[offset]);
++              set_fs(fs);
++              if(err){
++                      printk(KERN_ERR "cow_open - BLKGETSIZE failed, "
++                             "error = %d\n", err);
++                      goto out;
++              }
++
++              kernel_thread(cow_thread, dev, 
++                            CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
++              down(&dev->sem);
++      }
++      dev->count++;
++out:
++      spin_unlock(&cow_lock);
++      return(err);
++}
++
++static int cow_release(struct inode * inode, struct file * file)
++{
++      struct cow *dev;
++      int n, err;
++
++      n = DEVICE_NR(inode->i_rdev);
++      if(n >= MAX_DEV)
++              return(-ENODEV);
++      dev = &cow_dev[n];
++
++      spin_lock(&cow_lock);
++
++      if(--dev->count > 0)
++              goto out;
++
++      err = blkdev_put(dev->cow_bdev, BDEV_RAW);
++      if(err)
++              printk("cow_release - blkdev_put of cow device failed, "
++                     "error = %d\n", err);
++      bdput(dev->cow_bdev);
++      dev->cow_bdev = 0;
++
++      err = blkdev_put(dev->backing_bdev, BDEV_RAW);
++      if(err)
++              printk("cow_release - blkdev_put of backing device failed, "
++                     "error = %d\n", err);
++      bdput(dev->backing_bdev);
++      dev->backing_bdev = 0;
++
++out:
++      spin_unlock(&cow_lock);
++      return(0);
++}
++
++static int cow_ioctl(struct inode * inode, struct file * file,
++                   unsigned int cmd, unsigned long arg)
++{
++      struct cow *dev;
++      int (*dev_ioctl)(struct inode *, struct file *, unsigned int, 
++                       unsigned long);
++      int n;
++
++      n = DEVICE_NR(inode->i_rdev);
++      if(n >= MAX_DEV)
++              return(-ENODEV);
++      dev = &cow_dev[n];
++
++      dev_ioctl = dev->backing_bdev->bd_op->ioctl;
++      return((*dev_ioctl)(inode, file, cmd, arg));
++}
++
++static int cow_revalidate(kdev_t rdev)
++{
++      printk(KERN_ERR "Need to implement cow_revalidate\n");
++      return(0);
++}
++
++static int parse_unit(char **ptr)
++{
++      char *str = *ptr, *end;
++      int n = -1;
++
++      if(isdigit(*str)) {
++              n = simple_strtoul(str, &end, 0);
++              if(end == str)
++                      return(-1);
++              *ptr = end;
++      }
++      else if (('a' <= *str) && (*str <= 'h')) {
++              n = *str - 'a';
++              str++;
++              *ptr = str;
++      }
++      return(n);
++}
++
++static int cow_setup(char *str)
++{
++      struct cow *dev;
++      char *cow_name, *backing_name;
++      int unit;
++
++      unit = parse_unit(&str);
++      if(unit < 0){
++              printk(KERN_ERR "cow_setup - Couldn't parse unit number\n");
++              return(1);
++      }
++
++      if(*str != '='){
++              printk(KERN_ERR "cow_setup - Missing '=' after unit "
++                     "number\n");
++              return(1);
++      }
++      str++;
++
++      cow_name = str;
++      backing_name = strchr(str, ',');
++      if(backing_name == NULL){
++              printk(KERN_ERR "cow_setup - missing backing device name\n");
++              return(0);
++      }
++      *backing_name = '\0';
++      backing_name++;
++
++      spin_lock(&cow_lock);
++
++      dev = &cow_dev[unit];
++      dev->cow_path = cow_name;
++      dev->backing_path = backing_name;
++      
++      spin_unlock(&cow_lock);
++      return(0);
++}
++
++__setup("cow", cow_setup);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
+--- a/arch/um/drivers/cow_sys.h        1969-12-31 19:00:00.000000000 -0500
++++ b/arch/um/drivers/cow_sys.h        2004-01-08 22:29:45.000000000 -0500
+@@ -0,0 +1,48 @@
++#ifndef __COW_SYS_H__
++#define __COW_SYS_H__
++
++#include "kern_util.h"
++#include "user_util.h"
++#include "os.h"
++#include "user.h"
++
++static inline void *cow_malloc(int size)
++{
++      return(um_kmalloc(size));
++}
++
++static inline void cow_free(void *ptr)
++{
++      kfree(ptr);
++}
++
++#define cow_printf printk
++
++static inline char *cow_strdup(char *str)
++{
++      return(uml_strdup(str));
++}
++
++static inline int cow_seek_file(int fd, __u64 offset)
++{
++      return(os_seek_file(fd, offset));
++}
++
++static inline int cow_file_size(char *file, __u64 *size_out)
++{
++      return(os_file_size(file, size_out));
++}
++
++static inline int cow_write_file(int fd, char *buf, int size)
++{
++      return(os_write_file(fd, buf, size));
++}
++
++#endif
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c
+--- a/arch/um/drivers/cow_user.c       1969-12-31 19:00:00.000000000 -0500
++++ b/arch/um/drivers/cow_user.c       2004-01-08 22:28:43.000000000 -0500
+@@ -0,0 +1,375 @@
++#include <stddef.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <byteswap.h>
++#include <sys/time.h>
++#include <sys/param.h>
++#include <sys/user.h>
++#include <netinet/in.h>
++
++#include "os.h"
++
++#include "cow.h"
++#include "cow_sys.h"
++
++#define PATH_LEN_V1 256
++
++struct cow_header_v1 {
++      int magic;
++      int version;
++      char backing_file[PATH_LEN_V1];
++      time_t mtime;
++      __u64 size;
++      int sectorsize;
++};
++
++#define PATH_LEN_V2 MAXPATHLEN
++
++struct cow_header_v2 {
++      unsigned long magic;
++      unsigned long version;
++      char backing_file[PATH_LEN_V2];
++      time_t mtime;
++      __u64 size;
++      int sectorsize;
++};
++
++/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in 
++ * case other systems have different values for MAXPATHLEN
++ */
++#define PATH_LEN_V3 4096
++
++/* Changes from V2 - 
++ *    PATH_LEN_V3 as described above
++ *    Explicitly specify field bit lengths for systems with different
++ *            lengths for the usual C types.  Not sure whether char or
++ *            time_t should be changed, this can be changed later without
++ *            breaking compatibility
++ *    Add alignment field so that different alignments can be used for the
++ *            bitmap and data
++ *    Add cow_format field to allow for the possibility of different ways
++ *            of specifying the COW blocks.  For now, the only value is 0,
++ *            for the traditional COW bitmap.
++ *    Move the backing_file field to the end of the header.  This allows
++ *            for the possibility of expanding it into the padding required
++ *            by the bitmap alignment.
++ *    The bitmap and data portions of the file will be aligned as specified
++ *            by the alignment field.  This is to allow COW files to be
++ *            put on devices with restrictions on access alignments, such as
++ *            /dev/raw, with a 512 byte alignment restriction.  This also
++ *            allows the data to be more aligned more strictly than on
++ *            sector boundaries.  This is needed for ubd-mmap, which needs
++ *            the data to be page aligned.
++ *    Fixed (finally!) the rounding bug
++ */
++
++struct cow_header_v3 {
++      __u32 magic;
++      __u32 version;
++      time_t mtime;
++      __u64 size;
++      __u32 sectorsize;
++      __u32 alignment;
++      __u32 cow_format;
++      char backing_file[PATH_LEN_V3];
++};
++
++/* COW format definitions - for now, we have only the usual COW bitmap */
++#define COW_BITMAP 0
++
++union cow_header {
++      struct cow_header_v1 v1;
++      struct cow_header_v2 v2;
++      struct cow_header_v3 v3;
++};
++
++#define COW_MAGIC 0x4f4f4f4d  /* MOOO */
++#define COW_VERSION 3
++
++#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len))
++#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align)
++
++void cow_sizes(int version, __u64 size, int sectorsize, int align, 
++             int bitmap_offset, unsigned long *bitmap_len_out, 
++             int *data_offset_out)
++{
++      if(version < 3){
++              *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
++
++              *data_offset_out = bitmap_offset + *bitmap_len_out;
++              *data_offset_out = (*data_offset_out + sectorsize - 1) / 
++                      sectorsize;
++              *data_offset_out *= sectorsize;
++      }
++      else {
++              *bitmap_len_out = DIV_ROUND(size, sectorsize);
++              *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8);
++
++              *data_offset_out = bitmap_offset + *bitmap_len_out;
++              *data_offset_out = ROUND_UP(*data_offset_out, align);
++      }
++}
++
++static int absolutize(char *to, int size, char *from)
++{
++      char save_cwd[256], *slash;
++      int remaining;
++
++      if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
++              cow_printf("absolutize : unable to get cwd - errno = %d\n", 
++                         errno);
++              return(-1);
++      }
++      slash = strrchr(from, '/');
++      if(slash != NULL){
++              *slash = '\0';
++              if(chdir(from)){
++                      *slash = '/';
++                      cow_printf("absolutize : Can't cd to '%s' - " 
++                                 "errno = %d\n", from, errno);
++                      return(-1);
++              }
++              *slash = '/';
++              if(getcwd(to, size) == NULL){
++                      cow_printf("absolutize : unable to get cwd of '%s' - "
++                             "errno = %d\n", from, errno);
++                      return(-1);
++              }
++              remaining = size - strlen(to);
++              if(strlen(slash) + 1 > remaining){
++                      cow_printf("absolutize : unable to fit '%s' into %d "
++                             "chars\n", from, size);
++                      return(-1);
++              }
++              strcat(to, slash);
++      }
++      else {
++              if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
++                      cow_printf("absolutize : unable to fit '%s' into %d "
++                             "chars\n", from, size);
++                      return(-1);
++              }
++              strcpy(to, save_cwd);
++              strcat(to, "/");
++              strcat(to, from);
++      }
++      chdir(save_cwd);
++      return(0);
++}
++
++int write_cow_header(char *cow_file, int fd, char *backing_file, 
++                   int sectorsize, int alignment, long long *size)
++{
++      struct cow_header_v3 *header;
++      unsigned long modtime;
++      int err;
++
++      err = cow_seek_file(fd, 0);
++      if(err < 0){
++              cow_printf("write_cow_header - lseek failed, err = %d\n", -err);
++              goto out;
++      }
++
++      err = -ENOMEM;
++      header = cow_malloc(sizeof(*header));
++      if(header == NULL){
++              cow_printf("Failed to allocate COW V3 header\n");
++              goto out;
++      }
++      header->magic = htonl(COW_MAGIC);
++      header->version = htonl(COW_VERSION);
++
++      err = -EINVAL;
++      if(strlen(backing_file) > sizeof(header->backing_file) - 1){
++              cow_printf("Backing file name \"%s\" is too long - names are "
++                         "limited to %d characters\n", backing_file, 
++                         sizeof(header->backing_file) - 1);
++              goto out_free;
++      }
++
++      if(absolutize(header->backing_file, sizeof(header->backing_file), 
++                    backing_file))
++              goto out_free;
++
++      err = os_file_modtime(header->backing_file, &modtime);
++      if(err < 0){
++              cow_printf("Backing file '%s' mtime request failed, "
++                         "err = %d\n", header->backing_file, -err);
++              goto out_free;
++      }
++
++      err = cow_file_size(header->backing_file, size);
++      if(err < 0){
++              cow_printf("Couldn't get size of backing file '%s', "
++                         "err = %d\n", header->backing_file, -err);
++              goto out_free;
++      }
++
++      header->mtime = htonl(modtime);
++      header->size = htonll(*size);
++      header->sectorsize = htonl(sectorsize);
++      header->alignment = htonl(alignment);
++      header->cow_format = COW_BITMAP;
++
++      err = os_write_file(fd, header, sizeof(*header));
++      if(err != sizeof(*header)){
++              cow_printf("Write of header to new COW file '%s' failed, "
++                         "err = %d\n", cow_file, -err);
++              goto out_free;
++      }
++      err = 0;
++ out_free:
++      cow_free(header);
++ out:
++      return(err);
++}
++
++int file_reader(__u64 offset, char *buf, int len, void *arg)
++{
++      int fd = *((int *) arg);
++
++      return(pread(fd, buf, len, offset));
++}
++
++/* XXX Need to sanity-check the values read from the header */
++
++int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, 
++                  __u32 *version_out, char **backing_file_out, 
++                  time_t *mtime_out, __u64 *size_out, 
++                  int *sectorsize_out, __u32 *align_out, 
++                  int *bitmap_offset_out)
++{
++      union cow_header *header;
++      char *file;
++      int err, n;
++      unsigned long version, magic;
++
++      header = cow_malloc(sizeof(*header));
++      if(header == NULL){
++              cow_printf("read_cow_header - Failed to allocate header\n");
++              return(-ENOMEM);
++      }
++      err = -EINVAL;
++      n = (*reader)(0, (char *) header, sizeof(*header), arg);
++      if(n < offsetof(typeof(header->v1), backing_file)){
++              cow_printf("read_cow_header - short header\n");
++              goto out;
++      }
++
++      magic = header->v1.magic;
++      if(magic == COW_MAGIC) {
++              version = header->v1.version;
++      }
++      else if(magic == ntohl(COW_MAGIC)){
++              version = ntohl(header->v1.version);
++      }
++      /* No error printed because the non-COW case comes through here */
++      else goto out;
++
++      *version_out = version;
++
++      if(version == 1){
++              if(n < sizeof(header->v1)){
++                      cow_printf("read_cow_header - failed to read V1 "
++                                 "header\n");
++                      goto out;
++              }
++              *mtime_out = header->v1.mtime;
++              *size_out = header->v1.size;
++              *sectorsize_out = header->v1.sectorsize;
++              *bitmap_offset_out = sizeof(header->v1);
++              *align_out = *sectorsize_out;
++              file = header->v1.backing_file;
++      }
++      else if(version == 2){
++              if(n < sizeof(header->v2)){
++                      cow_printf("read_cow_header - failed to read V2 "
++                                 "header\n");
++                      goto out;
++              }
++              *mtime_out = ntohl(header->v2.mtime);
++              *size_out = ntohll(header->v2.size);
++              *sectorsize_out = ntohl(header->v2.sectorsize);
++              *bitmap_offset_out = sizeof(header->v2);
++              *align_out = *sectorsize_out;
++              file = header->v2.backing_file;
++      }
++      else if(version == 3){
++              if(n < sizeof(header->v3)){
++                      cow_printf("read_cow_header - failed to read V2 "
++                                 "header\n");
++                      goto out;
++              }
++              *mtime_out = ntohl(header->v3.mtime);
++              *size_out = ntohll(header->v3.size);
++              *sectorsize_out = ntohl(header->v3.sectorsize);
++              *align_out = ntohl(header->v3.alignment);
++              *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out);
++              file = header->v3.backing_file;
++      }
++      else {
++              cow_printf("read_cow_header - invalid COW version\n");
++              goto out;               
++      }
++      err = -ENOMEM;
++      *backing_file_out = cow_strdup(file);
++      if(*backing_file_out == NULL){
++              cow_printf("read_cow_header - failed to allocate backing "
++                         "file\n");
++              goto out;
++      }
++      err = 0;
++ out:
++      cow_free(header);
++      return(err);
++}
++
++int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize,
++                int alignment, int *bitmap_offset_out, 
++                unsigned long *bitmap_len_out, int *data_offset_out)
++{
++      __u64 size, offset;
++      char zero = 0;
++      int err;
++
++      err = write_cow_header(cow_file, fd, backing_file, sectorsize, 
++                             alignment, &size);
++      if(err) 
++              goto out;
++      
++      *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment);
++      cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out,
++                bitmap_len_out, data_offset_out);
++
++      offset = *data_offset_out + size - sizeof(zero);
++      err = cow_seek_file(fd, offset);
++      if(err < 0){
++              cow_printf("cow bitmap lseek failed : err = %d\n", -err);
++              goto out;
++      }
++
++      /* does not really matter how much we write it is just to set EOF 
++       * this also sets the entire COW bitmap
++       * to zero without having to allocate it 
++       */
++      err = cow_write_file(fd, &zero, sizeof(zero));
++      if(err != sizeof(zero)){
++              cow_printf("Write of bitmap to new COW file '%s' failed, "
++                         "err = %d\n", cow_file, -err);
++              err = -EINVAL;
++              goto out;
++      }
++
++      return(0);
++
++ out:
++      return(err);
++}
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
+--- a/arch/um/drivers/daemon_user.c    2004-01-08 22:19:18.000000000 -0500
++++ b/arch/um/drivers/daemon_user.c    2004-01-08 22:25:32.000000000 -0500
+@@ -53,7 +53,8 @@
+       struct request_v3 req;
+       int fd, n, err;
+-      if((pri->control = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
++      pri->control = socket(AF_UNIX, SOCK_STREAM, 0);
++      if(pri->control < 0){
+               printk("daemon_open : control socket failed, errno = %d\n", 
+                      errno);          
+               return(-errno);
+@@ -67,7 +68,8 @@
+               goto out;
+       }
+-      if((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
++      fd = socket(AF_UNIX, SOCK_DGRAM, 0);
++      if(fd < 0){
+               printk("daemon_open : data socket failed, errno = %d\n", 
+                      errno);
+               err = -errno;
+@@ -91,18 +93,18 @@
+       req.version = SWITCH_VERSION;
+       req.type = REQ_NEW_CONTROL;
+       req.sock = *local_addr;
+-      n = write(pri->control, &req, sizeof(req));
++      n = os_write_file(pri->control, &req, sizeof(req));
+       if(n != sizeof(req)){
+-              printk("daemon_open : control setup request returned %d, "
+-                     "errno = %d\n", n, errno);
++              printk("daemon_open : control setup request failed, err = %d\n",
++                     -n);
+               err = -ENOTCONN;
+               goto out;               
+       }
+-      n = read(pri->control, sun, sizeof(*sun));
++      n = os_read_file(pri->control, sun, sizeof(*sun));
+       if(n != sizeof(*sun)){
+-              printk("daemon_open : read of data socket returned %d, "
+-                     "errno = %d\n", n, errno);
++              printk("daemon_open : read of data socket failed, err = %d\n", 
++                     -n);
+               err = -ENOTCONN;
+               goto out_close;         
+       }
+@@ -111,9 +113,9 @@
+       return(fd);
+  out_close:
+-      close(fd);
++      os_close_file(fd);
+  out:
+-      close(pri->control);
++      os_close_file(pri->control);
+       return(err);
+ }
+@@ -153,8 +155,8 @@
+ {
+       struct daemon_data *pri = data;
+-      close(pri->fd);
+-      close(pri->control);
++      os_close_file(pri->fd);
++      os_close_file(pri->control);
+       if(pri->data_addr != NULL) kfree(pri->data_addr);
+       if(pri->ctl_addr != NULL) kfree(pri->ctl_addr);
+       if(pri->local_addr != NULL) kfree(pri->local_addr);
+diff -Naur a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
+--- a/arch/um/drivers/fd.c     2004-01-08 22:31:17.000000000 -0500
++++ b/arch/um/drivers/fd.c     2004-01-08 22:35:52.000000000 -0500
+@@ -35,7 +35,8 @@
+               printk("fd_init : couldn't parse file descriptor '%s'\n", str);
+               return(NULL);
+       }
+-      if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
++      data = um_kmalloc(sizeof(*data));
++      if(data == NULL) return(NULL);
+       *data = ((struct fd_chan) { .fd         = n,
+                                   .raw        = opts->raw });
+       return(data);
+diff -Naur a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c
+--- a/arch/um/drivers/harddog_user.c   2004-01-08 22:17:52.000000000 -0500
++++ b/arch/um/drivers/harddog_user.c   2004-01-08 22:23:56.000000000 -0500
+@@ -27,10 +27,10 @@
+       dup2(data->stdin, 0);
+       dup2(data->stdout, 1);
+       dup2(data->stdout, 2);
+-      close(data->stdin);
+-      close(data->stdout);
+-      close(data->close_me[0]);
+-      close(data->close_me[1]);
++      os_close_file(data->stdin);
++      os_close_file(data->stdout);
++      os_close_file(data->close_me[0]);
++      os_close_file(data->close_me[1]);
+ }
+ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
+@@ -44,15 +44,15 @@
+       char **args = NULL;
+       err = os_pipe(in_fds, 1, 0);
+-      if(err){
+-              printk("harddog_open - os_pipe failed, errno = %d\n", -err);
+-              return(err);
++      if(err < 0){
++              printk("harddog_open - os_pipe failed, err = %d\n", -err);
++              goto out;
+       }
+       err = os_pipe(out_fds, 1, 0);
+-      if(err){
+-              printk("harddog_open - os_pipe failed, errno = %d\n", -err);
+-              return(err);
++      if(err < 0){
++              printk("harddog_open - os_pipe failed, err = %d\n", -err);
++              goto out_close_in;
+       }
+       data.stdin = out_fds[0];
+@@ -72,42 +72,47 @@
+       pid = run_helper(pre_exec, &data, args, NULL);
+-      close(out_fds[0]);
+-      close(in_fds[1]);
++      os_close_file(out_fds[0]);
++      os_close_file(in_fds[1]);
+       if(pid < 0){
+               err = -pid;
+-              printk("harddog_open - run_helper failed, errno = %d\n", err);
+-              goto out;
++              printk("harddog_open - run_helper failed, errno = %d\n", -err);
++              goto out_close_out;
+       }
+-      n = read(in_fds[0], &c, sizeof(c));
++      n = os_read_file(in_fds[0], &c, sizeof(c));
+       if(n == 0){
+               printk("harddog_open - EOF on watchdog pipe\n");
+               helper_wait(pid);
+               err = -EIO;
+-              goto out;
++              goto out_close_out;
+       }
+       else if(n < 0){
+               printk("harddog_open - read of watchdog pipe failed, "
+-                     "errno = %d\n", errno);
++                     "err = %d\n", -n);
+               helper_wait(pid);
+-              err = -errno;
+-              goto out;
++              err = n;
++              goto out_close_out;
+       }
+       *in_fd_ret = in_fds[0];
+       *out_fd_ret = out_fds[1];
+       return(0);
++
++ out_close_in:
++      os_close_file(in_fds[0]);
++      os_close_file(in_fds[1]);
++ out_close_out:
++      os_close_file(out_fds[0]);
++      os_close_file(out_fds[1]);
+  out:
+-      close(out_fds[1]);
+-      close(in_fds[0]);
+       return(err);
+ }
+ void stop_watchdog(int in_fd, int out_fd)
+ {
+-      close(in_fd);
+-      close(out_fd);
++      os_close_file(in_fd);
++      os_close_file(out_fd);
+ }
+ int ping_watchdog(int fd)
+@@ -115,11 +120,12 @@
+       int n;
+       char c = '\n';
+-      n = write(fd, &c, sizeof(c));
+-      if(n < sizeof(c)){
+-              printk("ping_watchdog - write failed, errno = %d\n",
+-                     errno);
+-              return(-errno);
++      n = os_write_file(fd, &c, sizeof(c));
++      if(n != sizeof(c)){
++              printk("ping_watchdog - write failed, err = %d\n", -n);
++              if(n < 0) 
++                      return(n);
++              return(-EIO);
+       }
+       return 1;
+diff -Naur a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
+--- a/arch/um/drivers/hostaudio_kern.c 2004-01-08 22:31:38.000000000 -0500
++++ b/arch/um/drivers/hostaudio_kern.c 2004-01-08 22:36:17.000000000 -0500
+@@ -5,12 +5,12 @@
+ #include "linux/config.h"
+ #include "linux/module.h"
+-#include "linux/version.h"
+ #include "linux/init.h"
+ #include "linux/slab.h"
+ #include "linux/fs.h"
+ #include "linux/sound.h"
+ #include "linux/soundcard.h"
++#include "asm/uaccess.h"
+ #include "kern_util.h"
+ #include "init.h"
+ #include "hostaudio.h"
+@@ -19,30 +19,39 @@
+ char *dsp = HOSTAUDIO_DEV_DSP;
+ char *mixer = HOSTAUDIO_DEV_MIXER;
++#define DSP_HELP \
++"    This is used to specify the host dsp device to the hostaudio driver.\n" \
++"    The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
++
++#define MIXER_HELP \
++"    This is used to specify the host mixer device to the hostaudio driver.\n" \
++"    The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
++
+ #ifndef MODULE
+ static int set_dsp(char *name, int *add)
+ {
+-      dsp = uml_strdup(name);
++      dsp = name;
+       return(0);
+ }
+-__uml_setup("dsp=", set_dsp,
+-"dsp=<dsp device>\n"
+-"    This is used to specify the host dsp device to the hostaudio driver.\n"
+-"    The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
+-);
++__uml_setup("dsp=", set_dsp, "dsp=<dsp device>\n" DSP_HELP);
+ static int set_mixer(char *name, int *add)
+ {
+-      mixer = uml_strdup(name);
++      mixer = name;
+       return(0);
+ }
+-__uml_setup("mixer=", set_mixer,
+-"mixer=<mixer device>\n"
+-"    This is used to specify the host mixer device to the hostaudio driver.\n"
+-"    The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
+-);
++__uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP);
++
++#else /*MODULE*/
++
++MODULE_PARM(dsp, "s");
++MODULE_PARM_DESC(dsp, DSP_HELP);
++
++MODULE_PARM(mixer, "s");
++MODULE_PARM_DESC(mixer, MIXER_HELP);
++
+ #endif
+ /* /dev/dsp file operations */
+@@ -51,23 +60,55 @@
+                             loff_t *ppos)
+ {
+         struct hostaudio_state *state = file->private_data;
++      void *kbuf;
++      int err;
+ #ifdef DEBUG
+         printk("hostaudio: read called, count = %d\n", count);
+ #endif
+-        return(hostaudio_read_user(state, buffer, count, ppos));
++      kbuf = kmalloc(count, GFP_KERNEL);
++      if(kbuf == NULL)
++              return(-ENOMEM);
++
++        err = hostaudio_read_user(state, kbuf, count, ppos);
++      if(err < 0)
++              goto out;
++
++      if(copy_to_user(buffer, kbuf, err))
++              err = -EFAULT;
++
++ out:
++      kfree(kbuf);
++      return(err);
+ }
+ static ssize_t hostaudio_write(struct file *file, const char *buffer, 
+                              size_t count, loff_t *ppos)
+ {
+         struct hostaudio_state *state = file->private_data;
++      void *kbuf;
++      int err;
+ #ifdef DEBUG
+         printk("hostaudio: write called, count = %d\n", count);
+ #endif
+-        return(hostaudio_write_user(state, buffer, count, ppos));
++
++      kbuf = kmalloc(count, GFP_KERNEL);
++      if(kbuf == NULL)
++              return(-ENOMEM);
++
++      err = -EFAULT;
++      if(copy_from_user(kbuf, buffer, count))
++              goto out;
++
++        err = hostaudio_write_user(state, kbuf, count, ppos);
++      if(err < 0)
++              goto out;
++
++ out:
++      kfree(kbuf);
++      return(err);
+ }
+ static unsigned int hostaudio_poll(struct file *file, 
+@@ -86,12 +127,43 @@
+                          unsigned int cmd, unsigned long arg)
+ {
+         struct hostaudio_state *state = file->private_data;
++      unsigned long data = 0;
++      int err;
+ #ifdef DEBUG
+         printk("hostaudio: ioctl called, cmd = %u\n", cmd);
+ #endif
++      switch(cmd){
++      case SNDCTL_DSP_SPEED:
++      case SNDCTL_DSP_STEREO:
++      case SNDCTL_DSP_GETBLKSIZE:
++      case SNDCTL_DSP_CHANNELS:
++      case SNDCTL_DSP_SUBDIVIDE:
++      case SNDCTL_DSP_SETFRAGMENT:
++              if(get_user(data, (int *) arg))
++                      return(-EFAULT);
++              break;
++      default:
++              break;
++      }
++
++        err = hostaudio_ioctl_user(state, cmd, (unsigned long) &data);
++
++      switch(cmd){
++      case SNDCTL_DSP_SPEED:
++      case SNDCTL_DSP_STEREO:
++      case SNDCTL_DSP_GETBLKSIZE:
++      case SNDCTL_DSP_CHANNELS:
++      case SNDCTL_DSP_SUBDIVIDE:
++      case SNDCTL_DSP_SETFRAGMENT:
++              if(put_user(data, (int *) arg))
++                      return(-EFAULT);
++              break;
++      default:
++              break;
++      }
+-        return(hostaudio_ioctl_user(state, cmd, arg));
++      return(err);
+ }
+ static int hostaudio_open(struct inode *inode, struct file *file)
+@@ -225,7 +297,8 @@
+ static int __init hostaudio_init_module(void)
+ {
+-        printk(KERN_INFO "UML Audio Relay\n");
++        printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n",
++             dsp, mixer);
+       module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
+         if(module_data.dev_audio < 0){
+diff -Naur a/arch/um/drivers/hostaudio_user.c b/arch/um/drivers/hostaudio_user.c
+--- a/arch/um/drivers/hostaudio_user.c 2004-01-08 22:26:01.000000000 -0500
++++ b/arch/um/drivers/hostaudio_user.c 2004-01-08 22:33:41.000000000 -0500
+@@ -4,9 +4,6 @@
+  */
+ #include <sys/types.h>
+-#include <sys/stat.h>
+-#include <sys/ioctl.h>
+-#include <fcntl.h>
+ #include <unistd.h>
+ #include <errno.h>
+ #include "hostaudio.h"
+@@ -20,16 +17,11 @@
+ ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, 
+                           size_t count, loff_t *ppos)
+ {
+-      ssize_t ret;
+-
+ #ifdef DEBUG
+         printk("hostaudio: read_user called, count = %d\n", count);
+ #endif
+-        ret = read(state->fd, buffer, count);
+-
+-        if(ret < 0) return(-errno);
+-        return(ret);
++      return(os_read_file(state->fd, buffer, count));
+ }
+ ssize_t hostaudio_write_user(struct hostaudio_state *state, const char *buffer,
+@@ -41,24 +33,19 @@
+         printk("hostaudio: write_user called, count = %d\n", count);
+ #endif
+-        ret = write(state->fd, buffer, count);
++      return(os_write_file(state->fd, buffer, count));
+-        if(ret < 0) return(-errno);
+         return(ret);
+ }
+ int hostaudio_ioctl_user(struct hostaudio_state *state, unsigned int cmd, 
+                        unsigned long arg)
+ {
+-      int ret;
+ #ifdef DEBUG
+         printk("hostaudio: ioctl_user called, cmd = %u\n", cmd);
+ #endif
+-        ret = ioctl(state->fd, cmd, arg);
+-      
+-        if(ret < 0) return(-errno);
+-        return(ret);
++      return(os_ioctl_generic(state->fd, cmd, arg));
+ }
+ int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp)
+@@ -69,12 +56,13 @@
+         state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
+-        if(state->fd >= 0) return(0);
+-
+-        printk("hostaudio_open_user failed to open '%s', errno = %d\n",
+-             dsp, errno);
++      if(state->fd < 0) {
++              printk("hostaudio_open_user failed to open '%s', err = %d\n",
++                     dsp, -state->fd);
++              return(state->fd); 
++      }
+         
+-        return(-errno); 
++      return(0);
+ }
+ int hostaudio_release_user(struct hostaudio_state *state)
+@@ -83,8 +71,8 @@
+         printk("hostaudio: release called\n");
+ #endif
+         if(state->fd >= 0){
+-              close(state->fd);
+-              state->fd=-1;
++              os_close_file(state->fd);
++              state->fd = -1;
+         }
+         return(0);
+@@ -95,15 +83,11 @@
+ int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, 
+                               unsigned int cmd, unsigned long arg)
+ {
+-      int ret;
+ #ifdef DEBUG
+         printk("hostmixer: ioctl_user called cmd = %u\n",cmd);
+ #endif
+-        ret = ioctl(state->fd, cmd, arg);
+-      if(ret < 0) 
+-              return(-errno);
+-      return(ret);
++      return(os_ioctl_generic(state->fd, cmd, arg));
+ }
+ int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w,
+@@ -115,12 +99,13 @@
+         state->fd = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
+-        if(state->fd >= 0) return(0);
+-
+-        printk("hostaudio_open_mixdev_user failed to open '%s', errno = %d\n",
+-             mixer, errno);
++      if(state->fd < 0) {
++              printk("hostaudio_open_mixdev_user failed to open '%s', "
++                     "err = %d\n", mixer, state->fd);
++              return(state->fd); 
++      }
+         
+-        return(-errno); 
++      return(0);
+ }
+ int hostmixer_release_mixdev_user(struct hostmixer_state *state)
+@@ -130,7 +115,7 @@
+ #endif
+         if(state->fd >= 0){
+-              close(state->fd);
++              os_close_file(state->fd);
+               state->fd = -1;
+         }
+diff -Naur a/arch/um/drivers/line.c b/arch/um/drivers/line.c
+--- a/arch/um/drivers/line.c   2004-01-08 22:29:48.000000000 -0500
++++ b/arch/um/drivers/line.c   2004-01-08 22:35:21.000000000 -0500
+@@ -6,8 +6,8 @@
+ #include "linux/sched.h"
+ #include "linux/slab.h"
+ #include "linux/list.h"
++#include "linux/interrupt.h"
+ #include "linux/devfs_fs_kernel.h"
+-#include "asm/irq.h"
+ #include "asm/uaccess.h"
+ #include "chan_kern.h"
+ #include "irq_user.h"
+@@ -16,38 +16,55 @@
+ #include "user_util.h"
+ #include "kern_util.h"
+ #include "os.h"
++#include "irq_kern.h"
+ #define LINE_BUFSIZE 4096
+-void line_interrupt(int irq, void *data, struct pt_regs *unused)
++static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused)
+ {
+       struct line *dev = data;
+       if(dev->count > 0) 
+               chan_interrupt(&dev->chan_list, &dev->task, dev->tty, irq, 
+                              dev);
++      return IRQ_HANDLED;
+ }
+-void line_timer_cb(void *arg)
++static void line_timer_cb(void *arg)
+ {
+       struct line *dev = arg;
+       line_interrupt(dev->driver->read_irq, dev, NULL);
+ }
+-static void buffer_data(struct line *line, const char *buf, int len)
++static int write_room(struct line *dev)
+ {
+-      int end;
++      int n;
++
++      if(dev->buffer == NULL) return(LINE_BUFSIZE - 1);
++
++      n = dev->head - dev->tail;
++      if(n <= 0) n = LINE_BUFSIZE + n;
++      return(n - 1);
++}
++
++static int buffer_data(struct line *line, const char *buf, int len)
++{
++      int end, room;
+       if(line->buffer == NULL){
+               line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
+               if(line->buffer == NULL){
+                       printk("buffer_data - atomic allocation failed\n");
+-                      return;
++                      return(0);
+               }
+               line->head = line->buffer;
+               line->tail = line->buffer;
+       }
++
++      room = write_room(line);
++      len = (len > room) ? room : len;
++
+       end = line->buffer + LINE_BUFSIZE - line->tail;
+       if(len < end){
+               memcpy(line->tail, buf, len);
+@@ -60,6 +77,8 @@
+               memcpy(line->buffer, buf, len);
+               line->tail = line->buffer + len;
+       }
++
++      return(len);
+ }
+ static int flush_buffer(struct line *line)
+@@ -95,7 +114,7 @@
+       struct line *line;
+       char *new;
+       unsigned long flags;
+-      int n, err, i;
++      int n, err, i, ret = 0;
+       if(tty->stopped) return 0;
+@@ -104,9 +123,13 @@
+               if(new == NULL)
+                       return(0);
+               n = copy_from_user(new, buf, len);
+-              if(n == len)
+-                      return(-EFAULT);
+               buf = new;
++              if(n == len){
++                      len = -EFAULT;
++                      goto out_free;
++              }
++
++              len -= n;
+       }
+       i = tty->index;
+@@ -115,41 +138,50 @@
+       down(&line->sem);
+       if(line->head != line->tail){
+               local_irq_save(flags);
+-              buffer_data(line, buf, len);
++              ret += buffer_data(line, buf, len);
+               err = flush_buffer(line);
+               local_irq_restore(flags);
+               if(err <= 0)
+-                      goto out;
++                      goto out_up;
+       }
+       else {
+               n = write_chan(&line->chan_list, buf, len, 
+                              line->driver->write_irq);
+               if(n < 0){
+-                      len = n;
+-                      goto out;
++                      ret = n;
++                      goto out_up;
+               }
+-              if(n < len)
+-                      buffer_data(line, buf + n, len - n);
++
++              len -= n;
++              ret += n;
++              if(len > 0)
++                      ret += buffer_data(line, buf + n, len);
+       }
+- out:
++ out_up:
+       up(&line->sem);
+-      return(len);
++ out_free:
++      if(from_user)
++              kfree(buf);
++      return(ret);
+ }
+-void line_write_interrupt(int irq, void *data, struct pt_regs *unused)
++static irqreturn_t line_write_interrupt(int irq, void *data, 
++                                      struct pt_regs *unused)
+ {
+       struct line *dev = data;
+       struct tty_struct *tty = dev->tty;
+       int err;
+       err = flush_buffer(dev);
+-      if(err == 0) return;
++      if(err == 0) 
++              return(IRQ_NONE);
+       else if(err < 0){
+               dev->head = dev->buffer;
+               dev->tail = dev->buffer;
+       }
+-      if(tty == NULL) return;
++      if(tty == NULL) 
++              return(IRQ_NONE);
+       if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
+          (tty->ldisc.write_wakeup != NULL))
+@@ -161,21 +193,9 @@
+        * writes.
+        */
+-      if (waitqueue_active(&tty->write_wait))
++      if(waitqueue_active(&tty->write_wait))
+               wake_up_interruptible(&tty->write_wait);
+-
+-}
+-
+-int line_write_room(struct tty_struct *tty)
+-{
+-      struct line *dev = tty->driver_data;
+-      int n;
+-
+-      if(dev->buffer == NULL) return(LINE_BUFSIZE - 1);
+-
+-      n = dev->head - dev->tail;
+-      if(n <= 0) n = LINE_BUFSIZE + n;
+-      return(n - 1);
++      return(IRQ_HANDLED);
+ }
+ int line_setup_irq(int fd, int input, int output, void *data)
+@@ -305,7 +325,7 @@
+               if(*end != '='){
+                       printk(KERN_ERR "line_setup failed to parse \"%s\"\n", 
+                              init);
+-                      return(1);
++                      return(0);
+               }
+               init = end;
+       }
+@@ -313,12 +333,12 @@
+       if((n >= 0) && (n >= num)){
+               printk("line_setup - %d out of range ((0 ... %d) allowed)\n",
+                      n, num);
+-              return(1);
++              return(0);
+       }
+       else if(n >= 0){
+               if(lines[n].count > 0){
+                       printk("line_setup - device %d is open\n", n);
+-                      return(1);
++                      return(0);
+               }
+               if(lines[n].init_pri <= INIT_ONE){
+                       lines[n].init_pri = INIT_ONE;
+@@ -332,7 +352,7 @@
+       else if(!all_allowed){
+               printk("line_setup - can't configure all devices from "
+                      "mconsole\n");
+-              return(1);
++              return(0);
+       }
+       else {
+               for(i = 0; i < num; i++){
+@@ -346,7 +366,7 @@
+                       }
+               }
+       }
+-      return(0);
++      return(1);
+ }
+ int line_config(struct line *lines, int num, char *str)
+@@ -357,7 +377,7 @@
+               printk("line_config - uml_strdup failed\n");
+               return(-ENOMEM);
+       }
+-      return(line_setup(lines, num, new, 0));
++      return(!line_setup(lines, num, new, 0));
+ }
+ int line_get_config(char *name, struct line *lines, int num, char *str, 
+@@ -369,7 +389,7 @@
+       dev = simple_strtoul(name, &end, 0);
+       if((*end != '\0') || (end == name)){
+-              *error_out = "line_setup failed to parse device number";
++              *error_out = "line_get_config failed to parse device number";
+               return(0);
+       }
+@@ -379,15 +399,15 @@
+       }
+       line = &lines[dev];
++
+       down(&line->sem);
+-      
+       if(!line->valid)
+               CONFIG_CHUNK(str, size, n, "none", 1);
+       else if(line->count == 0)
+               CONFIG_CHUNK(str, size, n, line->init_str, 1);
+       else n = chan_config_string(&line->chan_list, str, size, error_out);
+-
+       up(&line->sem);
++
+       return(n);
+ }
+@@ -396,7 +416,14 @@
+       char config[sizeof("conxxxx=none\0")];
+       sprintf(config, "%s=none", str);
+-      return(line_setup(lines, num, config, 0));
++      return(!line_setup(lines, num, config, 0));
++}
++
++int line_write_room(struct tty_struct *tty)
++{
++      struct line *dev = tty->driver_data;
++
++      return(write_room(dev));
+ }
+ struct tty_driver *line_register_devfs(struct lines *set,
+@@ -412,7 +439,8 @@
+               return NULL;
+       driver->driver_name = line_driver->name;
+-      driver->name = line_driver->devfs_name;
++      driver->name = line_driver->device_name;
++      driver->devfs_name = line_driver->devfs_name;
+       driver->major = line_driver->major;
+       driver->minor_start = line_driver->minor_start;
+       driver->type = line_driver->type;
+@@ -432,7 +460,7 @@
+       for(i = 0; i < nlines; i++){
+               if(!lines[i].valid) 
+-                      tty_unregister_devfs(driver, i);
++                      tty_unregister_device(driver, i);
+       }
+       mconsole_register_dev(&line_driver->mc);
+@@ -465,24 +493,25 @@
+       struct line *line;
+ };
+-void winch_interrupt(int irq, void *data, struct pt_regs *unused)
++irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
+ {
+       struct winch *winch = data;
+       struct tty_struct *tty;
+       int err;
+       char c;
+-      err = generic_read(winch->fd, &c, NULL);
+-      if(err < 0){
+-              if(err != -EAGAIN){
+-                      printk("winch_interrupt : read failed, errno = %d\n", 
+-                             -err);
+-                      printk("fd %d is losing SIGWINCH support\n", 
+-                             winch->tty_fd);
+-                      free_irq(irq, data);
+-                      return;
++      if(winch->fd != -1){
++              err = generic_read(winch->fd, &c, NULL);
++              if(err < 0){
++                      if(err != -EAGAIN){
++                              printk("winch_interrupt : read failed, "
++                                     "errno = %d\n", -err);
++                              printk("fd %d is losing SIGWINCH support\n", 
++                                     winch->tty_fd);
++                              return(IRQ_HANDLED);
++                      }
++                      goto out;
+               }
+-              goto out;
+       }
+       tty = winch->line->tty;
+       if(tty != NULL){
+@@ -492,7 +521,9 @@
+               kill_pg(tty->pgrp, SIGWINCH, 1);
+       }
+  out:
+-      reactivate_fd(winch->fd, WINCH_IRQ);
++      if(winch->fd != -1)
++              reactivate_fd(winch->fd, WINCH_IRQ);
++      return(IRQ_HANDLED);
+ }
+ DECLARE_MUTEX(winch_handler_sem);
+@@ -529,7 +560,10 @@
+       list_for_each(ele, &winch_handlers){
+               winch = list_entry(ele, struct winch, list);
+-              close(winch->fd);
++              if(winch->fd != -1){
++                      deactivate_fd(winch->fd, WINCH_IRQ);
++                      os_close_file(winch->fd);
++              }
+               if(winch->pid != -1) 
+                       os_kill_process(winch->pid, 1);
+       }
+diff -Naur a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
+--- a/arch/um/drivers/Makefile 2004-01-08 22:23:04.000000000 -0500
++++ b/arch/um/drivers/Makefile 2004-01-08 22:30:06.000000000 -0500
+@@ -1,5 +1,5 @@
+ # 
+-# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
++# Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com)
+ # Licensed under the GPL
+ #
+@@ -39,6 +39,8 @@
+ obj-$(CONFIG_TTY_CHAN) += tty.o 
+ obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o
+ obj-$(CONFIG_UML_WATCHDOG) += harddog.o
++obj-$(CONFIG_BLK_DEV_COW) += cow_kern.o
++obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
+ obj-y += stdio_console.o $(CHAN_OBJS)
+@@ -46,7 +48,7 @@
+ USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \
+       null.o pty.o tty.o xterm.o
+-USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/drivers/$(file))
++USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+ $(USER_OBJS) : %.o: %.c
+       $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+diff -Naur a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
+--- a/arch/um/drivers/mcast_user.c     2004-01-08 22:22:02.000000000 -0500
++++ b/arch/um/drivers/mcast_user.c     2004-01-08 22:28:53.000000000 -0500
+@@ -23,6 +23,7 @@
+ #include "kern_util.h"
+ #include "user_util.h"
+ #include "user.h"
++#include "os.h"
+ #define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
+@@ -62,7 +63,8 @@
+               goto out;
+       }
+-      if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
++      fd = socket(AF_INET, SOCK_DGRAM, 0);
++      if (fd < 0){
+               printk("mcast_open : data socket failed, errno = %d\n", 
+                      errno);
+               fd = -ENOMEM;
+@@ -72,7 +74,7 @@
+       if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+               printk("mcast_open: SO_REUSEADDR failed, errno = %d\n",
+                       errno);
+-              close(fd);
++              os_close_file(fd);
+               fd = -EINVAL;
+               goto out;
+       }
+@@ -82,7 +84,7 @@
+                      sizeof(pri->ttl)) < 0) {
+               printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n",
+                       errno);
+-              close(fd);
++              os_close_file(fd);
+               fd = -EINVAL;
+               goto out;
+       }
+@@ -91,7 +93,7 @@
+       if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
+               printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n",
+                       errno);
+-              close(fd);
++              os_close_file(fd);
+               fd = -EINVAL;
+               goto out;
+       }
+@@ -99,7 +101,7 @@
+       /* bind socket to mcast address */
+       if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
+               printk("mcast_open : data bind failed, errno = %d\n", errno);
+-              close(fd);
++              os_close_file(fd);
+               fd = -EINVAL;
+               goto out;
+       }               
+@@ -115,7 +117,7 @@
+                      "interface on the host.\n");
+               printk("eth0 should be configured in order to use the "
+                      "multicast transport.\n");
+-              close(fd);
++              os_close_file(fd);
+               fd = -EINVAL;
+       }
+@@ -137,7 +139,7 @@
+                       errno);
+       }
+-      close(fd);
++      os_close_file(fd);
+ }
+ int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
+diff -Naur a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
+--- a/arch/um/drivers/mconsole_kern.c  2004-01-08 22:13:41.000000000 -0500
++++ b/arch/um/drivers/mconsole_kern.c  2004-01-08 22:17:57.000000000 -0500
+@@ -1,6 +1,6 @@
+ /*
+  * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
+- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+@@ -15,6 +15,9 @@
+ #include "linux/sysrq.h"
+ #include "linux/workqueue.h"
+ #include "linux/module.h"
++#include "linux/file.h"
++#include "linux/fs.h"
++#include "linux/namei.h"
+ #include "linux/proc_fs.h"
+ #include "asm/irq.h"
+ #include "asm/uaccess.h"
+@@ -27,6 +30,7 @@
+ #include "init.h"
+ #include "os.h"
+ #include "umid.h"
++#include "irq_kern.h"
+ static int do_unlink_socket(struct notifier_block *notifier, 
+                           unsigned long what, void *data)
+@@ -67,7 +71,7 @@
+ DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
+-void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+       int fd;
+       struct mconsole_entry *new;
+@@ -75,9 +79,10 @@
+       fd = (int) dev_id;
+       while (mconsole_get_request(fd, &req)){
+-              if(req.cmd->as_interrupt) (*req.cmd->handler)(&req);
++              if(req.cmd->context == MCONSOLE_INTR) 
++                      (*req.cmd->handler)(&req);
+               else {
+-                      new = kmalloc(sizeof(req), GFP_ATOMIC);
++                      new = kmalloc(sizeof(*new), GFP_ATOMIC);
+                       if(new == NULL)
+                               mconsole_reply(&req, "Out of memory", 1, 0);
+                       else {
+@@ -88,6 +93,7 @@
+       }
+       if(!list_empty(&mc_requests)) schedule_work(&mconsole_work);
+       reactivate_fd(fd, MCONSOLE_IRQ);
++      return(IRQ_HANDLED);
+ }
+ void mconsole_version(struct mc_request *req)
+@@ -100,20 +106,110 @@
+       mconsole_reply(req, version, 0, 0);
+ }
++void mconsole_log(struct mc_request *req)
++{
++      int len;
++      char *ptr = req->request.data;
++      
++      ptr += strlen("log");
++      while(isspace(*ptr)) ptr++;
++
++      len = req->len - (ptr - req->request.data);
++      printk("%.*s", len, ptr);
++      mconsole_reply(req, "", 0, 0);
++}
++
++void mconsole_proc(struct mc_request *req)
++{
++      struct nameidata nd;
++      struct file_system_type *proc;
++      struct super_block *super;
++      struct file *file;
++      int n, err;
++      char *ptr = req->request.data, *buf;
++      
++      ptr += strlen("proc");
++      while(isspace(*ptr)) ptr++;
++
++      proc = get_fs_type("proc");
++      if(proc == NULL){
++              mconsole_reply(req, "procfs not registered", 1, 0);
++              goto out;
++      }
++
++      super = (*proc->get_sb)(proc, 0, NULL, NULL);
++      put_filesystem(proc);
++      if(super == NULL){
++              mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
++              goto out;
++      }
++      up_write(&super->s_umount);
++
++      nd.dentry = super->s_root;
++      nd.mnt = NULL;
++      nd.flags = O_RDONLY + 1;
++      nd.last_type = LAST_ROOT;
++
++      err = link_path_walk(ptr, &nd);
++      if(err){
++              mconsole_reply(req, "Failed to look up file", 1, 0);
++              goto out_kill;
++      }
++
++      file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
++      if(IS_ERR(file)){
++              mconsole_reply(req, "Failed to open file", 1, 0);
++              goto out_kill;
++      }
++
++      buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
++      if(buf == NULL){
++              mconsole_reply(req, "Failed to allocate buffer", 1, 0);
++              goto out_fput;
++      }
++
++      if((file->f_op != NULL) && (file->f_op->read != NULL)){
++              do {
++                      n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1, 
++                                              &file->f_pos);
++                      if(n >= 0){
++                              buf[n] = '\0';
++                              mconsole_reply(req, buf, 0, (n > 0));
++                      }
++                      else {
++                              mconsole_reply(req, "Read of file failed", 
++                                             1, 0);
++                              goto out_free;
++                      }
++              } while(n > 0);
++      }
++      else mconsole_reply(req, "", 0, 0);
++
++ out_free:
++      kfree(buf);
++ out_fput:
++      fput(file);
++ out_kill:
++      deactivate_super(super);
++ out: ;
++}
++
+ #define UML_MCONSOLE_HELPTEXT \
+-"Commands:
+-    version - Get kernel version
+-    help - Print this message
+-    halt - Halt UML
+-    reboot - Reboot UML
+-    config <dev>=<config> - Add a new device to UML; 
+-      same syntax as command line
+-    config <dev> - Query the configuration of a device
+-    remove <dev> - Remove a device from UML
+-    sysrq <letter> - Performs the SysRq action controlled by the letter
+-    cad - invoke the Ctl-Alt-Del handler
+-    stop - pause the UML; it will do nothing until it receives a 'go'
+-    go - continue the UML after a 'stop'
++"Commands: \n\
++    version - Get kernel version \n\
++    help - Print this message \n\
++    halt - Halt UML \n\
++    reboot - Reboot UML \n\
++    config <dev>=<config> - Add a new device to UML;  \n\
++      same syntax as command line \n\
++    config <dev> - Query the configuration of a device \n\
++    remove <dev> - Remove a device from UML \n\
++    sysrq <letter> - Performs the SysRq action controlled by the letter \n\
++    cad - invoke the Ctl-Alt-Del handler \n\
++    stop - pause the UML; it will do nothing until it receives a 'go' \n\
++    go - continue the UML after a 'stop' \n\
++    log <string> - make UML enter <string> into the kernel log\n\
++    proc <file> - returns the contents of the UML's /proc/<file>\n\
+ "
+ void mconsole_help(struct mc_request *req)
+@@ -302,7 +398,7 @@
+       if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
+       snprintf(mconsole_socket_name, sizeof(file), "%s", file);
+-      sock = create_unix_socket(file, sizeof(file));
++      sock = os_create_unix_socket(file, sizeof(file), 1);
+       if (sock < 0){
+               printk("Failed to initialize management console\n");
+               return(1);
+@@ -344,11 +440,16 @@
+       if(buf == NULL) 
+               return(-ENOMEM);
+-      if(copy_from_user(buf, buffer, count))
+-              return(-EFAULT);
++      if(copy_from_user(buf, buffer, count)){
++              count = -EFAULT;
++              goto out;
++      }
++
+       buf[count] = '\0';
+       mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
++ out:
++      kfree(buf);
+       return(count);
+ }
+diff -Naur a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
+--- a/arch/um/drivers/mconsole_user.c  2004-01-08 22:15:23.000000000 -0500
++++ b/arch/um/drivers/mconsole_user.c  2004-01-08 22:21:13.000000000 -0500
+@@ -1,6 +1,6 @@
+ /*
+  * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
+- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+@@ -18,16 +18,18 @@
+ #include "umid.h"
+ static struct mconsole_command commands[] = {
+-      { "version", mconsole_version, 1 },
+-      { "halt", mconsole_halt, 0 },
+-      { "reboot", mconsole_reboot, 0 },
+-      { "config", mconsole_config, 0 },
+-      { "remove", mconsole_remove, 0 },
+-      { "sysrq", mconsole_sysrq, 1 },
+-      { "help", mconsole_help, 1 },
+-      { "cad", mconsole_cad, 1 },
+-      { "stop", mconsole_stop, 0 },
+-      { "go", mconsole_go, 1 },
++      { "version", mconsole_version, MCONSOLE_INTR },
++      { "halt", mconsole_halt, MCONSOLE_PROC },
++      { "reboot", mconsole_reboot, MCONSOLE_PROC },
++      { "config", mconsole_config, MCONSOLE_PROC },
++      { "remove", mconsole_remove, MCONSOLE_PROC },
++      { "sysrq", mconsole_sysrq, MCONSOLE_INTR },
++      { "help", mconsole_help, MCONSOLE_INTR },
++      { "cad", mconsole_cad, MCONSOLE_INTR },
++      { "stop", mconsole_stop, MCONSOLE_PROC },
++      { "go", mconsole_go, MCONSOLE_INTR },
++      { "log", mconsole_log, MCONSOLE_INTR },
++      { "proc", mconsole_proc, MCONSOLE_PROC },
+ };
+ /* Initialized in mconsole_init, which is an initcall */
+@@ -139,6 +141,7 @@
+               memcpy(reply.data, str, len);
+               reply.data[len] = '\0';
+               total -= len;
++              str += len;
+               reply.len = len + 1;
+               len = sizeof(reply) + reply.len - sizeof(reply.data);
+diff -Naur a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
+--- a/arch/um/drivers/mmapper_kern.c   2004-01-08 22:14:57.000000000 -0500
++++ b/arch/um/drivers/mmapper_kern.c   2004-01-08 22:20:27.000000000 -0500
+@@ -120,7 +120,10 @@
+       printk(KERN_INFO "Mapper v0.1\n");
+       v_buf = (char *) find_iomem("mmapper", &mmapper_size);
+-      if(mmapper_size == 0) return(0);
++      if(mmapper_size == 0){
++              printk(KERN_ERR "mmapper_init - find_iomem failed\n");
++              return(0);
++      }
+       p_buf = __pa(v_buf);
+diff -Naur a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
+--- a/arch/um/drivers/net_kern.c       2004-01-08 22:20:39.000000000 -0500
++++ b/arch/um/drivers/net_kern.c       2004-01-08 22:27:13.000000000 -0500
+@@ -26,6 +26,7 @@
+ #include "mconsole_kern.h"
+ #include "init.h"
+ #include "irq_user.h"
++#include "irq_kern.h"
+ static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED;
+ LIST_HEAD(opened);
+@@ -37,7 +38,8 @@
+       struct sk_buff *skb;
+       /* If we can't allocate memory, try again next round. */
+-      if ((skb = dev_alloc_skb(dev->mtu)) == NULL) {
++      skb = dev_alloc_skb(dev->mtu);
++      if (skb == NULL) {
+               lp->stats.rx_dropped++;
+               return 0;
+       }
+@@ -61,14 +63,14 @@
+       return pkt_len;
+ }
+-void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+       struct net_device *dev = dev_id;
+       struct uml_net_private *lp = dev->priv;
+       int err;
+       if(!netif_running(dev))
+-              return;
++              return(IRQ_NONE);
+       spin_lock(&lp->lock);
+       while((err = uml_net_rx(dev)) > 0) ;
+@@ -83,6 +85,7 @@
+  out:
+       spin_unlock(&lp->lock);
++      return(IRQ_HANDLED);
+ }
+ static int uml_net_open(struct net_device *dev)
+@@ -252,37 +255,6 @@
+ #endif
+ }
+-/*
+- * default do nothing hard header packet routines for struct net_device init.
+- * real ethernet transports will overwrite with real routines.
+- */
+-static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev,
+-                 unsigned short type, void *daddr, void *saddr, unsigned len)
+-{
+-      return(0); /* no change */
+-}
+-
+-static int uml_net_rebuild_header(struct sk_buff *skb)
+-{
+-      return(0); /* ignore */ 
+-}
+-
+-static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+-{
+-      return(-1); /* fail */
+-}
+-
+-static void uml_net_header_cache_update(struct hh_cache *hh,
+-                 struct net_device *dev, unsigned char * haddr)
+-{
+-      /* ignore */
+-}
+-
+-static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr)
+-{
+-      return(0); /* nothing */
+-}
+-
+ static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED;
+ static struct list_head devices = LIST_HEAD_INIT(devices);
+@@ -292,7 +264,7 @@
+       struct uml_net *device;
+       struct net_device *dev;
+       struct uml_net_private *lp;
+-      int err, size;
++      int save, err, size;
+       size = transport->private_size + sizeof(struct uml_net_private) + 
+               sizeof(((struct uml_net_private *) 0)->user);
+@@ -334,12 +306,6 @@
+       snprintf(dev->name, sizeof(dev->name), "eth%d", n);
+       device->dev = dev;
+-        dev->hard_header = uml_net_hard_header;
+-        dev->rebuild_header = uml_net_rebuild_header;
+-        dev->hard_header_cache = uml_net_header_cache;
+-        dev->header_cache_update= uml_net_header_cache_update;
+-        dev->hard_header_parse = uml_net_header_parse;
+-
+       (*transport->kern->init)(dev, init);
+       dev->mtu = transport->user->max_packet;
+@@ -362,21 +328,29 @@
+               return 1;
+       lp = dev->priv;
+-      INIT_LIST_HEAD(&lp->list);
+-      spin_lock_init(&lp->lock);
+-      lp->dev = dev;
+-      lp->fd = -1;
+-      lp->mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 };
+-      lp->have_mac = device->have_mac;
+-      lp->protocol = transport->kern->protocol;
+-      lp->open = transport->user->open;
+-      lp->close = transport->user->close;
+-      lp->remove = transport->user->remove;
+-      lp->read = transport->kern->read;
+-      lp->write = transport->kern->write;
+-      lp->add_address = transport->user->add_address;
+-      lp->delete_address = transport->user->delete_address;
+-      lp->set_mtu = transport->user->set_mtu;
++      /* lp.user is the first four bytes of the transport data, which
++       * has already been initialized.  This structure assignment will
++       * overwrite that, so we make sure that .user gets overwritten with
++       * what it already has.
++       */
++      save = lp->user[0];
++      *lp = ((struct uml_net_private) 
++              { .list                 = LIST_HEAD_INIT(lp->list),
++                .lock                 = SPIN_LOCK_UNLOCKED,
++                .dev                  = dev,
++                .fd                   = -1,
++                .mac                  = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
++                .have_mac             = device->have_mac,
++                .protocol             = transport->kern->protocol,
++                .open                 = transport->user->open,
++                .close                = transport->user->close,
++                .remove               = transport->user->remove,
++                .read                 = transport->kern->read,
++                .write                = transport->kern->write,
++                .add_address          = transport->user->add_address,
++                .delete_address       = transport->user->delete_address,
++                .set_mtu              = transport->user->set_mtu,
++                .user                 = { save } });
+       init_timer(&lp->tl);
+       lp->tl.function = uml_net_user_timer_expire;
+@@ -609,7 +583,8 @@
+       unregister_netdev(dev);
+       list_del(&device->list);
+-      free_netdev(device);
++      kfree(device);
++      free_netdev(dev);
+       return(0);
+ }
+diff -Naur a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
+--- a/arch/um/drivers/net_user.c       2004-01-08 22:16:01.000000000 -0500
++++ b/arch/um/drivers/net_user.c       2004-01-08 22:21:37.000000000 -0500
+@@ -26,8 +26,7 @@
+       if(gate_addr == NULL) return(0);
+       if(sscanf(gate_addr, "%d.%d.%d.%d", &tap_addr[0], 
+                 &tap_addr[1], &tap_addr[2], &tap_addr[3]) != 4){
+-              printk("Invalid tap IP address - '%s'\n", 
+-                     gate_addr);
++              printk("Invalid tap IP address - '%s'\n", gate_addr);
+               return(-EINVAL);
+       }
+       return(0);
+@@ -60,18 +59,18 @@
+       }
+               
+       *output = '\0';
+-      if(read(fd, &remain, sizeof(remain)) != sizeof(remain)){
+-              printk("read_output - read of length failed, errno = %d\n",
+-                     errno);
++      n = os_read_file(fd, &remain, sizeof(remain));
++      if(n != sizeof(remain)){
++              printk("read_output - read of length failed, err = %d\n", -n);
+               return;
+       }
+       while(remain != 0){
+               n = (remain < len) ? remain : len;
+-              actual = read(fd, output, n);
++              actual = os_read_file(fd, output, n);
+               if(actual != n){
+                       printk("read_output - read of data failed, "
+-                             "errno = %d\n", errno);
++                             "err = %d\n", -actual);
+                       return;
+               }
+               remain -= actual;
+@@ -83,13 +82,12 @@
+ {
+       int n;
+-      while(((n = read(fd,  buf,  len)) < 0) && (errno == EINTR)) ;
++      n = os_read_file(fd,  buf,  len);
+-      if(n < 0){
+-              if(errno == EAGAIN) return(0);
+-              return(-errno);
+-      }
+-      else if(n == 0) return(-ENOTCONN);
++      if(n == -EAGAIN) 
++              return(0);
++      else if(n == 0) 
++              return(-ENOTCONN);
+       return(n);
+ }
+@@ -112,13 +110,13 @@
+ {
+       int n;
+-      while(((n = write(fd, buf, len)) < 0) && (errno == EINTR)) ;
+-      if(n < 0){
+-              if(errno == EAGAIN) return(0);
+-              return(-errno);
+-      }
+-      else if(n == 0) return(-ENOTCONN);
+-      return(n);      
++      n = os_write_file(fd, buf, len);
++
++      if(n == -EAGAIN) 
++              return(0);
++      else if(n == 0) 
++              return(-ENOTCONN);
++      return(n);
+ }
+ int net_send(int fd, void *buf, int len)
+@@ -157,7 +155,7 @@
+ {
+       struct change_pre_exec_data *data = arg;
+-      close(data->close_me);
++      os_close_file(data->close_me);
+       dup2(data->stdout, 1);
+ }
+@@ -167,15 +165,15 @@
+       struct change_pre_exec_data pe_data;
+       err = os_pipe(fds, 1, 0);
+-      if(err){
+-              printk("change_tramp - pipe failed, errno = %d\n", -err);
++      if(err < 0){
++              printk("change_tramp - pipe failed, err = %d\n", -err);
+               return(err);
+       }
+       pe_data.close_me = fds[0];
+       pe_data.stdout = fds[1];
+       pid = run_helper(change_pre_exec, &pe_data, argv, NULL);
+-      close(fds[1]);
++      os_close_file(fds[1]);
+       read_output(fds[0], output, output_len);
+       waitpid(pid, NULL, 0);  
+       return(pid);
+diff -Naur a/arch/um/drivers/null.c b/arch/um/drivers/null.c
+--- a/arch/um/drivers/null.c   2004-01-08 22:14:29.000000000 -0500
++++ b/arch/um/drivers/null.c   2004-01-08 22:19:28.000000000 -0500
+@@ -5,7 +5,6 @@
+ #include <stdlib.h>
+ #include <errno.h>
+-#include <fcntl.h>
+ #include "chan_user.h"
+ #include "os.h"
+diff -Naur a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
+--- a/arch/um/drivers/port_kern.c      2004-01-08 22:13:51.000000000 -0500
++++ b/arch/um/drivers/port_kern.c      2004-01-08 22:18:54.000000000 -0500
+@@ -6,6 +6,7 @@
+ #include "linux/list.h"
+ #include "linux/sched.h"
+ #include "linux/slab.h"
++#include "linux/interrupt.h"
+ #include "linux/irq.h"
+ #include "linux/spinlock.h"
+ #include "linux/errno.h"
+@@ -14,6 +15,7 @@
+ #include "kern_util.h"
+ #include "kern.h"
+ #include "irq_user.h"
++#include "irq_kern.h"
+ #include "port.h"
+ #include "init.h"
+ #include "os.h"
+@@ -44,7 +46,7 @@
+       struct port_list *port;
+ };
+-static void pipe_interrupt(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs)
+ {
+       struct connection *conn = data;
+       int fd;
+@@ -52,7 +54,7 @@
+       fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
+       if(fd < 0){
+               if(fd == -EAGAIN)
+-                      return;
++                      return(IRQ_NONE);
+               printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", 
+                      -fd);
+@@ -65,6 +67,7 @@
+       list_add(&conn->list, &conn->port->connections);
+       up(&conn->port->sem);
++      return(IRQ_HANDLED);
+ }
+ static int port_accept(struct port_list *port)
+@@ -138,12 +141,13 @@
+ DECLARE_WORK(port_work, port_work_proc, NULL);
+-static void port_interrupt(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs)
+ {
+       struct port_list *port = data;
+       port->has_connection = 1;
+       schedule_work(&port_work);
++      return(IRQ_HANDLED);
+ } 
+ void *port_data(int port_num)
+diff -Naur a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
+--- a/arch/um/drivers/port_user.c      2004-01-08 22:24:12.000000000 -0500
++++ b/arch/um/drivers/port_user.c      2004-01-08 22:31:27.000000000 -0500
+@@ -47,10 +47,12 @@
+               return(NULL);
+       }
+-      if((kern_data = port_data(port)) == NULL) 
++      kern_data = port_data(port);
++      if(kern_data == NULL) 
+               return(NULL);
+-      if((data = um_kmalloc(sizeof(*data))) == NULL) 
++      data = um_kmalloc(sizeof(*data));
++      if(data == NULL) 
+               goto err;
+       *data = ((struct port_chan) { .raw              = opts->raw,
+@@ -90,7 +92,7 @@
+       struct port_chan *data = d;
+       port_remove_dev(data->kernel_data);
+-      close(fd);
++      os_close_file(fd);
+ }
+ int port_console_write(int fd, const char *buf, int n, void *d)
+@@ -130,11 +132,15 @@
+               goto out;
+       }
+   
+-      if((listen(fd, 1) < 0) || (os_set_fd_block(fd, 0))){
++      if(listen(fd, 1) < 0){
+               err = -errno;
+               goto out;
+       }
++      err = os_set_fd_block(fd, 0);
++      if(err < 0)
++              goto out;
++
+       return(fd);
+  out:
+       os_close_file(fd);
+@@ -153,10 +159,10 @@
+       dup2(data->sock_fd, 0);
+       dup2(data->sock_fd, 1);
+       dup2(data->sock_fd, 2);
+-      close(data->sock_fd);
++      os_close_file(data->sock_fd);
+       dup2(data->pipe_fd, 3);
+       os_shutdown_socket(3, 1, 0);
+-      close(data->pipe_fd);
++      os_close_file(data->pipe_fd);
+ }
+ int port_connection(int fd, int *socket, int *pid_out)
+@@ -166,11 +172,12 @@
+                        "/usr/lib/uml/port-helper", NULL };
+       struct port_pre_exec_data data;
+-      if((new = os_accept_connection(fd)) < 0)
+-              return(-errno);
++      new = os_accept_connection(fd);
++      if(new < 0)
++              return(new);
+       err = os_pipe(socket, 0, 0);
+-      if(err) 
++      if(err < 0) 
+               goto out_close;
+       data = ((struct port_pre_exec_data)
+@@ -186,11 +193,11 @@
+  out_shutdown:
+       os_shutdown_socket(socket[0], 1, 1);
+-      close(socket[0]);
++      os_close_file(socket[0]);
+       os_shutdown_socket(socket[1], 1, 1);    
+-      close(socket[1]);
++      os_close_file(socket[1]);
+  out_close:
+-      close(new);
++      os_close_file(new);
+       return(err);
+ }
+diff -Naur a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
+--- a/arch/um/drivers/pty.c    2004-01-08 22:29:41.000000000 -0500
++++ b/arch/um/drivers/pty.c    2004-01-08 22:35:17.000000000 -0500
+@@ -7,12 +7,12 @@
+ #include <unistd.h>
+ #include <string.h>
+ #include <errno.h>
+-#include <fcntl.h>
+ #include <termios.h>
+ #include "chan_user.h"
+ #include "user.h"
+ #include "user_util.h"
+ #include "kern_util.h"
++#include "os.h"
+ struct pty_chan {
+       void (*announce)(char *dev_name, int dev);
+@@ -26,7 +26,8 @@
+ {
+       struct pty_chan *data;
+-      if((data = um_kmalloc(sizeof(*data))) == NULL) return(NULL);
++      data = um_kmalloc(sizeof(*data));
++      if(data == NULL) return(NULL);
+       *data = ((struct pty_chan) { .announce          = opts->announce, 
+                                    .dev               = device,
+                                    .raw               = opts->raw });
+@@ -39,7 +40,8 @@
+       char *dev;
+       int fd;
+-      if((fd = get_pty()) < 0){
++      fd = get_pty();
++      if(fd < 0){
+               printk("open_pts : Failed to open pts\n");
+               return(-errno);
+       }
+@@ -57,29 +59,27 @@
+ int getmaster(char *line)
+ {
+-      struct stat stb;
+       char *pty, *bank, *cp;
+-      int master;
++      int master, err;
+       pty = &line[strlen("/dev/ptyp")];
+       for (bank = "pqrs"; *bank; bank++) {
+               line[strlen("/dev/pty")] = *bank;
+               *pty = '0';
+-              if (stat(line, &stb) < 0)
++              if (os_stat_file(line, NULL) < 0)
+                       break;
+               for (cp = "0123456789abcdef"; *cp; cp++) {
+                       *pty = *cp;
+-                      master = open(line, O_RDWR);
++                      master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
+                       if (master >= 0) {
+                               char *tp = &line[strlen("/dev/")];
+-                              int ok;
+                               /* verify slave side is usable */
+                               *tp = 't';
+-                              ok = access(line, R_OK|W_OK) == 0;
++                              err = os_access(line, OS_ACC_RW_OK);
+                               *tp = 'p';
+-                              if (ok) return(master);
+-                              (void) close(master);
++                              if(err == 0) return(master);
++                              (void) os_close_file(master);
+                       }
+               }
+       }
+diff -Naur a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
+--- a/arch/um/drivers/slip_user.c      2004-01-08 22:29:41.000000000 -0500
++++ b/arch/um/drivers/slip_user.c      2004-01-08 22:35:17.000000000 -0500
+@@ -4,11 +4,9 @@
+ #include <stddef.h>
+ #include <sched.h>
+ #include <string.h>
+-#include <sys/fcntl.h>
+ #include <sys/errno.h>
+ #include <sys/termios.h>
+ #include <sys/wait.h>
+-#include <sys/ioctl.h>
+ #include <sys/signal.h>
+ #include "user_util.h"
+ #include "kern_util.h"
+@@ -65,9 +63,9 @@
+ {
+       struct slip_pre_exec_data *data = arg;
+-      if(data->stdin != -1) dup2(data->stdin, 0);
++      if(data->stdin >= 0) dup2(data->stdin, 0);
+       dup2(data->stdout, 1);
+-      if(data->close_me != -1) close(data->close_me);
++      if(data->close_me >= 0) os_close_file(data->close_me);
+ }
+ static int slip_tramp(char **argv, int fd)
+@@ -77,8 +75,8 @@
+       int status, pid, fds[2], err, output_len;
+       err = os_pipe(fds, 1, 0);
+-      if(err){
+-              printk("slip_tramp : pipe failed, errno = %d\n", -err);
++      if(err < 0){
++              printk("slip_tramp : pipe failed, err = %d\n", -err);
+               return(err);
+       }
+@@ -96,7 +94,7 @@
+                       printk("slip_tramp : failed to allocate output "
+                              "buffer\n");
+-              close(fds[1]);
++              os_close_file(fds[1]);
+               read_output(fds[0], output, output_len);
+               if(output != NULL){
+                       printk("%s", output);
+@@ -105,7 +103,7 @@
+               if(waitpid(pid, &status, 0) < 0) err = errno;
+               else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
+                       printk("'%s' didn't exit with status 0\n", argv[0]);
+-                      err = EINVAL;
++                      err = -EINVAL;
+               }
+       }
+       return(err);
+@@ -118,15 +116,17 @@
+       char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
+       char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, 
+                        NULL };
+-      int sfd, mfd, disc, sencap, err;
++      int sfd, mfd, err;
+-      if((mfd = get_pty()) < 0){
+-              printk("umn : Failed to open pty\n");
+-              return(-1);
++      mfd = get_pty();
++      if(mfd < 0){
++              printk("umn : Failed to open pty, err = %d\n", -mfd);
++              return(mfd);
+       }
+-      if((sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0)) < 0){
+-              printk("Couldn't open tty for slip line\n");
+-              return(-1);
++      sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0);
++      if(sfd < 0){
++              printk("Couldn't open tty for slip line, err = %d\n", -sfd);
++              return(sfd);
+       }
+       if(set_up_tty(sfd)) return(-1);
+       pri->slave = sfd;
+@@ -138,28 +138,23 @@
+               err = slip_tramp(argv, sfd);
+-              if(err != 0){
+-                      printk("slip_tramp failed - errno = %d\n", err);
+-                      return(-err);
++              if(err < 0){
++                      printk("slip_tramp failed - err = %d\n", -err);
++                      return(err);
+               }
+-              if(ioctl(pri->slave, SIOCGIFNAME, pri->name) < 0){
+-                      printk("SIOCGIFNAME failed, errno = %d\n", errno);
+-                      return(-errno);
++              err = os_get_ifname(pri->slave, pri->name);
++              if(err < 0){
++                      printk("get_ifname failed, err = %d\n", -err);
++                      return(err);
+               }
+               iter_addresses(pri->dev, open_addr, pri->name);
+       }
+       else {
+-              disc = N_SLIP;
+-              if(ioctl(sfd, TIOCSETD, &disc) < 0){
+-                      printk("Failed to set slip line discipline - "
+-                             "errno = %d\n", errno);
+-                      return(-errno);
+-              }
+-              sencap = 0;
+-              if(ioctl(sfd, SIOCSIFENCAP, &sencap) < 0){
+-                      printk("Failed to set slip encapsulation - "
+-                             "errno = %d\n", errno);
+-                      return(-errno);
++              err = os_set_slip(sfd);
++              if(err < 0){
++                      printk("Failed to set slip discipline encapsulation - "
++                             "err = %d\n", -err);
++                      return(err);
+               }
+       }
+       return(mfd);
+@@ -181,9 +176,9 @@
+       err = slip_tramp(argv, -1);
+       if(err != 0)
+-              printk("slip_tramp failed - errno = %d\n", err);
+-      close(fd);
+-      close(pri->slave);
++              printk("slip_tramp failed - errno = %d\n", -err);
++      os_close_file(fd);
++      os_close_file(pri->slave);
+       pri->slave = -1;
+ }
+@@ -243,7 +238,7 @@
+ {
+       struct slip_data *pri = data;
+-      if(pri->slave == -1) return;
++      if(pri->slave < 0) return;
+       open_addr(addr, netmask, pri->name);
+ }
+@@ -252,7 +247,7 @@
+ {
+       struct slip_data *pri = data;
+-      if(pri->slave == -1) return;
++      if(pri->slave < 0) return;
+       close_addr(addr, netmask, pri->name);
+ }
+diff -Naur a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
+--- a/arch/um/drivers/slirp_user.c     2004-01-08 22:25:11.000000000 -0500
++++ b/arch/um/drivers/slirp_user.c     2004-01-08 22:32:27.000000000 -0500
+@@ -4,7 +4,6 @@
+ #include <stddef.h>
+ #include <sched.h>
+ #include <string.h>
+-#include <sys/fcntl.h>
+ #include <sys/errno.h>
+ #include <sys/wait.h>
+ #include <sys/signal.h>
+@@ -48,15 +47,15 @@
+       return(pid);
+ }
+- 
++
++/* XXX This is just a trivial wrapper around os_pipe */ 
+ static int slirp_datachan(int *mfd, int *sfd)
+ {
+       int fds[2], err;
+       err = os_pipe(fds, 1, 1);
+-      if(err){
+-              printk("slirp_datachan: Failed to open pipe, errno = %d\n",
+-                     -err);
++      if(err < 0){
++              printk("slirp_datachan: Failed to open pipe, err = %d\n", -err);
+               return(err);
+       }
+@@ -77,7 +76,7 @@
+       pid = slirp_tramp(pri->argw.argv, sfd);
+       if(pid < 0){
+-              printk("slirp_tramp failed - errno = %d\n", pid);
++              printk("slirp_tramp failed - errno = %d\n", -pid);
+               os_close_file(sfd);     
+               os_close_file(mfd);     
+               return(pid);
+@@ -97,8 +96,8 @@
+       struct slirp_data *pri = data;
+       int status,err;
+-      close(fd);
+-      close(pri->slave);
++      os_close_file(fd);
++      os_close_file(pri->slave);
+       pri->slave = -1;
+diff -Naur a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
+--- a/arch/um/drivers/ssl.c    2004-01-08 22:21:29.000000000 -0500
++++ b/arch/um/drivers/ssl.c    2004-01-08 22:28:16.000000000 -0500
+@@ -10,6 +10,7 @@
+ #include "linux/major.h"
+ #include "linux/mm.h"
+ #include "linux/init.h"
++#include "linux/console.h"
+ #include "asm/termbits.h"
+ #include "asm/irq.h"
+ #include "line.h"
+@@ -53,8 +54,9 @@
+ static struct line_driver driver = {
+       .name                   = "UML serial line",
+-      .devfs_name             = "tts/%d",
+-      .major                  = TTYAUX_MAJOR,
++      .device_name            = "ttS",
++      .devfs_name             = "tts/",
++      .major                  = TTY_MAJOR,
+       .minor_start            = 64,
+       .type                   = TTY_DRIVER_TYPE_SERIAL,
+       .subtype                = 0,
+@@ -149,6 +151,9 @@
+       case TCSETSW:
+       case TCGETA:
+       case TIOCMGET:
++      case TCSBRK:
++      case TCSBRKP:
++      case TIOCMSET:
+               ret = -ENOIOCTLCMD;
+               break;
+       default:
+@@ -212,6 +217,39 @@
+  */
+ static int ssl_init_done = 0;
++extern int tty_init(void);
++
++static void ssl_console_write(struct console *c, const char *string, 
++                            unsigned len)
++{
++      struct line *line = &serial_lines[c->index];
++      if(ssl_init_done)
++              down(&line->sem);
++      console_write_chan(&line->chan_list, string, len);
++      if(ssl_init_done)
++              up(&line->sem);
++}
++
++static struct tty_driver *ssl_console_device(struct console *c, int *index)
++{
++      *index = c->index;
++      return ssl_driver;
++}
++
++static int ssl_console_setup(struct console *co, char *options)
++{
++      return(0);
++}
++
++static struct console ssl_cons = {
++      name:           "ttyS",
++      write:          ssl_console_write,
++      device:         ssl_console_device,
++      setup:          ssl_console_setup,
++      flags:          CON_PRINTBUFFER,
++      index:          -1,
++};
++
+ int ssl_init(void)
+ {
+       char *new_title;
+@@ -219,6 +257,8 @@
+       printk(KERN_INFO "Initializing software serial port version %d\n", 
+              ssl_version);
++      tty_init();
++
+       ssl_driver = line_register_devfs(&lines, &driver, &ssl_ops,
+               serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]));
+@@ -227,6 +267,7 @@
+       new_title = add_xterm_umid(opts.xterm_title);
+       if(new_title != NULL) opts.xterm_title = new_title;
++      register_console(&ssl_cons);
+       ssl_init_done = 1;
+       return(0);
+ }
+@@ -235,9 +276,9 @@
+ static int ssl_chan_setup(char *str)
+ {
+-      line_setup(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0]),
+-                 str, 1);
+-      return(1);
++      return(line_setup(serial_lines, 
++                        sizeof(serial_lines)/sizeof(serial_lines[0]), 
++                        str, 1));
+ }
+ __setup("ssl", ssl_chan_setup);
+diff -Naur a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
+--- a/arch/um/drivers/stdio_console.c  2004-01-08 22:16:37.000000000 -0500
++++ b/arch/um/drivers/stdio_console.c  2004-01-08 22:22:42.000000000 -0500
+@@ -83,7 +83,8 @@
+ static struct line_driver driver = {
+       .name                   = "UML console",
+-      .devfs_name             = "vc/%d",
++      .device_name            = "tty",
++      .devfs_name             = "vc/",
+       .major                  = TTY_MAJOR,
+       .minor_start            = 0,
+       .type                   = TTY_DRIVER_TYPE_CONSOLE,
+@@ -159,14 +160,28 @@
+ static int con_init_done = 0;
++static struct tty_operations console_ops = {
++      .open                   = con_open,
++      .close                  = con_close,
++      .write                  = con_write,
++      .chars_in_buffer        = chars_in_buffer,
++      .set_termios            = set_termios,
++      .write_room             = line_write_room,
++};
++
++extern int tty_init(void);
++
+ int stdio_init(void)
+ {
+       char *new_title;
+       printk(KERN_INFO "Initializing stdio console driver\n");
++      tty_init();
++
+       console_driver = line_register_devfs(&console_lines, &driver,
+-                              &console_ops, vts, sizeof(vts)/sizeof(vts[0]));
++                                           &console_ops, vts,
++                                           sizeof(vts)/sizeof(vts[0]));
+       lines_init(vts, sizeof(vts)/sizeof(vts[0]));
+@@ -183,19 +198,14 @@
+ static void console_write(struct console *console, const char *string, 
+                         unsigned len)
+ {
+-      if(con_init_done) down(&vts[console->index].sem);
+-      console_write_chan(&vts[console->index].chan_list, string, len);
+-      if(con_init_done) up(&vts[console->index].sem);
+-}
++      struct line *line = &vts[console->index];
+-static struct tty_operations console_ops = {
+-      .open                   = con_open,
+-      .close                  = con_close,
+-      .write                  = con_write,
+-      .chars_in_buffer        = chars_in_buffer,
+-      .set_termios            = set_termios,
+-      .write_room             = line_write_room,
+-};
++      if(con_init_done)
++              down(&line->sem);
++      console_write_chan(&line->chan_list, string, len);
++      if(con_init_done)
++              up(&line->sem);
++}
+ static struct tty_driver *console_device(struct console *c, int *index)
+ {
+@@ -208,22 +218,28 @@
+       return(0);
+ }
+-static struct console stdiocons = INIT_CONSOLE("tty", console_write, 
+-                                             console_device, console_setup,
+-                                             CON_PRINTBUFFER);
++static struct console stdiocons = {
++      name:           "tty",
++      write:          console_write,
++      device:         console_device,
++      setup:          console_setup,
++      flags:          CON_PRINTBUFFER,
++      index:          -1,
++};
+-static void __init stdio_console_init(void)
++static int __init stdio_console_init(void)
+ {
+       INIT_LIST_HEAD(&vts[0].chan_list);
+       list_add(&init_console_chan.list, &vts[0].chan_list);
+       register_console(&stdiocons);
++      return(0);
+ }
++
+ console_initcall(stdio_console_init);
+ static int console_chan_setup(char *str)
+ {
+-      line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1);
+-      return(1);
++      return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1));
+ }
+ __setup("con", console_chan_setup);
+diff -Naur a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
+--- a/arch/um/drivers/tty.c    2004-01-08 22:18:51.000000000 -0500
++++ b/arch/um/drivers/tty.c    2004-01-08 22:24:43.000000000 -0500
+@@ -5,7 +5,6 @@
+ #include <stdio.h>
+ #include <termios.h>
+-#include <fcntl.h>
+ #include <errno.h>
+ #include <unistd.h>
+ #include "chan_user.h"
+@@ -30,7 +29,8 @@
+       }
+       str++;
+-      if((data = um_kmalloc(sizeof(*data))) == NULL) 
++      data = um_kmalloc(sizeof(*data)); 
++      if(data == NULL) 
+               return(NULL);
+       *data = ((struct tty_chan) { .dev       = str,
+                                    .raw       = opts->raw });
+diff -Naur a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
+--- a/arch/um/drivers/ubd_kern.c       2004-01-08 22:21:09.000000000 -0500
++++ b/arch/um/drivers/ubd_kern.c       2004-01-08 22:27:27.000000000 -0500
+@@ -8,6 +8,13 @@
+  * old style ubd by setting UBD_SHIFT to 0
+  * 2002-09-27...2002-10-18 massive tinkering for 2.5
+  * partitions have changed in 2.5
++ * 2003-01-29 more tinkering for 2.5.59-1
++ * This should now address the sysfs problems and has
++ * the symlink for devfs to allow for booting with
++ * the common /dev/ubd/discX/... names rather than
++ * only /dev/ubdN/discN this version also has lots of
++ * clean ups preparing for ubd-many.
++ * James McMechan
+  */
+ #define MAJOR_NR UBD_MAJOR
+@@ -40,9 +47,12 @@
+ #include "mconsole_kern.h"
+ #include "init.h"
+ #include "irq_user.h"
++#include "irq_kern.h"
+ #include "ubd_user.h"
+ #include "2_5compat.h"
+ #include "os.h"
++#include "mem.h"
++#include "mem_kern.h"
+ static spinlock_t ubd_io_lock = SPIN_LOCK_UNLOCKED;
+ static spinlock_t ubd_lock = SPIN_LOCK_UNLOCKED;
+@@ -56,6 +66,10 @@
+ #define MAX_DEV (8)
++/* Changed in early boot */
++static int ubd_do_mmap = 0;
++#define UBD_MMAP_BLOCK_SIZE PAGE_SIZE
++
+ static struct block_device_operations ubd_blops = {
+         .owner                = THIS_MODULE,
+         .open         = ubd_open,
+@@ -67,7 +81,7 @@
+ static request_queue_t *ubd_queue;
+ /* Protected by ubd_lock */
+-static int fake_major = 0;
++static int fake_major = MAJOR_NR;
+ static struct gendisk *ubd_gendisk[MAX_DEV];
+ static struct gendisk *fake_gendisk[MAX_DEV];
+@@ -96,13 +110,19 @@
+ struct ubd {
+       char *file;
+-      int is_dir;
+       int count;
+       int fd;
+       __u64 size;
+       struct openflags boot_openflags;
+       struct openflags openflags;
++      int no_cow;
+       struct cow cow;
++
++      int map_writes;
++      int map_reads;
++      int nomap_writes;
++      int nomap_reads;
++      int write_maps;
+ };
+ #define DEFAULT_COW { \
+@@ -115,21 +135,28 @@
+ #define DEFAULT_UBD { \
+       .file =                 NULL, \
+-      .is_dir =               0, \
+       .count =                0, \
+       .fd =                   -1, \
+       .size =                 -1, \
+       .boot_openflags =       OPEN_FLAGS, \
+       .openflags =            OPEN_FLAGS, \
++        .no_cow =               0, \
+         .cow =                        DEFAULT_COW, \
++      .map_writes             = 0, \
++      .map_reads              = 0, \
++      .nomap_writes           = 0, \
++      .nomap_reads            = 0, \
++      .write_maps             = 0, \
+ }
+ struct ubd ubd_dev[MAX_DEV] = { [ 0 ... MAX_DEV - 1 ] = DEFAULT_UBD };
+ static int ubd0_init(void)
+ {
+-      if(ubd_dev[0].file == NULL)
+-              ubd_dev[0].file = "root_fs";
++      struct ubd *dev = &ubd_dev[0];
++
++      if(dev->file == NULL)
++              dev->file = "root_fs";
+       return(0);
+ }
+@@ -196,19 +223,46 @@
+ "    Create ide0 entries that map onto ubd devices.\n\n"
+ );
++static int parse_unit(char **ptr)
++{
++      char *str = *ptr, *end;
++      int n = -1;
++
++      if(isdigit(*str)) {
++              n = simple_strtoul(str, &end, 0);
++              if(end == str)
++                      return(-1);
++              *ptr = end;
++      }
++      else if (('a' <= *str) && (*str <= 'h')) {
++              n = *str - 'a';
++              str++;
++              *ptr = str;
++      }
++      return(n);
++}
++
+ static int ubd_setup_common(char *str, int *index_out)
+ {
++      struct ubd *dev;
+       struct openflags flags = global_openflags;
+       char *backing_file;
+       int n, err;
+       if(index_out) *index_out = -1;
+-      n = *str++;
++      n = *str;
+       if(n == '='){
+-              static int fake_major_allowed = 1;
+               char *end;
+               int major;
++              str++;
++              if(!strcmp(str, "mmap")){
++                      CHOOSE_MODE(printk("mmap not supported by the ubd "
++                                         "driver in tt mode\n"),
++                                  ubd_do_mmap = 1);
++                      return(0);
++              }
++
+               if(!strcmp(str, "sync")){
+                       global_openflags.s = 1;
+                       return(0);
+@@ -220,20 +274,14 @@
+                       return(1);
+               }
+-              if(!fake_major_allowed){
+-                      printk(KERN_ERR "Can't assign a fake major twice\n");
+-                      return(1);
+-              }
+-
+               err = 1;
+               spin_lock(&ubd_lock);
+-              if(!fake_major_allowed){
++              if(fake_major != MAJOR_NR){
+                       printk(KERN_ERR "Can't assign a fake major twice\n");
+                       goto out1;
+               }
+  
+               fake_major = major;
+-              fake_major_allowed = 0;
+               printk(KERN_INFO "Setting extra ubd major number to %d\n",
+                      major);
+@@ -243,25 +291,23 @@
+               return(err);
+       }
+-      if(n < '0'){
+-              printk(KERN_ERR "ubd_setup : index out of range\n"); }
+-
+-      if((n >= '0') && (n <= '9')) n -= '0';
+-      else if((n >= 'a') && (n <= 'z')) n -= 'a';
+-      else {
+-              printk(KERN_ERR "ubd_setup : device syntax invalid\n");
++      n = parse_unit(&str);
++      if(n < 0){
++              printk(KERN_ERR "ubd_setup : couldn't parse unit number "
++                     "'%s'\n", str);
+               return(1);
+       }
+       if(n >= MAX_DEV){
+-              printk(KERN_ERR "ubd_setup : index out of range "
+-                     "(%d devices)\n", MAX_DEV);      
++              printk(KERN_ERR "ubd_setup : index %d out of range "
++                     "(%d devices)\n", n, MAX_DEV);
+               return(1);
+       }
+       err = 1;
+       spin_lock(&ubd_lock);
+-      if(ubd_dev[n].file != NULL){
++      dev = &ubd_dev[n];
++      if(dev->file != NULL){
+               printk(KERN_ERR "ubd_setup : device already configured\n");
+               goto out2;
+       }
+@@ -276,6 +322,11 @@
+               flags.s = 1;
+               str++;
+       }
++      if (*str == 'd'){
++              dev->no_cow = 1;
++              str++;
++      }
++
+       if(*str++ != '='){
+               printk(KERN_ERR "ubd_setup : Expected '='\n");
+               goto out2;
+@@ -284,14 +335,17 @@
+       err = 0;
+       backing_file = strchr(str, ',');
+       if(backing_file){
+-              *backing_file = '\0';
+-              backing_file++;
++              if(dev->no_cow)
++                      printk(KERN_ERR "Can't specify both 'd' and a "
++                             "cow file\n");
++              else {
++                      *backing_file = '\0';
++                      backing_file++;
++              }
+       }
+-      ubd_dev[n].file = str;
+-      if(ubd_is_dir(ubd_dev[n].file))
+-              ubd_dev[n].is_dir = 1;
+-      ubd_dev[n].cow.file = backing_file;
+-      ubd_dev[n].boot_openflags = flags;
++      dev->file = str;
++      dev->cow.file = backing_file;
++      dev->boot_openflags = flags;
+  out2:
+       spin_unlock(&ubd_lock);
+       return(err);
+@@ -321,8 +375,7 @@
+ static int fakehd_set = 0;
+ static int fakehd(char *str)
+ {
+-      printk(KERN_INFO 
+-             "fakehd : Changing ubd name to \"hd\".\n");
++      printk(KERN_INFO "fakehd : Changing ubd name to \"hd\".\n");
+       fakehd_set = 1;
+       return 1;
+ }
+@@ -368,32 +421,42 @@
+ {
+       struct io_thread_req req;
+       struct request *rq = elv_next_request(ubd_queue);
+-      int n;
++      int n, err;
+       do_ubd = NULL;
+       intr_count++;
+       n = read_ubd_fs(thread_fd, &req, sizeof(req));
+       if(n != sizeof(req)){
+               printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, "
+-                     "errno = %d\n", os_getpid(), -n);
++                     "err = %d\n", os_getpid(), -n);
+               spin_lock(&ubd_io_lock);
+               end_request(rq, 0);
+               spin_unlock(&ubd_io_lock);
+               return;
+       }
+         
+-        if((req.offset != ((__u64) (rq->sector)) << 9) ||
+-         (req.length != (rq->current_nr_sectors) << 9))
++      if((req.op != UBD_MMAP) && 
++         ((req.offset != ((__u64) (rq->sector)) << 9) ||
++          (req.length != (rq->current_nr_sectors) << 9)))
+               panic("I/O op mismatch");
+       
++      if(req.map_fd != -1){
++              err = physmem_subst_mapping(req.buffer, req.map_fd, 
++                                          req.map_offset, 1);
++              if(err)
++                      printk("ubd_handler - physmem_subst_mapping failed, "
++                             "err = %d\n", -err);
++      }
++
+       ubd_finish(rq, req.error);
+       reactivate_fd(thread_fd, UBD_IRQ);      
+       do_ubd_request(ubd_queue);
+ }
+-static void ubd_intr(int irq, void *dev, struct pt_regs *unused)
++static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused)
+ {
+       ubd_handler();
++      return(IRQ_HANDLED);
+ }
+ /* Only changed by ubd_init, which is an initcall. */
+@@ -429,18 +492,20 @@
+ static int ubd_open_dev(struct ubd *dev)
+ {
+       struct openflags flags;
+-      int err, n, create_cow, *create_ptr;
++      char **back_ptr;
++      int err, create_cow, *create_ptr;
++      dev->openflags = dev->boot_openflags;
+       create_cow = 0;
+       create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL;
+-      dev->fd = open_ubd_file(dev->file, &dev->openflags, &dev->cow.file,
++      back_ptr = dev->no_cow ? NULL : &dev->cow.file;
++      dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr,
+                               &dev->cow.bitmap_offset, &dev->cow.bitmap_len, 
+                               &dev->cow.data_offset, create_ptr);
+       if((dev->fd == -ENOENT) && create_cow){
+-              n = dev - ubd_dev;
+               dev->fd = create_cow_file(dev->file, dev->cow.file, 
+-                                        dev->openflags, 1 << 9,
++                                        dev->openflags, 1 << 9, PAGE_SIZE,
+                                         &dev->cow.bitmap_offset, 
+                                         &dev->cow.bitmap_len,
+                                         &dev->cow.data_offset);
+@@ -455,13 +520,17 @@
+       if(dev->cow.file != NULL){
+               err = -ENOMEM;
+               dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len);
+-              if(dev->cow.bitmap == NULL) goto error;
++              if(dev->cow.bitmap == NULL){
++                      printk(KERN_ERR "Failed to vmalloc COW bitmap\n");
++                      goto error;
++              }
+               flush_tlb_kernel_vm();
+               err = read_cow_bitmap(dev->fd, dev->cow.bitmap, 
+                                     dev->cow.bitmap_offset, 
+                                     dev->cow.bitmap_len);
+-              if(err) goto error;
++              if(err < 0)
++                      goto error;
+               flags = dev->openflags;
+               flags.w = 0;
+@@ -481,17 +550,31 @@
+                       
+ {
+       struct gendisk *disk;
++      char from[sizeof("ubd/nnnnn\0")], to[sizeof("discnnnnn/disc\0")];
++      int err;
+       disk = alloc_disk(1 << UBD_SHIFT);
+-      if (!disk)
+-              return -ENOMEM;
++      if(disk == NULL)
++              return(-ENOMEM);
+       disk->major = major;
+       disk->first_minor = unit << UBD_SHIFT;
+       disk->fops = &ubd_blops;
+       set_capacity(disk, size / 512);
+-      sprintf(disk->disk_name, "ubd");
+-      sprintf(disk->devfs_name, "ubd/disc%d", unit);
++      if(major == MAJOR_NR){
++              sprintf(disk->disk_name, "ubd%c", 'a' + unit);
++              sprintf(disk->devfs_name, "ubd/disc%d", unit);
++              sprintf(from, "ubd/%d", unit);
++              sprintf(to, "disc%d/disc", unit);
++              err = devfs_mk_symlink(from, to);
++              if(err)
++                      printk("ubd_new_disk failed to make link from %s to "
++                             "%s, error = %d\n", from, to, err);
++      }
++      else {
++              sprintf(disk->disk_name, "ubd_fake%d", unit);
++              sprintf(disk->devfs_name, "ubd_fake/disc%d", unit);
++      }
+       disk->private_data = &ubd_dev[unit];
+       disk->queue = ubd_queue;
+@@ -506,24 +589,21 @@
+       struct ubd *dev = &ubd_dev[n];
+       int err;
+-      if(dev->is_dir)
+-              return(-EISDIR);
+-
+-      if (!dev->file)
++      if(dev->file == NULL)
+               return(-ENODEV);
+       if (ubd_open_dev(dev))
+               return(-ENODEV);
+       err = ubd_file_size(dev, &dev->size);
+-      if(err)
++      if(err < 0)
+               return(err);
+       err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]);
+       if(err) 
+               return(err);
+  
+-      if(fake_major)
++      if(fake_major != MAJOR_NR)
+               ubd_new_disk(fake_major, dev->size, n, 
+                            &fake_gendisk[n]);
+@@ -561,42 +641,42 @@
+       return(err);
+ }
+-static int ubd_get_config(char *dev, char *str, int size, char **error_out)
++static int ubd_get_config(char *name, char *str, int size, char **error_out)
+ {
+-      struct ubd *ubd;
++      struct ubd *dev;
+       char *end;
+-      int major, n = 0;
++      int n, len = 0;
+-      major = simple_strtoul(dev, &end, 0);
+-      if((*end != '\0') || (end == dev)){
+-              *error_out = "ubd_get_config : didn't parse major number";
++      n = simple_strtoul(name, &end, 0);
++      if((*end != '\0') || (end == name)){
++              *error_out = "ubd_get_config : didn't parse device number";
+               return(-1);
+       }
+-      if((major >= MAX_DEV) || (major < 0)){
+-              *error_out = "ubd_get_config : major number out of range";
++      if((n >= MAX_DEV) || (n < 0)){
++              *error_out = "ubd_get_config : device number out of range";
+               return(-1);
+       }
+-      ubd = &ubd_dev[major];
++      dev = &ubd_dev[n];
+       spin_lock(&ubd_lock);
+-      if(ubd->file == NULL){
+-              CONFIG_CHUNK(str, size, n, "", 1);
++      if(dev->file == NULL){
++              CONFIG_CHUNK(str, size, len, "", 1);
+               goto out;
+       }
+-      CONFIG_CHUNK(str, size, n, ubd->file, 0);
++      CONFIG_CHUNK(str, size, len, dev->file, 0);
+-      if(ubd->cow.file != NULL){
+-              CONFIG_CHUNK(str, size, n, ",", 0);
+-              CONFIG_CHUNK(str, size, n, ubd->cow.file, 1);
++      if(dev->cow.file != NULL){
++              CONFIG_CHUNK(str, size, len, ",", 0);
++              CONFIG_CHUNK(str, size, len, dev->cow.file, 1);
+       }
+-      else CONFIG_CHUNK(str, size, n, "", 1);
++      else CONFIG_CHUNK(str, size, len, "", 1);
+  out:
+       spin_unlock(&ubd_lock);
+-      return(n);
++      return(len);
+ }
+ static int ubd_remove(char *str)
+@@ -604,11 +684,9 @@
+       struct ubd *dev;
+       int n, err = -ENODEV;
+-      if(!isdigit(*str))
+-              return(err);    /* it should be a number 0-7/a-h */
++      n = parse_unit(&str);
+-      n = *str - '0';
+-      if(n >= MAX_DEV) 
++      if((n < 0) || (n >= MAX_DEV))
+               return(err);
+       dev = &ubd_dev[n];
+@@ -669,7 +747,7 @@
+               
+       elevator_init(ubd_queue, &elevator_noop);
+-      if (fake_major != 0) {
++      if (fake_major != MAJOR_NR) {
+               char name[sizeof("ubd_nnn\0")];
+               snprintf(name, sizeof(name), "ubd_%d", fake_major);
+@@ -696,6 +774,7 @@
+       io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), 
+                                &thread_fd);
+       if(io_pid < 0){
++              io_pid = -1;
+               printk(KERN_ERR 
+                      "ubd : Failed to start I/O thread (errno = %d) - "
+                      "falling back to synchronous I/O\n", -io_pid);
+@@ -703,8 +782,8 @@
+       }
+       err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, 
+                            SA_INTERRUPT, "ubd", ubd_dev);
+-      if(err != 0) printk(KERN_ERR 
+-                          "um_request_irq failed - errno = %d\n", -err);
++      if(err != 0) 
++              printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err);
+       return(err);
+ }
+@@ -714,15 +793,9 @@
+ {
+       struct gendisk *disk = inode->i_bdev->bd_disk;
+       struct ubd *dev = disk->private_data;
+-      int err = -EISDIR;
+-
+-      if(dev->is_dir == 1)
+-              goto out;
++      int err = 0;
+-      err = 0;
+       if(dev->count == 0){
+-              dev->openflags = dev->boot_openflags;
+-
+               err = ubd_open_dev(dev);
+               if(err){
+                       printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n",
+@@ -749,62 +822,156 @@
+       return(0);
+ }
+-void cowify_req(struct io_thread_req *req, struct ubd *dev)
++static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, 
++                        __u64 *cow_offset, unsigned long *bitmap, 
++                        __u64 bitmap_offset, unsigned long *bitmap_words,
++                        __u64 bitmap_len)
++{
++      __u64 sector = io_offset >> 9;
++      int i, update_bitmap = 0;
++
++      for(i = 0; i < length >> 9; i++){
++              if(cow_mask != NULL)
++                      ubd_set_bit(i, (unsigned char *) cow_mask);
++              if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
++                      continue;
++
++              update_bitmap = 1;
++              ubd_set_bit(sector + i, (unsigned char *) bitmap);
++      }
++
++      if(!update_bitmap)
++              return;
++
++      *cow_offset = sector / (sizeof(unsigned long) * 8);
++
++      /* This takes care of the case where we're exactly at the end of the
++       * device, and *cow_offset + 1 is off the end.  So, just back it up
++       * by one word.  Thanks to Lynn Kerby for the fix and James McMechan
++       * for the original diagnosis.
++       */
++      if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) / 
++                         sizeof(unsigned long) - 1))
++              (*cow_offset)--;
++
++      bitmap_words[0] = bitmap[*cow_offset];
++      bitmap_words[1] = bitmap[*cow_offset + 1];
++
++      *cow_offset *= sizeof(unsigned long);
++      *cow_offset += bitmap_offset;
++}
++
++static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, 
++                     __u64 bitmap_offset, __u64 bitmap_len)
+ {
+-        int i, update_bitmap, sector = req->offset >> 9;
++      __u64 sector = req->offset >> 9;
++      int i;
+       if(req->length > (sizeof(req->sector_mask) * 8) << 9)
+               panic("Operation too long");
++
+       if(req->op == UBD_READ) {
+               for(i = 0; i < req->length >> 9; i++){
+-                      if(ubd_test_bit(sector + i, (unsigned char *) 
+-                                      dev->cow.bitmap)){
++                      if(ubd_test_bit(sector + i, (unsigned char *) bitmap))
+                               ubd_set_bit(i, (unsigned char *) 
+                                           &req->sector_mask);
+-                      }
+                 }
+-        } 
+-        else {
+-              update_bitmap = 0;
+-              for(i = 0; i < req->length >> 9; i++){
+-                      ubd_set_bit(i, (unsigned char *) 
+-                                  &req->sector_mask);
+-                      if(!ubd_test_bit(sector + i, (unsigned char *) 
+-                                       dev->cow.bitmap))
+-                              update_bitmap = 1;
+-                      ubd_set_bit(sector + i, (unsigned char *) 
+-                                  dev->cow.bitmap);
+-              }
+-              if(update_bitmap){
+-                      req->cow_offset = sector / (sizeof(unsigned long) * 8);
+-                      req->bitmap_words[0] = 
+-                              dev->cow.bitmap[req->cow_offset];
+-                      req->bitmap_words[1] = 
+-                              dev->cow.bitmap[req->cow_offset + 1];
+-                      req->cow_offset *= sizeof(unsigned long);
+-                      req->cow_offset += dev->cow.bitmap_offset;
++      }
++      else cowify_bitmap(req->offset, req->length, &req->sector_mask,
++                         &req->cow_offset, bitmap, bitmap_offset, 
++                         req->bitmap_words, bitmap_len);
++}
++
++static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset)
++{
++      __u64 sector;
++      unsigned char *bitmap;
++      int bit, i;
++
++      /* mmap must have been requested on the command line */
++      if(!ubd_do_mmap)
++              return(-1);
++
++      /* The buffer must be page aligned */
++      if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0)
++              return(-1);
++
++      /* The request must be a page long */
++      if((req->current_nr_sectors << 9) != PAGE_SIZE)
++              return(-1);
++
++      if(dev->cow.file == NULL)
++              return(dev->fd);
++
++      sector = offset >> 9;
++      bitmap = (unsigned char *) dev->cow.bitmap;
++      bit = ubd_test_bit(sector, bitmap);
++
++      for(i = 1; i < req->current_nr_sectors; i++){
++              if(ubd_test_bit(sector + i, bitmap) != bit)
++                      return(-1);
++      }
++
++      if(bit || (rq_data_dir(req) == WRITE))
++              offset += dev->cow.data_offset;
++
++      /* The data on disk must be page aligned */
++      if((offset % UBD_MMAP_BLOCK_SIZE) != 0)
++              return(-1);
++
++      return(bit ? dev->fd : dev->cow.fd);
++}
++
++static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset, 
++                              struct request *req, 
++                              struct io_thread_req *io_req)
++{
++      int err;
++
++      if(rq_data_dir(req) == WRITE){
++              /* Writes are almost no-ops since the new data is already in the
++               * host page cache
++               */
++              dev->map_writes++;
++              if(dev->cow.file != NULL)
++                      cowify_bitmap(io_req->offset, io_req->length, 
++                                    &io_req->sector_mask, &io_req->cow_offset,
++                                    dev->cow.bitmap, dev->cow.bitmap_offset,
++                                    io_req->bitmap_words, 
++                                    dev->cow.bitmap_len);
++      }
++      else {
++              int w;
++
++              if((dev->cow.file != NULL) && (fd == dev->cow.fd))
++                      w = 0;
++              else w = dev->openflags.w;
++
++              if((dev->cow.file != NULL) && (fd == dev->fd))
++                      offset += dev->cow.data_offset;
++
++              err = physmem_subst_mapping(req->buffer, fd, offset, w);
++              if(err){
++                      printk("physmem_subst_mapping failed, err = %d\n", 
++                             -err);
++                      return(1);
+               }
++              dev->map_reads++;
+       }
++      io_req->op = UBD_MMAP;
++      io_req->buffer = req->buffer;
++      return(0);
+ }
+ static int prepare_request(struct request *req, struct io_thread_req *io_req)
+ {
+       struct gendisk *disk = req->rq_disk;
+       struct ubd *dev = disk->private_data;
+-      __u64 block;
+-      int nsect;
++      __u64 offset;
++      int len, fd;
+       if(req->rq_status == RQ_INACTIVE) return(1);
+-      if(dev->is_dir){
+-              strcpy(req->buffer, "HOSTFS:");
+-              strcat(req->buffer, dev->file);
+-              spin_lock(&ubd_io_lock);
+-              end_request(req, 1);
+-              spin_unlock(&ubd_io_lock);
+-              return(1);
+-      }
+-
+       if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
+               printk("Write attempted on readonly ubd device %s\n", 
+                      disk->disk_name);
+@@ -814,23 +981,49 @@
+               return(1);
+       }
+-        block = req->sector;
+-        nsect = req->current_nr_sectors;
++      offset = ((__u64) req->sector) << 9;
++      len = req->current_nr_sectors << 9;
+-      io_req->op = rq_data_dir(req) == READ ? UBD_READ : UBD_WRITE;
+       io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd;
+       io_req->fds[1] = dev->fd;
++      io_req->map_fd = -1;
++      io_req->cow_offset = -1;
++      io_req->offset = offset;
++      io_req->length = len;
++      io_req->error = 0;
++      io_req->sector_mask = 0;
++
++      fd = mmap_fd(req, dev, io_req->offset);
++      if(fd > 0){
++              /* If mmapping is otherwise OK, but the first access to the 
++               * page is a write, then it's not mapped in yet.  So we have 
++               * to write the data to disk first, then we can map the disk
++               * page in and continue normally from there.
++               */
++              if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){
++                      io_req->map_fd = dev->fd;
++                      io_req->map_offset = io_req->offset + 
++                              dev->cow.data_offset;
++                      dev->write_maps++;
++              }
++              else return(prepare_mmap_request(dev, fd, io_req->offset, req, 
++                                               io_req));
++      }
++
++      if(rq_data_dir(req) == READ)
++              dev->nomap_reads++;
++      else dev->nomap_writes++;
++
++      io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE;
+       io_req->offsets[0] = 0;
+       io_req->offsets[1] = dev->cow.data_offset;
+-      io_req->offset = ((__u64) block) << 9;
+-      io_req->length = nsect << 9;
+       io_req->buffer = req->buffer;
+       io_req->sectorsize = 1 << 9;
+-      io_req->sector_mask = 0;
+-      io_req->cow_offset = -1;
+-      io_req->error = 0;
+-        if(dev->cow.file != NULL) cowify_req(io_req, dev);
++      if(dev->cow.file != NULL) 
++              cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset,
++                         dev->cow.bitmap_len);
++
+       return(0);
+ }
+@@ -885,7 +1078,7 @@
+               g.heads = 128;
+               g.sectors = 32;
+               g.cylinders = dev->size / (128 * 32 * 512);
+-              g.start = 2;
++              g.start = get_start_sect(inode->i_bdev);
+               return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0);
+       case HDIO_SET_UNMASKINTR:
+@@ -935,6 +1128,142 @@
+       return(-EINVAL);
+ }
++static int ubd_check_remapped(int fd, unsigned long address, int is_write,
++                            __u64 offset)
++{
++      __u64 bitmap_offset;
++      unsigned long new_bitmap[2];
++      int i, err, n;
++
++      /* If it's not a write access, we can't do anything about it */
++      if(!is_write)
++              return(0);
++
++      /* We have a write */
++      for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){
++              struct ubd *dev = &ubd_dev[i];
++
++              if((dev->fd != fd) && (dev->cow.fd != fd))
++                      continue;
++
++              /* It's a write to a ubd device */
++
++              if(!dev->openflags.w){
++                      /* It's a write access on a read-only device - probably
++                       * shouldn't happen.  If the kernel is trying to change
++                       * something with no intention of writing it back out,
++                       * then this message will clue us in that this needs
++                       * fixing
++                       */
++                      printk("Write access to mapped page from readonly ubd "
++                             "device %d\n", i);
++                      return(0);
++              }
++
++              /* It's a write to a writeable ubd device - it must be COWed
++               * because, otherwise, the page would have been mapped in 
++               * writeable
++               */
++
++              if(!dev->cow.file)
++                      panic("Write fault on writeable non-COW ubd device %d",
++                            i);
++
++              /* It should also be an access to the backing file since the 
++               * COW pages should be mapped in read-write
++               */
++
++              if(fd == dev->fd)
++                      panic("Write fault on a backing page of ubd "
++                            "device %d\n", i);
++
++              /* So, we do the write, copying the backing data to the COW 
++               * file... 
++               */
++
++              err = os_seek_file(dev->fd, offset + dev->cow.data_offset);
++              if(err < 0)
++                      panic("Couldn't seek to %lld in COW file of ubd "
++                            "device %d, err = %d", 
++                            offset + dev->cow.data_offset, i, -err);
++
++              n = os_write_file(dev->fd, (void *) address, PAGE_SIZE);
++              if(n != PAGE_SIZE)
++                      panic("Couldn't copy data to COW file of ubd "
++                            "device %d, err = %d", i, -n);
++
++              /* ... updating the COW bitmap... */
++
++              cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset, 
++                            dev->cow.bitmap, dev->cow.bitmap_offset, 
++                            new_bitmap, dev->cow.bitmap_len);
++
++              err = os_seek_file(dev->fd, bitmap_offset);
++              if(err < 0)
++                      panic("Couldn't seek to %lld in COW file of ubd "
++                            "device %d, err = %d", bitmap_offset, i, -err);
++
++              n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap));
++              if(n != sizeof(new_bitmap))
++                      panic("Couldn't update bitmap  of ubd device %d, "
++                            "err = %d", i, -n);
++              
++              /* Maybe we can map the COW page in, and maybe we can't.  If
++               * it is a pre-V3 COW file, we can't, since the alignment will 
++               * be wrong.  If it is a V3 or later COW file which has been 
++               * moved to a system with a larger page size, then maybe we 
++               * can't, depending on the exact location of the page.
++               */
++
++              offset += dev->cow.data_offset;
++
++              /* Remove the remapping, putting the original anonymous page
++               * back.  If the COW file can be mapped in, that is done.
++               * Otherwise, the COW page is read in.
++               */
++
++              if(!physmem_remove_mapping((void *) address))
++                      panic("Address 0x%lx not remapped by ubd device %d", 
++                            address, i);
++              if((offset % UBD_MMAP_BLOCK_SIZE) == 0)
++                      physmem_subst_mapping((void *) address, dev->fd, 
++                                            offset, 1);
++              else {
++                      err = os_seek_file(dev->fd, offset);
++                      if(err < 0)
++                              panic("Couldn't seek to %lld in COW file of "
++                                    "ubd device %d, err = %d", offset, i, 
++                                    -err);
++
++                      n = os_read_file(dev->fd, (void *) address, PAGE_SIZE);
++                      if(n != PAGE_SIZE)
++                              panic("Failed to read page from offset %llx of "
++                                    "COW file of ubd device %d, err = %d",
++                                    offset, i, -n);
++              }
++
++              return(1);
++      }
++
++      /* It's not a write on a ubd device */
++      return(0);
++}
++
++static struct remapper ubd_remapper = {
++      .list   = LIST_HEAD_INIT(ubd_remapper.list),
++      .proc   = ubd_check_remapped,
++};
++
++static int ubd_remapper_setup(void)
++{
++      if(ubd_do_mmap)
++              register_remapper(&ubd_remapper);
++
++      return(0);
++}
++
++__initcall(ubd_remapper_setup);
++
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+diff -Naur a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
+--- a/arch/um/drivers/ubd_user.c       2004-01-08 22:16:38.000000000 -0500
++++ b/arch/um/drivers/ubd_user.c       2004-01-08 22:22:42.000000000 -0500
+@@ -11,11 +11,8 @@
+ #include <signal.h>
+ #include <string.h>
+ #include <netinet/in.h>
+-#include <sys/stat.h>
+ #include <sys/time.h>
+-#include <sys/fcntl.h>
+ #include <sys/socket.h>
+-#include <string.h>
+ #include <sys/mman.h>
+ #include <sys/param.h>
+ #include "asm/types.h"
+@@ -24,146 +21,30 @@
+ #include "user.h"
+ #include "ubd_user.h"
+ #include "os.h"
++#include "cow.h"
+ #include <endian.h>
+ #include <byteswap.h>
+-#if __BYTE_ORDER == __BIG_ENDIAN
+-# define ntohll(x) (x)
+-# define htonll(x) (x)
+-#elif __BYTE_ORDER == __LITTLE_ENDIAN
+-# define ntohll(x)  bswap_64(x)
+-# define htonll(x)  bswap_64(x)
+-#else
+-#error "__BYTE_ORDER not defined"
+-#endif
+-
+-#define PATH_LEN_V1 256
+-
+-struct cow_header_v1 {
+-      int magic;
+-      int version;
+-      char backing_file[PATH_LEN_V1];
+-      time_t mtime;
+-      __u64 size;
+-      int sectorsize;
+-};
+-
+-#define PATH_LEN_V2 MAXPATHLEN
+-
+-struct cow_header_v2 {
+-      unsigned long magic;
+-      unsigned long version;
+-      char backing_file[PATH_LEN_V2];
+-      time_t mtime;
+-      __u64 size;
+-      int sectorsize;
+-};
+-
+-union cow_header {
+-      struct cow_header_v1 v1;
+-      struct cow_header_v2 v2;
+-};
+-
+-#define COW_MAGIC 0x4f4f4f4d  /* MOOO */
+-#define COW_VERSION 2
+-
+-static void sizes(__u64 size, int sectorsize, int bitmap_offset, 
+-                unsigned long *bitmap_len_out, int *data_offset_out)
+-{
+-      *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize);
+-
+-      *data_offset_out = bitmap_offset + *bitmap_len_out;
+-      *data_offset_out = (*data_offset_out + sectorsize - 1) / sectorsize;
+-      *data_offset_out *= sectorsize;
+-}
+-
+-static int read_cow_header(int fd, int *magic_out, char **backing_file_out, 
+-                         time_t *mtime_out, __u64 *size_out, 
+-                         int *sectorsize_out, int *bitmap_offset_out)
+-{
+-      union cow_header *header;
+-      char *file;
+-      int err, n;
+-      unsigned long version, magic;
+-
+-      header = um_kmalloc(sizeof(*header));
+-      if(header == NULL){
+-              printk("read_cow_header - Failed to allocate header\n");
+-              return(-ENOMEM);
+-      }
+-      err = -EINVAL;
+-      n = read(fd, header, sizeof(*header));
+-      if(n < offsetof(typeof(header->v1), backing_file)){
+-              printk("read_cow_header - short header\n");
+-              goto out;
+-      }
+-
+-      magic = header->v1.magic;
+-      if(magic == COW_MAGIC) {
+-              version = header->v1.version;
+-      }
+-      else if(magic == ntohl(COW_MAGIC)){
+-              version = ntohl(header->v1.version);
+-      }
+-      else goto out;
+-
+-      *magic_out = COW_MAGIC;
+-
+-      if(version == 1){
+-              if(n < sizeof(header->v1)){
+-                      printk("read_cow_header - failed to read V1 header\n");
+-                      goto out;
+-              }
+-              *mtime_out = header->v1.mtime;
+-              *size_out = header->v1.size;
+-              *sectorsize_out = header->v1.sectorsize;
+-              *bitmap_offset_out = sizeof(header->v1);
+-              file = header->v1.backing_file;
+-      }
+-      else if(version == 2){
+-              if(n < sizeof(header->v2)){
+-                      printk("read_cow_header - failed to read V2 header\n");
+-                      goto out;
+-              }
+-              *mtime_out = ntohl(header->v2.mtime);
+-              *size_out = ntohll(header->v2.size);
+-              *sectorsize_out = ntohl(header->v2.sectorsize);
+-              *bitmap_offset_out = sizeof(header->v2);
+-              file = header->v2.backing_file;
+-      }
+-      else {
+-              printk("read_cow_header - invalid COW version\n");
+-              goto out;
+-      }
+-      err = -ENOMEM;
+-      *backing_file_out = uml_strdup(file);
+-      if(*backing_file_out == NULL){
+-              printk("read_cow_header - failed to allocate backing file\n");
+-              goto out;
+-      }
+-      err = 0;
+- out:
+-      kfree(header);
+-      return(err);
+-}
+ static int same_backing_files(char *from_cmdline, char *from_cow, char *cow)
+ {
+-      struct stat buf1, buf2;
++      struct uml_stat buf1, buf2;
++      int err;
+       if(from_cmdline == NULL) return(1);
+       if(!strcmp(from_cmdline, from_cow)) return(1);
+-      if(stat(from_cmdline, &buf1) < 0){
+-              printk("Couldn't stat '%s', errno = %d\n", from_cmdline, 
+-                     errno);
++      err = os_stat_file(from_cmdline, &buf1);
++      if(err < 0){
++              printk("Couldn't stat '%s', err = %d\n", from_cmdline, -err);
+               return(1);
+       }
+-      if(stat(from_cow, &buf2) < 0){
+-              printk("Couldn't stat '%s', errno = %d\n", from_cow, errno);
++      err = os_stat_file(from_cow, &buf2);
++      if(err < 0){
++              printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
+               return(1);
+       }
+-      if((buf1.st_dev == buf2.st_dev) && (buf1.st_ino == buf2.st_ino))
++      if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
+               return(1);
+       printk("Backing file mismatch - \"%s\" requested,\n"
+@@ -174,20 +55,21 @@
+ static int backing_file_mismatch(char *file, __u64 size, time_t mtime)
+ {
+-      struct stat64 buf;
++      unsigned long modtime;
+       long long actual;
+       int err;
+-      if(stat64(file, &buf) < 0){
+-              printk("Failed to stat backing file \"%s\", errno = %d\n",
+-                     file, errno);
+-              return(-errno);
++      err = os_file_modtime(file, &modtime);
++      if(err < 0){
++              printk("Failed to get modification time of backing file "
++                     "\"%s\", err = %d\n", file, -err);
++              return(err);
+       }
+       err = os_file_size(file, &actual);
+-      if(err){
++      if(err < 0){
+               printk("Failed to get size of backing file \"%s\", "
+-                     "errno = %d\n", file, -err);
++                     "err = %d\n", file, -err);
+               return(err);
+       }
+@@ -196,9 +78,9 @@
+                      "file\n", size, actual);
+               return(-EINVAL);
+       }
+-      if(buf.st_mtime != mtime){
++      if(modtime != mtime){
+               printk("mtime mismatch (%ld vs %ld) of COW header vs backing "
+-                     "file\n", mtime, buf.st_mtime);
++                     "file\n", mtime, modtime);
+               return(-EINVAL);
+       }
+       return(0);
+@@ -209,124 +91,16 @@
+       int err;
+       err = os_seek_file(fd, offset);
+-      if(err != 0) return(-errno);
+-      err = read(fd, buf, len);
+-      if(err < 0) return(-errno);
+-      return(0);
+-}
++      if(err < 0) 
++              return(err);
+-static int absolutize(char *to, int size, char *from)
+-{
+-      char save_cwd[256], *slash;
+-      int remaining;
++      err = os_read_file(fd, buf, len);
++      if(err < 0) 
++              return(err);
+-      if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) {
+-              printk("absolutize : unable to get cwd - errno = %d\n", errno);
+-              return(-1);
+-      }
+-      slash = strrchr(from, '/');
+-      if(slash != NULL){
+-              *slash = '\0';
+-              if(chdir(from)){
+-                      *slash = '/';
+-                      printk("absolutize : Can't cd to '%s' - errno = %d\n",
+-                             from, errno);
+-                      return(-1);
+-              }
+-              *slash = '/';
+-              if(getcwd(to, size) == NULL){
+-                      printk("absolutize : unable to get cwd of '%s' - "
+-                             "errno = %d\n", from, errno);
+-                      return(-1);
+-              }
+-              remaining = size - strlen(to);
+-              if(strlen(slash) + 1 > remaining){
+-                      printk("absolutize : unable to fit '%s' into %d "
+-                             "chars\n", from, size);
+-                      return(-1);
+-              }
+-              strcat(to, slash);
+-      }
+-      else {
+-              if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){
+-                      printk("absolutize : unable to fit '%s' into %d "
+-                             "chars\n", from, size);
+-                      return(-1);
+-              }
+-              strcpy(to, save_cwd);
+-              strcat(to, "/");
+-              strcat(to, from);
+-      }
+-      chdir(save_cwd);
+       return(0);
+ }
+-static int write_cow_header(char *cow_file, int fd, char *backing_file, 
+-                          int sectorsize, long long *size)
+-{
+-        struct cow_header_v2 *header;
+-      struct stat64 buf;
+-      int err;
+-
+-      err = os_seek_file(fd, 0);
+-      if(err != 0){
+-              printk("write_cow_header - lseek failed, errno = %d\n", errno);
+-              return(-errno);
+-      }
+-
+-      err = -ENOMEM;
+-      header = um_kmalloc(sizeof(*header));
+-      if(header == NULL){
+-              printk("Failed to allocate COW V2 header\n");
+-              goto out;
+-      }
+-      header->magic = htonl(COW_MAGIC);
+-      header->version = htonl(COW_VERSION);
+-
+-      err = -EINVAL;
+-      if(strlen(backing_file) > sizeof(header->backing_file) - 1){
+-              printk("Backing file name \"%s\" is too long - names are "
+-                     "limited to %d characters\n", backing_file, 
+-                     sizeof(header->backing_file) - 1);
+-              goto out_free;
+-      }
+-
+-      if(absolutize(header->backing_file, sizeof(header->backing_file), 
+-                    backing_file))
+-              goto out_free;
+-
+-      err = stat64(header->backing_file, &buf);
+-      if(err < 0){
+-              printk("Stat of backing file '%s' failed, errno = %d\n",
+-                     header->backing_file, errno);
+-              err = -errno;
+-              goto out_free;
+-      }
+-
+-      err = os_file_size(header->backing_file, size);
+-      if(err){
+-              printk("Couldn't get size of backing file '%s', errno = %d\n",
+-                     header->backing_file, -*size);
+-              goto out_free;
+-      }
+-
+-      header->mtime = htonl(buf.st_mtime);
+-      header->size = htonll(*size);
+-      header->sectorsize = htonl(sectorsize);
+-
+-      err = write(fd, header, sizeof(*header));
+-      if(err != sizeof(*header)){
+-              printk("Write of header to new COW file '%s' failed, "
+-                     "errno = %d\n", cow_file, errno);
+-              goto out_free;
+-      }
+-      err = 0;
+- out_free:
+-      kfree(header);
+- out:
+-      return(err);
+-}
+-
+ int open_ubd_file(char *file, struct openflags *openflags, 
+                 char **backing_file_out, int *bitmap_offset_out, 
+                 unsigned long *bitmap_len_out, int *data_offset_out, 
+@@ -334,26 +108,36 @@
+ {
+       time_t mtime;
+       __u64 size;
++      __u32 version, align;
+       char *backing_file;
+-        int fd, err, sectorsize, magic, same, mode = 0644;
++      int fd, err, sectorsize, same, mode = 0644;
+-        if((fd = os_open_file(file, *openflags, mode)) < 0){
++      fd = os_open_file(file, *openflags, mode);
++      if(fd < 0){
+               if((fd == -ENOENT) && (create_cow_out != NULL))
+                       *create_cow_out = 1;
+                 if(!openflags->w ||
+                    ((errno != EROFS) && (errno != EACCES))) return(-errno);
+               openflags->w = 0;
+-                if((fd = os_open_file(file, *openflags, mode)) < 0) 
++              fd = os_open_file(file, *openflags, mode); 
++              if(fd < 0) 
+                       return(fd);
+         }
++
++      err = os_lock_file(fd, openflags->w);
++      if(err < 0){
++              printk("Failed to lock '%s', err = %d\n", file, -err);
++              goto out_close;
++      }
++      
+       if(backing_file_out == NULL) return(fd);
+-      err = read_cow_header(fd, &magic, &backing_file, &mtime, &size, 
+-                            &sectorsize, bitmap_offset_out);
++      err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime,
++                            &size, &sectorsize, &align, bitmap_offset_out);
+       if(err && (*backing_file_out != NULL)){
+               printk("Failed to read COW header from COW file \"%s\", "
+-                     "errno = %d\n", file, err);
+-              goto error;
++                     "errno = %d\n", file, -err);
++              goto out_close;
+       }
+       if(err) return(fd);
+@@ -363,36 +147,33 @@
+       if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){
+               printk("Switching backing file to '%s'\n", *backing_file_out);
+-              err = write_cow_header(file, fd, *backing_file_out, 
+-                                     sectorsize, &size);
++              err = write_cow_header(file, fd, *backing_file_out,
++                                     sectorsize, align, &size);
+               if(err){
+-                      printk("Switch failed, errno = %d\n", err);
++                      printk("Switch failed, errno = %d\n", -err);
+                       return(err);
+               }
+       }
+       else {
+               *backing_file_out = backing_file;
+               err = backing_file_mismatch(*backing_file_out, size, mtime);
+-              if(err) goto error;
++              if(err) goto out_close;
+       }
+-      sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out, 
+-            data_offset_out);
++      cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, 
++                bitmap_len_out, data_offset_out);
+         return(fd);
+- error:
+-      close(fd);
++ out_close:
++      os_close_file(fd);
+       return(err);
+ }
+ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags,
+-                  int sectorsize, int *bitmap_offset_out, 
++                  int sectorsize, int alignment, int *bitmap_offset_out, 
+                   unsigned long *bitmap_len_out, int *data_offset_out)
+ {
+-      __u64 blocks;
+-      long zero;
+-      int err, fd, i;
+-      long long size;
++      int err, fd;
+       flags.c = 1;
+       fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL);
+@@ -403,57 +184,49 @@
+               goto out;
+       }
+-      err = write_cow_header(cow_file, fd, backing_file, sectorsize, &size);
+-      if(err) goto out_close;
+-
+-      blocks = (size + sectorsize - 1) / sectorsize;
+-      blocks = (blocks + sizeof(long) * 8 - 1) / (sizeof(long) * 8);
+-      zero = 0;
+-      for(i = 0; i < blocks; i++){
+-              err = write(fd, &zero, sizeof(zero));
+-              if(err != sizeof(zero)){
+-                      printk("Write of bitmap to new COW file '%s' failed, "
+-                             "errno = %d\n", cow_file, errno);
+-                      goto out_close;
+-              }
+-      }
+-
+-      sizes(size, sectorsize, sizeof(struct cow_header_v2), 
+-            bitmap_len_out, data_offset_out);
+-      *bitmap_offset_out = sizeof(struct cow_header_v2);
+-
+-      return(fd);
+-
+- out_close:
+-      close(fd);
++      err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment,
++                          bitmap_offset_out, bitmap_len_out, 
++                          data_offset_out);
++      if(!err)
++              return(fd);
++      os_close_file(fd);
+  out:
+       return(err);
+ }
++/* XXX Just trivial wrappers around os_read_file and os_write_file */
+ int read_ubd_fs(int fd, void *buffer, int len)
+ {
+-      int n;
+-
+-      n = read(fd, buffer, len);
+-      if(n < 0) return(-errno);
+-      else return(n);
++      return(os_read_file(fd, buffer, len));
+ }
+ int write_ubd_fs(int fd, char *buffer, int len)
+ {
+-      int n;
+-
+-      n = write(fd, buffer, len);
+-      if(n < 0) return(-errno);
+-      else return(n);
++      return(os_write_file(fd, buffer, len));
+ }
+-int ubd_is_dir(char *file)
++static int update_bitmap(struct io_thread_req *req)
+ {
+-      struct stat64 buf;
++      int n;
++
++      if(req->cow_offset == -1)
++              return(0);
++
++      n = os_seek_file(req->fds[1], req->cow_offset);
++      if(n < 0){
++              printk("do_io - bitmap lseek failed : err = %d\n", -n);
++              return(1);
++      }
++
++      n = os_write_file(req->fds[1], &req->bitmap_words,
++                        sizeof(req->bitmap_words));
++      if(n != sizeof(req->bitmap_words)){
++              printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
++                     req->fds[1]);
++              return(1);
++      }
+-      if(stat64(file, &buf) < 0) return(0);
+-      return(S_ISDIR(buf.st_mode));
++      return(0);
+ }
+ void do_io(struct io_thread_req *req)
+@@ -461,8 +234,18 @@
+       char *buf;
+       unsigned long len;
+       int n, nsectors, start, end, bit;
++      int err;
+       __u64 off;
++      if(req->op == UBD_MMAP){
++              /* Touch the page to force the host to do any necessary IO to 
++               * get it into memory 
++               */
++              n = *((volatile int *) req->buffer);
++              req->error = update_bitmap(req);
++              return;
++      }
++
+       nsectors = req->length / req->sectorsize;
+       start = 0;
+       do {
+@@ -473,15 +256,14 @@
+                                   &req->sector_mask) == bit))
+                       end++;
+-              if(end != nsectors)
+-                      printk("end != nsectors\n");
+               off = req->offset + req->offsets[bit] + 
+                       start * req->sectorsize;
+               len = (end - start) * req->sectorsize;
+               buf = &req->buffer[start * req->sectorsize];
+-              if(os_seek_file(req->fds[bit], off) != 0){
+-                      printk("do_io - lseek failed : errno = %d\n", errno);
++              err = os_seek_file(req->fds[bit], off);
++              if(err < 0){
++                      printk("do_io - lseek failed : err = %d\n", -err);
+                       req->error = 1;
+                       return;
+               }
+@@ -490,11 +272,10 @@
+                       do {
+                               buf = &buf[n];
+                               len -= n;
+-                              n = read(req->fds[bit], buf, len);
++                              n = os_read_file(req->fds[bit], buf, len);
+                               if (n < 0) {
+-                                      printk("do_io - read returned %d : "
+-                                             "errno = %d fd = %d\n", n,
+-                                             errno, req->fds[bit]);
++                                      printk("do_io - read failed, err = %d "
++                                             "fd = %d\n", -n, req->fds[bit]);
+                                       req->error = 1;
+                                       return;
+                               }
+@@ -502,11 +283,10 @@
+                       if (n < len) memset(&buf[n], 0, len - n);
+               }
+               else {
+-                      n = write(req->fds[bit], buf, len);
++                      n = os_write_file(req->fds[bit], buf, len);
+                       if(n != len){
+-                              printk("do_io - write returned %d : "
+-                                     "errno = %d fd = %d\n", n, 
+-                                     errno, req->fds[bit]);
++                              printk("do_io - write failed err = %d "
++                                     "fd = %d\n", -n, req->fds[bit]);
+                               req->error = 1;
+                               return;
+                       }
+@@ -515,24 +295,7 @@
+               start = end;
+       } while(start < nsectors);
+-      if(req->cow_offset != -1){
+-              if(os_seek_file(req->fds[1], req->cow_offset) != 0){
+-                      printk("do_io - bitmap lseek failed : errno = %d\n",
+-                             errno);
+-                      req->error = 1;
+-                      return;
+-              }
+-              n = write(req->fds[1], &req->bitmap_words, 
+-                        sizeof(req->bitmap_words));
+-              if(n != sizeof(req->bitmap_words)){
+-                      printk("do_io - bitmap update returned %d : "
+-                             "errno = %d fd = %d\n", n, errno, req->fds[1]);
+-                      req->error = 1;
+-                      return;
+-              }
+-      }
+-      req->error = 0;
+-      return;
++      req->error = update_bitmap(req);
+ }
+ /* Changed in start_io_thread, which is serialized by being called only
+@@ -550,19 +313,23 @@
+       signal(SIGWINCH, SIG_IGN);
+       while(1){
+-              n = read(kernel_fd, &req, sizeof(req));
+-              if(n < 0) printk("io_thread - read returned %d, errno = %d\n",
+-                               n, errno);
+-              else if(n < sizeof(req)){
+-                      printk("io_thread - short read : length = %d\n", n);
++              n = os_read_file(kernel_fd, &req, sizeof(req));
++              if(n != sizeof(req)){
++                      if(n < 0)
++                              printk("io_thread - read failed, fd = %d, "
++                                     "err = %d\n", kernel_fd, -n);
++                      else {
++                              printk("io_thread - short read, fd = %d, "
++                                     "length = %d\n", kernel_fd, n);
++                      }
+                       continue;
+               }
+               io_count++;
+               do_io(&req);
+-              n = write(kernel_fd, &req, sizeof(req));
++              n = os_write_file(kernel_fd, &req, sizeof(req));
+               if(n != sizeof(req))
+-                      printk("io_thread - write failed, errno = %d\n",
+-                             errno);
++                      printk("io_thread - write failed, fd = %d, err = %d\n",
++                             kernel_fd, -n);
+       }
+ }
+@@ -571,10 +338,11 @@
+       int pid, fds[2], err;
+       err = os_pipe(fds, 1, 1);
+-      if(err){
+-              printk("start_io_thread - os_pipe failed, errno = %d\n", -err);
+-              return(-1);
++      if(err < 0){
++              printk("start_io_thread - os_pipe failed, err = %d\n", -err);
++              goto out;
+       }
++
+       kernel_fd = fds[0];
+       *fd_out = fds[1];
+@@ -582,32 +350,19 @@
+                   NULL);
+       if(pid < 0){
+               printk("start_io_thread - clone failed : errno = %d\n", errno);
+-              return(-errno);
+-      }
+-      return(pid);
+-}
+-
+-#ifdef notdef
+-int start_io_thread(unsigned long sp, int *fd_out)
+-{
+-      int pid;
+-
+-      if((kernel_fd = get_pty()) < 0) return(-1);
+-      raw(kernel_fd, 0);
+-      if((*fd_out = open(ptsname(kernel_fd), O_RDWR)) < 0){
+-              printk("Couldn't open tty for IO\n");
+-              return(-1);
++              goto out_close;
+       }
+-      pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
+-                  NULL);
+-      if(pid < 0){
+-              printk("start_io_thread - clone failed : errno = %d\n", errno);
+-              return(-errno);
+-      }
+       return(pid);
++
++ out_close:
++      os_close_file(fds[0]);
++      os_close_file(fds[1]);
++      kernel_fd = -1;
++      *fd_out = -1;
++out:
++      return(err);
+ }
+-#endif
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+diff -Naur a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
+--- a/arch/um/drivers/xterm.c  2004-01-08 22:13:50.000000000 -0500
++++ b/arch/um/drivers/xterm.c  2004-01-08 22:18:48.000000000 -0500
+@@ -8,7 +8,6 @@
+ #include <unistd.h>
+ #include <string.h>
+ #include <errno.h>
+-#include <fcntl.h>
+ #include <termios.h>
+ #include <signal.h>
+ #include <sched.h>
+@@ -36,7 +35,8 @@
+ {
+       struct xterm_chan *data;
+-      if((data = malloc(sizeof(*data))) == NULL) return(NULL);
++      data = malloc(sizeof(*data));
++      if(data == NULL) return(NULL);
+       *data = ((struct xterm_chan) { .pid             = -1, 
+                                      .helper_pid      = -1,
+                                      .device          = device, 
+@@ -93,7 +93,7 @@
+                        "/usr/lib/uml/port-helper", "-uml-socket",
+                        file, NULL };
+-      if(access(argv[4], X_OK))
++      if(os_access(argv[4], OS_ACC_X_OK) < 0)
+               argv[4] = "port-helper";
+       fd = mkstemp(file);
+@@ -106,13 +106,13 @@
+               printk("xterm_open : unlink failed, errno = %d\n", errno);
+               return(-errno);
+       }
+-      close(fd);
++      os_close_file(fd);
+-      fd = create_unix_socket(file, sizeof(file));
++      fd = os_create_unix_socket(file, sizeof(file), 1);
+       if(fd < 0){
+               printk("xterm_open : create_unix_socket failed, errno = %d\n", 
+                      -fd);
+-              return(-fd);
++              return(fd);
+       }
+       sprintf(title, data->title, data->device);
+@@ -128,15 +128,16 @@
+       if(data->direct_rcv)
+               new = os_rcv_fd(fd, &data->helper_pid);
+       else {
+-              if((err = os_set_fd_block(fd, 0)) != 0){
++              err = os_set_fd_block(fd, 0);
++              if(err < 0){
+                       printk("xterm_open : failed to set descriptor "
+-                             "non-blocking, errno = %d\n", err);
++                             "non-blocking, err = %d\n", -err);
+                       return(err);
+               }
+               new = xterm_fd(fd, &data->helper_pid);
+       }
+       if(new < 0){
+-              printk("xterm_open : os_rcv_fd failed, errno = %d\n", -new);
++              printk("xterm_open : os_rcv_fd failed, err = %d\n", -new);
+               goto out;
+       }
+@@ -160,7 +161,7 @@
+       if(data->helper_pid != -1) 
+               os_kill_process(data->helper_pid, 0);
+       data->helper_pid = -1;
+-      close(fd);
++      os_close_file(fd);
+ }
+ void xterm_free(void *d)
+diff -Naur a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
+--- a/arch/um/drivers/xterm_kern.c     2004-01-08 22:26:26.000000000 -0500
++++ b/arch/um/drivers/xterm_kern.c     2004-01-08 22:33:48.000000000 -0500
+@@ -5,9 +5,12 @@
+ #include "linux/errno.h"
+ #include "linux/slab.h"
++#include "linux/signal.h"
++#include "linux/interrupt.h"
+ #include "asm/semaphore.h"
+ #include "asm/irq.h"
+ #include "irq_user.h"
++#include "irq_kern.h"
+ #include "kern_util.h"
+ #include "os.h"
+ #include "xterm.h"
+@@ -19,17 +22,18 @@
+       int new_fd;
+ };
+-static void xterm_interrupt(int irq, void *data, struct pt_regs *regs)
++static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs)
+ {
+       struct xterm_wait *xterm = data;
+       int fd;
+       fd = os_rcv_fd(xterm->fd, &xterm->pid);
+       if(fd == -EAGAIN)
+-              return;
++              return(IRQ_NONE);
+       xterm->new_fd = fd;
+       up(&xterm->sem);
++      return(IRQ_HANDLED);
+ }
+ int xterm_fd(int socket, int *pid_out)
+@@ -54,7 +58,8 @@
+       if(err){
+               printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, "
+                      "err = %d\n",  err);
+-              return(err);
++              ret = err;
++              goto out;
+       }
+       down(&data->sem);
+@@ -62,6 +67,7 @@
+       ret = data->new_fd;
+       *pid_out = data->pid;
++ out:
+       kfree(data);
+       return(ret);
+diff -Naur a/arch/um/dyn.lds.S b/arch/um/dyn.lds.S
+--- a/arch/um/dyn.lds.S        2004-01-08 22:21:42.000000000 -0500
++++ b/arch/um/dyn.lds.S        2004-01-08 22:28:31.000000000 -0500
+@@ -10,12 +10,15 @@
+ {
+   . = START + SIZEOF_HEADERS;
+   .interp         : { *(.interp) }
+-  . = ALIGN(4096);
+   __binary_start = .;
+   . = ALIGN(4096);            /* Init code and data */
+   _stext = .;
+   __init_begin = .;
+-  .text.init : { *(.text.init) }
++  .init.text : { 
++      _sinittext = .;
++      *(.init.text)
++      _einittext = .;
++  }
+   . = ALIGN(4096);
+@@ -67,7 +70,7 @@
+   #include "asm/common.lds.S"
+-  .data.init : { *(.data.init) }
++  init.data : { *(.init.data) }
+   /* Ensure the __preinit_array_start label is properly aligned.  We
+      could instead move the label definition inside the section, but
+diff -Naur a/arch/um/include/2_5compat.h b/arch/um/include/2_5compat.h
+--- a/arch/um/include/2_5compat.h      2004-01-08 22:20:37.000000000 -0500
++++ b/arch/um/include/2_5compat.h      2004-01-08 22:27:07.000000000 -0500
+@@ -6,20 +6,6 @@
+ #ifndef __2_5_COMPAT_H__
+ #define __2_5_COMPAT_H__
+-#include "linux/version.h"
+-
+-#define INIT_CONSOLE(dev_name, write_proc, device_proc, setup_proc, f) { \
+-      name :          dev_name, \
+-      write :         write_proc, \
+-      read :          NULL, \
+-      device :        device_proc, \
+-      setup :         setup_proc, \
+-      flags :         f, \
+-      index :         -1, \
+-      cflag :         0, \
+-      next :          NULL \
+-}
+-
+ #define INIT_HARDSECT(arr, maj, sizes)
+ #define SET_PRI(task) do ; while(0)
+diff -Naur a/arch/um/include/irq_kern.h b/arch/um/include/irq_kern.h
+--- a/arch/um/include/irq_kern.h       1969-12-31 19:00:00.000000000 -0500
++++ b/arch/um/include/irq_kern.h       2004-01-08 22:27:54.000000000 -0500
+@@ -0,0 +1,28 @@
++/* 
++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __IRQ_KERN_H__
++#define __IRQ_KERN_H__
++
++#include "linux/interrupt.h"
++
++extern int um_request_irq(unsigned int irq, int fd, int type,
++                        irqreturn_t (*handler)(int, void *, 
++                                               struct pt_regs *),
++                        unsigned long irqflags,  const char * devname,
++                        void *dev_id);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
+--- a/arch/um/include/kern_util.h      2004-01-08 22:18:49.000000000 -0500
++++ b/arch/um/include/kern_util.h      2004-01-08 22:24:38.000000000 -0500
+@@ -63,10 +63,9 @@
+ extern void *syscall_sp(void *t);
+ extern void syscall_trace(void);
+ extern int hz(void);
+-extern void idle_timer(void);
++extern void uml_idle_timer(void);
+ extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs);
+ extern int external_pid(void *t);
+-extern int pid_to_processor_id(int pid);
+ extern void boot_timer_handler(int sig);
+ extern void interrupt_end(void);
+ extern void initial_thread_cb(void (*proc)(void *), void *arg);
+@@ -90,9 +89,7 @@
+ extern char *uml_strdup(char *string);
+ extern void unprotect_kernel_mem(void);
+ extern void protect_kernel_mem(void);
+-extern void set_kmem_end(unsigned long);
+ extern void uml_cleanup(void);
+-extern int pid_to_processor_id(int pid);
+ extern void set_current(void *t);
+ extern void lock_signalled_task(void *t);
+ extern void IPI_handler(int cpu);
+@@ -101,7 +98,9 @@
+ extern int clear_user_proc(void *buf, int size);
+ extern int copy_to_user_proc(void *to, void *from, int size);
+ extern int copy_from_user_proc(void *to, void *from, int size);
++extern int strlen_user_proc(char *str);
+ extern void bus_handler(int sig, union uml_pt_regs *regs);
++extern void winch(int sig, union uml_pt_regs *regs);
+ extern long execute_syscall(void *r);
+ extern int smp_sigio_handler(void);
+ extern void *get_current(void);
+@@ -112,6 +111,8 @@
+ extern void free_irq(unsigned int, void *);
+ extern int um_in_interrupt(void);
+ extern int cpu(void);
++extern unsigned long long time_stamp(void);
++
+ #endif
+ /*
+diff -Naur a/arch/um/include/line.h b/arch/um/include/line.h
+--- a/arch/um/include/line.h   2004-01-08 22:27:12.000000000 -0500
++++ b/arch/um/include/line.h   2004-01-08 22:34:07.000000000 -0500
+@@ -9,12 +9,14 @@
+ #include "linux/list.h"
+ #include "linux/workqueue.h"
+ #include "linux/tty.h"
++#include "linux/interrupt.h"
+ #include "asm/semaphore.h"
+ #include "chan_user.h"
+ #include "mconsole_kern.h"
+ struct line_driver {
+       char *name;
++      char *device_name;
+       char *devfs_name;
+       short major;
+       short minor_start;
+@@ -67,8 +69,6 @@
+ #define LINES_INIT(n) {  num :                n }
+-extern void line_interrupt(int irq, void *data, struct pt_regs *unused);
+-extern void line_write_interrupt(int irq, void *data, struct pt_regs *unused);
+ extern void line_close(struct line *lines, struct tty_struct *tty);
+ extern int line_open(struct line *lines, struct tty_struct *tty, 
+                    struct chan_opts *opts);
+diff -Naur a/arch/um/include/mconsole.h b/arch/um/include/mconsole.h
+--- a/arch/um/include/mconsole.h       2004-01-08 22:19:58.000000000 -0500
++++ b/arch/um/include/mconsole.h       2004-01-08 22:25:57.000000000 -0500
+@@ -41,11 +41,13 @@
+ struct mc_request;
++enum mc_context { MCONSOLE_INTR, MCONSOLE_PROC };
++
+ struct mconsole_command
+ {
+       char *command;
+       void (*handler)(struct mc_request *req);
+-      int as_interrupt;
++      enum mc_context context;
+ };
+ struct mc_request
+@@ -77,6 +79,8 @@
+ extern void mconsole_cad(struct mc_request *req);
+ extern void mconsole_stop(struct mc_request *req);
+ extern void mconsole_go(struct mc_request *req);
++extern void mconsole_log(struct mc_request *req);
++extern void mconsole_proc(struct mc_request *req);
+ extern int mconsole_get_request(int fd, struct mc_request *req);
+ extern int mconsole_notify(char *sock_name, int type, const void *data, 
+diff -Naur a/arch/um/include/mem.h b/arch/um/include/mem.h
+--- a/arch/um/include/mem.h    2004-01-08 22:32:37.000000000 -0500
++++ b/arch/um/include/mem.h    2004-01-08 22:36:37.000000000 -0500
+@@ -1,19 +1,17 @@
+ /* 
+- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2002, 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+ #ifndef __MEM_H__
+ #define __MEM_H__
+-struct vm_reserved {
+-      struct list_head list;
+-      unsigned long start;
+-      unsigned long end;
+-};
++#include "linux/types.h"
+-extern void set_usable_vm(unsigned long start, unsigned long end);
+-extern void set_kmem_end(unsigned long new);
++extern int phys_mapping(unsigned long phys, __u64 *offset_out);
++extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w);
++extern int is_remapped(void *virt);
++extern int physmem_remove_mapping(void *virt);
+ #endif
+diff -Naur a/arch/um/include/mem_kern.h b/arch/um/include/mem_kern.h
+--- a/arch/um/include/mem_kern.h       1969-12-31 19:00:00.000000000 -0500
++++ b/arch/um/include/mem_kern.h       2004-01-08 22:29:31.000000000 -0500
+@@ -0,0 +1,30 @@
++/* 
++ * Copyright (C) 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __MEM_KERN_H__
++#define __MEM_KERN_H__
++
++#include "linux/list.h"
++#include "linux/types.h"
++
++struct remapper {
++      struct list_head list;
++      int (*proc)(int, unsigned long, int, __u64);
++};
++
++extern void register_remapper(struct remapper *info);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h
+--- a/arch/um/include/mem_user.h       2004-01-08 22:25:06.000000000 -0500
++++ b/arch/um/include/mem_user.h       2004-01-08 22:32:22.000000000 -0500
+@@ -32,43 +32,38 @@
+ #ifndef _MEM_USER_H
+ #define _MEM_USER_H
+-struct mem_region {
++struct iomem_region {
++      struct iomem_region *next;
+       char *driver;
+-      unsigned long start_pfn;
+-      unsigned long start;
+-      unsigned long len;
+-      void *mem_map;
+       int fd;
++      int size;
++      unsigned long phys;
++      unsigned long virt;
+ };
+-extern struct mem_region *regions[];
+-extern struct mem_region physmem_region;
++extern struct iomem_region *iomem_regions;
++extern int iomem_size;
+ #define ROUND_4M(n) ((((unsigned long) (n)) + (1 << 22)) & ~((1 << 22) - 1))
+ extern unsigned long host_task_size;
+ extern unsigned long task_size;
++extern void check_devanon(void);
+ extern int init_mem_user(void);
+ extern int create_mem_file(unsigned long len);
+-extern void setup_range(int fd, char *driver, unsigned long start,
+-                      unsigned long pfn, unsigned long total, int need_vm, 
+-                      struct mem_region *region, void *reserved);
+ extern void setup_memory(void *entry);
+ extern unsigned long find_iomem(char *driver, unsigned long *len_out);
+-extern int init_maps(struct mem_region *region);
+-extern int nregions(void);
+-extern int reserve_vm(unsigned long start, unsigned long end, void *e);
++extern int init_maps(unsigned long physmem, unsigned long iomem, 
++                   unsigned long highmem);
+ extern unsigned long get_vm(unsigned long len);
+ extern void setup_physmem(unsigned long start, unsigned long usable,
+-                        unsigned long len);
+-extern int setup_region(struct mem_region *region, void *entry);
++                        unsigned long len, unsigned long highmem);
+ extern void add_iomem(char *name, int fd, unsigned long size);
+-extern struct mem_region *phys_region(unsigned long phys);
+ extern unsigned long phys_offset(unsigned long phys);
+ extern void unmap_physmem(void);
+-extern int map_memory(unsigned long virt, unsigned long phys, 
+-                    unsigned long len, int r, int w, int x);
++extern void map_memory(unsigned long virt, unsigned long phys, 
++                     unsigned long len, int r, int w, int x);
+ extern int protect_memory(unsigned long addr, unsigned long len, 
+                         int r, int w, int x, int must_succeed);
+ extern unsigned long get_kmem_end(void);
+diff -Naur a/arch/um/include/os.h b/arch/um/include/os.h
+--- a/arch/um/include/os.h     2004-01-08 22:16:19.000000000 -0500
++++ b/arch/um/include/os.h     2004-01-08 22:22:02.000000000 -0500
+@@ -17,6 +17,32 @@
+ #define OS_TYPE_FIFO 6
+ #define OS_TYPE_SOCK 7
++/* os_access() flags */
++#define OS_ACC_F_OK    0       /* Test for existence.  */
++#define OS_ACC_X_OK    1       /* Test for execute permission.  */
++#define OS_ACC_W_OK    2       /* Test for write permission.  */
++#define OS_ACC_R_OK    4       /* Test for read permission.  */
++#define OS_ACC_RW_OK   (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */
++
++/*
++ * types taken from stat_file() in hostfs_user.c
++ * (if they are wrong here, they are wrong there...).
++`*/
++struct uml_stat {
++      int                ust_dev;        /* device */
++      unsigned long long ust_ino;        /* inode */
++      int                ust_mode;       /* protection */
++      int                ust_nlink;      /* number of hard links */
++      int                ust_uid;        /* user ID of owner */
++      int                ust_gid;        /* group ID of owner */
++      unsigned long long ust_size;       /* total size, in bytes */
++      int                ust_blksize;    /* blocksize for filesystem I/O */
++      unsigned long long ust_blocks;     /* number of blocks allocated */
++      unsigned long      ust_atime;      /* time of last access */
++      unsigned long      ust_mtime;      /* time of last modification */
++      unsigned long      ust_ctime;      /* time of last change */
++};
++
+ struct openflags {
+       unsigned int r : 1;
+       unsigned int w : 1;
+@@ -91,22 +117,40 @@
+       return(flags); 
+ }
+   
++extern int os_stat_file(const char *file_name, struct uml_stat *buf);
++extern int os_stat_fd(const int fd, struct uml_stat *buf);
++extern int os_access(const char *file, int mode);
++extern void os_print_error(int error, const char* str);
++extern int os_get_exec_close(int fd, int *close_on_exec);
++extern int os_set_exec_close(int fd, int close_on_exec);
++extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg);
++extern int os_window_size(int fd, int *rows, int *cols);
++extern int os_new_tty_pgrp(int fd, int pid);
++extern int os_get_ifname(int fd, char *namebuf);
++extern int os_set_slip(int fd);
++extern int os_set_owner(int fd, int pid);
++extern int os_sigio_async(int master, int slave);
++extern int os_mode_fd(int fd, int mode);
++
+ extern int os_seek_file(int fd, __u64 offset);
+ extern int os_open_file(char *file, struct openflags flags, int mode);
+ extern int os_read_file(int fd, void *buf, int len);
+-extern int os_write_file(int fd, void *buf, int count);
++extern int os_write_file(int fd, const void *buf, int count);
+ extern int os_file_size(char *file, long long *size_out);
++extern int os_file_modtime(char *file, unsigned long *modtime);
+ extern int os_pipe(int *fd, int stream, int close_on_exec);
+ extern int os_set_fd_async(int fd, int owner);
+ extern int os_set_fd_block(int fd, int blocking);
+ extern int os_accept_connection(int fd);
++extern int os_create_unix_socket(char *file, int len, int close_on_exec);
+ extern int os_shutdown_socket(int fd, int r, int w);
+ extern void os_close_file(int fd);
+ extern int os_rcv_fd(int fd, int *helper_pid_out);
+-extern int create_unix_socket(char *file, int len);
++extern int create_unix_socket(char *file, int len, int close_on_exec);
+ extern int os_connect_socket(char *name);
+ extern int os_file_type(char *file);
+ extern int os_file_mode(char *file, struct openflags *mode_out);
++extern int os_lock_file(int fd, int excl);
+ extern unsigned long os_process_pc(int pid);
+ extern int os_process_parent(int pid);
+@@ -115,11 +159,12 @@
+ extern void os_usr1_process(int pid);
+ extern int os_getpid(void);
+-extern int os_map_memory(void *virt, int fd, unsigned long off, 
++extern int os_map_memory(void *virt, int fd, unsigned long long off, 
+                        unsigned long len, int r, int w, int x);
+ extern int os_protect_memory(void *addr, unsigned long len, 
+                            int r, int w, int x);
+ extern int os_unmap_memory(void *addr, int len);
++extern void os_flush_stdout(void);
+ #endif
+diff -Naur a/arch/um/include/sysdep-i386/sigcontext.h b/arch/um/include/sysdep-i386/sigcontext.h
+--- a/arch/um/include/sysdep-i386/sigcontext.h 2004-01-08 22:26:00.000000000 -0500
++++ b/arch/um/include/sysdep-i386/sigcontext.h 2004-01-08 22:33:43.000000000 -0500
+@@ -28,8 +28,8 @@
+  */
+ #define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0)
+-/* These are General Protection and Page Fault */
+-#define SEGV_IS_FIXABLE(trap) ((trap == 13) || (trap == 14))
++/* This is Page Fault */
++#define SEGV_IS_FIXABLE(trap) (trap == 14)
+ #define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc)))
+diff -Naur a/arch/um/include/ubd_user.h b/arch/um/include/ubd_user.h
+--- a/arch/um/include/ubd_user.h       2004-01-08 22:22:40.000000000 -0500
++++ b/arch/um/include/ubd_user.h       2004-01-08 22:29:35.000000000 -0500
+@@ -9,7 +9,7 @@
+ #include "os.h"
+-enum ubd_req { UBD_READ, UBD_WRITE };
++enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP };
+ struct io_thread_req {
+       enum ubd_req op;
+@@ -20,8 +20,10 @@
+       char *buffer;
+       int sectorsize;
+       unsigned long sector_mask;
+-      unsigned long cow_offset;
++      unsigned long long cow_offset;
+       unsigned long bitmap_words[2];
++      int map_fd;
++      unsigned long long map_offset;
+       int error;
+ };
+@@ -31,7 +33,7 @@
+                        int *create_cow_out);
+ extern int create_cow_file(char *cow_file, char *backing_file, 
+                          struct openflags flags, int sectorsize, 
+-                         int *bitmap_offset_out, 
++                         int alignment, int *bitmap_offset_out, 
+                          unsigned long *bitmap_len_out,
+                          int *data_offset_out);
+ extern int read_cow_bitmap(int fd, void *buf, int offset, int len);
+@@ -39,7 +41,6 @@
+ extern int write_ubd_fs(int fd, char *buffer, int len);
+ extern int start_io_thread(unsigned long sp, int *fds_out);
+ extern void do_io(struct io_thread_req *req);
+-extern int ubd_is_dir(char *file);
+ static inline int ubd_test_bit(__u64 bit, unsigned char *data)
+ {
+diff -Naur a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h
+--- a/arch/um/include/um_uaccess.h     2004-01-08 22:25:51.000000000 -0500
++++ b/arch/um/include/um_uaccess.h     2004-01-08 22:33:28.000000000 -0500
+@@ -38,22 +38,73 @@
+                               from, n));
+ }
++/*
++ * strncpy_from_user: - Copy a NUL terminated string from userspace.
++ * @dst:   Destination address, in kernel space.  This buffer must be at
++ *         least @count bytes long.
++ * @src:   Source address, in user space.
++ * @count: Maximum number of bytes to copy, including the trailing NUL.
++ * 
++ * Copies a NUL-terminated string from userspace to kernel space.
++ *
++ * On success, returns the length of the string (not including the trailing
++ * NUL).
++ *
++ * If access to userspace fails, returns -EFAULT (some data may have been
++ * copied).
++ *
++ * If @count is smaller than the length of the string, copies @count bytes
++ * and returns @count.
++ */
++
+ static inline int strncpy_from_user(char *dst, const char *src, int count)
+ {
+       return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas,
+                               dst, src, count));
+ }
++/*
++ * __clear_user: - Zero a block of memory in user space, with less checking.
++ * @to:   Destination address, in user space.
++ * @n:    Number of bytes to zero.
++ *
++ * Zero a block of memory in user space.  Caller must check
++ * the specified block with access_ok() before calling this function.
++ *
++ * Returns number of bytes that could not be cleared.
++ * On success, this will be zero.
++ */
+ static inline int __clear_user(void *mem, int len)
+ {
+       return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len));
+ }
++/*
++ * clear_user: - Zero a block of memory in user space.
++ * @to:   Destination address, in user space.
++ * @n:    Number of bytes to zero.
++ *
++ * Zero a block of memory in user space.
++ *
++ * Returns number of bytes that could not be cleared.
++ * On success, this will be zero.
++ */
+ static inline int clear_user(void *mem, int len)
+ {
+       return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len));
+ }
++/*
++ * strlen_user: - Get the size of a string in user space.
++ * @str: The string to measure.
++ * @n:   The maximum valid length
++ *
++ * Get the size of a NUL-terminated string in user space.
++ *
++ * Returns the size of the string INCLUDING the terminating NUL.
++ * On exception, returns 0.
++ * If the string is too long, returns a value greater than @n.
++ */
+ static inline int strnlen_user(const void *str, int len)
+ {
+       return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len));
+diff -Naur a/arch/um/include/user.h b/arch/um/include/user.h
+--- a/arch/um/include/user.h   2004-01-08 22:13:48.000000000 -0500
++++ b/arch/um/include/user.h   2004-01-08 22:18:35.000000000 -0500
+@@ -14,6 +14,7 @@
+ extern void kfree(void *ptr);
+ extern int in_aton(char *str);
+ extern int open_gdb_chan(void);
++extern int strlcpy(char *, const char *, int);
+ #endif
+diff -Naur a/arch/um/include/user_util.h b/arch/um/include/user_util.h
+--- a/arch/um/include/user_util.h      2004-01-08 22:14:54.000000000 -0500
++++ b/arch/um/include/user_util.h      2004-01-08 22:20:21.000000000 -0500
+@@ -14,8 +14,6 @@
+ extern int unlockpt(int __fd);
+ extern char *ptsname(int __fd);
+-enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
+-
+ struct cpu_task {
+       int pid;
+       void *task;
+@@ -59,7 +57,6 @@
+ extern void *add_signal_handler(int sig, void (*handler)(int));
+ extern int start_fork_tramp(void *arg, unsigned long temp_stack, 
+                           int clone_flags, int (*tramp)(void *));
+-extern int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags);
+ extern int linux_main(int argc, char **argv);
+ extern void set_cmdline(char *cmd);
+ extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
+@@ -86,11 +83,13 @@
+ extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
+ extern void write_sigio_workaround(void);
+ extern void arch_check_bugs(void);
++extern int cpu_feature(char *what, char *buf, int len);
+ extern int arch_handle_signal(int sig, union uml_pt_regs *regs);
+ extern int arch_fixup(unsigned long address, void *sc_ptr);
+ extern void forward_pending_sigio(int target);
+ extern int can_do_skas(void);
+- 
++extern void arch_init_thread(void);
++
+ #endif
+ /*
+diff -Naur a/arch/um/Kconfig b/arch/um/Kconfig
+--- a/arch/um/Kconfig  2004-01-08 22:21:13.000000000 -0500
++++ b/arch/um/Kconfig  2004-01-08 22:27:33.000000000 -0500
+@@ -61,6 +61,20 @@
+ config NET
+       bool "Networking support"
++      help
++      Unless you really know what you are doing, you should say Y here.
++      The reason is that some programs need kernel networking support even
++      when running on a stand-alone machine that isn't connected to any
++      other computer. If you are upgrading from an older kernel, you
++      should consider updating your networking tools too because changes
++      in the kernel and the tools often go hand in hand. The tools are
++      contained in the package net-tools, the location and version number
++      of which are given in Documentation/Changes.
++
++      For a general introduction to Linux networking, it is highly
++      recommended to read the NET-HOWTO, available from
++      <http://www.tldp.org/docs.html#howto>.
++
+ source "fs/Kconfig.binfmt"
+@@ -85,6 +99,19 @@
+         If you'd like to be able to work with files stored on the host, 
+         say Y or M here; otherwise say N.
++config HPPFS
++      tristate "HoneyPot ProcFS"
++      help
++      hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc 
++      entries to be overridden, removed, or fabricated from the host.
++      Its purpose is to allow a UML to appear to be a physical machine
++      by removing or changing anything in /proc which gives away the
++      identity of a UML.
++
++      See http://user-mode-linux.sf.net/hppfs.html for more information.
++
++      You only need this if you are setting up a UML honeypot.  Otherwise,
++      it is safe to say 'N' here.
+ config MCONSOLE
+       bool "Management console"
+@@ -105,6 +132,16 @@
+ config MAGIC_SYSRQ
+       bool "Magic SysRq key"
+       depends on MCONSOLE
++      help
++      If you say Y here, you will have some control over the system even
++      if the system crashes for example during kernel debugging (e.g., you
++      will be able to flush the buffer cache to disk, reboot the system
++      immediately or dump some status information). This is accomplished
++      by pressing various keys while holding SysRq (Alt+PrintScreen). It
++      also works on a serial console (on PC hardware at least), if you
++      send a BREAK and then within 5 seconds a command keypress. The
++      keys are documented in Documentation/sysrq.txt. Don't say Y
++      unless you really know what this hack does.
+ config HOST_2G_2G
+       bool "2G/2G host address space split"
+@@ -159,6 +196,9 @@
+ config HIGHMEM
+       bool "Highmem support"
++config PROC_MM
++      bool "/proc/mm support"
++
+ config KERNEL_STACK_ORDER
+       int "Kernel stack size order"
+       default 2
+@@ -167,6 +207,17 @@
+       be 1 << order pages.  The default is OK unless you're running Valgrind
+       on UML, in which case, set this to 3.
++config UML_REAL_TIME_CLOCK
++      bool "Real-time Clock"
++      default y
++      help
++      This option makes UML time deltas match wall clock deltas.  This should
++      normally be enabled.  The exception would be if you are debugging with
++      UML and spend long times with UML stopped at a breakpoint.  In this
++      case, when UML is restarted, it will call the timer enough times to make
++      up for the time spent at the breakpoint.  This could result in a 
++      noticable lag.  If this is a problem, then disable this option.
++
+ endmenu
+ source "init/Kconfig"
+@@ -239,6 +290,10 @@
+ config PT_PROXY
+       bool "Enable ptrace proxy"
+       depends on XTERM_CHAN && DEBUG_INFO
++      help
++      This option enables a debugging interface which allows gdb to debug
++      the kernel without needing to actually attach to kernel threads.
++      If you want to do kernel debugging, say Y here; otherwise say N.
+ config GPROF
+       bool "Enable gprof support"
+diff -Naur a/arch/um/Kconfig_block b/arch/um/Kconfig_block
+--- a/arch/um/Kconfig_block    2004-01-08 22:25:21.000000000 -0500
++++ b/arch/um/Kconfig_block    2004-01-08 22:32:41.000000000 -0500
+@@ -29,6 +29,20 @@
+         wise choice too.  In all other cases (for example, if you're just
+         playing around with User-Mode Linux) you can choose N.
++# Turn this back on when the driver actually works
++#
++#config BLK_DEV_COW
++#     tristate "COW block device"
++#     help
++#     This is a layered driver which sits above two other block devices.
++#     One is read-only, and the other is a read-write layer which stores
++#     all changes.  This provides the illusion that the read-only layer
++#     can be mounted read-write and changed.
++
++config BLK_DEV_COW_COMMON
++      bool
++      default BLK_DEV_COW || BLK_DEV_UBD
++
+ config BLK_DEV_LOOP
+       tristate "Loopback device support"
+diff -Naur a/arch/um/Kconfig_net b/arch/um/Kconfig_net
+--- a/arch/um/Kconfig_net      2004-01-08 22:23:21.000000000 -0500
++++ b/arch/um/Kconfig_net      2004-01-08 22:30:48.000000000 -0500
+@@ -1,5 +1,5 @@
+-menu "Network Devices"
++menu "UML Network Devices"
+       depends on NET
+ # UML virtual driver
+@@ -176,73 +176,5 @@
+       
+         Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp"
+-
+-# Below are hardware-independent drivers mirrored from
+-# drivers/net/Config.in. It would be nice if Linux
+-# had HW independent drivers separated from the other
+-# but it does not. Until then each non-ISA/PCI arch
+-# needs to provide it's own menu of network drivers
+-config DUMMY
+-      tristate "Dummy net driver support"
+-
+-config BONDING
+-      tristate "Bonding driver support"
+-
+-config EQUALIZER
+-      tristate "EQL (serial line load balancing) support"
+-
+-config TUN
+-      tristate "Universal TUN/TAP device driver support"
+-
+-config ETHERTAP
+-      tristate "Ethertap network tap (OBSOLETE)"
+-      depends on EXPERIMENTAL && NETLINK
+-
+-config PPP
+-      tristate "PPP (point-to-point protocol) support"
+-
+-config PPP_MULTILINK
+-      bool "PPP multilink support (EXPERIMENTAL)"
+-      depends on PPP && EXPERIMENTAL
+-
+-config PPP_FILTER
+-      bool "PPP filtering"
+-      depends on PPP && FILTER
+-
+-config PPP_ASYNC
+-      tristate "PPP support for async serial ports"
+-      depends on PPP
+-
+-config PPP_SYNC_TTY
+-      tristate "PPP support for sync tty ports"
+-      depends on PPP
+-
+-config PPP_DEFLATE
+-      tristate "PPP Deflate compression"
+-      depends on PPP
+-
+-config PPP_BSDCOMP
+-      tristate "PPP BSD-Compress compression"
+-      depends on PPP
+-
+-config PPPOE
+-      tristate "PPP over Ethernet (EXPERIMENTAL)"
+-      depends on PPP && EXPERIMENTAL
+-
+-config SLIP
+-      tristate "SLIP (serial line) support"
+-
+-config SLIP_COMPRESSED
+-      bool "CSLIP compressed headers"
+-      depends on SLIP=y
+-
+-config SLIP_SMART
+-      bool "Keepalive and linefill"
+-      depends on SLIP=y
+-
+-config SLIP_MODE_SLIP6
+-      bool "Six bit SLIP encapsulation"
+-      depends on SLIP=y
+-
+ endmenu
+diff -Naur a/arch/um/kernel/config.c.in b/arch/um/kernel/config.c.in
+--- a/arch/um/kernel/config.c.in       2004-01-08 22:26:26.000000000 -0500
++++ b/arch/um/kernel/config.c.in       2004-01-08 22:33:49.000000000 -0500
+@@ -7,9 +7,7 @@
+ #include <stdlib.h>
+ #include "init.h"
+-static __initdata char *config = "
+-CONFIG
+-";
++static __initdata char *config = "CONFIG";
+ static int __init print_config(char *line, int *add)
+ {
+diff -Naur a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c
+--- a/arch/um/kernel/exec_kern.c       2004-01-08 22:17:18.000000000 -0500
++++ b/arch/um/kernel/exec_kern.c       2004-01-08 22:23:06.000000000 -0500
+@@ -32,10 +32,15 @@
+       CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp);
+ }
++extern void log_exec(char **argv, void *tty);
++
+ static int execve1(char *file, char **argv, char **env)
+ {
+         int error;
++#ifdef CONFIG_TTY_LOG
++      log_exec(argv, current->tty);
++#endif
+         error = do_execve(file, argv, env, &current->thread.regs);
+         if (error == 0){
+                 current->ptrace &= ~PT_DTRACE;
+diff -Naur a/arch/um/kernel/frame.c b/arch/um/kernel/frame.c
+--- a/arch/um/kernel/frame.c   2004-01-08 22:18:38.000000000 -0500
++++ b/arch/um/kernel/frame.c   2004-01-08 22:24:26.000000000 -0500
+@@ -279,7 +279,7 @@
+       struct sc_frame_raw raw_sc;
+       struct si_frame_raw raw_si;
+       void *stack, *sigstack;
+-      unsigned long top, sig_top, base;
++      unsigned long top, base;
+       stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+@@ -292,7 +292,6 @@
+       }
+       top = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
+-      sig_top = (unsigned long) sigstack + PAGE_SIZE;
+       /* Get the sigcontext, no sigrestorer layout */
+       raw_sc.restorer = 0;
+diff -Naur a/arch/um/kernel/frame_kern.c b/arch/um/kernel/frame_kern.c
+--- a/arch/um/kernel/frame_kern.c      2004-01-08 22:33:46.000000000 -0500
++++ b/arch/um/kernel/frame_kern.c      2004-01-08 22:36:57.000000000 -0500
+@@ -6,7 +6,6 @@
+ #include "asm/ptrace.h"
+ #include "asm/uaccess.h"
+ #include "asm/signal.h"
+-#include "asm/uaccess.h"
+ #include "asm/ucontext.h"
+ #include "frame_kern.h"
+ #include "sigcontext.h"
+@@ -29,12 +28,15 @@
+                           sizeof(restorer)));
+ }
++extern int userspace_pid[];
++
+ static int copy_sc_to_user(void *to, void *fp, struct pt_regs *from, 
+                          struct arch_frame_data *arch)
+ {
+       return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), 
+                                             arch),
+-                         copy_sc_to_user_skas(to, fp, &from->regs,
++                         copy_sc_to_user_skas(userspace_pid[0], to, fp, 
++                                              &from->regs,
+                                               current->thread.cr2,
+                                               current->thread.err)));
+ }
+diff -Naur a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c
+--- a/arch/um/kernel/helper.c  2004-01-08 22:21:10.000000000 -0500
++++ b/arch/um/kernel/helper.c  2004-01-08 22:27:27.000000000 -0500
+@@ -7,7 +7,6 @@
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <errno.h>
+-#include <fcntl.h>
+ #include <sched.h>
+ #include <sys/signal.h>
+ #include <sys/wait.h>
+@@ -33,6 +32,7 @@
+ {
+       struct helper_data *data = arg;
+       char **argv = data->argv;
++      int errval;
+       if(helper_pause){
+               signal(SIGHUP, helper_hup);
+@@ -41,8 +41,9 @@
+       if(data->pre_exec != NULL)
+               (*data->pre_exec)(data->pre_data);
+       execvp(argv[0], argv);
++      errval = errno;
+       printk("execvp of '%s' failed - errno = %d\n", argv[0], errno);
+-      write(data->fd, &errno, sizeof(errno));
++      os_write_file(data->fd, &errval, sizeof(errval));
+       os_kill_process(os_getpid(), 0);
+       return(0);
+ }
+@@ -59,17 +60,20 @@
+       if((stack_out != NULL) && (*stack_out != 0))
+               stack = *stack_out;
+       else stack = alloc_stack(0, um_in_interrupt());
+-      if(stack == 0) return(-ENOMEM);
++      if(stack == 0) 
++              return(-ENOMEM);
+       err = os_pipe(fds, 1, 0);
+-      if(err){
+-              printk("run_helper : pipe failed, errno = %d\n", -err);
+-              return(err);
++      if(err < 0){
++              printk("run_helper : pipe failed, err = %d\n", -err);
++              goto out_free;
+       }
+-      if(fcntl(fds[1], F_SETFD, 1) != 0){
+-              printk("run_helper : setting FD_CLOEXEC failed, errno = %d\n",
+-                     errno);
+-              return(-errno);
++
++      err = os_set_exec_close(fds[1], 1);
++      if(err < 0){
++              printk("run_helper : setting FD_CLOEXEC failed, err = %d\n",
++                     -err);
++              goto out_close;
+       }
+       sp = stack + page_size() - sizeof(void *);
+@@ -80,23 +84,34 @@
+       pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data);
+       if(pid < 0){
+               printk("run_helper : clone failed, errno = %d\n", errno);
+-              return(-errno);
++              err = -errno;
++              goto out_close;
+       }
+-      close(fds[1]);
+-      n = read(fds[0], &err, sizeof(err));
++
++      os_close_file(fds[1]);
++      n = os_read_file(fds[0], &err, sizeof(err));
+       if(n < 0){
+-              printk("run_helper : read on pipe failed, errno = %d\n", 
+-                     errno);
+-              return(-errno);
++              printk("run_helper : read on pipe failed, err = %d\n", -n);
++              err = n;
++              goto out_kill;
+       }
+       else if(n != 0){
+               waitpid(pid, NULL, 0);
+-              pid = -err;
++              pid = -errno;
+       }
+       if(stack_out == NULL) free_stack(stack, 0);
+         else *stack_out = stack;
+       return(pid);
++
++ out_kill:
++      os_kill_process(pid, 1);
++ out_close:
++      os_close_file(fds[0]);
++      os_close_file(fds[1]);
++ out_free:
++      free_stack(stack, 0);
++      return(err);
+ }
+ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, 
+@@ -117,9 +132,11 @@
+       }
+       if(stack_out == NULL){
+               pid = waitpid(pid, &status, 0);
+-              if(pid < 0)
++              if(pid < 0){
+                       printk("run_helper_thread - wait failed, errno = %d\n",
+-                             pid);
++                             errno);
++                      pid = -errno;
++              }
+               if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
+                       printk("run_helper_thread - thread returned status "
+                              "0x%x\n", status);
+diff -Naur a/arch/um/kernel/initrd_user.c b/arch/um/kernel/initrd_user.c
+--- a/arch/um/kernel/initrd_user.c     2004-01-08 22:15:54.000000000 -0500
++++ b/arch/um/kernel/initrd_user.c     2004-01-08 22:21:30.000000000 -0500
+@@ -6,7 +6,6 @@
+ #include <unistd.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+-#include <fcntl.h>
+ #include <errno.h>
+ #include "user_util.h"
+@@ -19,13 +18,15 @@
+ {
+       int fd, n;
+-      if((fd = os_open_file(filename, of_read(OPENFLAGS()), 0)) < 0){
+-              printk("Opening '%s' failed - errno = %d\n", filename, errno);
++      fd = os_open_file(filename, of_read(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("Opening '%s' failed - err = %d\n", filename, -fd);
+               return(-1);
+       }
+-      if((n = read(fd, buf, size)) != size){
+-              printk("Read of %d bytes from '%s' returned %d, errno = %d\n",
+-                     size, filename, n, errno);
++      n = os_read_file(fd, buf, size);
++      if(n != size){
++              printk("Read of %d bytes from '%s' failed, err = %d\n", size, 
++                     filename, -n);
+               return(-1);
+       }
+       return(0);
+diff -Naur a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
+--- a/arch/um/kernel/init_task.c       2004-01-08 22:32:58.000000000 -0500
++++ b/arch/um/kernel/init_task.c       2004-01-08 22:36:48.000000000 -0500
+@@ -8,7 +8,6 @@
+ #include "linux/module.h"
+ #include "linux/sched.h"
+ #include "linux/init_task.h"
+-#include "linux/version.h"
+ #include "asm/uaccess.h"
+ #include "asm/pgtable.h"
+ #include "user_util.h"
+@@ -18,7 +17,7 @@
+ struct mm_struct init_mm = INIT_MM(init_mm);
+ static struct files_struct init_files = INIT_FILES;
+ static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+-
++static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+ EXPORT_SYMBOL(init_mm);
+ /*
+@@ -43,26 +42,12 @@
+ __attribute__((__section__(".data.init_task"))) = 
+ { INIT_THREAD_INFO(init_task) };
+-struct task_struct *alloc_task_struct(void)
+-{
+-      return((struct task_struct *) 
+-             __get_free_pages(GFP_KERNEL, CONFIG_KERNEL_STACK_ORDER));
+-}
+-
+ void unprotect_stack(unsigned long stack)
+ {
+       protect_memory(stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, 
+                      1, 1, 0, 1);
+ }
+-void free_task_struct(struct task_struct *task)
+-{
+-      /* free_pages decrements the page counter and only actually frees
+-       * the pages if they are now not accessed by anything.
+-       */
+-      free_pages((unsigned long) task, CONFIG_KERNEL_STACK_ORDER);
+-}
+-
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+diff -Naur a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
+--- a/arch/um/kernel/irq.c     2004-01-08 22:28:24.000000000 -0500
++++ b/arch/um/kernel/irq.c     2004-01-08 22:34:33.000000000 -0500
+@@ -29,6 +29,7 @@
+ #include "user_util.h"
+ #include "kern_util.h"
+ #include "irq_user.h"
++#include "irq_kern.h"
+ static void register_irq_proc (unsigned int irq);
+@@ -83,65 +84,52 @@
+       end_none
+ };
+-/* Not changed */
+-volatile unsigned long irq_err_count;
+-
+ /*
+  * Generic, controller-independent functions:
+  */
+-int get_irq_list(char *buf)
++int show_interrupts(struct seq_file *p, void *v)
+ {
+       int i, j;
+-      unsigned long flags;
+       struct irqaction * action;
+-      char *p = buf;
++      unsigned long flags;
+-      p += sprintf(p, "           ");
+-      for (j=0; j<num_online_cpus(); j++)
+-              p += sprintf(p, "CPU%d       ",j);
+-      *p++ = '\n';
++      seq_printf(p, "           ");
++      for (j=0; j<NR_CPUS; j++)
++              if (cpu_online(j))
++                      seq_printf(p, "CPU%d       ",j);
++      seq_putc(p, '\n');
+       for (i = 0 ; i < NR_IRQS ; i++) {
+               spin_lock_irqsave(&irq_desc[i].lock, flags);
+               action = irq_desc[i].action;
+               if (!action) 
+-                      goto end;
+-              p += sprintf(p, "%3d: ",i);
++                      goto skip;
++              seq_printf(p, "%3d: ",i);
+ #ifndef CONFIG_SMP
+-              p += sprintf(p, "%10u ", kstat_irqs(i));
++              seq_printf(p, "%10u ", kstat_irqs(i));
+ #else
+-              for (j = 0; j < num_online_cpus(); j++)
+-                      p += sprintf(p, "%10u ",
+-                              kstat_cpu(cpu_logical_map(j)).irqs[i]);
++              for (j = 0; j < NR_CPUS; j++)
++                      if (cpu_online(j))
++                              seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+ #endif
+-              p += sprintf(p, " %14s", irq_desc[i].handler->typename);
+-              p += sprintf(p, "  %s", action->name);
++              seq_printf(p, " %14s", irq_desc[i].handler->typename);
++              seq_printf(p, "  %s", action->name);
+               for (action=action->next; action; action = action->next)
+-                      p += sprintf(p, ", %s", action->name);
+-              *p++ = '\n';
+-      end:
++                      seq_printf(p, ", %s", action->name);
++
++              seq_putc(p, '\n');
++skip:
+               spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+       }
+-      p += sprintf(p, "\n");
+-#ifdef notdef
+-#ifdef CONFIG_SMP
+-      p += sprintf(p, "LOC: ");
+-      for (j = 0; j < num_online_cpus(); j++)
+-              p += sprintf(p, "%10u ",
+-                      apic_timer_irqs[cpu_logical_map(j)]);
+-      p += sprintf(p, "\n");
+-#endif
+-#endif
+-      p += sprintf(p, "ERR: %10lu\n", irq_err_count);
+-      return p - buf;
+-}
++      seq_printf(p, "NMI: ");
++      for (j = 0; j < NR_CPUS; j++)
++              if (cpu_online(j))
++                      seq_printf(p, "%10u ", nmi_count(j));
++      seq_putc(p, '\n');
+-
+-int show_interrupts(struct seq_file *p, void *v)
+-{
+-      return(0);
++      return 0;
+ }
+ /*
+@@ -230,8 +218,11 @@
+  
+ void disable_irq(unsigned int irq)
+ {
++      irq_desc_t *desc = irq_desc + irq;
++
+       disable_irq_nosync(irq);
+-      synchronize_irq(irq);
++      if(desc->action)
++              synchronize_irq(irq);
+ }
+ /**
+@@ -252,7 +243,7 @@
+       spin_lock_irqsave(&desc->lock, flags);
+       switch (desc->depth) {
+       case 1: {
+-              unsigned int status = desc->status & ~IRQ_DISABLED;
++              unsigned int status = desc->status & IRQ_DISABLED;
+               desc->status = status;
+               if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
+                       desc->status = status | IRQ_REPLAY;
+@@ -282,13 +273,12 @@
+        * 0 return value means that this irq is already being
+        * handled by some other CPU. (or is disabled)
+        */
+-      int cpu = smp_processor_id();
+       irq_desc_t *desc = irq_desc + irq;
+       struct irqaction * action;
+       unsigned int status;
+       irq_enter();
+-      kstat_cpu(cpu).irqs[irq]++;
++      kstat_this_cpu.irqs[irq]++;
+       spin_lock(&desc->lock);
+       desc->handler->ack(irq);
+       /*
+@@ -385,7 +375,7 @@
+  */
+  
+ int request_irq(unsigned int irq,
+-              void (*handler)(int, void *, struct pt_regs *),
++              irqreturn_t (*handler)(int, void *, struct pt_regs *),
+               unsigned long irqflags, 
+               const char * devname,
+               void *dev_id)
+@@ -433,15 +423,19 @@
+ EXPORT_SYMBOL(request_irq);
+ int um_request_irq(unsigned int irq, int fd, int type,
+-                 void (*handler)(int, void *, struct pt_regs *),
++                 irqreturn_t (*handler)(int, void *, struct pt_regs *),
+                  unsigned long irqflags, const char * devname,
+                  void *dev_id)
+ {
+-      int retval;
++      int err;
+-      retval = request_irq(irq, handler, irqflags, devname, dev_id);
+-      if(retval) return(retval);
+-      return(activate_fd(irq, fd, type, dev_id));
++      err = request_irq(irq, handler, irqflags, devname, dev_id);
++      if(err) 
++              return(err);
++
++      if(fd != -1)
++              err = activate_fd(irq, fd, type, dev_id);
++      return(err);
+ }
+ /* this was setup_x86_irq but it seems pretty generic */
+@@ -474,7 +468,8 @@
+        */
+       spin_lock_irqsave(&desc->lock,flags);
+       p = &desc->action;
+-      if ((old = *p) != NULL) {
++      old = *p;
++      if (old != NULL) {
+               /* Can't share interrupts unless both agree to */
+               if (!(old->flags & new->flags & SA_SHIRQ)) {
+                       spin_unlock_irqrestore(&desc->lock,flags);
+@@ -597,8 +592,8 @@
+               return -EFAULT;
+       /*
+-       * Parse the first 8 characters as a hex string, any non-hex char
+-       * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
++       * Parse the first HEX_DIGITS characters as a hex string, any non-hex 
++       * char is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same.
+        */
+       for (i = 0; i < count; i++) {
+@@ -625,12 +620,14 @@
+                                       unsigned long count, void *data)
+ {
+       int irq = (long) data, full_count = count, err;
+-      cpumask_t new_value, tmp;
++      cpumask_t new_value;
+       if (!irq_desc[irq].handler->set_affinity)
+               return -EIO;
+       err = parse_hex_value(buffer, count, &new_value);
++      if(err)
++              return(err);
+ #ifdef CONFIG_SMP
+       /*
+@@ -659,7 +656,7 @@
+               return -EINVAL;
+       tmp = *mask;
+       for (k = 0; k < sizeof(cpumask_t)/sizeof(u16); ++k) {
+-              int j = sprintf(page, "%04hx", cpus_coerce(tmp));
++              int j = sprintf(page, "%04hx", (short) cpus_coerce(tmp));
+               len += j;
+               page += j;
+               cpus_shift_right(tmp, tmp, 16);
+diff -Naur a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
+--- a/arch/um/kernel/irq_user.c        2004-01-08 22:20:11.000000000 -0500
++++ b/arch/um/kernel/irq_user.c        2004-01-08 22:26:28.000000000 -0500
+@@ -6,7 +6,6 @@
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <errno.h>
+-#include <fcntl.h>
+ #include <signal.h>
+ #include <string.h>
+ #include <sys/poll.h>
+@@ -49,7 +48,8 @@
+       if(smp_sigio_handler()) return;
+       while(1){
+-              if((n = poll(pollfds, pollfds_num, 0)) < 0){
++              n = poll(pollfds, pollfds_num, 0);
++              if(n < 0){
+                       if(errno == EINTR) continue;
+                       printk("sigio_handler : poll returned %d, "
+                              "errno = %d\n", n, errno);
+@@ -366,34 +366,31 @@
+ void forward_ipi(int fd, int pid)
+ {
+-      if(fcntl(fd, F_SETOWN, pid) < 0){
+-              int save_errno = errno;
+-              if(fcntl(fd, F_GETOWN, 0) != pid){
+-                      printk("forward_ipi: F_SETOWN failed, fd = %d, "
+-                             "me = %d, target = %d, errno = %d\n", fd, 
+-                             os_getpid(), pid, save_errno);
+-              }
+-      }
++      int err;
++
++      err = os_set_owner(fd, pid);
++      if(err < 0)
++              printk("forward_ipi: set_owner failed, fd = %d, me = %d, "
++                     "target = %d, err = %d\n", fd, os_getpid(), pid, -err);
+ }
+ void forward_interrupts(int pid)
+ {
+       struct irq_fd *irq;
+       unsigned long flags;
++      int err;
+       flags = irq_lock();
+       for(irq=active_fds;irq != NULL;irq = irq->next){
+-              if(fcntl(irq->fd, F_SETOWN, pid) < 0){
+-                      int save_errno = errno;
+-                      if(fcntl(irq->fd, F_GETOWN, 0) != pid){
+-                              /* XXX Just remove the irq rather than
+-                               * print out an infinite stream of these
+-                               */
+-                              printk("Failed to forward %d to pid %d, "
+-                                     "errno = %d\n", irq->fd, pid, 
+-                                     save_errno);
+-                      }
++              err = os_set_owner(irq->fd, pid);
++              if(err < 0){
++                      /* XXX Just remove the irq rather than
++                       * print out an infinite stream of these
++                       */
++                      printk("Failed to forward %d to pid %d, err = %d\n",
++                             irq->fd, pid, -err);
+               }
++
+               irq->pid = pid;
+       }
+       irq_unlock(flags);
+diff -Naur a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
+--- a/arch/um/kernel/ksyms.c   2004-01-08 22:13:48.000000000 -0500
++++ b/arch/um/kernel/ksyms.c   2004-01-08 22:18:39.000000000 -0500
+@@ -1,5 +1,5 @@
+ /* 
+- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+@@ -34,34 +34,62 @@
+ EXPORT_SYMBOL(flush_tlb_range);
+ EXPORT_SYMBOL(host_task_size);
+ EXPORT_SYMBOL(arch_validate);
++EXPORT_SYMBOL(get_kmem_end);
+-EXPORT_SYMBOL(region_pa);
+-EXPORT_SYMBOL(region_va);
+-EXPORT_SYMBOL(phys_mem_map);
+-EXPORT_SYMBOL(page_mem_map);
+ EXPORT_SYMBOL(page_to_phys);
+ EXPORT_SYMBOL(phys_to_page);
+ EXPORT_SYMBOL(high_physmem);
+ EXPORT_SYMBOL(empty_zero_page);
+ EXPORT_SYMBOL(um_virt_to_phys);
++EXPORT_SYMBOL(__virt_to_page);
++EXPORT_SYMBOL(to_phys);
++EXPORT_SYMBOL(to_virt);
+ EXPORT_SYMBOL(mode_tt);
+ EXPORT_SYMBOL(handle_page_fault);
++#ifdef CONFIG_MODE_TT
++EXPORT_SYMBOL(copy_from_user_tt);
++EXPORT_SYMBOL(copy_to_user_tt);
++#endif
++
++#ifdef CONFIG_MODE_SKAS
++EXPORT_SYMBOL(copy_to_user_skas);
++EXPORT_SYMBOL(copy_from_user_skas);
++#endif
++
++EXPORT_SYMBOL(os_stat_fd);
++EXPORT_SYMBOL(os_stat_file);
++EXPORT_SYMBOL(os_access);
++EXPORT_SYMBOL(os_print_error);
++EXPORT_SYMBOL(os_get_exec_close);
++EXPORT_SYMBOL(os_set_exec_close);
+ EXPORT_SYMBOL(os_getpid);
+ EXPORT_SYMBOL(os_open_file);
+ EXPORT_SYMBOL(os_read_file);
+ EXPORT_SYMBOL(os_write_file);
+ EXPORT_SYMBOL(os_seek_file);
++EXPORT_SYMBOL(os_lock_file);
+ EXPORT_SYMBOL(os_pipe);
+ EXPORT_SYMBOL(os_file_type);
++EXPORT_SYMBOL(os_file_mode);
++EXPORT_SYMBOL(os_file_size);
++EXPORT_SYMBOL(os_flush_stdout);
+ EXPORT_SYMBOL(os_close_file);
++EXPORT_SYMBOL(os_set_fd_async);
++EXPORT_SYMBOL(os_set_fd_block);
+ EXPORT_SYMBOL(helper_wait);
+ EXPORT_SYMBOL(os_shutdown_socket);
++EXPORT_SYMBOL(os_create_unix_socket);
+ EXPORT_SYMBOL(os_connect_socket);
++EXPORT_SYMBOL(os_accept_connection);
++EXPORT_SYMBOL(os_rcv_fd);
+ EXPORT_SYMBOL(run_helper);
+ EXPORT_SYMBOL(start_thread);
+ EXPORT_SYMBOL(dump_thread);
++EXPORT_SYMBOL(do_gettimeofday);
++EXPORT_SYMBOL(do_settimeofday);
++
+ /* This is here because UML expands open to sys_open, not to a system
+  * call instruction.
+  */
+@@ -90,3 +118,13 @@
+ EXPORT_SYMBOL(kmap_atomic_to_page);
+ #endif
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
+--- a/arch/um/kernel/Makefile  2004-01-08 22:25:20.000000000 -0500
++++ b/arch/um/kernel/Makefile  2004-01-08 22:32:41.000000000 -0500
+@@ -7,11 +7,11 @@
+ obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o \
+       helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \
+-      process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \
+-      sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o \
+-      syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o \
+-      time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \
+-      umid.o user_syms.o user_util.o
++      physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \
++      sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \
++      syscall_kern.o syscall_user.o sysrq.o sys_call_table.o tempfile.o \
++      time.o time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o \
++      um_arch.o umid.o user_syms.o user_util.o
+ obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
+ obj-$(CONFIG_GPROF)   += gprof_syms.o
+@@ -21,6 +21,8 @@
+ obj-$(CONFIG_MODE_TT) += tt/
+ obj-$(CONFIG_MODE_SKAS) += skas/
++clean-files   := config.c
++
+ user-objs-$(CONFIG_TTY_LOG) += tty_log.o
+ USER_OBJS := $(filter %_user.o,$(obj-y))  $(user-objs-y) config.o helper.o \
+@@ -45,17 +47,13 @@
+ $(obj)/frame.o: $(src)/frame.c
+       $(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $<
+-QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
++QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; $$config =~ s/\n/\\n"\n"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }'
+ $(obj)/config.c : $(src)/config.c.in $(TOPDIR)/.config
+       $(PERL) -e $(QUOTE) < $(src)/config.c.in > $@
+ $(obj)/config.o : $(obj)/config.c
+-clean:
+-      rm -f config.c
+-      for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done
+-
+ modules:
+ fastdep:
+diff -Naur a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
+--- a/arch/um/kernel/mem.c     2004-01-08 22:19:21.000000000 -0500
++++ b/arch/um/kernel/mem.c     2004-01-08 22:25:37.000000000 -0500
+@@ -1,74 +1,67 @@
+ /* 
+- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+-#include "linux/config.h"
+-#include "linux/module.h"
+-#include "linux/types.h"
++#include "linux/stddef.h"
++#include "linux/kernel.h"
+ #include "linux/mm.h"
+-#include "linux/fs.h"
+-#include "linux/init.h"
+ #include "linux/bootmem.h"
+ #include "linux/swap.h"
+-#include "linux/slab.h"
+-#include "linux/vmalloc.h"
+ #include "linux/highmem.h"
++#include "linux/gfp.h"
+ #include "asm/page.h"
+-#include "asm/pgtable.h"
++#include "asm/fixmap.h"
+ #include "asm/pgalloc.h"
+-#include "asm/bitops.h"
+-#include "asm/uaccess.h"
+-#include "asm/tlb.h"
+ #include "user_util.h"
+ #include "kern_util.h"
+-#include "mem_user.h"
+-#include "mem.h"
+ #include "kern.h"
+-#include "init.h"
+-#include "os.h"
+-#include "mode_kern.h"
++#include "mem_user.h"
+ #include "uml_uaccess.h"
++#include "os.h"
++
++extern char __binary_start;
+ /* Changed during early boot */
+-pgd_t swapper_pg_dir[1024];
+-unsigned long high_physmem;
+-unsigned long vm_start;
+-unsigned long vm_end;
+-unsigned long highmem;
+ unsigned long *empty_zero_page = NULL;
+ unsigned long *empty_bad_page = NULL;
+-
+-/* Not modified */
+-const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n";
+-
+-extern char __init_begin, __init_end;
+-extern long physmem_size;
+-
+-/* Not changed by UML */
+-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+-
+-/* Changed during early boot */
++pgd_t swapper_pg_dir[1024];
++unsigned long highmem;
+ int kmalloc_ok = 0;
+-#define NREGIONS (phys_region_index(0xffffffff) - phys_region_index(0x0) + 1)
+-struct mem_region *regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] = NULL };
+-#define REGION_SIZE ((0xffffffff & ~REGION_MASK) + 1)
+-
+-/* Changed during early boot */
+ static unsigned long brk_end;
++static unsigned long totalram_pages = 0;
++
++void unmap_physmem(void)
++{
++      os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
++}
+ static void map_cb(void *unused)
+ {
+       map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0);
+ }
+-void unmap_physmem(void)
++#ifdef CONFIG_HIGHMEM
++static void setup_highmem(unsigned long highmem_start, 
++                        unsigned long highmem_len)
+ {
+-      os_unmap_memory((void *) brk_end, uml_reserved - brk_end);
+-}
++      struct page *page;
++      unsigned long highmem_pfn;
++      int i;
+-extern char __binary_start;
++      highmem_start_page = virt_to_page(highmem_start);
++
++      highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT;
++      for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
++              page = &mem_map[highmem_pfn + i];
++              ClearPageReserved(page);
++              set_bit(PG_highmem, &page->flags);
++              atomic_set(&page->count, 1);
++              __free_page(page);
++      }
++}
++#endif
+ void mem_init(void)
+ {
+@@ -103,50 +96,15 @@
+       totalhigh_pages = highmem >> PAGE_SHIFT;
+       totalram_pages += totalhigh_pages;
+       num_physpages = totalram_pages;
+-      max_mapnr = totalram_pages;
+       max_pfn = totalram_pages;
+       printk(KERN_INFO "Memory: %luk available\n", 
+              (unsigned long) nr_free_pages() << (PAGE_SHIFT-10));
+       kmalloc_ok = 1;
+-}
+-
+-/* Changed during early boot */
+-static unsigned long kmem_top = 0;
+-
+-unsigned long get_kmem_end(void)
+-{
+-      if(kmem_top == 0)
+-              kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
+-      return(kmem_top);
+-}
+-
+-void set_kmem_end(unsigned long new)
+-{
+-      kmem_top = new;
+-}
+ #ifdef CONFIG_HIGHMEM
+-/* Changed during early boot */
+-pte_t *kmap_pte;
+-pgprot_t kmap_prot;
+-
+-EXPORT_SYMBOL(kmap_prot);
+-EXPORT_SYMBOL(kmap_pte);
+-
+-#define kmap_get_fixmap_pte(vaddr)                                    \
+-      pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
+-
+-void __init kmap_init(void)
+-{
+-      unsigned long kmap_vstart;
+-
+-      /* cache the first kmap pte */
+-      kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
+-      kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
+-
+-      kmap_prot = PAGE_KERNEL;
++      setup_highmem(end_iomem, highmem);
++#endif
+ }
+-#endif /* CONFIG_HIGHMEM */
+ static void __init fixrange_init(unsigned long start, unsigned long end, 
+                                pgd_t *pgd_base)
+@@ -178,76 +136,24 @@
+       }
+ }
+-int init_maps(struct mem_region *region)
+-{
+-      struct page *p, *map;
+-      int i, n, len;
+-
+-      if(region == &physmem_region){
+-              region->mem_map = mem_map;
+-              return(0);
+-      }
+-      else if(region->mem_map != NULL) return(0);
+-
+-      n = region->len >> PAGE_SHIFT;
+-      len = n * sizeof(struct page);
+-      if(kmalloc_ok){
+-              map = kmalloc(len, GFP_KERNEL);
+-              if(map == NULL) map = vmalloc(len);
+-      }
+-      else map = alloc_bootmem_low_pages(len);
+-
+-      if(map == NULL)
+-              return(-ENOMEM);
+-      for(i = 0; i < n; i++){
+-              p = &map[i];
+-              set_page_count(p, 0);
+-              SetPageReserved(p);
+-              INIT_LIST_HEAD(&p->list);
+-      }
+-      region->mem_map = map;
+-      return(0);
+-}
++#if CONFIG_HIGHMEM
++pte_t *kmap_pte;
++pgprot_t kmap_prot;
+-DECLARE_MUTEX(regions_sem);
++#define kmap_get_fixmap_pte(vaddr)                                    \
++      pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
+-static int setup_one_range(int fd, char *driver, unsigned long start, 
+-                         unsigned long pfn, int len, 
+-                         struct mem_region *region)
++void __init kmap_init(void)
+ {
+-      int i;
+-
+-      down(&regions_sem);
+-      for(i = 0; i < NREGIONS; i++){
+-              if(regions[i] == NULL) break;           
+-      }
+-      if(i == NREGIONS){
+-              printk("setup_range : no free regions\n");
+-              i = -1;
+-              goto out;
+-      }
+-
+-      if(fd == -1)
+-              fd = create_mem_file(len);
++      unsigned long kmap_vstart;
+-      if(region == NULL){
+-              region = alloc_bootmem_low_pages(sizeof(*region));
+-              if(region == NULL)
+-                      panic("Failed to allocating mem_region");
+-      }
++      /* cache the first kmap pte */
++      kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
++      kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
+-      *region = ((struct mem_region) { .driver        = driver,
+-                                       .start_pfn     = pfn,
+-                                       .start         = start, 
+-                                       .len           = len, 
+-                                       .fd            = fd } );
+-      regions[i] = region;
+- out:
+-      up(&regions_sem);
+-      return(i);
++      kmap_prot = PAGE_KERNEL;
+ }
+-#ifdef CONFIG_HIGHMEM
+ static void init_highmem(void)
+ {
+       pgd_t *pgd;
+@@ -268,63 +174,20 @@
+       kmap_init();
+ }
+-
+-void setup_highmem(unsigned long len)
+-{
+-      struct mem_region *region;
+-      struct page *page, *map;
+-      unsigned long phys;
+-      int i, cur, index;
+-
+-      phys = physmem_size;
+-      do {
+-              cur = min(len, (unsigned long) REGION_SIZE);
+-              i = setup_one_range(-1, NULL, -1, phys >> PAGE_SHIFT, cur, 
+-                                  NULL);
+-              if(i == -1){
+-                      printk("setup_highmem - setup_one_range failed\n");
+-                      return;
+-              }
+-              region = regions[i];
+-              index = phys / PAGE_SIZE;
+-              region->mem_map = &mem_map[index];
+-
+-              map = region->mem_map;
+-              for(i = 0; i < (cur >> PAGE_SHIFT); i++){
+-                      page = &map[i];
+-                      ClearPageReserved(page);
+-                      set_bit(PG_highmem, &page->flags);
+-                      atomic_set(&page->count, 1);
+-                      __free_page(page);
+-              }
+-              phys += cur;
+-              len -= cur;
+-      } while(len > 0);
+-}
+-#endif
++#endif /* CONFIG_HIGHMEM */
+ void paging_init(void)
+ {
+-      struct mem_region *region;
+-      unsigned long zones_size[MAX_NR_ZONES], start, end, vaddr;
+-      int i, index;
++      unsigned long zones_size[MAX_NR_ZONES], vaddr;
++      int i;
+       empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
+       empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE);
+       for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++) 
+               zones_size[i] = 0;
+-      zones_size[0] = (high_physmem >> PAGE_SHIFT) - 
+-              (uml_physmem >> PAGE_SHIFT);
++      zones_size[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT);
+       zones_size[2] = highmem >> PAGE_SHIFT;
+       free_area_init(zones_size);
+-      start = phys_region_index(__pa(uml_physmem));
+-      end = phys_region_index(__pa(high_physmem - 1));
+-      for(i = start; i <= end; i++){
+-              region = regions[i];
+-              index = (region->start - uml_physmem) / PAGE_SIZE;
+-              region->mem_map = &mem_map[index];
+-              if(i > start) free_bootmem(__pa(region->start), region->len);
+-      }
+       /*
+        * Fixed mappings, only the page table structure has to be
+@@ -335,15 +198,33 @@
+ #ifdef CONFIG_HIGHMEM
+       init_highmem();
+-      setup_highmem(highmem);
+ #endif
+ }
+-pte_t __bad_page(void)
++struct page *arch_validate(struct page *page, int mask, int order)
+ {
+-      clear_page(empty_bad_page);
+-        return pte_mkdirty(mk_pte((struct page *) empty_bad_page, 
+-                                PAGE_SHARED));
++      unsigned long addr, zero = 0;
++      int i;
++
++ again:
++      if(page == NULL) return(page);
++      if(PageHighMem(page)) return(page);
++
++      addr = (unsigned long) page_address(page);
++      for(i = 0; i < (1 << order); i++){
++              current->thread.fault_addr = (void *) addr;
++              if(__do_copy_to_user((void *) addr, &zero, 
++                                   sizeof(zero),
++                                   &current->thread.fault_addr,
++                                   &current->thread.fault_catcher)){
++                      if(!(mask & __GFP_WAIT)) return(NULL);
++                      else break;
++              }
++              addr += PAGE_SIZE;
++      }
++      if(i == (1 << order)) return(page);
++      page = alloc_pages(mask, order);
++      goto again;
+ }
+ /* This can't do anything because nothing in the kernel image can be freed
+@@ -401,395 +282,6 @@
+         printk("%d pages swap cached\n", cached);
+ }
+-static int __init uml_mem_setup(char *line, int *add)
+-{
+-      char *retptr;
+-      physmem_size = memparse(line,&retptr);
+-      return 0;
+-}
+-__uml_setup("mem=", uml_mem_setup,
+-"mem=<Amount of desired ram>\n"
+-"    This controls how much \"physical\" memory the kernel allocates\n"
+-"    for the system. The size is specified as a number followed by\n"
+-"    one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
+-"    This is not related to the amount of memory in the physical\n"
+-"    machine. It can be more, and the excess, if it's ever used, will\n"
+-"    just be swapped out.\n        Example: mem=64M\n\n"
+-);
+-
+-struct page *arch_validate(struct page *page, int mask, int order)
+-{
+-      unsigned long addr, zero = 0;
+-      int i;
+-
+- again:
+-      if(page == NULL) return(page);
+-      if(PageHighMem(page)) return(page);
+-
+-      addr = (unsigned long) page_address(page);
+-      for(i = 0; i < (1 << order); i++){
+-              current->thread.fault_addr = (void *) addr;
+-              if(__do_copy_to_user((void *) addr, &zero, 
+-                                   sizeof(zero),
+-                                   &current->thread.fault_addr,
+-                                   &current->thread.fault_catcher)){
+-                      if(!(mask & __GFP_WAIT)) return(NULL);
+-                      else break;
+-              }
+-              addr += PAGE_SIZE;
+-      }
+-      if(i == (1 << order)) return(page);
+-      page = alloc_pages(mask, order);
+-      goto again;
+-}
+-
+-DECLARE_MUTEX(vm_reserved_sem);
+-static struct list_head vm_reserved = LIST_HEAD_INIT(vm_reserved);
+-
+-/* Static structures, linked in to the list in early boot */
+-static struct vm_reserved head = {
+-      .list           = LIST_HEAD_INIT(head.list),
+-      .start          = 0,
+-      .end            = 0xffffffff
+-};
+-
+-static struct vm_reserved tail = {
+-      .list           = LIST_HEAD_INIT(tail.list),
+-      .start          = 0,
+-      .end            = 0xffffffff
+-};
+-
+-void set_usable_vm(unsigned long start, unsigned long end)
+-{
+-      list_add(&head.list, &vm_reserved);
+-      list_add(&tail.list, &head.list);
+-      head.end = start;
+-      tail.start = end;
+-}
+-
+-int reserve_vm(unsigned long start, unsigned long end, void *e)
+-             
+-{
+-      struct vm_reserved *entry = e, *reserved, *prev;
+-      struct list_head *ele;
+-      int err;
+-
+-      down(&vm_reserved_sem);
+-      list_for_each(ele, &vm_reserved){
+-              reserved = list_entry(ele, struct vm_reserved, list);
+-              if(reserved->start >= end) goto found;
+-      }
+-      panic("Reserved vm out of range");
+- found:
+-      prev = list_entry(ele->prev, struct vm_reserved, list);
+-      if(prev->end > start)
+-              panic("Can't reserve vm");
+-      if(entry == NULL)
+-              entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+-      if(entry == NULL){
+-              printk("reserve_vm : Failed to allocate entry\n");
+-              err = -ENOMEM;
+-              goto out;
+-      }
+-      *entry = ((struct vm_reserved) 
+-              { .list         = LIST_HEAD_INIT(entry->list),
+-                .start        = start,
+-                .end          = end });
+-      list_add(&entry->list, &prev->list);
+-      err = 0;
+- out:
+-      up(&vm_reserved_sem);
+-      return(0);
+-}
+-
+-unsigned long get_vm(unsigned long len)
+-{
+-      struct vm_reserved *this, *next;
+-      struct list_head *ele;
+-      unsigned long start;
+-      int err;
+-      
+-      down(&vm_reserved_sem);
+-      list_for_each(ele, &vm_reserved){
+-              this = list_entry(ele, struct vm_reserved, list);
+-              next = list_entry(ele->next, struct vm_reserved, list);
+-              if((this->start < next->start) && 
+-                 (this->end + len + PAGE_SIZE <= next->start))
+-                      goto found;
+-      }
+-      up(&vm_reserved_sem);
+-      return(0);
+- found:
+-      up(&vm_reserved_sem);
+-      start = (unsigned long) UML_ROUND_UP(this->end) + PAGE_SIZE;
+-      err = reserve_vm(start, start + len, NULL);
+-      if(err) return(0);
+-      return(start);
+-}
+-
+-int nregions(void)
+-{
+-      return(NREGIONS);
+-}
+-
+-void setup_range(int fd, char *driver, unsigned long start, unsigned long pfn,
+-               unsigned long len, int need_vm, struct mem_region *region, 
+-               void *reserved)
+-{
+-      int i, cur;
+-
+-      do {
+-              cur = min(len, (unsigned long) REGION_SIZE);
+-              i = setup_one_range(fd, driver, start, pfn, cur, region);
+-              region = regions[i];
+-              if(need_vm && setup_region(region, reserved)){
+-                      kfree(region);
+-                      regions[i] = NULL;
+-                      return;
+-              }
+-              start += cur;
+-              if(pfn != -1) pfn += cur;
+-              len -= cur;
+-      } while(len > 0);
+-}
+-
+-struct iomem {
+-      char *name;
+-      int fd;
+-      unsigned long size;
+-};
+-
+-/* iomem regions can only be added on the command line at the moment.  
+- * Locking will be needed when they can be added via mconsole.
+- */
+-
+-struct iomem iomem_regions[NREGIONS] = { [ 0 ... NREGIONS - 1 ] =
+-                                       { .name        = NULL,
+-                                         .fd          = -1,
+-                                         .size        = 0 } };
+-
+-int num_iomem_regions = 0;
+-
+-void add_iomem(char *name, int fd, unsigned long size)
+-{
+-      if(num_iomem_regions == sizeof(iomem_regions)/sizeof(iomem_regions[0]))
+-              return;
+-      size = (size + PAGE_SIZE - 1) & PAGE_MASK;
+-      iomem_regions[num_iomem_regions++] = 
+-              ((struct iomem) { .name         = name,
+-                                .fd           = fd,
+-                                .size         = size } );
+-}
+-
+-int setup_iomem(void)
+-{
+-      struct iomem *iomem;
+-      int i;
+-
+-      for(i = 0; i < num_iomem_regions; i++){
+-              iomem = &iomem_regions[i];
+-              setup_range(iomem->fd, iomem->name, -1, -1, iomem->size, 1, 
+-                          NULL, NULL);
+-      }
+-      return(0);
+-}
+-
+-__initcall(setup_iomem);
+-
+-#define PFN_UP(x)     (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+-#define PFN_DOWN(x)   ((x) >> PAGE_SHIFT)
+-
+-/* Changed during early boot */
+-static struct mem_region physmem_region;
+-static struct vm_reserved physmem_reserved;
+-
+-void setup_physmem(unsigned long start, unsigned long reserve_end,
+-                 unsigned long len)
+-{
+-      struct mem_region *region = &physmem_region;
+-      struct vm_reserved *reserved = &physmem_reserved;
+-      unsigned long cur, pfn = 0;
+-      int do_free = 1, bootmap_size;
+-
+-      do {
+-              cur = min(len, (unsigned long) REGION_SIZE);
+-              if(region == NULL) 
+-                      region = alloc_bootmem_low_pages(sizeof(*region));
+-              if(reserved == NULL) 
+-                      reserved = alloc_bootmem_low_pages(sizeof(*reserved));
+-              if((region == NULL) || (reserved == NULL))
+-                      panic("Couldn't allocate physmem region or vm "
+-                            "reservation\n");
+-              setup_range(-1, NULL, start, pfn, cur, 1, region, reserved);
+-
+-              if(do_free){
+-                      unsigned long reserve = reserve_end - start;
+-                      int pfn = PFN_UP(__pa(reserve_end));
+-                      int delta = (len - reserve) >> PAGE_SHIFT;
+-
+-                      bootmap_size = init_bootmem(pfn, pfn + delta);
+-                      free_bootmem(__pa(reserve_end) + bootmap_size,
+-                                   cur - bootmap_size - reserve);
+-                      do_free = 0;
+-              }
+-              start += cur;
+-              pfn += cur >> PAGE_SHIFT;
+-              len -= cur;
+-              region = NULL;
+-              reserved = NULL;
+-      } while(len > 0);
+-}
+-
+-struct mem_region *phys_region(unsigned long phys)
+-{
+-      unsigned int n = phys_region_index(phys);
+-
+-      if(regions[n] == NULL) 
+-              panic("Physical address in uninitialized region");
+-      return(regions[n]);
+-}
+-
+-unsigned long phys_offset(unsigned long phys)
+-{
+-      return(phys_addr(phys));
+-}
+-
+-struct page *phys_mem_map(unsigned long phys)
+-{
+-      return((struct page *) phys_region(phys)->mem_map);
+-}
+-
+-struct page *pte_mem_map(pte_t pte)
+-{
+-      return(phys_mem_map(pte_val(pte)));
+-}
+-
+-struct mem_region *page_region(struct page *page, int *index_out)
+-{
+-      int i;
+-      struct mem_region *region;
+-      struct page *map;
+-
+-      for(i = 0; i < NREGIONS; i++){
+-              region = regions[i];
+-              if(region == NULL) continue;
+-              map = region->mem_map;
+-              if((page >= map) && (page < &map[region->len >> PAGE_SHIFT])){
+-                      if(index_out != NULL) *index_out = i;
+-                      return(region);
+-              }
+-      }
+-      panic("No region found for page");
+-      return(NULL);
+-}
+-
+-unsigned long page_to_pfn(struct page *page)
+-{
+-      struct mem_region *region = page_region(page, NULL);
+-
+-      return(region->start_pfn + (page - (struct page *) region->mem_map));
+-}
+-
+-struct mem_region *pfn_to_region(unsigned long pfn, int *index_out)
+-{
+-      struct mem_region *region;
+-      int i;
+-
+-      for(i = 0; i < NREGIONS; i++){
+-              region = regions[i];
+-              if(region == NULL)
+-                      continue;
+-
+-              if((region->start_pfn <= pfn) &&
+-                 (region->start_pfn + (region->len >> PAGE_SHIFT) > pfn)){
+-                      if(index_out != NULL) 
+-                              *index_out = i;
+-                      return(region);
+-              }
+-      }
+-      return(NULL);
+-}
+-
+-struct page *pfn_to_page(unsigned long pfn)
+-{
+-      struct mem_region *region = pfn_to_region(pfn, NULL);
+-      struct page *mem_map = (struct page *) region->mem_map;
+-
+-      return(&mem_map[pfn - region->start_pfn]);
+-}
+-
+-unsigned long phys_to_pfn(unsigned long p)
+-{
+-      struct mem_region *region = regions[phys_region_index(p)];
+-
+-      return(region->start_pfn + (phys_addr(p) >> PAGE_SHIFT));
+-}
+-
+-unsigned long pfn_to_phys(unsigned long pfn)
+-{
+-      int n;
+-      struct mem_region *region = pfn_to_region(pfn, &n);
+-
+-      return(mk_phys((pfn - region->start_pfn) << PAGE_SHIFT, n));
+-}
+-
+-struct page *page_mem_map(struct page *page)
+-{
+-      return((struct page *) page_region(page, NULL)->mem_map);
+-}
+-
+-extern unsigned long region_pa(void *virt)
+-{
+-      struct mem_region *region;
+-      unsigned long addr = (unsigned long) virt;
+-      int i;
+-
+-      for(i = 0; i < NREGIONS; i++){
+-              region = regions[i];
+-              if(region == NULL) continue;
+-              if((region->start <= addr) && 
+-                 (addr <= region->start + region->len))
+-                      return(mk_phys(addr - region->start, i));
+-      }
+-      panic("region_pa : no region for virtual address");
+-      return(0);
+-}
+-
+-extern void *region_va(unsigned long phys)
+-{
+-      return((void *) (phys_region(phys)->start + phys_addr(phys)));
+-}
+-
+-unsigned long page_to_phys(struct page *page)
+-{
+-      int n;
+-      struct mem_region *region = page_region(page, &n);
+-      struct page *map = region->mem_map;
+-      return(mk_phys((page - map) << PAGE_SHIFT, n));
+-}
+-
+-struct page *phys_to_page(unsigned long phys)
+-{
+-      struct page *mem_map;
+-
+-      mem_map = phys_mem_map(phys);
+-      return(mem_map + (phys_offset(phys) >> PAGE_SHIFT));
+-}
+-
+-static int setup_mem_maps(void)
+-{
+-      struct mem_region *region;
+-      int i;
+-
+-      for(i = 0; i < NREGIONS; i++){
+-              region = regions[i];
+-              if((region != NULL) && (region->fd > 0)) init_maps(region);
+-      }
+-      return(0);
+-}
+-
+-__initcall(setup_mem_maps);
+-
+ /*
+  * Allocate and free page tables.
+  */
+diff -Naur a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c
+--- a/arch/um/kernel/mem_user.c        2004-01-08 22:22:10.000000000 -0500
++++ b/arch/um/kernel/mem_user.c        2004-01-08 22:29:21.000000000 -0500
+@@ -34,10 +34,9 @@
+ #include <stddef.h>
+ #include <stdarg.h>
+ #include <unistd.h>
+-#include <fcntl.h>
+ #include <errno.h>
+ #include <string.h>
+-#include <sys/stat.h>
++#include <fcntl.h>
+ #include <sys/types.h>
+ #include <sys/mman.h>
+ #include "kern_util.h"
+@@ -47,105 +46,145 @@
+ #include "init.h"
+ #include "os.h"
+ #include "tempfile.h"
++#include "kern_constants.h"
+ extern struct mem_region physmem_region;
+ #define TEMPNAME_TEMPLATE "vm_file-XXXXXX"
+-int create_mem_file(unsigned long len)
++static int create_tmp_file(unsigned long len)
+ {
+-      int fd;
++      int fd, err;
+       char zero;
+       fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1);
+-      if (fchmod(fd, 0777) < 0){
+-              perror("fchmod");
++      if(fd < 0) {
++              os_print_error(fd, "make_tempfile");
++              exit(1);
++      }
++
++      err = os_mode_fd(fd, 0777);
++      if(err < 0){
++              os_print_error(err, "os_mode_fd");
+               exit(1);
+       }
+-      if(os_seek_file(fd, len) < 0){
+-              perror("lseek");
++      err = os_seek_file(fd, len);
++      if(err < 0){
++              os_print_error(err, "os_seek_file");
+               exit(1);
+       }
+       zero = 0;
+-      if(write(fd, &zero, 1) != 1){
+-              perror("write");
++      err = os_write_file(fd, &zero, 1);
++      if(err != 1){
++              os_print_error(err, "os_write_file");
+               exit(1);
+       }
+-      if(fcntl(fd, F_SETFD, 1) != 0)
+-              perror("Setting FD_CLOEXEC failed");
++
+       return(fd);
+ }
+-int setup_region(struct mem_region *region, void *entry)
++static int have_devanon = 0;
++
++void check_devanon(void)
++{
++      int fd;
++
++      printk("Checking for /dev/anon on the host...");
++      fd = open("/dev/anon", O_RDWR);
++      if(fd < 0){
++              printk("Not available (open failed with errno %d)\n", errno);
++              return;
++      }
++
++      printk("OK\n");
++      have_devanon = 1;
++}
++
++static int create_anon_file(unsigned long len)
+ {
+-      void *loc, *start;
+-      char *driver;
+-      int err, offset;
+-
+-      if(region->start != -1){
+-              err = reserve_vm(region->start, 
+-                               region->start + region->len, entry);
+-              if(err){
+-                      printk("setup_region : failed to reserve "
+-                             "0x%x - 0x%x for driver '%s'\n",
+-                             region->start, 
+-                             region->start + region->len,
+-                             region->driver);
+-                      return(-1);
+-              }
+-      }
+-      else region->start = get_vm(region->len);
+-      if(region->start == 0){
+-              if(region->driver == NULL) driver = "physmem";
+-              else driver = region->driver;
+-              printk("setup_region : failed to find vm for "
+-                     "driver '%s' (length %d)\n", driver, region->len);
+-              return(-1);
+-      }
+-      if(region->start == uml_physmem){
+-              start = (void *) uml_reserved;
+-              offset = uml_reserved - uml_physmem;
+-      }
+-      else {
+-              start = (void *) region->start;
+-              offset = 0;
+-      }
+-
+-      loc = mmap(start, region->len - offset, PROT_READ | PROT_WRITE, 
+-                 MAP_SHARED | MAP_FIXED, region->fd, offset);
+-      if(loc != start){
+-              perror("Mapping memory");
++      void *addr;
++      int fd;
++
++      fd = open("/dev/anon", O_RDWR);
++      if(fd < 0) {
++              os_print_error(fd, "opening /dev/anon");
+               exit(1);
+       }
+-      return(0);
++
++      addr = mmap(NULL, len, PROT_READ | PROT_WRITE , MAP_PRIVATE, fd, 0);
++      if(addr == MAP_FAILED){
++              os_print_error((int) addr, "mapping physmem file");
++              exit(1);
++      }
++      munmap(addr, len);
++
++      return(fd);
++}
++
++int create_mem_file(unsigned long len)
++{
++      int err, fd;
++
++      if(have_devanon)
++              fd = create_anon_file(len);
++      else fd = create_tmp_file(len);
++
++      err = os_set_exec_close(fd, 1);
++      if(err < 0)
++              os_print_error(err, "exec_close");
++      return(fd);
+ }
++struct iomem_region *iomem_regions = NULL;
++int iomem_size = 0;
++
+ static int __init parse_iomem(char *str, int *add)
+ {
+-      struct stat buf;
++      struct iomem_region *new;
++      struct uml_stat buf;
+       char *file, *driver;
+-      int fd;
++      int fd, err;
+       driver = str;
+       file = strchr(str,',');
+       if(file == NULL){
+-              printk("parse_iomem : failed to parse iomem\n");
+-              return(1);
++              printf("parse_iomem : failed to parse iomem\n");
++              goto out;
+       }
+       *file = '\0';
+       file++;
+       fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0);
+       if(fd < 0){
+-              printk("parse_iomem - Couldn't open io file, errno = %d\n", 
+-                     errno);
+-              return(1);
+-      }
+-      if(fstat(fd, &buf) < 0) {
+-              printk("parse_iomem - cannot fstat file, errno = %d\n", errno);
+-              return(1);
++              os_print_error(fd, "parse_iomem - Couldn't open io file");
++              goto out;
+       }
+-      add_iomem(driver, fd, buf.st_size);
++
++      err = os_stat_fd(fd, &buf);
++      if(err < 0){
++              os_print_error(err, "parse_iomem - cannot stat_fd file");
++              goto out_close;
++      }
++
++      new = malloc(sizeof(*new));
++      if(new == NULL){
++              perror("Couldn't allocate iomem_region struct");
++              goto out_close;
++      }
++
++      *new = ((struct iomem_region) { .next           = iomem_regions,
++                                      .driver         = driver,
++                                      .fd             = fd,
++                                      .size           = buf.ust_size,
++                                      .phys           = 0,
++                                      .virt           = 0 });
++      iomem_regions = new;
++      iomem_size += new->size + UM_KERN_PAGE_SIZE;
++
+       return(0);
++ out_close:
++      os_close_file(fd);
++ out:
++      return(1);
+ }
+ __uml_setup("iomem=", parse_iomem,
+@@ -153,73 +192,20 @@
+ "    Configure <file> as an IO memory region named <name>.\n\n"
+ );
+-#ifdef notdef
+-int logging = 0;
+-int logging_fd = -1;
+-
+-int logging_line = 0;
+-char logging_buf[256];
+-
+-void log(char *fmt, ...)
+-{
+-      va_list ap;
+-      struct timeval tv;
+-      struct openflags flags;
+-
+-      if(logging == 0) return;
+-      if(logging_fd < 0){
+-              flags = of_create(of_trunc(of_rdrw(OPENFLAGS())));
+-              logging_fd = os_open_file("log", flags, 0644);
+-      }
+-      gettimeofday(&tv, NULL);
+-      sprintf(logging_buf, "%d\t %u.%u  ", logging_line++, tv.tv_sec, 
+-              tv.tv_usec);
+-      va_start(ap, fmt);
+-      vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap);
+-      va_end(ap);
+-      write(logging_fd, logging_buf, strlen(logging_buf));
+-}
+-#endif
+-
+-int map_memory(unsigned long virt, unsigned long phys, unsigned long len, 
+-             int r, int w, int x)
+-{
+-      struct mem_region *region = phys_region(phys);
+-
+-      return(os_map_memory((void *) virt, region->fd, phys_offset(phys), len,
+-                           r, w, x));
+-}
+-
+ int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x,
+                  int must_succeed)
+ {
+-      if(os_protect_memory((void *) addr, len, r, w, x) < 0){
++      int err;
++
++      err = os_protect_memory((void *) addr, len, r, w, x);
++      if(err < 0){
+                 if(must_succeed)
+-                        panic("protect failed, errno = %d", errno);
+-                else return(-errno);
++                      panic("protect failed, err = %d", -err);
++              else return(err);
+       }
+       return(0);
+ }
+-unsigned long find_iomem(char *driver, unsigned long *len_out)
+-{
+-      struct mem_region *region;
+-      int i, n;
+-
+-      n = nregions();
+-      for(i = 0; i < n; i++){
+-              region = regions[i];
+-              if(region == NULL) continue;
+-              if((region->driver != NULL) &&
+-                 !strcmp(region->driver, driver)){
+-                      *len_out = region->len;
+-                      return(region->start);
+-              }
+-      }
+-      *len_out = 0;
+-      return 0;
+-}
+-
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+diff -Naur a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
+--- a/arch/um/kernel/physmem.c 1969-12-31 19:00:00.000000000 -0500
++++ b/arch/um/kernel/physmem.c 2004-01-08 22:20:43.000000000 -0500
+@@ -0,0 +1,349 @@
++/* 
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "linux/ghash.h"
++#include "linux/slab.h"
++#include "linux/vmalloc.h"
++#include "linux/bootmem.h"
++#include "asm/types.h"
++#include "asm/pgtable.h"
++#include "kern_util.h"
++#include "user_util.h"
++#include "mode_kern.h"
++#include "mem.h"
++#include "mem_user.h"
++#include "os.h"
++#include "kern.h"
++#include "init.h"
++
++#define PHYS_HASHSIZE (8192)
++
++struct phys_desc;
++
++DEF_HASH_STRUCTS(virtmem, PHYS_HASHSIZE, struct phys_desc);
++
++struct phys_desc {
++      struct virtmem_ptrs virt_ptrs;
++      int fd;
++      __u64 offset;
++      void *virt;
++      unsigned long phys;
++};
++
++struct virtmem_table virtmem_hash;
++
++static int virt_cmp(void *virt1, void *virt2)
++{
++      return(virt1 != virt2);
++}
++
++static int virt_hash(void *virt)
++{
++      unsigned long addr = ((unsigned long) virt) >> PAGE_SHIFT;
++      return(addr % PHYS_HASHSIZE);
++}
++
++DEF_HASH(static, virtmem, struct phys_desc, virt_ptrs, void *, virt, virt_cmp, 
++       virt_hash);
++
++int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w)
++{
++      struct phys_desc *desc;
++      unsigned long phys;
++      int err;
++
++      virt = (void *) ((unsigned long) virt & PAGE_MASK);
++      err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0);
++      if(err)
++              goto out;
++
++      phys = __pa(virt);
++      if(find_virtmem_hash(&virtmem_hash, virt) != NULL)
++              panic("Address 0x%p is already substituted\n", virt);
++
++      err = -ENOMEM;
++      desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
++      if(desc == NULL)
++              goto out;
++
++      *desc = ((struct phys_desc) { .virt_ptrs =      { NULL, NULL },
++                                    .fd =             fd,
++                                    .offset =         offset,
++                                    .virt =           virt,
++                                    .phys =           __pa(virt) });
++      insert_virtmem_hash(&virtmem_hash, desc);
++      err = 0;
++ out:
++      return(err);
++}
++
++static int physmem_fd = -1;
++
++int physmem_remove_mapping(void *virt)
++{
++      struct phys_desc *desc;
++      int err;
++
++      virt = (void *) ((unsigned long) virt & PAGE_MASK);
++      desc = find_virtmem_hash(&virtmem_hash, virt);
++      if(desc == NULL)
++              return(0);
++
++      remove_virtmem_hash(&virtmem_hash, desc);
++      kfree(desc);
++
++      err = os_map_memory(virt, physmem_fd, __pa(virt), PAGE_SIZE, 1, 1, 0);
++      if(err)
++              panic("Failed to unmap block device page from physical memory, "
++                    "errno = %d", -err);
++      return(1);
++}
++
++void arch_free_page(struct page *page, int order)
++{
++      void *virt;
++      int i;
++
++      for(i = 0; i < 1 << order; i++){
++              virt = __va(page_to_phys(page + i));
++              physmem_remove_mapping(virt);
++      }
++}
++
++int is_remapped(void *virt)
++{
++      return(find_virtmem_hash(&virtmem_hash, virt) != NULL);
++}
++
++/* Changed during early boot */
++unsigned long high_physmem;
++
++extern unsigned long physmem_size;
++
++void *to_virt(unsigned long phys)
++{
++      return((void *) uml_physmem + phys);
++}
++
++unsigned long to_phys(void *virt)
++{
++      return(((unsigned long) virt) - uml_physmem);
++}
++
++int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem)
++{
++      struct page *p, *map;
++      unsigned long phys_len, phys_pages, highmem_len, highmem_pages;
++      unsigned long iomem_len, iomem_pages, total_len, total_pages;
++      int i;
++
++      phys_pages = physmem >> PAGE_SHIFT;
++      phys_len = phys_pages * sizeof(struct page);
++
++      iomem_pages = iomem >> PAGE_SHIFT;
++      iomem_len = iomem_pages * sizeof(struct page);
++
++      highmem_pages = highmem >> PAGE_SHIFT;
++      highmem_len = highmem_pages * sizeof(struct page);
++
++      total_pages = phys_pages + iomem_pages + highmem_pages;
++      total_len = phys_len + iomem_pages + highmem_len;
++
++      if(kmalloc_ok){
++              map = kmalloc(total_len, GFP_KERNEL);
++              if(map == NULL) 
++                      map = vmalloc(total_len);
++      }
++      else map = alloc_bootmem_low_pages(total_len);
++
++      if(map == NULL)
++              return(-ENOMEM);
++
++      for(i = 0; i < total_pages; i++){
++              p = &map[i];
++              set_page_count(p, 0);
++              SetPageReserved(p);
++              INIT_LIST_HEAD(&p->list);
++      }
++
++      mem_map = map;
++      max_mapnr = total_pages;
++      return(0);
++}
++
++struct page *phys_to_page(const unsigned long phys)
++{
++      return(&mem_map[phys >> PAGE_SHIFT]);
++}
++
++struct page *__virt_to_page(const unsigned long virt)
++{
++      return(&mem_map[__pa(virt) >> PAGE_SHIFT]);
++}
++
++unsigned long page_to_phys(struct page *page)
++{
++      return((page - mem_map) << PAGE_SHIFT);
++}
++
++pte_t mk_pte(struct page *page, pgprot_t pgprot)
++{
++      pte_t pte;
++
++      pte_val(pte) = page_to_phys(page) + pgprot_val(pgprot);
++      if(pte_present(pte)) pte_mknewprot(pte_mknewpage(pte));
++      return(pte);
++}
++
++/* Changed during early boot */
++static unsigned long kmem_top = 0;
++
++unsigned long get_kmem_end(void)
++{
++      if(kmem_top == 0) 
++              kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas);
++      return(kmem_top);
++}
++
++void map_memory(unsigned long virt, unsigned long phys, unsigned long len, 
++              int r, int w, int x)
++{
++      __u64 offset;
++      int fd, err;
++
++      fd = phys_mapping(phys, &offset);
++      err = os_map_memory((void *) virt, fd, offset, len, r, w, x);
++      if(err)
++              panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, "
++                    "err = %d\n", virt, fd, offset, len, r, w, x, err);
++}
++
++#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
++
++void setup_physmem(unsigned long start, unsigned long reserve_end,
++                 unsigned long len, unsigned long highmem)
++{
++      unsigned long reserve = reserve_end - start;
++      int pfn = PFN_UP(__pa(reserve_end));
++      int delta = (len - reserve) >> PAGE_SHIFT;
++      int err, offset, bootmap_size;
++
++      physmem_fd = create_mem_file(len + highmem);
++
++      offset = uml_reserved - uml_physmem;
++      err = os_map_memory((void *) uml_reserved, physmem_fd, offset, 
++                          len - offset, 1, 1, 0);
++      if(err < 0){
++              os_print_error(err, "Mapping memory");
++              exit(1);
++      }
++
++      bootmap_size = init_bootmem(pfn, pfn + delta);
++      free_bootmem(__pa(reserve_end) + bootmap_size,
++                   len - bootmap_size - reserve);
++}
++
++int phys_mapping(unsigned long phys, __u64 *offset_out)
++{
++      struct phys_desc *desc = find_virtmem_hash(&virtmem_hash, 
++                                                 __va(phys & PAGE_MASK));
++      int fd = -1;
++
++      if(desc != NULL){
++              fd = desc->fd;
++              *offset_out = desc->offset;
++      }
++      else if(phys < physmem_size){
++              fd = physmem_fd;
++              *offset_out = phys;
++      }
++      else if(phys < __pa(end_iomem)){
++              struct iomem_region *region = iomem_regions;
++      
++              while(region != NULL){
++                      if((phys >= region->phys) && 
++                         (phys < region->phys + region->size)){
++                              fd = region->fd;
++                              *offset_out = phys - region->phys;
++                              break;
++                      }
++                      region = region->next;
++              }
++      }
++      else if(phys < __pa(end_iomem) + highmem){
++              fd = physmem_fd;
++              *offset_out = phys - iomem_size;
++      }
++
++      return(fd);
++}
++
++static int __init uml_mem_setup(char *line, int *add)
++{
++      char *retptr;
++      physmem_size = memparse(line,&retptr);
++      return 0;
++}
++__uml_setup("mem=", uml_mem_setup,
++"mem=<Amount of desired ram>\n"
++"    This controls how much \"physical\" memory the kernel allocates\n"
++"    for the system. The size is specified as a number followed by\n"
++"    one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n"
++"    This is not related to the amount of memory in the host.  It can\n"
++"    be more, and the excess, if it's ever used, will just be swapped out.\n"
++"     Example: mem=64M\n\n"
++);
++
++unsigned long find_iomem(char *driver, unsigned long *len_out)
++{
++      struct iomem_region *region = iomem_regions;
++      
++      while(region != NULL){
++              if(!strcmp(region->driver, driver)){
++                      *len_out = region->size;
++                      return(region->virt);
++              }
++      }
++
++      return(0);
++}
++
++int setup_iomem(void)
++{
++      struct iomem_region *region = iomem_regions;
++      unsigned long iomem_start = high_physmem + PAGE_SIZE;
++      int err;
++
++      while(region != NULL){
++              err = os_map_memory((void *) iomem_start, region->fd, 0, 
++                                  region->size, 1, 1, 0);
++              if(err)
++                      printk("Mapping iomem region for driver '%s' failed, "
++                             "errno = %d\n", region->driver, -err);
++              else {
++                      region->virt = iomem_start;
++                      region->phys = __pa(region->virt);
++              }
++
++              iomem_start += region->size + PAGE_SIZE;
++              region = region->next;
++      }
++
++      return(0);
++}
++
++__initcall(setup_iomem);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/arch/um/kernel/process.c b/arch/um/kernel/process.c
+--- a/arch/um/kernel/process.c 2004-01-08 22:29:24.000000000 -0500
++++ b/arch/um/kernel/process.c 2004-01-08 22:35:08.000000000 -0500
+@@ -9,12 +9,10 @@
+ #include <sched.h>
+ #include <errno.h>
+ #include <stdarg.h>
+-#include <fcntl.h>
+ #include <stdlib.h>
+ #include <setjmp.h>
+ #include <sys/time.h>
+ #include <sys/ptrace.h>
+-#include <sys/ioctl.h>
+ #include <sys/wait.h>
+ #include <sys/mman.h>
+ #include <asm/ptrace.h>
+@@ -58,7 +56,11 @@
+ {
+       int flags = altstack ? SA_ONSTACK : 0;
+-      set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
++      /* NODEFER is set here because SEGV isn't turned back on when the 
++       * handler is ready to receive signals.  This causes any segfault
++       * during a copy_user to kill the process because the fault is blocked.
++       */
++      set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags | SA_NODEFER,
+                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+       set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, 
+                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+@@ -72,7 +74,6 @@
+                   SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
+       set_handler(SIGUSR2, (__sighandler_t) sig_handler, 
+                   SA_NOMASK | flags, -1);
+-      (void) CHOOSE_MODE(signal(SIGCHLD, SIG_IGN), (void *) 0);
+       signal(SIGHUP, SIG_IGN);
+       init_irq_signals(altstack);
+@@ -123,11 +124,12 @@
+       /* Start the process and wait for it to kill itself */
+       new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
+       if(new_pid < 0) return(-errno);
+-      while((err = waitpid(new_pid, &status, 0) < 0) && (errno == EINTR)) ;
++      while(((err = waitpid(new_pid, &status, 0)) < 0) && (errno == EINTR)) ;
+       if(err < 0) panic("Waiting for outer trampoline failed - errno = %d", 
+                         errno);
+       if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
+-              panic("outer trampoline didn't exit with SIGKILL");
++              panic("outer trampoline didn't exit with SIGKILL, "
++                    "status = %d", status);
+       return(arg.pid);
+ }
+@@ -138,7 +140,7 @@
+       os_stop_process(os_getpid());
+-      if(read(fd, &c, sizeof(c)) != sizeof(c))
++      if(os_read_file(fd, &c, sizeof(c)) != sizeof(c))
+               panic("read failed in suspend_new_thread");
+ }
+@@ -233,7 +235,7 @@
+       int n;
+       *jmp_ptr = &buf;
+-      n = setjmp(buf);
++      n = sigsetjmp(buf, 1);
+       if(n != 0)
+               return(n);
+       (*fn)(arg);
+@@ -273,7 +275,7 @@
+       stop_ptraced_child(pid, stack, 1);
+       printf("Checking for /proc/mm...");
+-      if(access("/proc/mm", W_OK)){
++      if(os_access("/proc/mm", OS_ACC_W_OK) < 0){
+               printf("not found\n");
+               ret = 0;
+       }
+diff -Naur a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
+--- a/arch/um/kernel/process_kern.c    2004-01-08 22:21:59.000000000 -0500
++++ b/arch/um/kernel/process_kern.c    2004-01-08 22:28:53.000000000 -0500
+@@ -16,6 +16,7 @@
+ #include "linux/module.h"
+ #include "linux/init.h"
+ #include "linux/capability.h"
++#include "linux/spinlock.h"
+ #include "asm/unistd.h"
+ #include "asm/mman.h"
+ #include "asm/segment.h"
+@@ -23,7 +24,6 @@
+ #include "asm/pgtable.h"
+ #include "asm/processor.h"
+ #include "asm/tlbflush.h"
+-#include "asm/spinlock.h"
+ #include "asm/uaccess.h"
+ #include "asm/user.h"
+ #include "user_util.h"
+@@ -52,17 +52,12 @@
+ struct task_struct *get_task(int pid, int require)
+ {
+-        struct task_struct *task, *ret;
++        struct task_struct *ret;
+-        ret = NULL;
+         read_lock(&tasklist_lock);
+-        for_each_process(task){
+-                if(task->pid == pid){
+-                        ret = task;
+-                        break;
+-                }
+-        }
++      ret = find_task_by_pid(pid);
+         read_unlock(&tasklist_lock);
++
+         if(require && (ret == NULL)) panic("get_task couldn't find a task\n");
+         return(ret);
+ }
+@@ -95,7 +90,8 @@
+       int flags = GFP_KERNEL;
+       if(atomic) flags |= GFP_ATOMIC;
+-      if((page = __get_free_pages(flags, order)) == 0)
++      page = __get_free_pages(flags, order);
++      if(page == 0)
+               return(0);
+       stack_protections(page);
+       return(page);
+@@ -103,13 +99,15 @@
+ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+ {
+-      struct task_struct *p;
++      int pid;
+       current->thread.request.u.thread.proc = fn;
+       current->thread.request.u.thread.arg = arg;
+-      p = do_fork(CLONE_VM | flags, 0, NULL, 0, NULL, NULL);
+-      if(IS_ERR(p)) panic("do_fork failed in kernel_thread");
+-      return(p->pid);
++      pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0, NULL, 
++                    NULL);
++      if(pid < 0)
++              panic("do_fork failed in kernel_thread, errno = %d", pid);
++      return(pid);
+ }
+ void switch_mm(struct mm_struct *prev, struct mm_struct *next, 
+@@ -129,7 +127,7 @@
+               { external_pid(task), task });
+ }
+-void *switch_to(void *prev, void *next, void *last)
++void *_switch_to(void *prev, void *next, void *last)
+ {
+       return(CHOOSE_MODE(switch_to_tt(prev, next), 
+                          switch_to_skas(prev, next)));
+@@ -149,7 +147,7 @@
+ void exit_thread(void)
+ {
+       CHOOSE_MODE(exit_thread_tt(), exit_thread_skas());
+-      unprotect_stack((unsigned long) current->thread_info);
++      unprotect_stack((unsigned long) current_thread);
+ }
+  
+ void *get_current(void)
+@@ -157,6 +155,10 @@
+       return(current);
+ }
++void prepare_to_copy(struct task_struct *tsk)
++{
++}
++
+ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
+               unsigned long stack_top, struct task_struct * p, 
+               struct pt_regs *regs)
+@@ -190,7 +192,7 @@
+ void default_idle(void)
+ {
+-      idle_timer();
++      uml_idle_timer();
+       atomic_inc(&init_mm.mm_count);
+       current->mm = &init_mm;
+@@ -367,10 +369,15 @@
+       return(clear_user(buf, size));
+ }
++int strlen_user_proc(char *str)
++{
++      return(strlen_user(str));
++}
++
+ int smp_sigio_handler(void)
+ {
+ #ifdef CONFIG_SMP
+-      int cpu = current->thread_info->cpu;
++      int cpu = current_thread->cpu;
+       IPI_handler(cpu);
+       if(cpu != 0)
+               return(1);
+@@ -385,7 +392,7 @@
+ int cpu(void)
+ {
+-      return(current->thread_info->cpu);
++      return(current_thread->cpu);
+ }
+ /*
+diff -Naur a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
+--- a/arch/um/kernel/ptrace.c  2004-01-08 22:15:02.000000000 -0500
++++ b/arch/um/kernel/ptrace.c  2004-01-08 22:20:32.000000000 -0500
+@@ -311,11 +311,8 @@
+       /* the 0x80 provides a way for the tracing parent to distinguish
+          between a syscall stop and SIGTRAP delivery */
+-      current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+-                                      ? 0x80 : 0);
+-      current->state = TASK_STOPPED;
+-      notify_parent(current, SIGCHLD);
+-      schedule();
++      ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
++                               ? 0x80 : 0));
+       /*
+        * this isn't the same as continuing with a signal, but it will do
+diff -Naur a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
+--- a/arch/um/kernel/reboot.c  2004-01-08 22:21:48.000000000 -0500
++++ b/arch/um/kernel/reboot.c  2004-01-08 22:28:40.000000000 -0500
+@@ -15,6 +15,7 @@
+ #ifdef CONFIG_SMP
+ static void kill_idlers(int me)
+ {
++#ifdef CONFIG_MODE_TT
+       struct task_struct *p;
+       int i;
+@@ -23,6 +24,7 @@
+               if((p != NULL) && (p->thread.mode.tt.extern_pid != me))
+                       os_kill_process(p->thread.mode.tt.extern_pid, 0);
+       }
++#endif
+ }
+ #endif
+diff -Naur a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c
+--- a/arch/um/kernel/sigio_kern.c      2004-01-08 22:16:51.000000000 -0500
++++ b/arch/um/kernel/sigio_kern.c      2004-01-08 22:22:53.000000000 -0500
+@@ -6,18 +6,21 @@
+ #include "linux/kernel.h"
+ #include "linux/list.h"
+ #include "linux/slab.h"
+-#include "asm/irq.h"
++#include "linux/signal.h"
++#include "linux/interrupt.h"
+ #include "init.h"
+ #include "sigio.h"
+ #include "irq_user.h"
++#include "irq_kern.h"
+ /* Protected by sigio_lock() called from write_sigio_workaround */
+ static int sigio_irq_fd = -1;
+-void sigio_interrupt(int irq, void *data, struct pt_regs *unused)
++irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused)
+ {
+       read_sigio_fd(sigio_irq_fd);
+       reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
++      return(IRQ_HANDLED);
+ }
+ int write_sigio_irq(int fd)
+diff -Naur a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c
+--- a/arch/um/kernel/sigio_user.c      2004-01-08 22:31:33.000000000 -0500
++++ b/arch/um/kernel/sigio_user.c      2004-01-08 22:36:15.000000000 -0500
+@@ -7,7 +7,6 @@
+ #include <stdlib.h>
+ #include <termios.h>
+ #include <pty.h>
+-#include <fcntl.h>
+ #include <signal.h>
+ #include <errno.h>
+ #include <string.h>
+@@ -26,7 +25,7 @@
+ int pty_close_sigio = 0;
+ /* Used as a flag during SIGIO testing early in boot */
+-static int got_sigio = 0;
++static volatile int got_sigio = 0;
+ void __init handler(int sig)
+ {
+@@ -45,7 +44,7 @@
+       info->err = 0;
+       if(openpty(&info->master, &info->slave, NULL, NULL, NULL))
+-              info->err = errno;
++              info->err = -errno;
+ }
+ void __init check_one_sigio(void (*proc)(int, int))
+@@ -53,11 +52,11 @@
+       struct sigaction old, new;
+       struct termios tt;
+       struct openpty_arg pty = { .master = -1, .slave = -1 };
+-      int master, slave, flags;
++      int master, slave, err;
+       initial_thread_cb(openpty_cb, &pty);
+       if(pty.err){
+-              printk("openpty failed, errno = %d\n", pty.err);
++              printk("openpty failed, errno = %d\n", -pty.err);
+               return;
+       }
+@@ -69,23 +68,16 @@
+               return;
+       }
++      /* XXX These can fail with EINTR */
+       if(tcgetattr(master, &tt) < 0)
+               panic("check_sigio : tcgetattr failed, errno = %d\n", errno);
+       cfmakeraw(&tt);
+       if(tcsetattr(master, TCSADRAIN, &tt) < 0)
+               panic("check_sigio : tcsetattr failed, errno = %d\n", errno);
+-      if((flags = fcntl(master, F_GETFL)) < 0)
+-              panic("tty_fds : fcntl F_GETFL failed, errno = %d\n", errno);
+-
+-      if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
+-         (fcntl(master, F_SETOWN, os_getpid()) < 0))
+-              panic("check_sigio : fcntl F_SETFL or F_SETOWN failed, "
+-                    "errno = %d\n", errno);
+-
+-      if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0))
+-              panic("check_sigio : fcntl F_SETFL failed, errno = %d\n", 
+-                    errno);
++      err = os_sigio_async(master, slave);
++      if(err < 0)
++              panic("tty_fds : sigio_async failed, err = %d\n", -err);
+       if(sigaction(SIGIO, NULL, &old) < 0)
+               panic("check_sigio : sigaction 1 failed, errno = %d\n", errno);
+@@ -97,8 +89,8 @@
+       got_sigio = 0;
+       (*proc)(master, slave);
+               
+-      close(master);
+-      close(slave);
++      os_close_file(master);
++      os_close_file(slave);
+       if(sigaction(SIGIO, &old, NULL) < 0)
+               panic("check_sigio : sigaction 3 failed, errno = %d\n", errno);
+@@ -112,25 +104,25 @@
+       printk("Checking that host ptys support output SIGIO...");
+       memset(buf, 0, sizeof(buf));
+-      while(write(master, buf, sizeof(buf)) > 0) ;
++
++      while(os_write_file(master, buf, sizeof(buf)) > 0) ;
+       if(errno != EAGAIN)
+               panic("check_sigio : write failed, errno = %d\n", errno);
+-
+-      while(((n = read(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
++      while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ;
+       if(got_sigio){
+               printk("Yes\n");
+               pty_output_sigio = 1;
+       }
+-      else if(errno == EAGAIN) printk("No, enabling workaround\n");
+-      else panic("check_sigio : read failed, errno = %d\n", errno);
++      else if(n == -EAGAIN) printk("No, enabling workaround\n");
++      else panic("check_sigio : read failed, err = %d\n", n);
+ }
+ static void tty_close(int master, int slave)
+ {
+       printk("Checking that host ptys support SIGIO on close...");
+-      close(slave);
++      os_close_file(slave);
+       if(got_sigio){
+               printk("Yes\n");
+               pty_close_sigio = 1;
+@@ -140,7 +132,8 @@
+ void __init check_sigio(void)
+ {
+-      if(access("/dev/ptmx", R_OK) && access("/dev/ptyp0", R_OK)){
++      if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) &&
++         (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){
+               printk("No pseudo-terminals available - skipping pty SIGIO "
+                      "check\n");
+               return;
+@@ -201,11 +194,10 @@
+                       p = &fds->poll[i];
+                       if(p->revents == 0) continue;
+                       if(p->fd == sigio_private[1]){
+-                              n = read(sigio_private[1], &c, sizeof(c));
++                              n = os_read_file(sigio_private[1], &c, sizeof(c));
+                               if(n != sizeof(c))
+                                       printk("write_sigio_thread : "
+-                                             "read failed, errno = %d\n",
+-                                             errno);
++                                             "read failed, err = %d\n", -n);
+                               tmp = current_poll;
+                               current_poll = next_poll;
+                               next_poll = tmp;
+@@ -218,10 +210,10 @@
+                                       (fds->used - i) * sizeof(*fds->poll));
+                       }
+-                      n = write(respond_fd, &c, sizeof(c));
++                      n = os_write_file(respond_fd, &c, sizeof(c));
+                       if(n != sizeof(c))
+                               printk("write_sigio_thread : write failed, "
+-                                     "errno = %d\n", errno);
++                                     "err = %d\n", -n);
+               }
+       }
+ }
+@@ -252,15 +244,15 @@
+       char c;
+       flags = set_signals(0);
+-      n = write(sigio_private[0], &c, sizeof(c));
++      n = os_write_file(sigio_private[0], &c, sizeof(c));
+       if(n != sizeof(c)){
+-              printk("update_thread : write failed, errno = %d\n", errno);
++              printk("update_thread : write failed, err = %d\n", -n);
+               goto fail;
+       }
+-      n = read(sigio_private[0], &c, sizeof(c));
++      n = os_read_file(sigio_private[0], &c, sizeof(c));
+       if(n != sizeof(c)){
+-              printk("update_thread : read failed, errno = %d\n", errno);
++              printk("update_thread : read failed, err = %d\n", -n);
+               goto fail;
+       }
+@@ -271,10 +263,10 @@
+       if(write_sigio_pid != -1) 
+               os_kill_process(write_sigio_pid, 1);
+       write_sigio_pid = -1;
+-      close(sigio_private[0]);
+-      close(sigio_private[1]);        
+-      close(write_sigio_fds[0]);
+-      close(write_sigio_fds[1]);
++      os_close_file(sigio_private[0]);
++      os_close_file(sigio_private[1]);        
++      os_close_file(write_sigio_fds[0]);
++      os_close_file(write_sigio_fds[1]);
+       sigio_unlock();
+       set_signals(flags);
+ }
+@@ -369,15 +361,15 @@
+               goto out;
+       err = os_pipe(write_sigio_fds, 1, 1);
+-      if(err){
++      if(err < 0){
+               printk("write_sigio_workaround - os_pipe 1 failed, "
+-                     "errno = %d\n", -err);
++                     "err = %d\n", -err);
+               goto out;
+       }
+       err = os_pipe(sigio_private, 1, 1);
+-      if(err){
++      if(err < 0){
+               printk("write_sigio_workaround - os_pipe 2 failed, "
+-                     "errno = %d\n", -err);
++                     "err = %d\n", -err);
+               goto out_close1;
+       }
+       if(setup_initial_poll(sigio_private[1]))
+@@ -399,11 +391,11 @@
+       os_kill_process(write_sigio_pid, 1);
+       write_sigio_pid = -1;
+  out_close2:
+-      close(sigio_private[0]);
+-      close(sigio_private[1]);        
++      os_close_file(sigio_private[0]);
++      os_close_file(sigio_private[1]);        
+  out_close1:
+-      close(write_sigio_fds[0]);
+-      close(write_sigio_fds[1]);
++      os_close_file(write_sigio_fds[0]);
++      os_close_file(write_sigio_fds[1]);
+       sigio_unlock();
+ }
+@@ -412,10 +404,16 @@
+       int n;
+       char c;
+-      n = read(fd, &c, sizeof(c));
++      n = os_read_file(fd, &c, sizeof(c));
+       if(n != sizeof(c)){
+-              printk("read_sigio_fd - read failed, errno = %d\n", errno);
+-              return(-errno);
++              if(n < 0) {
++                      printk("read_sigio_fd - read failed, err = %d\n", -n);
++                      return(n);
++              } 
++              else { 
++                      printk("read_sigio_fd - short read, bytes = %d\n", n);
++                      return(-EIO);
++              }
+       }
+       return(n);
+ }
+diff -Naur a/arch/um/kernel/signal_kern.c b/arch/um/kernel/signal_kern.c
+--- a/arch/um/kernel/signal_kern.c     2004-01-08 22:22:59.000000000 -0500
++++ b/arch/um/kernel/signal_kern.c     2004-01-08 22:29:59.000000000 -0500
+@@ -36,7 +36,7 @@
+       if(sig == SIGSEGV){
+               struct k_sigaction *ka;
+-              ka = &current->sig->action[SIGSEGV - 1];
++              ka = &current->sighand->action[SIGSEGV - 1];
+               ka->sa.sa_handler = SIG_DFL;
+       }
+       force_sig(SIGSEGV, current);
+@@ -60,10 +60,10 @@
+       int err, ret;
+       ret = 0;
++      /* Always make any pending restarted system calls return -EINTR */
++      current_thread_info()->restart_block.fn = do_no_restart_syscall;
+       switch(error){
+       case -ERESTART_RESTARTBLOCK:
+-              current_thread_info()->restart_block.fn = 
+-                      do_no_restart_syscall;
+       case -ERESTARTNOHAND:
+               ret = -EINTR;
+               break;
+@@ -142,7 +142,7 @@
+               return(0);
+       /* Whee!  Actually deliver the signal.  */
+-      ka = &current->sig->action[sig -1 ];
++      ka = &current->sighand->action[sig -1 ];
+       err = handle_signal(regs, sig, ka, &info, oldset, error);
+       if(!err) return(1);
+@@ -201,7 +201,7 @@
+       }
+ }
+-int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize)
++int sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
+ {
+       sigset_t saveset, newset;
+@@ -227,20 +227,59 @@
+       }
+ }
++int sys_sigaction(int sig, const struct old_sigaction __user *act,
++                       struct old_sigaction __user *oact)
++{
++      struct k_sigaction new_ka, old_ka;
++      int ret;
++
++      if (act) {
++              old_sigset_t mask;
++              if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
++                  __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
++                  __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
++                      return -EFAULT;
++              __get_user(new_ka.sa.sa_flags, &act->sa_flags);
++              __get_user(mask, &act->sa_mask);
++              siginitset(&new_ka.sa.sa_mask, mask);
++      }
++
++      ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
++
++      if (!ret && oact) {
++              if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
++                  __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
++                  __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
++                      return -EFAULT;
++              __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
++              __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
++      }
++
++      return ret;
++}
++
++int sys_sigaltstack(const stack_t *uss, stack_t *uoss)
++{
++      return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
++}
++
++extern int userspace_pid[];
++
+ static int copy_sc_from_user(struct pt_regs *to, void *from, 
+                            struct arch_frame_data *arch)
+ {
+       int ret;
+       ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch),
+-                        copy_sc_from_user_skas(&to->regs, from));
++                        copy_sc_from_user_skas(userspace_pid[0], 
++                                               &to->regs, from));
+       return(ret);
+ }
+ int sys_sigreturn(struct pt_regs regs)
+ {
+-      void *sc = sp_to_sc(PT_REGS_SP(&current->thread.regs));
+-      void *mask = sp_to_mask(PT_REGS_SP(&current->thread.regs));
++      void __user *sc = sp_to_sc(PT_REGS_SP(&current->thread.regs));
++      void __user *mask = sp_to_mask(PT_REGS_SP(&current->thread.regs));
+       int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
+       spin_lock_irq(&current->sighand->siglock);
+@@ -257,8 +296,8 @@
+ int sys_rt_sigreturn(struct pt_regs regs)
+ {
+-      struct ucontext *uc = sp_to_uc(PT_REGS_SP(&current->thread.regs));
+-      void *fp;
++      unsigned long sp = PT_REGS_SP(&current->thread.regs);
++      struct ucontext __user *uc = sp_to_uc(sp);
+       int sig_size = _NSIG_WORDS * sizeof(unsigned long);
+       spin_lock_irq(&current->sighand->siglock);
+@@ -266,7 +305,6 @@
+       sigdelsetmask(&current->blocked, ~_BLOCKABLE);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+-      fp = (void *) (((unsigned long) uc) + sizeof(struct ucontext));
+       copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext,
+                         &signal_frame_si.common.arch);
+       return(PT_REGS_SYSCALL_RET(&current->thread.regs));
+diff -Naur a/arch/um/kernel/skas/include/mode.h b/arch/um/kernel/skas/include/mode.h
+--- a/arch/um/kernel/skas/include/mode.h       2004-01-08 22:22:40.000000000 -0500
++++ b/arch/um/kernel/skas/include/mode.h       2004-01-08 22:29:35.000000000 -0500
+@@ -12,14 +12,16 @@
+ extern int have_fpx_regs;
+ extern void user_time_init_skas(void);
+-extern int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr);
+-extern int copy_sc_to_user_skas(void *to_ptr, void *fp, 
++extern int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, 
++                                void *from_ptr);
++extern int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, 
+                               union uml_pt_regs *regs, 
+                               unsigned long fault_addr, int fault_type);
+ extern void sig_handler_common_skas(int sig, void *sc_ptr);
+ extern void halt_skas(void);
+ extern void reboot_skas(void);
+ extern void kill_off_processes_skas(void);
++extern int is_skas_winch(int pid, int fd, void *data);
+ #endif
+diff -Naur a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
+--- a/arch/um/kernel/skas/include/skas.h       2004-01-08 22:17:37.000000000 -0500
++++ b/arch/um/kernel/skas/include/skas.h       2004-01-08 22:23:23.000000000 -0500
+@@ -8,7 +8,7 @@
+ #include "sysdep/ptrace.h"
+-extern int userspace_pid;
++extern int userspace_pid[];
+ extern void switch_threads(void *me, void *next);
+ extern void thread_wait(void *sw, void *fb);
+@@ -32,7 +32,7 @@
+ extern int new_mm(int from);
+ extern void save_registers(union uml_pt_regs *regs);
+ extern void restore_registers(union uml_pt_regs *regs);
+-extern void start_userspace(void);
++extern void start_userspace(int cpu);
+ extern void init_registers(int pid);
+ #endif
+diff -Naur a/arch/um/kernel/skas/include/uaccess.h b/arch/um/kernel/skas/include/uaccess.h
+--- a/arch/um/kernel/skas/include/uaccess.h    2004-01-08 22:20:08.000000000 -0500
++++ b/arch/um/kernel/skas/include/uaccess.h    2004-01-08 22:26:25.000000000 -0500
+@@ -6,20 +6,10 @@
+ #ifndef __SKAS_UACCESS_H
+ #define __SKAS_UACCESS_H
+-#include "linux/string.h"
+-#include "linux/sched.h"
+-#include "linux/err.h"
+-#include "asm/processor.h"
+-#include "asm/pgtable.h"
+-#include "asm/errno.h"
+-#include "asm/current.h"
+-#include "asm/a.out.h"
+-#include "kern_util.h"
+-
+ #define access_ok_skas(type, addr, size) \
+       ((segment_eq(get_fs(), KERNEL_DS)) || \
+        (((unsigned long) (addr) < TASK_SIZE) && \
+-        ((unsigned long) (addr) + (size) < TASK_SIZE)))
++        ((unsigned long) (addr) + (size) <= TASK_SIZE)))
+ static inline int verify_area_skas(int type, const void * addr, 
+                                  unsigned long size)
+@@ -27,197 +17,12 @@
+       return(access_ok_skas(type, addr, size) ? 0 : -EFAULT);
+ }
+-static inline unsigned long maybe_map(unsigned long virt, int is_write)
+-{
+-      pte_t pte;
+-
+-      void *phys = um_virt_to_phys(current, virt, &pte);
+-      int dummy_code;
+-
+-      if(IS_ERR(phys) || (is_write && !pte_write(pte))){
+-              if(handle_page_fault(virt, 0, is_write, 0, &dummy_code))
+-                      return(0);
+-              phys = um_virt_to_phys(current, virt, NULL);
+-      }
+-      return((unsigned long) __va((unsigned long) phys));
+-}
+-
+-static inline int buffer_op(unsigned long addr, int len, 
+-                          int (*op)(unsigned long addr, int len, void *arg),
+-                          void *arg)
+-{
+-      int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
+-      int remain = len, n;
+-
+-      n = (*op)(addr, size, arg);
+-      if(n != 0)
+-              return(n < 0 ? remain : 0);
+-
+-      addr += size;
+-      remain -= size;
+-      if(remain == 0) 
+-              return(0);
+-
+-      while(addr < ((addr + remain) & PAGE_MASK)){
+-              n = (*op)(addr, PAGE_SIZE, arg);
+-              if(n != 0)
+-                      return(n < 0 ? remain : 0);
+-
+-              addr += PAGE_SIZE;
+-              remain -= PAGE_SIZE;
+-      }
+-      if(remain == 0)
+-              return(0);
+-
+-      n = (*op)(addr, remain, arg);
+-      if(n != 0)
+-              return(n < 0 ? remain : 0);
+-      return(0);
+-}
+-
+-static inline int copy_chunk_from_user(unsigned long from, int len, void *arg)
+-{
+-      unsigned long *to_ptr = arg, to = *to_ptr;
+-
+-      from = maybe_map(from, 0);
+-      if(from == 0)
+-              return(-1);
+-
+-      memcpy((void *) to, (void *) from, len);
+-      *to_ptr += len;
+-      return(0);
+-}
+-
+-static inline int copy_from_user_skas(void *to, const void *from, int n)
+-{
+-      if(segment_eq(get_fs(), KERNEL_DS)){
+-              memcpy(to, from, n);
+-              return(0);
+-      }
+-
+-      return(access_ok_skas(VERIFY_READ, from, n) ?
+-             buffer_op((unsigned long) from, n, copy_chunk_from_user, &to) :
+-             n);
+-}
+-
+-static inline int copy_chunk_to_user(unsigned long to, int len, void *arg)
+-{
+-      unsigned long *from_ptr = arg, from = *from_ptr;
+-
+-      to = maybe_map(to, 1);
+-      if(to == 0)
+-              return(-1);
+-
+-      memcpy((void *) to, (void *) from, len);
+-      *from_ptr += len;
+-      return(0);
+-}
+-
+-static inline int copy_to_user_skas(void *to, const void *from, int n)
+-{
+-      if(segment_eq(get_fs(), KERNEL_DS)){
+-              memcpy(to, from, n);
+-              return(0);
+-      }
+-
+-      return(access_ok_skas(VERIFY_WRITE, to, n) ?
+-             buffer_op((unsigned long) to, n, copy_chunk_to_user, &from) :
+-             n);
+-}
+-
+-static inline int strncpy_chunk_from_user(unsigned long from, int len, 
+-                                        void *arg)
+-{
+-        char **to_ptr = arg, *to = *to_ptr;
+-      int n;
+-
+-      from = maybe_map(from, 0);
+-      if(from == 0)
+-              return(-1);
+-
+-      strncpy(to, (void *) from, len);
+-      n = strnlen(to, len);
+-      *to_ptr += n;
+-
+-      if(n < len) 
+-              return(1);
+-      return(0);
+-}
+-
+-static inline int strncpy_from_user_skas(char *dst, const char *src, int count)
+-{
+-      int n;
+-      char *ptr = dst;
+-
+-      if(segment_eq(get_fs(), KERNEL_DS)){
+-              strncpy(dst, src, count);
+-              return(strnlen(dst, count));
+-      }
+-
+-      if(!access_ok_skas(VERIFY_READ, src, 1))
+-              return(-EFAULT);
+-
+-      n = buffer_op((unsigned long) src, count, strncpy_chunk_from_user, 
+-                    &ptr);
+-      if(n != 0)
+-              return(-EFAULT);
+-      return(strnlen(dst, count));
+-}
+-
+-static inline int clear_chunk(unsigned long addr, int len, void *unused)
+-{
+-      addr = maybe_map(addr, 1);
+-      if(addr == 0) 
+-              return(-1);
+-
+-      memset((void *) addr, 0, len);
+-      return(0);
+-}
+-
+-static inline int __clear_user_skas(void *mem, int len)
+-{
+-      return(buffer_op((unsigned long) mem, len, clear_chunk, NULL));
+-}
+-
+-static inline int clear_user_skas(void *mem, int len)
+-{
+-      if(segment_eq(get_fs(), KERNEL_DS)){
+-              memset(mem, 0, len);
+-              return(0);
+-      }
+-
+-      return(access_ok_skas(VERIFY_WRITE, mem, len) ? 
+-             buffer_op((unsigned long) mem, len, clear_chunk, NULL) : len);
+-}
+-
+-static inline int strnlen_chunk(unsigned long str, int len, void *arg)
+-{
+-      int *len_ptr = arg, n;
+-
+-      str = maybe_map(str, 0);
+-      if(str == 0) 
+-              return(-1);
+-
+-      n = strnlen((void *) str, len);
+-      *len_ptr += n;
+-
+-      if(n < len)
+-              return(1);
+-      return(0);
+-}
+-
+-static inline int strnlen_user_skas(const void *str, int len)
+-{
+-      int count = 0, n;
+-
+-      if(segment_eq(get_fs(), KERNEL_DS))
+-              return(strnlen(str, len) + 1);
+-
+-      n = buffer_op((unsigned long) str, len, strnlen_chunk, &count);
+-      if(n == 0)
+-              return(count + 1);
+-      return(-EFAULT);
+-}
++extern int copy_from_user_skas(void *to, const void *from, int n);
++extern int copy_to_user_skas(void *to, const void *from, int n);
++extern int strncpy_from_user_skas(char *dst, const char *src, int count);
++extern int __clear_user_skas(void *mem, int len);
++extern int clear_user_skas(void *mem, int len);
++extern int strnlen_user_skas(const void *str, int len);
+ #endif
+diff -Naur a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
+--- a/arch/um/kernel/skas/Makefile     2004-01-08 22:17:52.000000000 -0500
++++ b/arch/um/kernel/skas/Makefile     2004-01-08 22:23:56.000000000 -0500
+@@ -5,20 +5,24 @@
+ obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \
+       process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.o \
+-      sys-$(SUBARCH)/
++      uaccess.o sys-$(SUBARCH)/
++
++host-progs    := util/mk_ptregs
++clean-files   := include/skas_ptregs.h
+ USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o
+ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+-include/skas_ptregs.h : util/mk_ptregs
+-      util/mk_ptregs > $@
+-
+-util/mk_ptregs :
+-      $(MAKE) -C util
++$(TOPDIR)/arch/um/include/skas_ptregs.h : $(src)/util/mk_ptregs
++      @echo -n '  Generating $@'
++      @$< > $@.tmp
++      @if [ -r $@ ] && cmp -s $@ $@.tmp; then \
++              echo ' (unchanged)'; \
++              rm -f $@.tmp; \
++      else \
++              echo ' (updated)'; \
++              mv -f $@.tmp $@; \
++      fi
+ $(USER_OBJS) : %.o: %.c
+       $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+-
+-clean :
+-      $(MAKE) -C util clean
+-      $(RM) -f include/skas_ptregs.h
+diff -Naur a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
+--- a/arch/um/kernel/skas/mem_user.c   2004-01-08 22:18:42.000000000 -0500
++++ b/arch/um/kernel/skas/mem_user.c   2004-01-08 22:24:31.000000000 -0500
+@@ -7,6 +7,7 @@
+ #include <sys/mman.h>
+ #include <sys/ptrace.h>
+ #include "mem_user.h"
++#include "mem.h"
+ #include "user.h"
+ #include "os.h"
+ #include "proc_mm.h"
+@@ -15,12 +16,12 @@
+        int r, int w, int x)
+ {
+       struct proc_mm_op map;
+-      struct mem_region *region;
+-      int prot, n;
++      __u64 offset;
++      int prot, n, phys_fd;
+       prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
+               (x ? PROT_EXEC : 0);
+-      region = phys_region(phys);
++      phys_fd = phys_mapping(phys, &offset);
+       map = ((struct proc_mm_op) { .op        = MM_MMAP,
+                                    .u         = 
+@@ -30,12 +31,12 @@
+                                        .prot          = prot,
+                                        .flags         = MAP_SHARED | 
+                                                         MAP_FIXED,
+-                                       .fd            = region->fd,
+-                                       .offset        = phys_offset(phys)
++                                       .fd            = phys_fd,
++                                       .offset        = offset
+                                      } } } );
+       n = os_write_file(fd, &map, sizeof(map));
+       if(n != sizeof(map)) 
+-              printk("map : /proc/mm map failed, errno = %d\n", errno);
++              printk("map : /proc/mm map failed, err = %d\n", -n);
+ }
+ int unmap(int fd, void *addr, int len)
+@@ -49,8 +50,13 @@
+                                        { .addr        = (unsigned long) addr,
+                                          .len         = len } } } );
+       n = os_write_file(fd, &unmap, sizeof(unmap));
+-      if((n != 0) && (n != sizeof(unmap)))
+-              return(-errno);
++      if(n != sizeof(unmap)) {
++              if(n < 0) 
++                      return(n);
++              else if(n > 0) 
++                      return(-EIO);
++      }
++
+       return(0);
+ }
+@@ -71,11 +77,15 @@
+                                          .prot        = prot } } } );
+       n = os_write_file(fd, &protect, sizeof(protect));
+-      if((n != 0) && (n != sizeof(protect))){
++      if(n != sizeof(protect)) {
++              if(n == 0) return(0);
++
+               if(must_succeed)
+-                      panic("protect failed, errno = %d", errno);
+-              return(-errno);
++                      panic("protect failed, err = %d", -n);
++
++              return(-EIO);
+       }
++
+       return(0);
+ }
+diff -Naur a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
+--- a/arch/um/kernel/skas/mmu.c        2004-01-08 22:33:46.000000000 -0500
++++ b/arch/um/kernel/skas/mmu.c        2004-01-08 22:36:57.000000000 -0500
+@@ -22,9 +22,11 @@
+       else from = -1;
+       mm->context.skas.mm_fd = new_mm(from);
+-      if(mm->context.skas.mm_fd < 0)
+-              panic("init_new_context_skas - new_mm failed, errno = %d\n",
+-                    mm->context.skas.mm_fd);
++      if(mm->context.skas.mm_fd < 0){
++              printk("init_new_context_skas - new_mm failed, errno = %d\n",
++                     mm->context.skas.mm_fd);
++              return(mm->context.skas.mm_fd);
++      }
+       return(0);
+ }
+diff -Naur a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
+--- a/arch/um/kernel/skas/process.c    2004-01-08 22:31:21.000000000 -0500
++++ b/arch/um/kernel/skas/process.c    2004-01-08 22:36:09.000000000 -0500
+@@ -4,6 +4,7 @@
+  */
+ #include <stdlib.h>
++#include <unistd.h>
+ #include <errno.h>
+ #include <signal.h>
+ #include <setjmp.h>
+@@ -24,6 +25,18 @@
+ #include "os.h"
+ #include "proc_mm.h"
+ #include "skas_ptrace.h"
++#include "chan_user.h"
++
++int is_skas_winch(int pid, int fd, void *data)
++{
++      if(pid != getpid())
++              return(0);
++
++      register_winch_irq(-1, fd, -1, data);
++      return(1);
++}
++
++/* These are set once at boot time and not changed thereafter */
+ unsigned long exec_regs[FRAME_SIZE];
+ unsigned long exec_fp_regs[HOST_FP_SIZE];
+@@ -48,11 +61,11 @@
+       int err, syscall_nr, status;
+       syscall_nr = PT_SYSCALL_NR(regs->skas.regs);
++      UPT_SYSCALL_NR(regs) = syscall_nr;
+       if(syscall_nr < 1){
+               relay_signal(SIGTRAP, regs);
+               return;
+       }
+-      UPT_SYSCALL_NR(regs) = syscall_nr;
+       err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid);
+       if(err < 0)
+@@ -72,8 +85,6 @@
+       handle_syscall(regs);
+ }
+-int userspace_pid;
+-
+ static int userspace_tramp(void *arg)
+ {
+       init_new_thread_signals(0);
+@@ -83,7 +94,11 @@
+       return(0);
+ }
+-void start_userspace(void)
++/* Each element set once, and only accessed by a single processor anyway */
++#define NR_CPUS 1
++int userspace_pid[NR_CPUS];
++
++void start_userspace(int cpu)
+ {
+       void *stack;
+       unsigned long sp;
+@@ -114,21 +129,21 @@
+       if(munmap(stack, PAGE_SIZE) < 0)
+               panic("start_userspace : munmap failed, errno = %d\n", errno);
+-      userspace_pid = pid;
++      userspace_pid[cpu] = pid;
+ }
+ void userspace(union uml_pt_regs *regs)
+ {
+-      int err, status, op;
++      int err, status, op, pid = userspace_pid[0];
+       restore_registers(regs);
+               
+-      err = ptrace(PTRACE_SYSCALL, userspace_pid, 0, 0);
++      err = ptrace(PTRACE_SYSCALL, pid, 0, 0);
+       if(err)
+               panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", 
+                      errno);
+       while(1){
+-              err = waitpid(userspace_pid, &status, WUNTRACED);
++              err = waitpid(pid, &status, WUNTRACED);
+               if(err < 0)
+                       panic("userspace - waitpid failed, errno = %d\n", 
+                             errno);
+@@ -139,16 +154,17 @@
+               if(WIFSTOPPED(status)){
+                       switch(WSTOPSIG(status)){
+                       case SIGSEGV:
+-                              handle_segv(userspace_pid);
++                              handle_segv(pid);
+                               break;
+                       case SIGTRAP:
+-                              handle_trap(userspace_pid, regs);
++                              handle_trap(pid, regs);
+                               break;
+                       case SIGIO:
+                       case SIGVTALRM:
+                       case SIGILL:
+                       case SIGBUS:
+                       case SIGFPE:
++                      case SIGWINCH:
+                               user_signal(WSTOPSIG(status), regs);
+                               break;
+                       default:
+@@ -162,7 +178,7 @@
+               op = singlestepping_skas() ? PTRACE_SINGLESTEP : 
+                       PTRACE_SYSCALL;
+-              err = ptrace(op, userspace_pid, 0, 0);
++              err = ptrace(op, pid, 0, 0);
+               if(err)
+                       panic("userspace - PTRACE_SYSCALL failed, "
+                             "errno = %d\n", errno);
+@@ -177,7 +193,7 @@
+       *switch_buf_ptr = &switch_buf;
+       *fork_buf_ptr = &fork_buf;
+-      if(setjmp(fork_buf) == 0)
++      if(sigsetjmp(fork_buf, 1) == 0)
+               new_thread_proc(stack, handler);
+       remove_sigstack();
+@@ -189,16 +205,16 @@
+       *switch_buf = &buf;
+       fork_buf = fb;
+-      if(setjmp(buf) == 0)
+-              longjmp(*fork_buf, 1);
++      if(sigsetjmp(buf, 1) == 0)
++              siglongjmp(*fork_buf, 1);
+ }
+-static int move_registers(int int_op, int fp_op, union uml_pt_regs *regs,
+-                        unsigned long *fp_regs)
++static int move_registers(int pid, int int_op, int fp_op, 
++                        union uml_pt_regs *regs, unsigned long *fp_regs)
+ {
+-      if(ptrace(int_op, userspace_pid, 0, regs->skas.regs) < 0)
++      if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
+               return(-errno);
+-      if(ptrace(fp_op, userspace_pid, 0, fp_regs) < 0)
++      if(ptrace(fp_op, pid, 0, fp_regs) < 0)
+               return(-errno);
+       return(0);
+ }
+@@ -217,10 +233,11 @@
+               fp_regs = regs->skas.fp;
+       }
+-      err = move_registers(PTRACE_GETREGS, fp_op, regs, fp_regs);
++      err = move_registers(userspace_pid[0], PTRACE_GETREGS, fp_op, regs, 
++                           fp_regs);
+       if(err)
+               panic("save_registers - saving registers failed, errno = %d\n",
+-                    err);
++                    -err);
+ }
+ void restore_registers(union uml_pt_regs *regs)
+@@ -237,10 +254,11 @@
+               fp_regs = regs->skas.fp;
+       }
+-      err = move_registers(PTRACE_SETREGS, fp_op, regs, fp_regs);
++      err = move_registers(userspace_pid[0], PTRACE_SETREGS, fp_op, regs, 
++                           fp_regs);
+       if(err)
+               panic("restore_registers - saving registers failed, "
+-                    "errno = %d\n", err);
++                    "errno = %d\n", -err);
+ }
+ void switch_threads(void *me, void *next)
+@@ -248,8 +266,8 @@
+       jmp_buf my_buf, **me_ptr = me, *next_buf = next;
+       
+       *me_ptr = &my_buf;
+-      if(setjmp(my_buf) == 0)
+-              longjmp(*next_buf, 1);
++      if(sigsetjmp(my_buf, 1) == 0)
++              siglongjmp(*next_buf, 1);
+ }
+ static jmp_buf initial_jmpbuf;
+@@ -265,14 +283,14 @@
+       int n;
+       *fork_buf_ptr = &initial_jmpbuf;
+-      n = setjmp(initial_jmpbuf);
++      n = sigsetjmp(initial_jmpbuf, 1);
+       if(n == 0)
+               new_thread_proc((void *) stack, new_thread_handler);
+       else if(n == 1)
+               remove_sigstack();
+       else if(n == 2){
+               (*cb_proc)(cb_arg);
+-              longjmp(*cb_back, 1);
++              siglongjmp(*cb_back, 1);
+       }
+       else if(n == 3){
+               kmalloc_ok = 0;
+@@ -282,7 +300,7 @@
+               kmalloc_ok = 0;
+               return(1);
+       }
+-      longjmp(**switch_buf, 1);
++      siglongjmp(**switch_buf, 1);
+ }
+ void remove_sigstack(void)
+@@ -304,8 +322,8 @@
+       cb_back = &here;
+       block_signals();
+-      if(setjmp(here) == 0)
+-              longjmp(initial_jmpbuf, 2);
++      if(sigsetjmp(here, 1) == 0)
++              siglongjmp(initial_jmpbuf, 2);
+       unblock_signals();
+       cb_proc = NULL;
+@@ -316,22 +334,23 @@
+ void halt_skas(void)
+ {
+       block_signals();
+-      longjmp(initial_jmpbuf, 3);
++      siglongjmp(initial_jmpbuf, 3);
+ }
+ void reboot_skas(void)
+ {
+       block_signals();
+-      longjmp(initial_jmpbuf, 4);
++      siglongjmp(initial_jmpbuf, 4);
+ }
+ int new_mm(int from)
+ {
+       struct proc_mm_op copy;
+-      int n, fd = os_open_file("/proc/mm", of_write(OPENFLAGS()), 0);
++      int n, fd = os_open_file("/proc/mm", 
++                               of_cloexec(of_write(OPENFLAGS())), 0);
+       if(fd < 0)
+-              return(-errno);
++              return(fd);
+       if(from != -1){
+               copy = ((struct proc_mm_op) { .op       = MM_COPY_SEGMENTS,
+@@ -340,8 +359,9 @@
+               n = os_write_file(fd, &copy, sizeof(copy));
+               if(n != sizeof(copy)) 
+                       printk("new_mm : /proc/mm copy_segments failed, "
+-                             "errno = %d\n", errno);
++                             "err = %d\n", -n);
+       }
++
+       return(fd);
+ }
+@@ -349,7 +369,8 @@
+ {
+       int err;
+-      err = ptrace(PTRACE_SWITCH_MM, userspace_pid, 0, mm_fd);
++#warning need cpu pid in switch_mm_skas
++      err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd);
+       if(err)
+               panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n",
+                     errno);
+@@ -357,7 +378,8 @@
+ void kill_off_processes_skas(void)
+ {
+-      os_kill_process(userspace_pid, 1);
++#warning need to loop over userspace_pids in kill_off_processes_skas
++      os_kill_process(userspace_pid[0], 1);
+ }
+ void init_registers(int pid)
+diff -Naur a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
+--- a/arch/um/kernel/skas/process_kern.c       2004-01-08 22:16:41.000000000 -0500
++++ b/arch/um/kernel/skas/process_kern.c       2004-01-08 22:22:45.000000000 -0500
+@@ -61,11 +61,13 @@
+       thread_wait(&current->thread.mode.skas.switch_buf, 
+                   current->thread.mode.skas.fork_buf);
+-#ifdef CONFIG_SMP
+-      schedule_tail(NULL);
+-#endif
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
+       current->thread.prev_sched = NULL;
++      /* The return value is 1 if the kernel thread execs a process,
++       * 0 if it just exits
++       */
+       n = run_kernel_thread(fn, arg, &current->thread.exec_buf);
+       if(n == 1)
+               userspace(&current->thread.regs.regs);
+@@ -93,9 +95,8 @@
+                   current->thread.mode.skas.fork_buf);
+       
+       force_flush_all();
+-#ifdef CONFIG_SMP
+-      schedule_tail(current->thread.prev_sched);
+-#endif
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
+       current->thread.prev_sched = NULL;
+       unblock_signals();
+@@ -136,7 +137,7 @@
+ void init_idle_skas(void)
+ {
+-      cpu_tasks[current->thread_info->cpu].pid = os_getpid();
++      cpu_tasks[current_thread->cpu].pid = os_getpid();
+       default_idle();
+ }
+@@ -160,11 +161,11 @@
+ int start_uml_skas(void)
+ {
+-      start_userspace();
++      start_userspace(0);
+       capture_signal_stack();
++      uml_idle_timer();
+       init_new_thread_signals(1);
+-      idle_timer();
+       init_task.thread.request.u.thread.proc = start_kernel_proc;
+       init_task.thread.request.u.thread.arg = NULL;
+@@ -175,12 +176,14 @@
+ int external_pid_skas(struct task_struct *task)
+ {
+-      return(userspace_pid);
++#warning Need to look up userspace_pid by cpu 
++      return(userspace_pid[0]);
+ }
+ int thread_pid_skas(struct task_struct *task)
+ {
+-      return(userspace_pid);
++#warning Need to look up userspace_pid by cpu 
++      return(userspace_pid[0]);
+ }
+ /*
+diff -Naur a/arch/um/kernel/skas/syscall_kern.c b/arch/um/kernel/skas/syscall_kern.c
+--- a/arch/um/kernel/skas/syscall_kern.c       2004-01-08 22:24:03.000000000 -0500
++++ b/arch/um/kernel/skas/syscall_kern.c       2004-01-08 22:31:17.000000000 -0500
+@@ -1,5 +1,5 @@
+ /* 
+- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+diff -Naur a/arch/um/kernel/skas/sys-i386/sigcontext.c b/arch/um/kernel/skas/sys-i386/sigcontext.c
+--- a/arch/um/kernel/skas/sys-i386/sigcontext.c        2004-01-08 22:13:52.000000000 -0500
++++ b/arch/um/kernel/skas/sys-i386/sigcontext.c        2004-01-08 22:18:57.000000000 -0500
+@@ -12,10 +12,9 @@
+ #include "kern_util.h"
+ #include "user.h"
+ #include "sigcontext.h"
++#include "mode.h"
+-extern int userspace_pid;
+-
+-int copy_sc_from_user_skas(union uml_pt_regs *regs, void *from_ptr)
++int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, void *from_ptr)
+ {
+       struct sigcontext sc, *from = from_ptr;
+       unsigned long fpregs[FP_FRAME_SIZE];
+@@ -41,13 +40,12 @@
+       regs->skas.regs[EIP] = sc.eip;
+       regs->skas.regs[CS] = sc.cs;
+       regs->skas.regs[EFL] = sc.eflags;
+-      regs->skas.regs[UESP] = sc.esp_at_signal;
+       regs->skas.regs[SS] = sc.ss;
+       regs->skas.fault_addr = sc.cr2;
+       regs->skas.fault_type = FAULT_WRITE(sc.err);
+       regs->skas.trap_type = sc.trapno;
+-      err = ptrace(PTRACE_SETFPREGS, userspace_pid, 0, fpregs);
++      err = ptrace(PTRACE_SETFPREGS, pid, 0, fpregs);
+       if(err < 0){
+               printk("copy_sc_to_user - PTRACE_SETFPREGS failed, "
+                      "errno = %d\n", errno);
+@@ -57,8 +55,9 @@
+       return(0);
+ }
+-int copy_sc_to_user_skas(void *to_ptr, void *fp, union uml_pt_regs *regs, 
+-                       unsigned long fault_addr, int fault_type)
++int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, 
++                       union uml_pt_regs *regs, unsigned long fault_addr, 
++                       int fault_type)
+ {
+       struct sigcontext sc, *to = to_ptr;
+       struct _fpstate *to_fp;
+@@ -86,7 +85,7 @@
+       sc.err = TO_SC_ERR(fault_type);
+       sc.trapno = regs->skas.trap_type;
+-      err = ptrace(PTRACE_GETFPREGS, userspace_pid, 0, fpregs);
++      err = ptrace(PTRACE_GETFPREGS, pid, 0, fpregs);
+       if(err < 0){
+               printk("copy_sc_to_user - PTRACE_GETFPREGS failed, "
+                      "errno = %d\n", errno);
+diff -Naur a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c
+--- a/arch/um/kernel/skas/trap_user.c  2004-01-08 22:20:11.000000000 -0500
++++ b/arch/um/kernel/skas/trap_user.c  2004-01-08 22:26:28.000000000 -0500
+@@ -1,5 +1,5 @@
+ /* 
+- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+@@ -41,8 +41,6 @@
+ {
+       struct signal_info *info;
+-      if(sig == SIGVTALRM)
+-              missed_ticks[cpu()]++;
+       regs->skas.is_user = 1;
+       regs->skas.fault_addr = 0;
+       regs->skas.fault_type = 0;
+diff -Naur a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
+--- a/arch/um/kernel/skas/uaccess.c    1969-12-31 19:00:00.000000000 -0500
++++ b/arch/um/kernel/skas/uaccess.c    2004-01-08 22:33:48.000000000 -0500
+@@ -0,0 +1,219 @@
++/* 
++ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/stddef.h"
++#include "linux/kernel.h"
++#include "linux/string.h"
++#include "linux/fs.h"
++#include "linux/highmem.h"
++#include "asm/page.h"
++#include "asm/pgtable.h"
++#include "asm/uaccess.h"
++#include "kern_util.h"
++
++extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, 
++                           pte_t *pte_out);
++
++static unsigned long maybe_map(unsigned long virt, int is_write)
++{
++      pte_t pte;
++      int err;
++
++      void *phys = um_virt_to_phys(current, virt, &pte);
++      int dummy_code;
++
++      if(IS_ERR(phys) || (is_write && !pte_write(pte))){
++              err = handle_page_fault(virt, 0, is_write, 0, &dummy_code);
++              if(err)
++                      return(0);
++              phys = um_virt_to_phys(current, virt, NULL);
++      }
++      return((unsigned long) phys);
++}
++
++static int do_op(unsigned long addr, int len, int is_write, 
++               int (*op)(unsigned long addr, int len, void *arg), void *arg)
++{
++      struct page *page;
++      int n;
++
++      addr = maybe_map(addr, is_write);
++      if(addr == -1)
++              return(-1);
++
++      page = phys_to_page(addr);
++      addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK);
++      n = (*op)(addr, len, arg);
++      kunmap(page);
++
++      return(n);
++}
++
++static int buffer_op(unsigned long addr, int len, int is_write,
++                   int (*op)(unsigned long addr, int len, void *arg),
++                   void *arg)
++{
++      int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
++      int remain = len, n;
++
++      n = do_op(addr, size, is_write, op, arg);
++      if(n != 0)
++              return(n < 0 ? remain : 0);
++
++      addr += size;
++      remain -= size;
++      if(remain == 0) 
++              return(0);
++
++      while(addr < ((addr + remain) & PAGE_MASK)){
++              n = do_op(addr, PAGE_SIZE, is_write, op, arg);
++              if(n != 0)
++                      return(n < 0 ? remain : 0);
++
++              addr += PAGE_SIZE;
++              remain -= PAGE_SIZE;
++      }
++      if(remain == 0)
++              return(0);
++
++      n = do_op(addr, remain, is_write, op, arg);
++      if(n != 0)
++              return(n < 0 ? remain : 0);
++      return(0);
++}
++
++static int copy_chunk_from_user(unsigned long from, int len, void *arg)
++{
++      unsigned long *to_ptr = arg, to = *to_ptr;
++
++      memcpy((void *) to, (void *) from, len);
++      *to_ptr += len;
++      return(0);
++}
++
++int copy_from_user_skas(void *to, const void *from, int n)
++{
++      if(segment_eq(get_fs(), KERNEL_DS)){
++              memcpy(to, from, n);
++              return(0);
++      }
++
++      return(access_ok_skas(VERIFY_READ, from, n) ?
++             buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
++             n);
++}
++
++static int copy_chunk_to_user(unsigned long to, int len, void *arg)
++{
++      unsigned long *from_ptr = arg, from = *from_ptr;
++
++      memcpy((void *) to, (void *) from, len);
++      *from_ptr += len;
++      return(0);
++}
++
++int copy_to_user_skas(void *to, const void *from, int n)
++{
++      if(segment_eq(get_fs(), KERNEL_DS)){
++              memcpy(to, from, n);
++              return(0);
++      }
++
++      return(access_ok_skas(VERIFY_WRITE, to, n) ?
++             buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
++             n);
++}
++
++static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
++{
++      char **to_ptr = arg, *to = *to_ptr;
++      int n;
++
++      strncpy(to, (void *) from, len);
++      n = strnlen(to, len);
++      *to_ptr += n;
++
++      if(n < len) 
++              return(1);
++      return(0);
++}
++
++int strncpy_from_user_skas(char *dst, const char *src, int count)
++{
++      int n;
++      char *ptr = dst;
++
++      if(segment_eq(get_fs(), KERNEL_DS)){
++              strncpy(dst, src, count);
++              return(strnlen(dst, count));
++      }
++
++      if(!access_ok_skas(VERIFY_READ, src, 1))
++              return(-EFAULT);
++
++      n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user, 
++                    &ptr);
++      if(n != 0)
++              return(-EFAULT);
++      return(strnlen(dst, count));
++}
++
++static int clear_chunk(unsigned long addr, int len, void *unused)
++{
++      memset((void *) addr, 0, len);
++      return(0);
++}
++
++int __clear_user_skas(void *mem, int len)
++{
++      return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL));
++}
++
++int clear_user_skas(void *mem, int len)
++{
++      if(segment_eq(get_fs(), KERNEL_DS)){
++              memset(mem, 0, len);
++              return(0);
++      }
++
++      return(access_ok_skas(VERIFY_WRITE, mem, len) ? 
++             buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len);
++}
++
++static int strnlen_chunk(unsigned long str, int len, void *arg)
++{
++      int *len_ptr = arg, n;
++
++      n = strnlen((void *) str, len);
++      *len_ptr += n;
++
++      if(n < len)
++              return(1);
++      return(0);
++}
++
++int strnlen_user_skas(const void *str, int len)
++{
++      int count = 0, n;
++
++      if(segment_eq(get_fs(), KERNEL_DS))
++              return(strnlen(str, len) + 1);
++
++      n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count);
++      if(n == 0)
++              return(count + 1);
++      return(-EFAULT);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/arch/um/kernel/skas/util/Makefile b/arch/um/kernel/skas/util/Makefile
+--- a/arch/um/kernel/skas/util/Makefile        2004-01-08 22:28:48.000000000 -0500
++++ b/arch/um/kernel/skas/util/Makefile        2004-01-08 22:35:00.000000000 -0500
+@@ -1,10 +1,10 @@
+ all: mk_ptregs
+ mk_ptregs : mk_ptregs.o
+-      $(CC) -o mk_ptregs mk_ptregs.o
++      $(HOSTCC) -o mk_ptregs mk_ptregs.o
+ mk_ptregs.o : mk_ptregs.c
+-      $(CC) -c $< 
++      $(HOSTCC) -c $< 
+ clean : 
+       $(RM) -f mk_ptregs *.o *~
+diff -Naur a/arch/um/kernel/skas/util/mk_ptregs.c b/arch/um/kernel/skas/util/mk_ptregs.c
+--- a/arch/um/kernel/skas/util/mk_ptregs.c     2004-01-08 22:19:28.000000000 -0500
++++ b/arch/um/kernel/skas/util/mk_ptregs.c     2004-01-08 22:25:46.000000000 -0500
+@@ -1,3 +1,4 @@
++#include <stdio.h>
+ #include <asm/ptrace.h>
+ #include <asm/user.h>
+diff -Naur a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
+--- a/arch/um/kernel/smp.c     2004-01-08 22:16:25.000000000 -0500
++++ b/arch/um/kernel/smp.c     2004-01-08 22:22:29.000000000 -0500
+@@ -1,9 +1,15 @@
+ /* 
+- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+ #include "linux/config.h"
++#include "linux/percpu.h"
++#include "asm/pgalloc.h"
++#include "asm/tlb.h"
++
++/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */
++DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+ #ifdef CONFIG_SMP
+@@ -23,7 +29,7 @@
+ #include "os.h"
+ /* CPU online map, set by smp_boot_cpus */
+-unsigned long cpu_online_map = cpumask_of_cpu(0);
++unsigned long cpu_online_map = CPU_MASK_NONE;
+ EXPORT_SYMBOL(cpu_online_map);
+@@ -55,7 +61,7 @@
+ void smp_send_reschedule(int cpu)
+ {
+-      write(cpu_data[cpu].ipi_pipe[1], "R", 1);
++      os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1);
+       num_reschedules_sent++;
+ }
+@@ -100,35 +106,34 @@
+       printk(KERN_INFO "Stopping all CPUs...");
+       for(i = 0; i < num_online_cpus(); i++){
+-              if(i == current->thread_info->cpu)
++              if(i == current_thread->cpu)
+                       continue;
+-              write(cpu_data[i].ipi_pipe[1], "S", 1);
++              os_write_file(cpu_data[i].ipi_pipe[1], "S", 1);
+       }
+       printk("done\n");
+ }
+-static cpumask_t smp_commenced_mask;
+-static cpumask_t smp_callin_map = CPU_MASK_NONE;
++static cpumask_t smp_commenced_mask = CPU_MASK_NONE;
++static cpumask_t cpu_callin_map = CPU_MASK_NONE;
+ static int idle_proc(void *cpup)
+ {
+       int cpu = (int) cpup, err;
+       err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1);
+-      if(err)
+-              panic("CPU#%d failed to create IPI pipe, errno = %d", cpu, 
+-                    -err);
++      if(err < 0)
++              panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err);
+       activate_ipi(cpu_data[cpu].ipi_pipe[0], 
+                    current->thread.mode.tt.extern_pid);
+  
+       wmb();
+-      if (cpu_test_and_set(cpu, &smp_callin_map)) {
++      if (cpu_test_and_set(cpu, cpu_callin_map)) {
+               printk("huh, CPU#%d already present??\n", cpu);
+               BUG();
+       }
+-      while (!cpu_isset(cpu, &smp_commenced_mask))
++      while (!cpu_isset(cpu, smp_commenced_mask))
+               cpu_relax();
+       cpu_set(cpu, cpu_online_map);
+@@ -143,16 +148,20 @@
+         current->thread.request.u.thread.proc = idle_proc;
+         current->thread.request.u.thread.arg = (void *) cpu;
+-      new_task = do_fork(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL, NULL);
+-      if(IS_ERR(new_task)) panic("do_fork failed in idle_thread");
++      new_task = copy_process(CLONE_VM | CLONE_IDLETASK, 0, NULL, 0, NULL, 
++                              NULL);
++      if(IS_ERR(new_task)) 
++              panic("copy_process failed in idle_thread, error = %ld",
++                    PTR_ERR(new_task));
+       cpu_tasks[cpu] = ((struct cpu_task) 
+                         { .pid =      new_task->thread.mode.tt.extern_pid,
+                           .task =     new_task } );
+       idle_threads[cpu] = new_task;
+-      CHOOSE_MODE(write(new_task->thread.mode.tt.switch_pipe[1], &c, 
++      CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c, 
+                         sizeof(c)),
+                   ({ panic("skas mode doesn't support SMP"); }));
++      wake_up_forked_process(new_task);
+       return(new_task);
+ }
+@@ -160,15 +169,17 @@
+ {
+       struct task_struct *idle;
+       unsigned long waittime;
+-      int err, cpu;
++      int err, cpu, me = smp_processor_id();
+-      cpu_set(0, cpu_online_map);
+-      cpu_set(0, smp_callin_map);
++      cpu_clear(me, cpu_online_map);
++      cpu_set(me, cpu_online_map);
++      cpu_set(me, cpu_callin_map);
+-      err = os_pipe(cpu_data[0].ipi_pipe, 1, 1);
+-      if(err) panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
++      err = os_pipe(cpu_data[me].ipi_pipe, 1, 1);
++      if(err < 0)
++              panic("CPU#0 failed to create IPI pipe, errno = %d", -err);
+-      activate_ipi(cpu_data[0].ipi_pipe[0], 
++      activate_ipi(cpu_data[me].ipi_pipe[0], 
+                    current->thread.mode.tt.extern_pid);
+       for(cpu = 1; cpu < ncpus; cpu++){
+@@ -180,10 +191,10 @@
+               unhash_process(idle);
+               waittime = 200000000;
+-              while (waittime-- && !cpu_isset(cpu, smp_callin_map))
++              while (waittime-- && !cpu_isset(cpu, cpu_callin_map))
+                       cpu_relax();
+-              if (cpu_isset(cpu, smp_callin_map))
++              if (cpu_isset(cpu, cpu_callin_map))
+                       printk("done\n");
+               else printk("failed\n");
+       }
+@@ -216,7 +227,7 @@
+       int fd;
+       fd = cpu_data[cpu].ipi_pipe[0];
+-      while (read(fd, &c, 1) == 1) {
++      while (os_read_file(fd, &c, 1) == 1) {
+               switch (c) {
+               case 'C':
+                       smp_call_function_slave(cpu);
+@@ -273,9 +284,9 @@
+       info = _info;
+       for (i=0;i<NR_CPUS;i++)
+-              if((i != current->thread_info->cpu) && 
++              if((i != current_thread->cpu) && 
+                  cpu_isset(i, cpu_online_map))
+-                      write(cpu_data[i].ipi_pipe[1], "C", 1);
++                      os_write_file(cpu_data[i].ipi_pipe[1], "C", 1);
+       while (atomic_read(&scf_started) != cpus)
+               barrier();
+diff -Naur a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
+--- a/arch/um/kernel/syscall_kern.c    2004-01-08 22:26:00.000000000 -0500
++++ b/arch/um/kernel/syscall_kern.c    2004-01-08 22:33:41.000000000 -0500
+@@ -1,5 +1,5 @@
+ /* 
+- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+@@ -35,39 +35,40 @@
+ long sys_fork(void)
+ {
+-      struct task_struct *p;
++      long ret;
+       current->thread.forking = 1;
+-        p = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
++        ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
+       current->thread.forking = 0;
+-      return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
++      return(ret);
+ }
+-long sys_clone(unsigned long clone_flags, unsigned long newsp)
++long sys_clone(unsigned long clone_flags, unsigned long newsp, 
++             int *parent_tid, int *child_tid)
+ {
+-      struct task_struct *p;
++      long ret;
+       current->thread.forking = 1;
+-      p = do_fork(clone_flags, newsp, NULL, 0, NULL, NULL);
++      ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
+       current->thread.forking = 0;
+-      return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
++      return(ret);
+ }
+ long sys_vfork(void)
+ {
+-      struct task_struct *p;
++      long ret;
+       current->thread.forking = 1;
+-      p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, NULL);
++      ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL, 
++                    NULL);
+       current->thread.forking = 0;
+-      return(IS_ERR(p) ? PTR_ERR(p) : p->pid);
++      return(ret);
+ }
+ /* common code for old and new mmaps */
+-static inline long do_mmap2(
+-      unsigned long addr, unsigned long len,
+-      unsigned long prot, unsigned long flags,
+-      unsigned long fd, unsigned long pgoff)
++long do_mmap2(struct mm_struct *mm, unsigned long addr, unsigned long len,
++            unsigned long prot, unsigned long flags, unsigned long fd,
++            unsigned long pgoff)
+ {
+       int error = -EBADF;
+       struct file * file = NULL;
+@@ -79,9 +80,9 @@
+                       goto out;
+       }
+-      down_write(&current->mm->mmap_sem);
+-      error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+-      up_write(&current->mm->mmap_sem);
++      down_write(&mm->mmap_sem);
++      error = do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff);
++      up_write(&mm->mmap_sem);
+       if (file)
+               fput(file);
+@@ -93,7 +94,7 @@
+              unsigned long prot, unsigned long flags,
+              unsigned long fd, unsigned long pgoff)
+ {
+-      return do_mmap2(addr, len, prot, flags, fd, pgoff);
++      return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff);
+ }
+ /*
+@@ -120,7 +121,8 @@
+       if (offset & ~PAGE_MASK)
+               goto out;
+-      err = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
++      err = do_mmap2(current->mm, addr, len, prot, flags, fd, 
++                     offset >> PAGE_SHIFT);
+  out:
+       return err;
+ }
+@@ -135,43 +137,12 @@
+         error = do_pipe(fd);
+         if (!error) {
+-                if (copy_to_user(fildes, fd, 2*sizeof(int)))
++              if (copy_to_user(fildes, fd, sizeof(fd)))
+                         error = -EFAULT;
+         }
+         return error;
+ }
+-int sys_sigaction(int sig, const struct old_sigaction *act,
+-                       struct old_sigaction *oact)
+-{
+-      struct k_sigaction new_ka, old_ka;
+-      int ret;
+-
+-      if (act) {
+-              old_sigset_t mask;
+-              if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
+-                  __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
+-                  __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+-                      return -EFAULT;
+-              __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+-              __get_user(mask, &act->sa_mask);
+-              siginitset(&new_ka.sa.sa_mask, mask);
+-      }
+-
+-      ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
+-
+-      if (!ret && oact) {
+-              if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
+-                  __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
+-                  __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+-                      return -EFAULT;
+-              __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+-              __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+-      }
+-
+-      return ret;
+-}
+-
+ /*
+  * sys_ipc() is the de-multiplexer for the SysV IPC calls..
+  *
+@@ -253,7 +224,7 @@
+               return sys_shmctl (first, second,
+                                  (struct shmid_ds *) ptr);
+       default:
+-              return -EINVAL;
++              return -ENOSYS;
+       }
+ }
+@@ -302,11 +273,6 @@
+       return error;
+ }
+-int sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+-{
+-      return(do_sigaltstack(uss, uoss, PT_REGS_SP(&current->thread.regs)));
+-}
+-
+ long execute_syscall(void *r)
+ {
+       return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r));
+diff -Naur a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c
+--- a/arch/um/kernel/sys_call_table.c  2004-01-08 22:28:47.000000000 -0500
++++ b/arch/um/kernel/sys_call_table.c  2004-01-08 22:35:00.000000000 -0500
+@@ -5,7 +5,6 @@
+ #include "linux/config.h"
+ #include "linux/unistd.h"
+-#include "linux/version.h"
+ #include "linux/sys.h"
+ #include "linux/swap.h"
+ #include "linux/sysctl.h"
+@@ -219,15 +218,30 @@
+ extern syscall_handler_t sys_gettid;
+ extern syscall_handler_t sys_readahead;
+ extern syscall_handler_t sys_tkill;
++extern syscall_handler_t sys_setxattr;
++extern syscall_handler_t sys_lsetxattr;
++extern syscall_handler_t sys_fsetxattr;
++extern syscall_handler_t sys_getxattr;
++extern syscall_handler_t sys_lgetxattr;
++extern syscall_handler_t sys_fgetxattr;
++extern syscall_handler_t sys_listxattr;
++extern syscall_handler_t sys_llistxattr;
++extern syscall_handler_t sys_flistxattr;
++extern syscall_handler_t sys_removexattr;
++extern syscall_handler_t sys_lremovexattr;
++extern syscall_handler_t sys_fremovexattr;
+ extern syscall_handler_t sys_sendfile64;
+ extern syscall_handler_t sys_futex;
+ extern syscall_handler_t sys_sched_setaffinity;
+ extern syscall_handler_t sys_sched_getaffinity;
++extern syscall_handler_t sys_set_thread_area;
++extern syscall_handler_t sys_get_thread_area;
+ extern syscall_handler_t sys_io_setup;
+ extern syscall_handler_t sys_io_destroy;
+ extern syscall_handler_t sys_io_getevents;
+ extern syscall_handler_t sys_io_submit;
+ extern syscall_handler_t sys_io_cancel;
++extern syscall_handler_t sys_fadvise64;
+ extern syscall_handler_t sys_exit_group;
+ extern syscall_handler_t sys_lookup_dcookie;
+ extern syscall_handler_t sys_epoll_create;
+@@ -235,6 +249,20 @@
+ extern syscall_handler_t sys_epoll_wait;
+ extern syscall_handler_t sys_remap_file_pages;
+ extern syscall_handler_t sys_set_tid_address;
++extern syscall_handler_t sys_timer_create;
++extern syscall_handler_t sys_timer_settime;
++extern syscall_handler_t sys_timer_gettime;
++extern syscall_handler_t sys_timer_getoverrun;
++extern syscall_handler_t sys_timer_delete;
++extern syscall_handler_t sys_clock_settime;
++extern syscall_handler_t sys_clock_gettime;
++extern syscall_handler_t sys_clock_getres;
++extern syscall_handler_t sys_clock_nanosleep;
++extern syscall_handler_t sys_statfs64;
++extern syscall_handler_t sys_fstatfs64;
++extern syscall_handler_t sys_tgkill;
++extern syscall_handler_t sys_utimes;
++extern syscall_handler_t sys_fadvise64_64;
+ #ifdef CONFIG_NFSD
+ #define NFSSERVCTL sys_nfsservctl
+@@ -246,7 +274,7 @@
+ extern syscall_handler_t um_time;
+ extern syscall_handler_t um_stime;
+-#define LAST_GENERIC_SYSCALL __NR_set_tid_address
++#define LAST_GENERIC_SYSCALL __NR_vserver
+ #if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
+ #define LAST_SYSCALL LAST_GENERIC_SYSCALL
+@@ -455,32 +483,37 @@
+       [ __NR_stat64 ] = sys_stat64,
+       [ __NR_lstat64 ] = sys_lstat64,
+       [ __NR_fstat64 ] = sys_fstat64,
+-      [ __NR_fcntl64 ] = sys_fcntl64,
+       [ __NR_getdents64 ] = sys_getdents64,
++      [ __NR_fcntl64 ] = sys_fcntl64,
++      [ 223 ] = sys_ni_syscall,
+       [ __NR_gettid ] = sys_gettid,
+       [ __NR_readahead ] = sys_readahead,
+-      [ __NR_setxattr ] = sys_ni_syscall,
+-      [ __NR_lsetxattr ] = sys_ni_syscall,
+-      [ __NR_fsetxattr ] = sys_ni_syscall,
+-      [ __NR_getxattr ] = sys_ni_syscall,
+-      [ __NR_lgetxattr ] = sys_ni_syscall,
+-      [ __NR_fgetxattr ] = sys_ni_syscall,
+-      [ __NR_listxattr ] = sys_ni_syscall,
+-      [ __NR_llistxattr ] = sys_ni_syscall,
+-      [ __NR_flistxattr ] = sys_ni_syscall,
+-      [ __NR_removexattr ] = sys_ni_syscall,
+-      [ __NR_lremovexattr ] = sys_ni_syscall,
+-      [ __NR_fremovexattr ] = sys_ni_syscall,
++      [ __NR_setxattr ] = sys_setxattr,
++      [ __NR_lsetxattr ] = sys_lsetxattr,
++      [ __NR_fsetxattr ] = sys_fsetxattr,
++      [ __NR_getxattr ] = sys_getxattr,
++      [ __NR_lgetxattr ] = sys_lgetxattr,
++      [ __NR_fgetxattr ] = sys_fgetxattr,
++      [ __NR_listxattr ] = sys_listxattr,
++      [ __NR_llistxattr ] = sys_llistxattr,
++      [ __NR_flistxattr ] = sys_flistxattr,
++      [ __NR_removexattr ] = sys_removexattr,
++      [ __NR_lremovexattr ] = sys_lremovexattr,
++      [ __NR_fremovexattr ] = sys_fremovexattr,
+       [ __NR_tkill ] = sys_tkill,
+       [ __NR_sendfile64 ] = sys_sendfile64,
+       [ __NR_futex ] = sys_futex,
+       [ __NR_sched_setaffinity ] = sys_sched_setaffinity,
+       [ __NR_sched_getaffinity ] = sys_sched_getaffinity,
++      [ __NR_set_thread_area ] = sys_ni_syscall,
++      [ __NR_get_thread_area ] = sys_ni_syscall,
+       [ __NR_io_setup ] = sys_io_setup,
+       [ __NR_io_destroy ] = sys_io_destroy,
+       [ __NR_io_getevents ] = sys_io_getevents,
+       [ __NR_io_submit ] = sys_io_submit,
+       [ __NR_io_cancel ] = sys_io_cancel,
++      [ __NR_fadvise64 ] = sys_fadvise64,
++      [ 251 ] = sys_ni_syscall,
+       [ __NR_exit_group ] = sys_exit_group,
+       [ __NR_lookup_dcookie ] = sys_lookup_dcookie,
+       [ __NR_epoll_create ] = sys_epoll_create,
+@@ -488,6 +521,21 @@
+       [ __NR_epoll_wait ] = sys_epoll_wait,
+         [ __NR_remap_file_pages ] = sys_remap_file_pages,
+         [ __NR_set_tid_address ] = sys_set_tid_address,
++      [ __NR_timer_create ] = sys_timer_create,
++      [ __NR_timer_settime ] = sys_timer_settime,
++      [ __NR_timer_gettime ] = sys_timer_gettime,
++      [ __NR_timer_getoverrun ] = sys_timer_getoverrun,
++      [ __NR_timer_delete ] = sys_timer_delete,
++      [ __NR_clock_settime ] = sys_clock_settime,
++      [ __NR_clock_gettime ] = sys_clock_gettime,
++      [ __NR_clock_getres ] = sys_clock_getres,
++      [ __NR_clock_nanosleep ] = sys_clock_nanosleep,
++      [ __NR_statfs64 ] = sys_statfs64,
++      [ __NR_fstatfs64 ] = sys_fstatfs64,
++      [ __NR_tgkill ] = sys_tgkill,
++      [ __NR_utimes ] = sys_utimes,
++      [ __NR_fadvise64_64 ] = sys_fadvise64_64,
++      [ __NR_vserver ] = sys_ni_syscall,
+       ARCH_SYSCALLS
+       [ LAST_SYSCALL + 1 ... NR_syscalls ] = 
+diff -Naur a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
+--- a/arch/um/kernel/sysrq.c   2004-01-08 22:18:31.000000000 -0500
++++ b/arch/um/kernel/sysrq.c   2004-01-08 22:24:21.000000000 -0500
+@@ -55,6 +55,14 @@
+       show_trace((unsigned long *)esp);
+ }
++void show_stack(struct task_struct *task, unsigned long *sp)
++{
++      if(task)
++              show_trace_task(task);
++      else
++              show_trace(sp);
++}
++
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+diff -Naur a/arch/um/kernel/tempfile.c b/arch/um/kernel/tempfile.c
+--- a/arch/um/kernel/tempfile.c        2004-01-08 22:22:40.000000000 -0500
++++ b/arch/um/kernel/tempfile.c        2004-01-08 22:29:35.000000000 -0500
+@@ -28,6 +28,7 @@
+       }
+       if((dir == NULL) || (*dir == '\0')) 
+               dir = "/tmp";
++
+       tempdir = malloc(strlen(dir) + 2);
+       if(tempdir == NULL){
+               fprintf(stderr, "Failed to malloc tempdir, "
+@@ -49,7 +50,8 @@
+       else
+               *tempname = 0;
+       strcat(tempname, template);
+-      if((fd = mkstemp(tempname)) < 0){
++      fd = mkstemp(tempname);
++      if(fd < 0){
+               fprintf(stderr, "open - cannot create %s: %s\n", tempname, 
+                       strerror(errno));
+               return -1;
+@@ -59,7 +61,8 @@
+               return -1;
+       }
+       if(out_tempname){
+-              if((*out_tempname = strdup(tempname)) == NULL){
++              *out_tempname = strdup(tempname);
++              if(*out_tempname == NULL){
+                       perror("strdup");
+                       return -1;
+               }
+diff -Naur a/arch/um/kernel/time.c b/arch/um/kernel/time.c
+--- a/arch/um/kernel/time.c    2004-01-08 22:16:05.000000000 -0500
++++ b/arch/um/kernel/time.c    2004-01-08 22:21:46.000000000 -0500
+@@ -4,24 +4,33 @@
+  */
+ #include <stdio.h>
++#include <stdlib.h>
+ #include <unistd.h>
+ #include <time.h>
+ #include <sys/time.h>
+ #include <signal.h>
+ #include <errno.h>
+-#include "linux/module.h"
+ #include "user_util.h"
+ #include "kern_util.h"
+ #include "user.h"
+ #include "process.h"
+ #include "signal_user.h"
+ #include "time_user.h"
++#include "kern_constants.h"
++
++/* XXX This really needs to be declared and initialized in a kernel file since 
++ * it's in <linux/time.h>
++ */
++extern struct timespec wall_to_monotonic;
+ extern struct timeval xtime;
++struct timeval local_offset = { 0, 0 };
++
+ void timer(void)
+ {
+       gettimeofday(&xtime, NULL);
++      timeradd(&xtime, &local_offset, &xtime);
+ }
+ void set_interval(int timer_type)
+@@ -66,7 +75,7 @@
+                      errno);
+ }
+-void idle_timer(void)
++void uml_idle_timer(void)
+ {
+       if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
+               panic("Couldn't unset SIGVTALRM handler");
+@@ -76,14 +85,54 @@
+       set_interval(ITIMER_REAL);
+ }
++static unsigned long long get_host_hz(void)
++{
++      char mhzline[16], *end;
++      int ret, mult, mhz, rest, len;
++
++      ret = cpu_feature("cpu MHz", mhzline, 
++                        sizeof(mhzline) / sizeof(mhzline[0]));
++      if(!ret)
++              panic ("Could not get host MHZ");
++
++      mhz = strtoul(mhzline, &end, 10);
++
++      /* This business is to parse a floating point number without using
++       * floating types.
++       */
++
++      rest = 0;
++      mult = 0;
++      if(*end == '.'){
++              end++;
++              len = strlen(end);
++              if(len < 6)
++                      mult = 6 - len;
++              else if(len > 6)
++                      end[6] = '\0';
++              rest = strtoul(end, NULL, 10);
++              while(mult-- > 0)
++                      rest *= 10;
++      }
++
++      return(1000000 * mhz + rest);
++}
++
++unsigned long long host_hz = 0;
++
+ void time_init(void)
+ {
++      struct timespec now;
++ 
++      host_hz = get_host_hz();
+       if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
+               panic("Couldn't set SIGVTALRM handler");
+       set_interval(ITIMER_VIRTUAL);
+-}
+-struct timeval local_offset = { 0, 0 };
++      do_posix_clock_monotonic_gettime(&now);
++      wall_to_monotonic.tv_sec = -now.tv_sec;
++      wall_to_monotonic.tv_nsec = -now.tv_nsec;
++}
+ void do_gettimeofday(struct timeval *tv)
+ {
+@@ -95,15 +144,13 @@
+       time_unlock(flags);
+ }
+-EXPORT_SYMBOL(do_gettimeofday);
+-
+ int do_settimeofday(struct timespec *tv)
+ {
+       struct timeval now;
+       unsigned long flags;
+       struct timeval tv_in;
+-      if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
++      if ((unsigned long) tv->tv_nsec >= UM_NSEC_PER_SEC)
+               return -EINVAL;
+       tv_in.tv_sec = tv->tv_sec;
+@@ -113,9 +160,9 @@
+       gettimeofday(&now, NULL);
+       timersub(&tv_in, &now, &local_offset);
+       time_unlock(flags);
+-}
+-EXPORT_SYMBOL(do_settimeofday);
++      return(0);
++}
+ void idle_sleep(int secs)
+ {
+diff -Naur a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
+--- a/arch/um/kernel/time_kern.c       2004-01-08 22:24:10.000000000 -0500
++++ b/arch/um/kernel/time_kern.c       2004-01-08 22:31:27.000000000 -0500
+@@ -30,6 +30,14 @@
+       return(HZ);
+ }
++/*
++ * Scheduler clock - returns current time in nanosec units.
++ */
++unsigned long long sched_clock(void)
++{
++      return (unsigned long long)jiffies_64 * (1000000000 / HZ);
++}
++
+ /* Changed at early boot */
+ int timer_irq_inited = 0;
+@@ -39,13 +47,47 @@
+  */
+ int __attribute__ ((__section__ (".unprotected"))) missed_ticks[NR_CPUS];
++static int first_tick;
++static unsigned long long prev_tsc;
++static long long delta;               /* Deviation per interval */
++
++extern unsigned long long host_hz;
++
+ void timer_irq(union uml_pt_regs *regs)
+ {
+-      int cpu = current->thread_info->cpu, ticks = missed_ticks[cpu];
++      unsigned long long ticks = 0;
++
++      if(!timer_irq_inited){
++              /* This is to ensure that ticks don't pile up when
++               * the timer handler is suspended */
++              first_tick = 0;
++              return;
++      }
++
++      if(first_tick){
++#if defined(CONFIG_UML_REAL_TIME_CLOCK)
++              unsigned long long tsc;
++              /* We've had 1 tick */
++              tsc = time_stamp();
++
++              delta += tsc - prev_tsc;
++              prev_tsc = tsc;
++
++              ticks += (delta * HZ) / host_hz;
++              delta -= (ticks * host_hz) / HZ;
++#else
++              ticks = 1;
++#endif
++      }
++      else {
++              prev_tsc = time_stamp();
++              first_tick = 1;
++      }
+-        if(!timer_irq_inited) return;
+-      missed_ticks[cpu] = 0;
+-      while(ticks--) do_IRQ(TIMER_IRQ, regs);
++      while(ticks > 0){
++              do_IRQ(TIMER_IRQ, regs);
++              ticks--;
++      }
+ }
+ void boot_timer_handler(int sig)
+@@ -58,12 +100,13 @@
+       do_timer(&regs);
+ }
+-void um_timer(int irq, void *dev, struct pt_regs *regs)
++irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
+ {
+       do_timer(regs);
+-      write_seqlock(&xtime_lock);
++      write_seqlock_irq(&xtime_lock);
+       timer();
+-      write_sequnlock(&xtime_lock);
++      write_sequnlock_irq(&xtime_lock);
++      return(IRQ_HANDLED);
+ }
+ long um_time(int * tloc)
+@@ -81,12 +124,12 @@
+ long um_stime(int * tptr)
+ {
+       int value;
+-      struct timeval new;
++      struct timespec new;
+       if (get_user(value, tptr))
+                 return -EFAULT;
+       new.tv_sec = value;
+-      new.tv_usec = 0;
++      new.tv_nsec = 0;
+       do_settimeofday(&new);
+       return 0;
+ }
+@@ -125,9 +168,11 @@
+ void timer_handler(int sig, union uml_pt_regs *regs)
+ {
+ #ifdef CONFIG_SMP
++      local_irq_disable();
+       update_process_times(user_context(UPT_SP(regs)));
++      local_irq_enable();
+ #endif
+-      if(current->thread_info->cpu == 0)
++      if(current_thread->cpu == 0)
+               timer_irq(regs);
+ }
+@@ -136,6 +181,7 @@
+ unsigned long time_lock(void)
+ {
+       unsigned long flags;
++
+       spin_lock_irqsave(&timer_spinlock, flags);
+       return(flags);
+ }
+@@ -150,8 +196,8 @@
+       int err;
+       CHOOSE_MODE(user_time_init_tt(), user_time_init_skas());
+-      if((err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", 
+-                            NULL)) != 0)
++      err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL);
++      if(err != 0)
+               printk(KERN_ERR "timer_init : request_irq failed - "
+                      "errno = %d\n", -err);
+       timer_irq_inited = 1;
+@@ -160,7 +206,6 @@
+ __initcall(timer_init);
+-
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+diff -Naur a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
+--- a/arch/um/kernel/trap_kern.c       2004-01-08 22:13:51.000000000 -0500
++++ b/arch/um/kernel/trap_kern.c       2004-01-08 22:18:52.000000000 -0500
+@@ -16,12 +16,15 @@
+ #include "asm/tlbflush.h"
+ #include "asm/a.out.h"
+ #include "asm/current.h"
++#include "asm/irq.h"
+ #include "user_util.h"
+ #include "kern_util.h"
+ #include "kern.h"
+ #include "chan_kern.h"
+ #include "mconsole_kern.h"
+ #include "2_5compat.h"
++#include "mem.h"
++#include "mem_kern.h"
+ int handle_page_fault(unsigned long address, unsigned long ip, 
+                     int is_write, int is_user, int *code_out)
+@@ -51,12 +54,12 @@
+       if(is_write && !(vma->vm_flags & VM_WRITE)) 
+               goto out;
+       page = address & PAGE_MASK;
+-      if(page == (unsigned long) current->thread_info + PAGE_SIZE)
++      if(page == (unsigned long) current_thread + PAGE_SIZE)
+               panic("Kernel stack overflow");
+       pgd = pgd_offset(mm, page);
+       pmd = pmd_offset(pgd, page);
+- survive:
+       do {
++ survive:
+               switch (handle_mm_fault(mm, vma, address, is_write)){
+               case VM_FAULT_MINOR:
+                       current->min_flt++;
+@@ -71,14 +74,20 @@
+                       err = -ENOMEM;
+                       goto out_of_memory;
+               default:
+-                      BUG();
++                      if (current->pid == 1) {
++                              up_read(&mm->mmap_sem);
++                              yield();
++                              down_read(&mm->mmap_sem);
++                              goto survive;
++                      }
++                      goto out;
+               }
+               pte = pte_offset_kernel(pmd, page);
+       } while(!pte_present(*pte));
++      err = 0;
+       *pte = pte_mkyoung(*pte);
+       if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
+       flush_tlb_page(vma, page);
+-      err = 0;
+  out:
+       up_read(&mm->mmap_sem);
+       return(err);
+@@ -98,6 +107,33 @@
+       goto out;
+ }
++LIST_HEAD(physmem_remappers);
++
++void register_remapper(struct remapper *info)
++{
++      list_add(&info->list, &physmem_remappers);
++}
++
++static int check_remapped_addr(unsigned long address, int is_write)
++{
++      struct remapper *remapper;
++      struct list_head *ele;
++      __u64 offset;
++      int fd;
++
++      fd = phys_mapping(__pa(address), &offset);
++      if(fd == -1)
++              return(0);
++
++      list_for_each(ele, &physmem_remappers){
++              remapper = list_entry(ele, struct remapper, list);
++              if((*remapper->proc)(fd, address, is_write, offset))
++                      return(1);
++      }
++
++      return(0);
++}
++
+ unsigned long segv(unsigned long address, unsigned long ip, int is_write, 
+                  int is_user, void *sc)
+ {
+@@ -109,7 +145,9 @@
+                 flush_tlb_kernel_vm();
+                 return(0);
+         }
+-        if(current->mm == NULL)
++      else if(check_remapped_addr(address & PAGE_MASK, is_write))
++              return(0);
++      else if(current->mm == NULL)
+               panic("Segfault with no mm");
+       err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
+@@ -120,9 +158,8 @@
+               current->thread.fault_addr = (void *) address;
+               do_longjmp(catcher, 1);
+       } 
+-      else if(current->thread.fault_addr != NULL){
++      else if(current->thread.fault_addr != NULL)
+               panic("fault_addr set but no fault catcher");
+-      }
+       else if(arch_fixup(ip, sc))
+               return(0);
+@@ -155,8 +192,6 @@
+ {
+       struct siginfo si;
+-      printk(KERN_ERR "Unfixable SEGV in '%s' (pid %d) at 0x%lx "
+-             "(ip 0x%lx)\n", current->comm, current->pid, address, ip);
+       si.si_signo = SIGSEGV;
+       si.si_code = SEGV_ACCERR;
+       si.si_addr = (void *) address;
+@@ -180,6 +215,11 @@
+       else relay_signal(sig, regs);
+ }
++void winch(int sig, union uml_pt_regs *regs)
++{
++      do_IRQ(WINCH_IRQ, regs);
++}
++
+ void trap_init(void)
+ {
+ }
+diff -Naur a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c
+--- a/arch/um/kernel/trap_user.c       2004-01-08 22:20:37.000000000 -0500
++++ b/arch/um/kernel/trap_user.c       2004-01-08 22:27:07.000000000 -0500
+@@ -5,11 +5,9 @@
+ #include <stdlib.h>
+ #include <errno.h>
+-#include <fcntl.h>
+ #include <setjmp.h>
+ #include <signal.h>
+ #include <sys/time.h>
+-#include <sys/ioctl.h>
+ #include <sys/ptrace.h>
+ #include <sys/wait.h>
+ #include <asm/page.h>
+@@ -82,6 +80,8 @@
+                    .is_irq            = 0 },
+       [ SIGILL ] { .handler           = relay_signal,
+                    .is_irq            = 0 },
++      [ SIGWINCH ] { .handler         = winch,
++                     .is_irq          = 1 },
+       [ SIGBUS ] { .handler           = bus_handler,
+                    .is_irq            = 0 },
+       [ SIGSEGV] { .handler           = segv_handler,
+@@ -123,7 +123,7 @@
+ {
+       jmp_buf *buf = b;
+-      longjmp(*buf, val);
++      siglongjmp(*buf, val);
+ }
+ /*
+diff -Naur a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
+--- a/arch/um/kernel/tt/exec_kern.c    2004-01-08 22:16:01.000000000 -0500
++++ b/arch/um/kernel/tt/exec_kern.c    2004-01-08 22:21:37.000000000 -0500
+@@ -17,6 +17,7 @@
+ #include "mem_user.h"
+ #include "os.h"
+ #include "tlb.h"
++#include "mode.h"
+ static int exec_tramp(void *sig_stack)
+ {
+@@ -47,17 +48,17 @@
+               do_exit(SIGKILL);
+       }
+-      if(current->thread_info->cpu == 0)
++      if(current_thread->cpu == 0)
+               forward_interrupts(new_pid);
+       current->thread.request.op = OP_EXEC;
+       current->thread.request.u.exec.pid = new_pid;
+-      unprotect_stack((unsigned long) current->thread_info);
++      unprotect_stack((unsigned long) current_thread);
+       os_usr1_process(os_getpid());
+       enable_timer();
+       free_page(stack);
+       protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
+-      task_protections((unsigned long) current->thread_info);
++      task_protections((unsigned long) current_thread);
+       force_flush_all();
+       unblock_signals();
+ }
+diff -Naur a/arch/um/kernel/tt/include/mode.h b/arch/um/kernel/tt/include/mode.h
+--- a/arch/um/kernel/tt/include/mode.h 2004-01-08 22:24:28.000000000 -0500
++++ b/arch/um/kernel/tt/include/mode.h 2004-01-08 22:32:04.000000000 -0500
+@@ -8,6 +8,8 @@
+ #include "sysdep/ptrace.h"
++enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
++
+ extern int tracing_pid;
+ extern int tracer(int (*init_proc)(void *), void *sp);
+diff -Naur a/arch/um/kernel/tt/include/uaccess.h b/arch/um/kernel/tt/include/uaccess.h
+--- a/arch/um/kernel/tt/include/uaccess.h      2004-01-08 22:24:32.000000000 -0500
++++ b/arch/um/kernel/tt/include/uaccess.h      2004-01-08 22:32:07.000000000 -0500
+@@ -1,5 +1,5 @@
+ /* 
+- * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+@@ -43,65 +43,19 @@
+ extern int __do_copy_from_user(void *to, const void *from, int n,
+                              void **fault_addr, void **fault_catcher);
+-
+-static inline int copy_from_user_tt(void *to, const void *from, int n)
+-{
+-      return(access_ok_tt(VERIFY_READ, from, n) ?
+-             __do_copy_from_user(to, from, n, 
+-                                 &current->thread.fault_addr,
+-                                 &current->thread.fault_catcher) : n);
+-}
+-
+-static inline int copy_to_user_tt(void *to, const void *from, int n)
+-{
+-      return(access_ok_tt(VERIFY_WRITE, to, n) ?
+-             __do_copy_to_user(to, from, n, 
+-                                 &current->thread.fault_addr,
+-                                 &current->thread.fault_catcher) : n);
+-}
+-
+ extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
+                                 void **fault_addr, void **fault_catcher);
+-
+-static inline int strncpy_from_user_tt(char *dst, const char *src, int count)
+-{
+-      int n;
+-
+-      if(!access_ok_tt(VERIFY_READ, src, 1)) return(-EFAULT);
+-      n = __do_strncpy_from_user(dst, src, count, 
+-                                 &current->thread.fault_addr,
+-                                 &current->thread.fault_catcher);
+-      if(n < 0) return(-EFAULT);
+-      return(n);
+-}
+-
+ extern int __do_clear_user(void *mem, size_t len, void **fault_addr,
+                          void **fault_catcher);
+-
+-static inline int __clear_user_tt(void *mem, int len)
+-{
+-      return(__do_clear_user(mem, len,
+-                             &current->thread.fault_addr,
+-                             &current->thread.fault_catcher));
+-}
+-
+-static inline int clear_user_tt(void *mem, int len)
+-{
+-      return(access_ok_tt(VERIFY_WRITE, mem, len) ? 
+-             __do_clear_user(mem, len, 
+-                             &current->thread.fault_addr,
+-                             &current->thread.fault_catcher) : len);
+-}
+-
+ extern int __do_strnlen_user(const char *str, unsigned long n,
+                            void **fault_addr, void **fault_catcher);
+-static inline int strnlen_user_tt(const void *str, int len)
+-{
+-      return(__do_strnlen_user(str, len,
+-                               &current->thread.fault_addr,
+-                               &current->thread.fault_catcher));
+-}
++extern int copy_from_user_tt(void *to, const void *from, int n);
++extern int copy_to_user_tt(void *to, const void *from, int n);
++extern int strncpy_from_user_tt(char *dst, const char *src, int count);
++extern int __clear_user_tt(void *mem, int len);
++extern int clear_user_tt(void *mem, int len);
++extern int strnlen_user_tt(const void *str, int len);
+ #endif
+diff -Naur a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile
+--- a/arch/um/kernel/tt/Makefile       2004-01-08 22:21:51.000000000 -0500
++++ b/arch/um/kernel/tt/Makefile       2004-01-08 22:28:40.000000000 -0500
+@@ -1,5 +1,5 @@
+ # 
+-# Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com)
+ # Licensed under the GPL
+ #
+@@ -7,7 +7,7 @@
+ obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
+       syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \
+-      uaccess_user.o sys-$(SUBARCH)/
++      uaccess.o uaccess_user.o sys-$(SUBARCH)/
+ obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
+diff -Naur a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c
+--- a/arch/um/kernel/tt/mem_user.c     2004-01-08 22:17:23.000000000 -0500
++++ b/arch/um/kernel/tt/mem_user.c     2004-01-08 22:23:10.000000000 -0500
+@@ -25,14 +25,13 @@
+       size = (unsigned long) segment_end - 
+               (unsigned long) segment_start;
+       data = create_mem_file(size);
+-      if((addr = mmap(NULL, size, PROT_WRITE | PROT_READ, 
+-                      MAP_SHARED, data, 0)) == MAP_FAILED){
++      addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0);
++      if(addr == MAP_FAILED){
+               perror("mapping new data segment");
+               exit(1);
+       }
+       memcpy(addr, segment_start, size);
+-      if(switcheroo(data, prot, addr, segment_start, 
+-                    size) < 0){
++      if(switcheroo(data, prot, addr, segment_start, size) < 0){
+               printf("switcheroo failed\n");
+               exit(1);
+       }
+diff -Naur a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
+--- a/arch/um/kernel/tt/process_kern.c 2004-01-08 22:28:38.000000000 -0500
++++ b/arch/um/kernel/tt/process_kern.c 2004-01-08 22:34:56.000000000 -0500
+@@ -62,7 +62,7 @@
+       reading = 0;
+       err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c));
+       if(err != sizeof(c))
+-              panic("write of switch_pipe failed, errno = %d", -err);
++              panic("write of switch_pipe failed, err = %d", -err);
+       reading = 1;
+       if((from->state == TASK_ZOMBIE) || (from->state == TASK_DEAD))
+@@ -104,48 +104,72 @@
+ void release_thread_tt(struct task_struct *task)
+ {
+-      os_kill_process(task->thread.mode.tt.extern_pid, 0);
++      int pid = task->thread.mode.tt.extern_pid;
++
++      if(os_getpid() != pid)
++              os_kill_process(pid, 0);
+ }
+ void exit_thread_tt(void)
+ {
+-      close(current->thread.mode.tt.switch_pipe[0]);
+-      close(current->thread.mode.tt.switch_pipe[1]);
++      os_close_file(current->thread.mode.tt.switch_pipe[0]);
++      os_close_file(current->thread.mode.tt.switch_pipe[1]);
+ }
+ void schedule_tail(task_t *prev);
+ static void new_thread_handler(int sig)
+ {
++      unsigned long disable;
+       int (*fn)(void *);
+       void *arg;
+       fn = current->thread.request.u.thread.proc;
+       arg = current->thread.request.u.thread.arg;
++
+       UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
++      disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) |
++              (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1));
++      SC_SIGMASK(UPT_SC(&current->thread.regs.regs)) &= ~disable;
++
+       suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
+-      block_signals();
++      force_flush_all();
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
++      current->thread.prev_sched = NULL;
++
+       init_new_thread_signals(1);
+-#ifdef CONFIG_SMP
+-      schedule_tail(current->thread.prev_sched);
+-#endif
+       enable_timer();
+       free_page(current->thread.temp_stack);
+       set_cmdline("(kernel thread)");
+-      force_flush_all();
+-      current->thread.prev_sched = NULL;
+       change_sig(SIGUSR1, 1);
+       change_sig(SIGVTALRM, 1);
+       change_sig(SIGPROF, 1);
+-      unblock_signals();
++      local_irq_enable();
+       if(!run_kernel_thread(fn, arg, &current->thread.exec_buf))
+               do_exit(0);
+ }
+ static int new_thread_proc(void *stack)
+ {
++      /* local_irq_disable is needed to block out signals until this thread is
++       * properly scheduled.  Otherwise, the tracing thread will get mighty 
++       * upset about any signals that arrive before that.  
++       * This has the complication that it sets the saved signal mask in
++       * the sigcontext to block signals.  This gets restored when this
++       * thread (or a descendant, since they get a copy of this sigcontext)
++       * returns to userspace.
++       * So, this is compensated for elsewhere.
++       * XXX There is still a small window until local_irq_disable() actually 
++       * finishes where signals are possible - shouldn't be a problem in 
++       * practice since SIGIO hasn't been forwarded here yet, and the 
++       * local_irq_disable should finish before a SIGVTALRM has time to be 
++       * delivered.
++       */
++
++      local_irq_disable();
+       init_new_thread_stack(stack, new_thread_handler);
+       os_usr1_process(os_getpid());
+       return(0);
+@@ -156,7 +180,7 @@
+  * itself with a SIGUSR1.  set_user_mode has to be run with SIGUSR1 off,
+  * so it is blocked before it's called.  They are re-enabled on sigreturn
+  * despite the fact that they were blocked when the SIGUSR1 was issued because
+- * copy_thread copies the parent's signcontext, including the signal mask
++ * copy_thread copies the parent's sigcontext, including the signal mask
+  * onto the signal frame.
+  */
+@@ -165,35 +189,32 @@
+       UPT_SC(&current->thread.regs.regs) = (void *) (&sig + 1);
+       suspend_new_thread(current->thread.mode.tt.switch_pipe[0]);
+-#ifdef CONFIG_SMP     
+-      schedule_tail(NULL);
+-#endif
++      force_flush_all();
++      if(current->thread.prev_sched != NULL)
++              schedule_tail(current->thread.prev_sched);
++      current->thread.prev_sched = NULL;
++
+       enable_timer();
+       change_sig(SIGVTALRM, 1);
+       local_irq_enable();
+-      force_flush_all();
+       if(current->mm != current->parent->mm)
+               protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 
+                              1, 0, 1);
+-      task_protections((unsigned long) current->thread_info);
+-
+-      current->thread.prev_sched = NULL;
++      task_protections((unsigned long) current_thread);
+       free_page(current->thread.temp_stack);
++      local_irq_disable();
+       change_sig(SIGUSR1, 0);
+       set_user_mode(current);
+ }
+-static int sigusr1 = SIGUSR1;
+-
+ int fork_tramp(void *stack)
+ {
+-      int sig = sigusr1;
+-
+       local_irq_disable();
++      arch_init_thread();
+       init_new_thread_stack(stack, finish_fork_handler);
+-      kill(os_getpid(), sig);
++      os_usr1_process(os_getpid());
+       return(0);
+ }
+@@ -213,8 +234,8 @@
+       }
+       err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
+-      if(err){
+-              printk("copy_thread : pipe failed, errno = %d\n", -err);
++      if(err < 0){
++              printk("copy_thread : pipe failed, err = %d\n", -err);
+               return(err);
+       }
+@@ -377,8 +398,8 @@
+       pages = (1 << CONFIG_KERNEL_STACK_ORDER);
+-      start = (unsigned long) current->thread_info + PAGE_SIZE;
+-      end = (unsigned long) current + PAGE_SIZE * pages;
++      start = (unsigned long) current_thread + PAGE_SIZE;
++      end = (unsigned long) current_thread + PAGE_SIZE * pages;
+       protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1);
+       protect_memory(end, high_physmem - end, 1, w, 1, 1);
+@@ -454,8 +475,9 @@
+       init_task.thread.mode.tt.extern_pid = pid;
+       err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1);
+-      if(err) panic("Can't create switch pipe for init_task, errno = %d", 
+-                    err);
++      if(err) 
++              panic("Can't create switch pipe for init_task, errno = %d", 
++                    -err);
+ }
+ int singlestepping_tt(void *t)
+diff -Naur a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c
+--- a/arch/um/kernel/tt/ptproxy/proxy.c        2004-01-08 22:23:52.000000000 -0500
++++ b/arch/um/kernel/tt/ptproxy/proxy.c        2004-01-08 22:31:01.000000000 -0500
+@@ -15,7 +15,6 @@
+ #include <unistd.h>
+ #include <signal.h>
+ #include <string.h>
+-#include <fcntl.h>
+ #include <termios.h>
+ #include <sys/wait.h>
+ #include <sys/types.h>
+@@ -293,10 +292,10 @@
+ }
+ char gdb_init_string[] = 
+-"att 1
+-b panic
+-b stop
+-handle SIGWINCH nostop noprint pass
++"att 1 \n\
++b panic \n\
++b stop \n\
++handle SIGWINCH nostop noprint pass \n\
+ ";
+ int start_debugger(char *prog, int startup, int stop, int *fd_out)
+@@ -304,7 +303,8 @@
+       int slave, child;
+       slave = open_gdb_chan();
+-      if((child = fork()) == 0){
++      child = fork();
++      if(child == 0){
+               char *tempname = NULL;
+               int fd;
+@@ -327,18 +327,19 @@
+                       exit(1);
+ #endif
+               }
+-              if((fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0)) < 0){
+-                      printk("start_debugger : make_tempfile failed, errno = %d\n",
+-                             errno);
++              fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0);
++              if(fd < 0){
++                      printk("start_debugger : make_tempfile failed,"
++                             "err = %d\n", -fd);
+                       exit(1);
+               }
+-              write(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
++              os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1);
+               if(startup){
+                       if(stop){
+-                              write(fd, "b start_kernel\n",
++                              os_write_file(fd, "b start_kernel\n",
+                                     strlen("b start_kernel\n"));
+                       }
+-                      write(fd, "c\n", strlen("c\n"));
++                      os_write_file(fd, "c\n", strlen("c\n"));
+               }
+               if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){
+                       printk("start_debugger :  PTRACE_TRACEME failed, "
+diff -Naur a/arch/um/kernel/tt/ptproxy/sysdep.c b/arch/um/kernel/tt/ptproxy/sysdep.c
+--- a/arch/um/kernel/tt/ptproxy/sysdep.c       2004-01-08 22:27:13.000000000 -0500
++++ b/arch/um/kernel/tt/ptproxy/sysdep.c       2004-01-08 22:34:07.000000000 -0500
+@@ -9,6 +9,7 @@
+ #include <string.h>
+ #include <stdlib.h>
+ #include <signal.h>
++#include <errno.h>
+ #include <sys/types.h>
+ #include <sys/ptrace.h>
+ #include <asm/ptrace.h>
+diff -Naur a/arch/um/kernel/tt/ptproxy/wait.c b/arch/um/kernel/tt/ptproxy/wait.c
+--- a/arch/um/kernel/tt/ptproxy/wait.c 2004-01-08 22:29:38.000000000 -0500
++++ b/arch/um/kernel/tt/ptproxy/wait.c 2004-01-08 22:35:16.000000000 -0500
+@@ -56,21 +56,23 @@
+ int real_wait_return(struct debugger *debugger)
+ {
+       unsigned long ip;
+-      int err, pid;
++      int pid;
+       pid = debugger->pid;
++
+       ip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0);
+       ip = IP_RESTART_SYSCALL(ip);
+-      err = ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip);
++
+       if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0)
+               tracer_panic("real_wait_return : Failed to restart system "
+-                           "call, errno = %d\n");
++                           "call, errno = %d\n", errno);
++
+       if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) ||
+          (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
+          (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) ||
+          debugger_normal_return(debugger, -1))
+               tracer_panic("real_wait_return : gdb failed to wait, "
+-                           "errno = %d\n");
++                           "errno = %d\n", errno);
+       return(0);
+ }
+diff -Naur a/arch/um/kernel/tt/syscall_kern.c b/arch/um/kernel/tt/syscall_kern.c
+--- a/arch/um/kernel/tt/syscall_kern.c 2004-01-08 22:13:31.000000000 -0500
++++ b/arch/um/kernel/tt/syscall_kern.c 2004-01-08 22:17:14.000000000 -0500
+@@ -1,5 +1,5 @@
+ /* 
+- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+diff -Naur a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
+--- a/arch/um/kernel/tt/tracer.c       2004-01-08 22:13:44.000000000 -0500
++++ b/arch/um/kernel/tt/tracer.c       2004-01-08 22:18:08.000000000 -0500
+@@ -39,16 +39,17 @@
+               return(0);
+       register_winch_irq(tracer_winch[0], fd, -1, data);
+-      return(0);
++      return(1);
+ }
+ static void tracer_winch_handler(int sig)
+ {
++      int n;
+       char c = 1;
+-      if(write(tracer_winch[1], &c, sizeof(c)) != sizeof(c))
+-              printk("tracer_winch_handler - write failed, errno = %d\n",
+-                     errno);
++      n = os_write_file(tracer_winch[1], &c, sizeof(c));
++      if(n != sizeof(c))
++              printk("tracer_winch_handler - write failed, err = %d\n", -n);
+ }
+ /* Called only by the tracing thread during initialization */
+@@ -58,9 +59,8 @@
+       int err;
+       err = os_pipe(tracer_winch, 1, 1);
+-      if(err){
+-              printk("setup_tracer_winch : os_pipe failed, errno = %d\n", 
+-                     -err);
++      if(err < 0){
++              printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err);
+               return;
+       }
+       signal(SIGWINCH, tracer_winch_handler);
+@@ -130,8 +130,8 @@
+       case SIGTSTP:
+               if(ptrace(PTRACE_CONT, pid, 0, sig) < 0)
+                       tracer_panic("sleeping_process_signal : Failed to "
+-                                   "continue pid %d, errno = %d\n", pid,
+-                                   sig);
++                                   "continue pid %d, signal = %d, "
++                                   "errno = %d\n", pid, sig, errno);
+               break;
+       /* This happens when the debugger (e.g. strace) is doing system call 
+@@ -145,7 +145,7 @@
+               if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
+                       tracer_panic("sleeping_process_signal : Failed to "
+                                    "PTRACE_SYSCALL pid %d, errno = %d\n",
+-                                   pid, sig);
++                                   pid, errno);
+               break;
+       case SIGSTOP:
+               break;
+@@ -218,7 +218,7 @@
+                       err = attach(debugger_parent);
+                       if(err){
+                               printf("Failed to attach debugger parent %d, "
+-                                     "errno = %d\n", debugger_parent, err);
++                                     "errno = %d\n", debugger_parent, -err);
+                               debugger_parent = -1;
+                       }
+                       else {
+@@ -233,7 +233,8 @@
+       }
+       set_cmdline("(tracing thread)");
+       while(1){
+-              if((pid = waitpid(-1, &status, WUNTRACED)) <= 0){
++              pid = waitpid(-1, &status, WUNTRACED);
++              if(pid <= 0){
+                       if(errno != ECHILD){
+                               printf("wait failed - errno = %d\n", errno);
+                       }
+@@ -401,7 +402,7 @@
+               
+               if(!strcmp(line, "go")) debug_stop = 0;
+               else if(!strcmp(line, "parent")) debug_parent = 1;
+-              else printk("Unknown debug option : '%s'\n", line);
++              else printf("Unknown debug option : '%s'\n", line);
+               line = next;
+       }
+diff -Naur a/arch/um/kernel/tt/uaccess.c b/arch/um/kernel/tt/uaccess.c
+--- a/arch/um/kernel/tt/uaccess.c      1969-12-31 19:00:00.000000000 -0500
++++ b/arch/um/kernel/tt/uaccess.c      2004-01-08 22:18:04.000000000 -0500
+@@ -0,0 +1,73 @@
++/* 
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/sched.h"
++#include "asm/uaccess.h"
++
++int copy_from_user_tt(void *to, const void *from, int n)
++{
++      if(!access_ok_tt(VERIFY_READ, from, n)) 
++              return(n);
++
++      return(__do_copy_from_user(to, from, n, &current->thread.fault_addr,
++                                 &current->thread.fault_catcher));
++}
++
++int copy_to_user_tt(void *to, const void *from, int n)
++{
++      if(!access_ok_tt(VERIFY_WRITE, to, n))
++              return(n);
++              
++      return(__do_copy_to_user(to, from, n, &current->thread.fault_addr,
++                               &current->thread.fault_catcher));
++}
++
++int strncpy_from_user_tt(char *dst, const char *src, int count)
++{
++      int n;
++
++      if(!access_ok_tt(VERIFY_READ, src, 1)) 
++              return(-EFAULT);
++
++      n = __do_strncpy_from_user(dst, src, count, 
++                                 &current->thread.fault_addr,
++                                 &current->thread.fault_catcher);
++      if(n < 0) return(-EFAULT);
++      return(n);
++}
++
++int __clear_user_tt(void *mem, int len)
++{
++      return(__do_clear_user(mem, len,
++                             &current->thread.fault_addr,
++                             &current->thread.fault_catcher));
++}
++
++int clear_user_tt(void *mem, int len)
++{
++      if(!access_ok_tt(VERIFY_WRITE, mem, len))
++              return(len);
++
++      return(__do_clear_user(mem, len, &current->thread.fault_addr,
++                             &current->thread.fault_catcher));
++}
++
++int strnlen_user_tt(const void *str, int len)
++{
++      return(__do_strnlen_user(str, len,
++                               &current->thread.fault_addr,
++                               &current->thread.fault_catcher));
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
+--- a/arch/um/kernel/tt/uaccess_user.c 2004-01-08 22:17:56.000000000 -0500
++++ b/arch/um/kernel/tt/uaccess_user.c 2004-01-08 22:24:00.000000000 -0500
+@@ -8,15 +8,20 @@
+ #include <string.h>
+ #include "user_util.h"
+ #include "uml_uaccess.h"
++#include "task.h"
++#include "kern_util.h"
+ int __do_copy_from_user(void *to, const void *from, int n,
+                       void **fault_addr, void **fault_catcher)
+ {
++      struct tt_regs save = TASK_REGS(get_current())->tt;
+       unsigned long fault;
+       int faulted;
+       fault = __do_user_copy(to, from, n, fault_addr, fault_catcher,
+                              __do_copy, &faulted);
++      TASK_REGS(get_current())->tt = save;
++
+       if(!faulted) return(0);
+       else return(n - (fault - (unsigned long) from));
+ }
+@@ -29,11 +34,14 @@
+ int __do_strncpy_from_user(char *dst, const char *src, unsigned long count,
+                          void **fault_addr, void **fault_catcher)
+ {
++      struct tt_regs save = TASK_REGS(get_current())->tt;
+       unsigned long fault;
+       int faulted;
+       fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher,
+                              __do_strncpy, &faulted);
++      TASK_REGS(get_current())->tt = save;
++
+       if(!faulted) return(strlen(dst));
+       else return(-1);
+ }
+@@ -46,11 +54,14 @@
+ int __do_clear_user(void *mem, unsigned long len,
+                   void **fault_addr, void **fault_catcher)
+ {
++      struct tt_regs save = TASK_REGS(get_current())->tt;
+       unsigned long fault;
+       int faulted;
+       fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher,
+                              __do_clear, &faulted);
++      TASK_REGS(get_current())->tt = save;
++
+       if(!faulted) return(0);
+       else return(len - (fault - (unsigned long) mem));
+ }
+@@ -58,19 +69,20 @@
+ int __do_strnlen_user(const char *str, unsigned long n,
+                     void **fault_addr, void **fault_catcher)
+ {
++      struct tt_regs save = TASK_REGS(get_current())->tt;
+       int ret;
+       unsigned long *faddrp = (unsigned long *)fault_addr;
+       jmp_buf jbuf;
+       *fault_catcher = &jbuf;
+-      if(setjmp(jbuf) == 0){
++      if(sigsetjmp(jbuf, 1) == 0)
+               ret = strlen(str) + 1;
+-      } 
+-      else {
+-              ret = *faddrp - (unsigned long) str;
+-      }
++      else ret = *faddrp - (unsigned long) str;
++
+       *fault_addr = NULL;
+       *fault_catcher = NULL;
++
++      TASK_REGS(get_current())->tt = save;
+       return ret;
+ }
+diff -Naur a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c
+--- a/arch/um/kernel/tty_log.c 2004-01-08 22:23:59.000000000 -0500
++++ b/arch/um/kernel/tty_log.c 2004-01-08 22:31:12.000000000 -0500
+@@ -9,10 +9,10 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <unistd.h>
+-#include <fcntl.h>
+ #include <sys/time.h>
+ #include "init.h"
+ #include "user.h"
++#include "kern_util.h"
+ #include "os.h"
+ #define TTY_LOG_DIR "./"
+@@ -24,29 +24,40 @@
+ #define TTY_LOG_OPEN 1
+ #define TTY_LOG_CLOSE 2
+ #define TTY_LOG_WRITE 3
++#define TTY_LOG_EXEC 4
++
++#define TTY_READ 1
++#define TTY_WRITE 2
+ struct tty_log_buf {
+       int what;
+       unsigned long tty;
+       int len;
++      int direction;
++      unsigned long sec;
++      unsigned long usec;
+ };
+-int open_tty_log(void *tty)
++int open_tty_log(void *tty, void *current_tty)
+ {
+       struct timeval tv;
+       struct tty_log_buf data;
+       char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")];
+       int fd;
++      gettimeofday(&tv, NULL);
+       if(tty_log_fd != -1){
+-              data = ((struct tty_log_buf) { what :   TTY_LOG_OPEN,
+-                                             tty : (unsigned long) tty,
+-                                             len : 0 });
+-              write(tty_log_fd, &data, sizeof(data));
++              data = ((struct tty_log_buf) { .what    = TTY_LOG_OPEN,
++                                             .tty  = (unsigned long) tty,
++                                             .len  = sizeof(current_tty),
++                                             .direction = 0,
++                                             .sec = tv.tv_sec,
++                                             .usec = tv.tv_usec } );
++              os_write_file(tty_log_fd, &data, sizeof(data));
++              os_write_file(tty_log_fd, &current_tty, data.len);
+               return(tty_log_fd);
+       }
+-      gettimeofday(&tv, NULL);
+       sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, 
+               (unsigned int) tv.tv_usec);
+@@ -62,30 +73,117 @@
+ void close_tty_log(int fd, void *tty)
+ {
+       struct tty_log_buf data;
++      struct timeval tv;
+       if(tty_log_fd != -1){
+-              data = ((struct tty_log_buf) { what :   TTY_LOG_CLOSE,
+-                                             tty : (unsigned long) tty,
+-                                             len : 0 });
+-              write(tty_log_fd, &data, sizeof(data));
++              gettimeofday(&tv, NULL);
++              data = ((struct tty_log_buf) { .what    = TTY_LOG_CLOSE,
++                                             .tty  = (unsigned long) tty,
++                                             .len  = 0,
++                                             .direction = 0,
++                                             .sec = tv.tv_sec,
++                                             .usec = tv.tv_usec } );
++              os_write_file(tty_log_fd, &data, sizeof(data));
+               return;
+       }
+-      close(fd);
++      os_close_file(fd);
+ }
+-int write_tty_log(int fd, char *buf, int len, void *tty)
++static int log_chunk(int fd, const char *buf, int len)
+ {
++      int total = 0, try, missed, n;
++      char chunk[64];
++
++      while(len > 0){
++              try = (len > sizeof(chunk)) ? sizeof(chunk) : len;
++              missed = copy_from_user_proc(chunk, (char *) buf, try);
++              try -= missed;
++              n = os_write_file(fd, chunk, try);
++              if(n != try) {
++                      if(n < 0) 
++                              return(n);
++                      return(-EIO);
++              }
++              if(missed != 0)
++                      return(-EFAULT);
++
++              len -= try;
++              total += try;
++              buf += try;
++      }
++
++      return(total);
++}
++
++int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read)
++{
++      struct timeval tv;
+       struct tty_log_buf data;
++      int direction;
+       if(fd == tty_log_fd){
+-              data = ((struct tty_log_buf) { what :   TTY_LOG_WRITE,
+-                                             tty : (unsigned long) tty,
+-                                             len : len });
+-              write(tty_log_fd, &data, sizeof(data));
++              gettimeofday(&tv, NULL);
++              direction = is_read ? TTY_READ : TTY_WRITE;
++              data = ((struct tty_log_buf) { .what    = TTY_LOG_WRITE,
++                                             .tty  = (unsigned long) tty,
++                                             .len  = len,
++                                             .direction = direction,
++                                             .sec = tv.tv_sec,
++                                             .usec = tv.tv_usec } );
++              os_write_file(tty_log_fd, &data, sizeof(data));
+       }
+-      return(write(fd, buf, len));
++
++      return(log_chunk(fd, buf, len));
+ }
++void log_exec(char **argv, void *tty)
++{
++      struct timeval tv;
++      struct tty_log_buf data;
++      char **ptr,*arg;
++      int len;
++      
++      if(tty_log_fd == -1) return;
++
++      gettimeofday(&tv, NULL);
++
++      len = 0;
++      for(ptr = argv; ; ptr++){
++              if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
++                      return;
++              if(arg == NULL) break;
++              len += strlen_user_proc(arg);
++      }
++
++      data = ((struct tty_log_buf) { .what    = TTY_LOG_EXEC,
++                                     .tty  = (unsigned long) tty,
++                                     .len  = len,
++                                     .direction = 0,
++                                     .sec = tv.tv_sec,
++                                     .usec = tv.tv_usec } );
++      os_write_file(tty_log_fd, &data, sizeof(data));
++
++      for(ptr = argv; ; ptr++){
++              if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
++                      return;
++              if(arg == NULL) break;
++              log_chunk(tty_log_fd, arg, strlen_user_proc(arg));
++      }
++}
++
++extern void register_tty_logger(int (*opener)(void *, void *),
++                              int (*writer)(int, const char *, int, 
++                                            void *, int),
++                              void (*closer)(int, void *));
++
++static int register_logger(void)
++{
++      register_tty_logger(open_tty_log, write_tty_log, close_tty_log);
++      return(0);
++}
++
++__uml_initcall(register_logger);
++
+ static int __init set_tty_log_dir(char *name, int *add)
+ {
+       tty_log_dir = name;
+@@ -104,7 +202,7 @@
+       tty_log_fd = strtoul(name, &end, 0);
+       if((*end != '\0') || (end == name)){
+-              printk("set_tty_log_fd - strtoul failed on '%s'\n", name);
++              printf("set_tty_log_fd - strtoul failed on '%s'\n", name);
+               tty_log_fd = -1;
+       }
+       return 0;
+diff -Naur a/arch/um/kernel/uaccess_user.c b/arch/um/kernel/uaccess_user.c
+--- a/arch/um/kernel/uaccess_user.c    2004-01-08 22:26:03.000000000 -0500
++++ b/arch/um/kernel/uaccess_user.c    2004-01-08 22:33:46.000000000 -0500
+@@ -20,7 +20,7 @@
+       jmp_buf jbuf;
+       *fault_catcher = &jbuf;
+-      if(setjmp(jbuf) == 0){
++      if(sigsetjmp(jbuf, 1) == 0){
+               (*op)(to, from, n);
+               ret = 0;
+               *faulted_out = 0;
+diff -Naur a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
+--- a/arch/um/kernel/um_arch.c 2004-01-08 22:28:03.000000000 -0500
++++ b/arch/um/kernel/um_arch.c 2004-01-08 22:34:23.000000000 -0500
+@@ -38,13 +38,18 @@
+ #include "mode_kern.h"
+ #include "mode.h"
+-#define DEFAULT_COMMAND_LINE "root=6200"
++#define DEFAULT_COMMAND_LINE "root=98:0"
+ struct cpuinfo_um boot_cpu_data = { 
+       .loops_per_jiffy        = 0,
+       .ipi_pipe               = { -1, -1 }
+ };
++/* Placeholder to make UML link until the vsyscall stuff is actually 
++ * implemented
++ */
++void *__kernel_vsyscall;
++
+ unsigned long thread_saved_pc(struct task_struct *task)
+ {
+       return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas,
+@@ -53,18 +58,22 @@
+ static int show_cpuinfo(struct seq_file *m, void *v)
+ {
+-      int index;
++      int index = 0;
+-      index = (struct cpuinfo_um *)v - cpu_data;
+ #ifdef CONFIG_SMP
++      index = (struct cpuinfo_um *) v - cpu_data;
+       if (!cpu_online(index))
+               return 0;
+ #endif
+-      seq_printf(m, "bogomips\t: %lu.%02lu\n",
++      seq_printf(m, "processor\t: %d\n", index);
++      seq_printf(m, "vendor_id\t: User Mode Linux\n");
++      seq_printf(m, "model name\t: UML\n");
++      seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas"));
++      seq_printf(m, "host\t\t: %s\n", host_info);
++      seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
+                  loops_per_jiffy/(500000/HZ),
+                  (loops_per_jiffy/(5000/HZ)) % 100);
+-      seq_printf(m, "host\t\t: %s\n", host_info);
+       return(0);
+ }
+@@ -134,12 +143,12 @@
+       if(umid != NULL){
+               snprintf(argv1_begin, 
+                        (argv1_end - argv1_begin) * sizeof(*ptr), 
+-                       "(%s)", umid);
++                       "(%s) ", umid);
+               ptr = &argv1_begin[strlen(argv1_begin)];
+       }
+       else ptr = argv1_begin;
+-      snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), " [%s]", cmd);
++      snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd);
+       memset(argv1_begin + strlen(argv1_begin), '\0', 
+              argv1_end - argv1_begin - strlen(argv1_begin));
+ #endif
+@@ -179,7 +188,7 @@
+ static int __init uml_ncpus_setup(char *line, int *add)
+ {
+        if (!sscanf(line, "%d", &ncpus)) {
+-               printk("Couldn't parse [%s]\n", line);
++               printf("Couldn't parse [%s]\n", line);
+                return -1;
+        }
+@@ -210,7 +219,7 @@
+ static int __init mode_tt_setup(char *line, int *add)
+ {
+-      printk("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
++      printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n");
+       return(0);
+ }
+@@ -221,7 +230,7 @@
+ static int __init mode_tt_setup(char *line, int *add)
+ {
+-      printk("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
++      printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n");
+       return(0);
+ }
+@@ -291,7 +300,7 @@
+ /* Set during early boot */
+ unsigned long brk_start;
+-static struct vm_reserved kernel_vm_reserved;
++unsigned long end_iomem;
+ #define MIN_VMALLOC (32 * 1024 * 1024)
+@@ -299,7 +308,7 @@
+ {
+       unsigned long avail;
+       unsigned long virtmem_size, max_physmem;
+-      unsigned int i, add, err;
++      unsigned int i, add;
+       for (i = 1; i < argc; i++){
+               if((i == 1) && (argv[i][0] == ' ')) continue;
+@@ -328,12 +337,16 @@
+       argv1_end = &argv[1][strlen(argv[1])];
+ #endif
+   
+-      set_usable_vm(uml_physmem, get_kmem_end());
+-
+       highmem = 0;
+-      max_physmem = get_kmem_end() - uml_physmem - MIN_VMALLOC;
+-      if(physmem_size > max_physmem){
+-              highmem = physmem_size - max_physmem;
++      iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK;
++      max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC;
++
++      /* Zones have to begin on a 1 << MAX_ORDER page boundary,
++       * so this makes sure that's true for highmem
++       */
++      max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1);
++      if(physmem_size + iomem_size > max_physmem){
++              highmem = physmem_size + iomem_size - max_physmem;
+               physmem_size -= highmem;
+ #ifndef CONFIG_HIGHMEM
+               highmem = 0;
+@@ -343,11 +356,19 @@
+       }
+       high_physmem = uml_physmem + physmem_size;
+-      high_memory = (void *) high_physmem;
++      end_iomem = high_physmem + iomem_size;
++      high_memory = (void *) end_iomem;
+       start_vm = VMALLOC_START;
+-      setup_physmem(uml_physmem, uml_reserved, physmem_size);
++      setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem);
++      if(init_maps(physmem_size, iomem_size, highmem)){
++              printf("Failed to allocate mem_map for %ld bytes of physical "
++                     "memory and %ld bytes of highmem\n", physmem_size,
++                     highmem);
++              exit(1);
++      }
++
+       virtmem_size = physmem_size;
+       avail = get_kmem_end() - start_vm;
+       if(physmem_size > avail) virtmem_size = avail;
+@@ -357,18 +378,13 @@
+               printf("Kernel virtual memory size shrunk to %ld bytes\n",
+                      virtmem_size);
+-      err = reserve_vm(high_physmem, end_vm, &kernel_vm_reserved);
+-      if(err){
+-              printf("Failed to reserve VM area for kernel VM\n");
+-              exit(1);
+-      }
+-
+       uml_postsetup();
+       init_task.thread.kernel_stack = (unsigned long) &init_thread_info + 
+               2 * PAGE_SIZE;
+       task_protections((unsigned long) &init_thread_info);
++      os_flush_stdout();
+       return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
+ }
+@@ -403,6 +419,7 @@
+       arch_check_bugs();
+       check_ptrace();
+       check_sigio();
++      check_devanon();
+ }
+ /*
+diff -Naur a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
+--- a/arch/um/kernel/umid.c    2004-01-08 22:30:24.000000000 -0500
++++ b/arch/um/kernel/umid.c    2004-01-08 22:35:37.000000000 -0500
+@@ -5,7 +5,6 @@
+ #include <stdio.h>
+ #include <unistd.h>
+-#include <fcntl.h>
+ #include <errno.h>
+ #include <string.h>
+ #include <stdlib.h>
+@@ -33,18 +32,19 @@
+ static int umid_is_random = 1;
+ static int umid_inited = 0;
+-static int make_umid(void);
++static int make_umid(int (*printer)(const char *fmt, ...));
+-static int __init set_umid(char *name, int is_random)
++static int __init set_umid(char *name, int is_random, 
++                         int (*printer)(const char *fmt, ...))
+ {
+       if(umid_inited){
+-              printk("Unique machine name can't be set twice\n");
++              (*printer)("Unique machine name can't be set twice\n");
+               return(-1);
+       }
+       if(strlen(name) > UMID_LEN - 1)
+-              printk("Unique machine name is being truncated to %s "
+-                     "characters\n", UMID_LEN);
++              (*printer)("Unique machine name is being truncated to %s "
++                         "characters\n", UMID_LEN);
+       strlcpy(umid, name, sizeof(umid));
+       umid_is_random = is_random;
+@@ -54,7 +54,7 @@
+ static int __init set_umid_arg(char *name, int *add)
+ {
+-      return(set_umid(name, 0));
++      return(set_umid(name, 0, printf));
+ }
+ __uml_setup("umid=", set_umid_arg,
+@@ -67,7 +67,7 @@
+ {
+       int n;
+-      if(!umid_inited && make_umid()) return(-1);
++      if(!umid_inited && make_umid(printk)) return(-1);
+       n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1;
+       if(n > len){
+@@ -85,22 +85,23 @@
+ {
+       char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
+       char pid[sizeof("nnnnn\0")];
+-      int fd;
++      int fd, n;
+       if(umid_file_name("pid", file, sizeof(file))) return 0;
+       fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), 
+                         0644);
+       if(fd < 0){
+-              printk("Open of machine pid file \"%s\" failed - "
+-                     "errno = %d\n", file, -fd);
++              printf("Open of machine pid file \"%s\" failed - "
++                     "err = %d\n", file, -fd);
+               return 0;
+       }
+       sprintf(pid, "%d\n", os_getpid());
+-      if(write(fd, pid, strlen(pid)) != strlen(pid))
+-              printk("Write of pid file failed - errno = %d\n", errno);
+-      close(fd);
++      n = os_write_file(fd, pid, strlen(pid));
++      if(n != strlen(pid))
++              printf("Write of pid file failed - err = %d\n", -n);
++      os_close_file(fd);
+       return 0;
+ }
+@@ -111,7 +112,8 @@
+       int len;
+       char file[256];
+-      if((directory = opendir(dir)) == NULL){
++      directory = opendir(dir);
++      if(directory == NULL){
+               printk("actually_do_remove : couldn't open directory '%s', "
+                      "errno = %d\n", dir, errno);
+               return(1);
+@@ -160,22 +162,24 @@
+ {
+       char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")];
+       char pid[sizeof("nnnnn\0")], *end;
+-      int dead, fd, p;
++      int dead, fd, p, n;
+       sprintf(file, "%s/pid", dir);
+       dead = 0;
+-      if((fd = os_open_file(file, of_read(OPENFLAGS()), 0)) < 0){
++      fd = os_open_file(file, of_read(OPENFLAGS()), 0);
++      if(fd < 0){
+               if(fd != -ENOENT){
+                       printk("not_dead_yet : couldn't open pid file '%s', "
+-                             "errno = %d\n", file, -fd);
++                             "err = %d\n", file, -fd);
+                       return(1);
+               }
+               dead = 1;
+       }
+       if(fd > 0){
+-              if(read(fd, pid, sizeof(pid)) < 0){
++              n = os_read_file(fd, pid, sizeof(pid));
++              if(n < 0){
+                       printk("not_dead_yet : couldn't read pid file '%s', "
+-                             "errno = %d\n", file, errno);
++                             "err = %d\n", file, -n);
+                       return(1);
+               }
+               p = strtoul(pid, &end, 0);
+@@ -197,7 +201,7 @@
+       if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
+               uml_dir = malloc(strlen(name) + 1);
+               if(uml_dir == NULL){
+-                      printk("Failed to malloc uml_dir - error = %d\n",
++                      printf("Failed to malloc uml_dir - error = %d\n",
+                              errno);
+                       uml_dir = name;
+                       return(0);
+@@ -217,7 +221,7 @@
+               char *home = getenv("HOME");
+               if(home == NULL){
+-                      printk("make_uml_dir : no value in environment for "
++                      printf("make_uml_dir : no value in environment for "
+                              "$HOME\n");
+                       exit(1);
+               }
+@@ -232,57 +236,59 @@
+               dir[len + 1] = '\0';
+       }
+-      if((uml_dir = malloc(strlen(dir) + 1)) == NULL){
++      uml_dir = malloc(strlen(dir) + 1);
++      if(uml_dir == NULL){
+               printf("make_uml_dir : malloc failed, errno = %d\n", errno);
+               exit(1);
+       }
+       strcpy(uml_dir, dir);
+       
+       if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){
+-              printk("Failed to mkdir %s - errno = %i\n", uml_dir, errno);
++              printf("Failed to mkdir %s - errno = %i\n", uml_dir, errno);
+               return(-1);
+       }
+       return 0;
+ }
+-static int __init make_umid(void)
++static int __init make_umid(int (*printer)(const char *fmt, ...))
+ {
+       int fd, err;
+       char tmp[strlen(uml_dir) + UMID_LEN + 1];
+       strlcpy(tmp, uml_dir, sizeof(tmp));
+-      if(*umid == 0){
++      if(!umid_inited){
+               strcat(tmp, "XXXXXX");
+               fd = mkstemp(tmp);
+               if(fd < 0){
+-                      printk("make_umid - mkstemp failed, errno = %d\n",
+-                             errno);
++                      (*printer)("make_umid - mkstemp failed, errno = %d\n",
++                                 errno);
+                       return(1);
+               }
+-              close(fd);
++              os_close_file(fd);
+               /* There's a nice tiny little race between this unlink and
+                * the mkdir below.  It'd be nice if there were a mkstemp
+                * for directories.
+                */
+               unlink(tmp);
+-              set_umid(&tmp[strlen(uml_dir)], 1);
++              set_umid(&tmp[strlen(uml_dir)], 1, printer);
+       }
+       
+       sprintf(tmp, "%s%s", uml_dir, umid);
+-      if((err = mkdir(tmp, 0777)) < 0){
++      err = mkdir(tmp, 0777);
++      if(err < 0){
+               if(errno == EEXIST){
+                       if(not_dead_yet(tmp)){
+-                              printk("umid '%s' is in use\n", umid);
++                              (*printer)("umid '%s' is in use\n", umid);
+                               return(-1);
+                       }
+                       err = mkdir(tmp, 0777);
+               }
+       }
+       if(err < 0){
+-              printk("Failed to create %s - errno = %d\n", umid, errno);
++              (*printer)("Failed to create %s - errno = %d\n", umid, errno);
+               return(-1);
+       }
+@@ -295,7 +301,13 @@
+ );
+ __uml_postsetup(make_uml_dir);
+-__uml_postsetup(make_umid);
++
++static int __init make_umid_setup(void)
++{
++      return(make_umid(printf));
++}
++
++__uml_postsetup(make_umid_setup);
+ __uml_postsetup(create_pid_file);
+ /*
+diff -Naur a/arch/um/kernel/user_syms.c b/arch/um/kernel/user_syms.c
+--- a/arch/um/kernel/user_syms.c       2004-01-08 22:30:12.000000000 -0500
++++ b/arch/um/kernel/user_syms.c       2004-01-08 22:35:31.000000000 -0500
+@@ -1,7 +1,7 @@
+ #include <stdio.h>
+ #include <unistd.h>
+-#include <fcntl.h>
+ #include <dirent.h>
++#include <fcntl.h>
+ #include <errno.h>
+ #include <utime.h>
+ #include <string.h>
+@@ -27,7 +27,7 @@
+ #define __MODULE_STRING_1(x)  #x
+ #define __MODULE_STRING(x)    __MODULE_STRING_1(x)
+-#if !defined(__AUTOCONF_INCLUDED__)
++#if !defined(AUTOCONF_INCLUDED)
+ #define __EXPORT_SYMBOL(sym,str)   error config_must_be_included_before_module
+ #define EXPORT_SYMBOL(var)       error config_must_be_included_before_module
+diff -Naur a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c
+--- a/arch/um/kernel/user_util.c       2004-01-08 22:15:27.000000000 -0500
++++ b/arch/um/kernel/user_util.c       2004-01-08 22:21:18.000000000 -0500
+@@ -5,7 +5,6 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+-#include <fcntl.h>
+ #include <unistd.h>
+ #include <limits.h>
+ #include <sys/mman.h> 
+@@ -82,7 +81,8 @@
+       int status, ret;
+       while(1){
+-              if(((ret = waitpid(pid, &status, WUNTRACED)) < 0) ||
++              ret = waitpid(pid, &status, WUNTRACED);
++              if((ret < 0) ||
+                  !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){
+                       if(ret < 0){
+                               if(errno == EINTR) continue;
+@@ -119,17 +119,6 @@
+       }
+ }
+-int clone_and_wait(int (*fn)(void *), void *arg, void *sp, int flags)
+-{
+-      int pid;
+-
+-      pid = clone(fn, sp, flags, arg);
+-      if(pid < 0) return(-1);
+-      wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL);
+-      ptrace(PTRACE_CONT, pid, 0, 0);
+-      return(pid);
+-}
+-
+ int raw(int fd, int complain)
+ {
+       struct termios tt;
+diff -Naur a/arch/um/main.c b/arch/um/main.c
+--- a/arch/um/main.c   2004-01-08 22:28:01.000000000 -0500
++++ b/arch/um/main.c   2004-01-08 22:34:21.000000000 -0500
+@@ -8,6 +8,7 @@
+ #include <stdlib.h>
+ #include <string.h>
+ #include <signal.h>
++#include <errno.h>
+ #include <sys/resource.h>
+ #include <sys/mman.h>
+ #include <sys/user.h>
+@@ -123,12 +124,14 @@
+       set_stklim();
+-      if((new_argv = malloc((argc + 1) * sizeof(char *))) == NULL){
++      new_argv = malloc((argc + 1) * sizeof(char *));
++      if(new_argv == NULL){
+               perror("Mallocing argv");
+               exit(1);
+       }
+       for(i=0;i<argc;i++){
+-              if((new_argv[i] = strdup(argv[i])) == NULL){
++              new_argv[i] = strdup(argv[i]);
++              if(new_argv[i] == NULL){
+                       perror("Mallocing an arg");
+                       exit(1);
+               }
+diff -Naur a/arch/um/Makefile b/arch/um/Makefile
+--- a/arch/um/Makefile 2004-01-08 22:24:07.000000000 -0500
++++ b/arch/um/Makefile 2004-01-08 22:31:23.000000000 -0500
+@@ -24,15 +24,17 @@
+ # Have to precede the include because the included Makefiles reference them.
+ SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \
+       include/asm-um/sigcontext.h include/asm-um/processor.h \
+-      include/asm-um/ptrace.h include/asm-um/arch-signal.h
++      include/asm-um/ptrace.h include/asm-um/arch-signal.h \
++      include/asm-um/module.h
+ ARCH_SYMLINKS = include/asm-um/arch $(ARCH_DIR)/include/sysdep $(ARCH_DIR)/os \
+       $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h
+ GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h
+-include $(ARCH_DIR)/Makefile-$(SUBARCH)
+-include $(ARCH_DIR)/Makefile-os-$(OS)
++.PHONY: sys_prepare
++sys_prepare:
++      @:
+ MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt
+ MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas
+@@ -41,6 +43,9 @@
+   include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y))
+ endif
++include $(ARCH_DIR)/Makefile-$(SUBARCH)
++include $(ARCH_DIR)/Makefile-os-$(OS)
++
+ EXTRAVERSION := $(EXTRAVERSION)-1um
+ ARCH_INCLUDE = -I$(ARCH_DIR)/include
+@@ -52,14 +57,20 @@
+ CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
+       -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \
+-      $(MODE_INCLUDE)
++      -Dsigprocmask=kernel_sigprocmask $(MODE_INCLUDE)
+ LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
++# These are needed for clean and mrproper, since in that case .config is not
++# included; the values here are meaningless
++
++CONFIG_NEST_LEVEL ?= 0
++CONFIG_KERNEL_HALF_GIGS ?=  0
++
+ SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
+ ifeq ($(CONFIG_MODE_SKAS), y)
+-$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
++$(SYS_HEADERS) : $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h
+ endif
+ include/linux/version.h: arch/$(ARCH)/Makefile
+@@ -98,17 +109,17 @@
+ CONFIG_KERNEL_STACK_ORDER ?= 2
+ STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] )
+-AFLAGS_vmlinux.lds.o = -U$(SUBARCH) \
++AFLAGS_vmlinux.lds.o = $(shell echo -U$(SUBARCH) \
+       -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \
+       -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \
+-      -DKERNEL_STACK_SIZE=$(STACK_SIZE)
++      -DKERNEL_STACK_SIZE=$(STACK_SIZE))
+-AFLAGS_$(LD_SCRIPT-y:.s=).o = $(AFLAGS_vmlinux.lds.o) -P -C -Uum
++export AFLAGS_$(LD_SCRIPT-y:.s=).o = $(AFLAGS_vmlinux.lds.o) -P -C -Uum
+ LD_SCRIPT-y := $(ARCH_DIR)/$(LD_SCRIPT-y)
+-$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE
+-      $(call if_changed_dep,as_s_S)
++#$(LD_SCRIPT-y) : $(LD_SCRIPT-y:.s=.S) scripts FORCE
++#     $(call if_changed_dep,as_s_S)
+ linux: vmlinux $(LD_SCRIPT-y)
+       $(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \
+@@ -116,16 +127,22 @@
+ USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
+ USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS))
++USER_CFLAGS := $(patsubst -Dsigprocmask=kernel_sigprocmask,,$(USER_CFLAGS))
+ USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
+       $(MODE_INCLUDE)
+ # To get a definition of F_SETSIG
+ USER_CFLAGS += -D_GNU_SOURCE
++ifdef CONFIG_DEBUG_INFO
++USER_CFLAGS          += -g
++endif
++
+ CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/uml.lds.s \
+-      $(ARCH_DIR)/dyn_link.ld.s $(GEN_HEADERS)
++      $(ARCH_DIR)/dyn_link.ld.s $(ARCH_DIR)/include/uml-config.h \
++      $(GEN_HEADERS)
+-$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c
++$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c sys_prepare
+       $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<
+ archmrproper:
+@@ -161,19 +178,23 @@
+ $(ARCH_DIR)/os:
+       cd $(ARCH_DIR) && ln -sf os-$(OS) os
+-$(ARCH_DIR)/include/uml-config.h :
++$(ARCH_DIR)/include/uml-config.h : $(TOPDIR)/include/linux/autoconf.h
+       sed 's/ CONFIG/ UML_CONFIG/' $(TOPDIR)/include/linux/autoconf.h > $@
++filechk_$(ARCH_DIR)/include/task.h := $(ARCH_DIR)/util/mk_task
++
+ $(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task
+-      $< > $@
++      $(call filechk,$@)
++
++filechk_$(ARCH_DIR)/include/kern_constants.h := $(ARCH_DIR)/util/mk_constants
+ $(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants
+-      $< > $@
++      $(call filechk,$@)
+-$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h \
+-      $(ARCH_DIR)/util FORCE ;
++$(ARCH_DIR)/util/mk_task $(ARCH_DIR)/util/mk_constants : $(ARCH_DIR)/util \
++      sys_prepare FORCE ;
+ $(ARCH_DIR)/util: FORCE
+-      @$(call descend,$@,)
++      $(MAKE) -f scripts/Makefile.build obj=$@
+-export SUBARCH USER_CFLAGS OS
++export SUBARCH USER_CFLAGS OS 
+diff -Naur a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
+--- a/arch/um/Makefile-i386    2004-01-08 22:28:01.000000000 -0500
++++ b/arch/um/Makefile-i386    2004-01-08 22:34:22.000000000 -0500
+@@ -16,22 +16,28 @@
+ SYS_HEADERS = $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h
++sys_prepare: $(SYS_DIR)/sc.h
++
+ prepare: $(SYS_HEADERS)
++filechk_$(SYS_DIR)/sc.h := $(SYS_UTIL_DIR)/mk_sc
++
+ $(SYS_DIR)/sc.h: $(SYS_UTIL_DIR)/mk_sc
+-      $< > $@
++      $(call filechk,$@)
++
++filechk_$(SYS_DIR)/thread.h := $(SYS_UTIL_DIR)/mk_thread 
+ $(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread 
+-      $< > $@
++      $(call filechk,$@)
+-$(SYS_UTIL_DIR)/mk_sc: FORCE ; 
+-      @$(call descend,$(SYS_UTIL_DIR),$@)
++$(SYS_UTIL_DIR)/mk_sc: scripts/fixdep include/config/MARKER FORCE ; 
++      +@$(call descend,$(SYS_UTIL_DIR),$@)
+-$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) FORCE ; 
+-      @$(call descend,$(SYS_UTIL_DIR),$@)
++$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) $(GEN_HEADERS) sys_prepare FORCE ; 
++      +@$(call descend,$(SYS_UTIL_DIR),$@)
+ $(SYS_UTIL_DIR): include/asm FORCE
+-      @$(call descend,$@,)
++      +@$(call descend,$@,)
+ sysclean :
+       rm -f $(SYS_HEADERS)
+diff -Naur a/arch/um/Makefile-skas b/arch/um/Makefile-skas
+--- a/arch/um/Makefile-skas    2004-01-08 22:20:33.000000000 -0500
++++ b/arch/um/Makefile-skas    2004-01-08 22:27:05.000000000 -0500
+@@ -14,7 +14,7 @@
+ LINK_SKAS = -Wl,-rpath,/lib 
+ LD_SCRIPT_SKAS = dyn.lds.s
+-GEN_HEADERS += $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h
++GEN_HEADERS += $(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h
+-$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h :
+-      $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h
++$(TOPDIR)/$(ARCH_DIR)/include/skas_ptregs.h :
++      $(call descend,$(ARCH_DIR)/kernel/skas,$@)
+diff -Naur a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c
+--- a/arch/um/os-Linux/drivers/ethertap_kern.c 2004-01-08 22:13:47.000000000 -0500
++++ b/arch/um/os-Linux/drivers/ethertap_kern.c 2004-01-08 22:18:35.000000000 -0500
+@@ -8,7 +8,6 @@
+ #include "linux/init.h"
+ #include "linux/netdevice.h"
+ #include "linux/etherdevice.h"
+-#include "linux/init.h"
+ #include "net_kern.h"
+ #include "net_user.h"
+ #include "etap.h"
+diff -Naur a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
+--- a/arch/um/os-Linux/drivers/ethertap_user.c 2004-01-08 22:21:31.000000000 -0500
++++ b/arch/um/os-Linux/drivers/ethertap_user.c 2004-01-08 22:28:16.000000000 -0500
+@@ -8,7 +8,6 @@
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <stddef.h>
+-#include <fcntl.h>
+ #include <stdlib.h>
+ #include <sys/errno.h>
+ #include <sys/socket.h>
+@@ -42,13 +41,14 @@
+ {
+       struct addr_change change;
+       void *output;
++      int n;
+       change.what = op;
+       memcpy(change.addr, addr, sizeof(change.addr));
+       memcpy(change.netmask, netmask, sizeof(change.netmask));
+-      if(write(fd, &change, sizeof(change)) != sizeof(change))
+-              printk("etap_change - request failed, errno = %d\n",
+-                     errno);
++      n = os_write_file(fd, &change, sizeof(change));
++      if(n != sizeof(change))
++              printk("etap_change - request failed, err = %d\n", -n);
+       output = um_kmalloc(page_size());
+       if(output == NULL)
+               printk("etap_change : Failed to allocate output buffer\n");
+@@ -82,15 +82,15 @@
+       struct etap_pre_exec_data *data = arg;
+       dup2(data->control_remote, 1);
+-      close(data->data_me);
+-      close(data->control_me);
++      os_close_file(data->data_me);
++      os_close_file(data->control_me);
+ }
+ static int etap_tramp(char *dev, char *gate, int control_me, 
+                     int control_remote, int data_me, int data_remote)
+ {
+       struct etap_pre_exec_data pe_data;
+-      int pid, status, err;
++      int pid, status, err, n;
+       char version_buf[sizeof("nnnnn\0")];
+       char data_fd_buf[sizeof("nnnnnn\0")];
+       char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
+@@ -114,21 +114,21 @@
+       pe_data.data_me = data_me;
+       pid = run_helper(etap_pre_exec, &pe_data, args, NULL);
+-      if(pid < 0) err = errno;
+-      close(data_remote);
+-      close(control_remote);
+-      if(read(control_me, &c, sizeof(c)) != sizeof(c)){
+-              printk("etap_tramp : read of status failed, errno = %d\n",
+-                     errno);
+-              return(EINVAL);
++      if(pid < 0) err = pid;
++      os_close_file(data_remote);
++      os_close_file(control_remote);
++      n = os_read_file(control_me, &c, sizeof(c));
++      if(n != sizeof(c)){
++              printk("etap_tramp : read of status failed, err = %d\n", -n);
++              return(-EINVAL);
+       }
+       if(c != 1){
+               printk("etap_tramp : uml_net failed\n");
+-              err = EINVAL;
+-              if(waitpid(pid, &status, 0) < 0) err = errno;
+-              else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)){
++              err = -EINVAL;
++              if(waitpid(pid, &status, 0) < 0)
++                      err = -errno;
++              else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1))
+                       printk("uml_net didn't exit with status 1\n");
+-              }
+       }
+       return(err);
+ }
+@@ -143,14 +143,14 @@
+       if(err) return(err);
+       err = os_pipe(data_fds, 0, 0);
+-      if(err){
+-              printk("data os_pipe failed - errno = %d\n", -err);
++      if(err < 0){
++              printk("data os_pipe failed - err = %d\n", -err);
+               return(err);
+       }
+       err = os_pipe(control_fds, 1, 0);
+-      if(err){
+-              printk("control os_pipe failed - errno = %d\n", -err);
++      if(err < 0){
++              printk("control os_pipe failed - err = %d\n", -err);
+               return(err);
+       }
+       
+@@ -167,9 +167,9 @@
+               kfree(output);
+       }
+-      if(err != 0){
+-              printk("etap_tramp failed - errno = %d\n", err);
+-              return(-err);
++      if(err < 0){
++              printk("etap_tramp failed - err = %d\n", -err);
++              return(err);
+       }
+       pri->data_fd = data_fds[0];
+@@ -183,11 +183,11 @@
+       struct ethertap_data *pri = data;
+       iter_addresses(pri->dev, etap_close_addr, &pri->control_fd);
+-      close(fd);
++      os_close_file(fd);
+       os_shutdown_socket(pri->data_fd, 1, 1);
+-      close(pri->data_fd);
++      os_close_file(pri->data_fd);
+       pri->data_fd = -1;
+-      close(pri->control_fd);
++      os_close_file(pri->control_fd);
+       pri->control_fd = -1;
+ }
+diff -Naur a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
+--- a/arch/um/os-Linux/drivers/tuntap_user.c   2004-01-08 22:32:42.000000000 -0500
++++ b/arch/um/os-Linux/drivers/tuntap_user.c   2004-01-08 22:36:41.000000000 -0500
+@@ -8,7 +8,6 @@
+ #include <stdlib.h>
+ #include <unistd.h>
+ #include <errno.h>
+-#include <fcntl.h>
+ #include <sys/wait.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
+@@ -61,7 +60,7 @@
+       struct tuntap_pre_exec_data *data = arg;
+       
+       dup2(data->stdout, 1);
+-      close(data->close_me);
++      os_close_file(data->close_me);
+ }
+ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
+@@ -86,7 +85,7 @@
+       if(pid < 0) return(-pid);
+-      close(remote);
++      os_close_file(remote);
+       msg.msg_name = NULL;
+       msg.msg_namelen = 0;
+@@ -107,19 +106,19 @@
+       if(n < 0){
+               printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", 
+                      errno);
+-              return(errno);
++              return(-errno);
+       }
+       waitpid(pid, NULL, 0);
+       cmsg = CMSG_FIRSTHDR(&msg);
+       if(cmsg == NULL){
+               printk("tuntap_open_tramp : didn't receive a message\n");
+-              return(EINVAL);
++              return(-EINVAL);
+       }
+       if((cmsg->cmsg_level != SOL_SOCKET) || 
+          (cmsg->cmsg_type != SCM_RIGHTS)){
+               printk("tuntap_open_tramp : didn't receive a descriptor\n");
+-              return(EINVAL);
++              return(-EINVAL);
+       }
+       *fd_out = ((int *) CMSG_DATA(cmsg))[0];
+       return(0);
+@@ -133,27 +132,29 @@
+       int err, fds[2], len, used;
+       err = tap_open_common(pri->dev, pri->gate_addr);
+-      if(err) return(err);
++      if(err < 0) 
++              return(err);
+       if(pri->fixed_config){
+-              if((pri->fd = open("/dev/net/tun", O_RDWR)) < 0){
+-                      printk("Failed to open /dev/net/tun, errno = %d\n",
+-                             errno);
+-                      return(-errno);
+-              }
++              pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0);
++              if(pri->fd < 0){
++                      printk("Failed to open /dev/net/tun, err = %d\n",
++                             -pri->fd);
++                      return(pri->fd);
++              } 
+               memset(&ifr, 0, sizeof(ifr));
+-              ifr.ifr_flags = IFF_TAP;
++              ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+               strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name));
+               if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){
+-                      printk("TUNSETIFF failed, errno = %d", errno);
+-                      close(pri->fd);
++                      printk("TUNSETIFF failed, errno = %d\n", errno);
++                      os_close_file(pri->fd);
+                       return(-errno);
+               }
+       }
+       else {
+               err = os_pipe(fds, 0, 0);
+-              if(err){
+-                      printk("tuntap_open : os_pipe failed - errno = %d\n",
++              if(err < 0){
++                      printk("tuntap_open : os_pipe failed - err = %d\n",
+                              -err);
+                       return(err);
+               }
+@@ -166,19 +167,19 @@
+                                       fds[1], buffer, len, &used);
+               output = buffer;
+-              if(err == 0){
+-                      pri->dev_name = uml_strdup(buffer);
+-                      output += IFNAMSIZ;
+-                      printk(output);
+-                      free_output_buffer(buffer);
+-              }
+-              else {
+-                      printk(output);
++              if(err < 0) {
++                      printk("%s", output);
+                       free_output_buffer(buffer);
+-                      printk("tuntap_open_tramp failed - errno = %d\n", err);
+-                      return(-err);
++                      printk("tuntap_open_tramp failed - err = %d\n", -err);
++                      return(err);
+               }
+-              close(fds[0]);
++
++              pri->dev_name = uml_strdup(buffer);
++              output += IFNAMSIZ;
++              printk("%s", output);
++              free_output_buffer(buffer);
++
++              os_close_file(fds[0]);
+               iter_addresses(pri->dev, open_addr, pri->dev_name);
+       }
+@@ -191,7 +192,7 @@
+       if(!pri->fixed_config) 
+               iter_addresses(pri->dev, close_addr, pri->dev_name);
+-      close(fd);
++      os_close_file(fd);
+       pri->fd = -1;
+ }
+diff -Naur a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
+--- a/arch/um/os-Linux/file.c  2004-01-08 22:32:23.000000000 -0500
++++ b/arch/um/os-Linux/file.c  2004-01-08 22:36:32.000000000 -0500
+@@ -8,6 +8,8 @@
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <signal.h>
++#include <sys/types.h>
++#include <sys/stat.h>
+ #include <sys/socket.h>
+ #include <sys/un.h>
+ #include <sys/ioctl.h>
+@@ -17,33 +19,236 @@
+ #include "user.h"
+ #include "kern_util.h"
+-int os_file_type(char *file)
++static void copy_stat(struct uml_stat *dst, struct stat64 *src)
++{
++      *dst = ((struct uml_stat) {
++              .ust_dev     = src->st_dev,     /* device */
++              .ust_ino     = src->st_ino,     /* inode */
++              .ust_mode    = src->st_mode,    /* protection */
++              .ust_nlink   = src->st_nlink,   /* number of hard links */
++              .ust_uid     = src->st_uid,     /* user ID of owner */
++              .ust_gid     = src->st_gid,     /* group ID of owner */
++              .ust_size    = src->st_size,    /* total size, in bytes */
++              .ust_blksize = src->st_blksize, /* blocksize for filesys I/O */
++              .ust_blocks  = src->st_blocks,  /* number of blocks allocated */
++              .ust_atime   = src->st_atime,   /* time of last access */
++              .ust_mtime   = src->st_mtime,   /* time of last modification */
++              .ust_ctime   = src->st_ctime,   /* time of last change */
++      });
++}
++
++int os_stat_fd(const int fd, struct uml_stat *ubuf)
++{
++      struct stat64 sbuf;
++      int err;
++
++      do {
++              err = fstat64(fd, &sbuf);
++      } while((err < 0) && (errno == EINTR)) ;
++
++      if(err < 0) 
++              return(-errno);
++
++      if(ubuf != NULL)
++              copy_stat(ubuf, &sbuf);
++      return(err);
++}
++
++int os_stat_file(const char *file_name, struct uml_stat *ubuf)
++{
++      struct stat64 sbuf;
++      int err;
++
++      do {
++              err = stat64(file_name, &sbuf);
++      } while((err < 0) && (errno == EINTR)) ;
++
++      if(err < 0) 
++              return(-errno);
++
++      if(ubuf != NULL)
++              copy_stat(ubuf, &sbuf);
++      return(err);
++}
++
++int os_access(const char* file, int mode)
++{
++      int amode, err;
++
++      amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) |
++            (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ;
++
++      err = access(file, amode);
++      if(err < 0)
++              return(-errno);
++
++      return(0);
++}
++
++void os_print_error(int error, const char* str)
++{
++      errno = error < 0 ? -error : error;
++
++      perror(str);
++}
++
++/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */
++int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg)
++{
++      int err;
++
++      err = ioctl(fd, cmd, arg);
++      if(err < 0)
++              return(-errno);
++
++      return(err);
++}
++
++int os_window_size(int fd, int *rows, int *cols)
++{
++      struct winsize size;
++
++      if(ioctl(fd, TIOCGWINSZ, &size) < 0)
++              return(-errno);
++
++      *rows = size.ws_row;
++      *cols = size.ws_col;
++
++      return(0);
++}
++
++int os_new_tty_pgrp(int fd, int pid)
+ {
+-      struct stat64 buf;
++      if(ioctl(fd, TIOCSCTTY, 0) < 0){
++              printk("TIOCSCTTY failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      if(tcsetpgrp(fd, pid) < 0){
++              printk("tcsetpgrp failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      return(0);
++}
++
++/* FIXME: ensure namebuf in os_get_if_name is big enough */
++int os_get_ifname(int fd, char* namebuf)
++{
++      if(ioctl(fd, SIOCGIFNAME, namebuf) < 0)
++              return(-errno);
++
++      return(0);
++}
++
++int os_set_slip(int fd)
++{
++      int disc, sencap;
++
++      disc = N_SLIP;
++      if(ioctl(fd, TIOCSETD, &disc) < 0){
++              printk("Failed to set slip line discipline - "
++                     "errno = %d\n", errno);
++              return(-errno);
++      }
++
++      sencap = 0;
++      if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0){
++              printk("Failed to set slip encapsulation - "
++                     "errno = %d\n", errno);
++              return(-errno);
++      }
++
++      return(0);
++}
++
++int os_set_owner(int fd, int pid)
++{
++      if(fcntl(fd, F_SETOWN, pid) < 0){
++              int save_errno = errno;
++
++              if(fcntl(fd, F_GETOWN, 0) != pid){
++                      return(-save_errno);
++              }
++      }
++
++      return(0);
++}
++
++/* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */ 
++int os_sigio_async(int master, int slave)
++{
++      int flags;
+-      if(stat64(file, &buf) == -1)
++      flags = fcntl(master, F_GETFL);
++      if(flags < 0) {
++              printk("fcntl F_GETFL failed, errno = %d\n", errno);
+               return(-errno);
++      }
+-      if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR);
+-      else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK);
+-      else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV);
+-      else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV);
+-      else if(S_ISFIFO(buf.st_mode)) return(OS_TYPE_FIFO);
+-      else if(S_ISSOCK(buf.st_mode)) return(OS_TYPE_SOCK);
++      if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
++         (fcntl(master, F_SETOWN, os_getpid()) < 0)){
++              printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)){
++              printk("fcntl F_SETFL failed, errno = %d\n", errno);
++              return(-errno);
++      }
++
++      return(0);
++}
++
++int os_mode_fd(int fd, int mode)
++{
++      int err;
++
++      do {
++              err = fchmod(fd, mode);
++      } while((err < 0) && (errno==EINTR)) ;
++
++      if(err < 0)
++              return(-errno);
++
++      return(0);
++}
++
++int os_file_type(char *file)
++{
++      struct uml_stat buf;
++      int err;
++
++      err = os_stat_file(file, &buf);
++      if(err < 0)
++              return(err);
++
++      if(S_ISDIR(buf.ust_mode)) return(OS_TYPE_DIR);
++      else if(S_ISLNK(buf.ust_mode)) return(OS_TYPE_SYMLINK);
++      else if(S_ISCHR(buf.ust_mode)) return(OS_TYPE_CHARDEV);
++      else if(S_ISBLK(buf.ust_mode)) return(OS_TYPE_BLOCKDEV);
++      else if(S_ISFIFO(buf.ust_mode)) return(OS_TYPE_FIFO);
++      else if(S_ISSOCK(buf.ust_mode)) return(OS_TYPE_SOCK);
+       else return(OS_TYPE_FILE);
+ }
+ int os_file_mode(char *file, struct openflags *mode_out)
+ {
++      int err;
++
+       *mode_out = OPENFLAGS();
+-      if(!access(file, W_OK)) *mode_out = of_write(*mode_out);
+-      else if(errno != EACCES) 
+-              return(-errno);
++      err = os_access(file, OS_ACC_W_OK);
++      if((err < 0) && (err != -EACCES))
++              return(err);
+-      if(!access(file, R_OK)) *mode_out = of_read(*mode_out);
+-      else if(errno != EACCES) 
+-              return(-errno);
++      *mode_out = of_write(*mode_out);
++
++      err = os_access(file, OS_ACC_R_OK);
++      if((err < 0) && (err != -EACCES))
++              return(err);
++
++      *mode_out = of_read(*mode_out);
+       return(0);
+ }
+@@ -63,16 +268,14 @@
+       if(flags.e) f |= O_EXCL;
+       fd = open64(file, f, mode);
+-      if(fd < 0) return(-errno);
++      if(fd < 0) 
++              return(-errno);
+       
+-      if(flags.cl){
+-              if(fcntl(fd, F_SETFD, 1)){
+-                      close(fd);
+-                      return(-errno);
+-              }
++      if(flags.cl && fcntl(fd, F_SETFD, 1)){
++              os_close_file(fd);
++              return(-errno);
+       }
+-      return(fd);
+       return(fd);
+ }
+@@ -90,7 +293,7 @@
+       err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
+       if(err)
+-              return(err);
++              return(-errno);
+       return(fd);
+ }
+@@ -109,88 +312,162 @@
+       return(0);
+ }
+-int os_read_file(int fd, void *buf, int len)
++static int fault_buffer(void *start, int len, 
++                      int (*copy_proc)(void *addr, void *buf, int len))
+ {
+-      int n;
++      int page = getpagesize(), i;
++      char c;
+-      /* Force buf into memory if it's not already. */
++      for(i = 0; i < len; i += page){
++              if((*copy_proc)(start + i, &c, sizeof(c)))
++                      return(-EFAULT);
++      }
++      if((len % page) != 0){
++              if((*copy_proc)(start + len - 1, &c, sizeof(c)))
++                      return(-EFAULT);
++      }
++      return(0);
++}
+-      /* XXX This fails if buf is kernel memory */
+-#ifdef notdef
+-      if(copy_to_user_proc(buf, &c, sizeof(c)))
+-              return(-EFAULT);
+-#endif
++static int file_io(int fd, void *buf, int len,
++                 int (*io_proc)(int fd, void *buf, int len),
++                 int (*copy_user_proc)(void *addr, void *buf, int len))
++{
++      int n, err;
++
++      do {
++              n = (*io_proc)(fd, buf, len);
++              if((n < 0) && (errno == EFAULT)){
++                      err = fault_buffer(buf, len, copy_user_proc);
++                      if(err)
++                              return(err);
++                      n = (*io_proc)(fd, buf, len);
++              }
++      } while((n < 0) && (errno == EINTR));
+-      n = read(fd, buf, len);
+       if(n < 0)
+               return(-errno);
+       return(n);
+ }
+-int os_write_file(int fd, void *buf, int count)
++int os_read_file(int fd, void *buf, int len)
+ {
+-      int n;
+-
+-      /* Force buf into memory if it's not already. */
+-      
+-      /* XXX This fails if buf is kernel memory */
+-#ifdef notdef
+-      if(copy_to_user_proc(buf, buf, buf[0]))
+-              return(-EFAULT);
+-#endif
++      return(file_io(fd, buf, len, (int (*)(int, void *, int)) read, 
++                     copy_from_user_proc));
++}
+-      n = write(fd, buf, count);
+-      if(n < 0)
+-              return(-errno);
+-      return(n);
++int os_write_file(int fd, const void *buf, int len)
++{
++      return(file_io(fd, (void *) buf, len, 
++                     (int (*)(int, void *, int)) write, copy_to_user_proc));
+ }
+ int os_file_size(char *file, long long *size_out)
+ {
+-      struct stat64 buf;
++      struct uml_stat buf;
++      int err;
+-      if(stat64(file, &buf) == -1){
+-              printk("Couldn't stat \"%s\" : errno = %d\n", file, errno);
+-              return(-errno);
++      err = os_stat_file(file, &buf);
++      if(err < 0){
++              printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
++              return(err);
+       }
+-      if(S_ISBLK(buf.st_mode)){
++
++      if(S_ISBLK(buf.ust_mode)){
+               int fd, blocks;
+-              if((fd = open64(file, O_RDONLY)) < 0){
+-                      printk("Couldn't open \"%s\", errno = %d\n", file,
+-                             errno);
+-                      return(-errno);
++              fd = os_open_file(file, of_read(OPENFLAGS()), 0);
++              if(fd < 0){
++                      printk("Couldn't open \"%s\", errno = %d\n", file, -fd);
++                      return(fd);
+               }
+               if(ioctl(fd, BLKGETSIZE, &blocks) < 0){
+                       printk("Couldn't get the block size of \"%s\", "
+                              "errno = %d\n", file, errno);
+-                      close(fd);
+-                      return(-errno);
++                      err = -errno;
++                      os_close_file(fd);
++                      return(err);
+               }
+               *size_out = ((long long) blocks) * 512;
+-              close(fd);
++              os_close_file(fd);
+               return(0);
+       }
+-      *size_out = buf.st_size;
++      *size_out = buf.ust_size;
++      return(0);
++}
++
++int os_file_modtime(char *file, unsigned long *modtime)
++{
++      struct uml_stat buf;
++      int err;
++
++      err = os_stat_file(file, &buf);
++      if(err < 0){
++              printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
++              return(err);
++      }
++
++      *modtime = buf.ust_mtime;
+       return(0);
+ }
++int os_get_exec_close(int fd, int* close_on_exec)
++{
++      int ret;
++
++      do {
++              ret = fcntl(fd, F_GETFD);
++      } while((ret < 0) && (errno == EINTR)) ;
++
++      if(ret < 0)
++              return(-errno);
++
++      *close_on_exec = (ret&FD_CLOEXEC) ? 1 : 0;
++      return(ret);
++}
++
++int os_set_exec_close(int fd, int close_on_exec)
++{
++      int flag, err;
++
++      if(close_on_exec) flag = FD_CLOEXEC;
++      else flag = 0;
++
++      do {
++              err = fcntl(fd, F_SETFD, flag);
++      } while((err < 0) && (errno == EINTR)) ;
++
++      if(err < 0)
++              return(-errno);
++      return(err);
++}
++
+ int os_pipe(int *fds, int stream, int close_on_exec)
+ {
+       int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
+       err = socketpair(AF_UNIX, type, 0, fds);
+-      if(err) 
++      if(err < 0) 
+               return(-errno);
+       if(!close_on_exec)
+               return(0);
+-      if((fcntl(fds[0], F_SETFD, 1) < 0) || (fcntl(fds[1], F_SETFD, 1) < 0))
+-              printk("os_pipe : Setting FD_CLOEXEC failed, errno = %d", 
+-                     errno);
++      err = os_set_exec_close(fds[0], 1);
++      if(err < 0)
++              goto error;
++
++      err = os_set_exec_close(fds[1], 1);
++      if(err < 0)
++              goto error;
+       return(0);
++
++ error:
++      printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err);
++      os_close_file(fds[1]);
++      os_close_file(fds[0]);
++      return(err);
+ }
+ int os_set_fd_async(int fd, int owner)
+@@ -270,7 +547,7 @@
+               return(-EINVAL);
+       }
+       err = shutdown(fd, what);
+-      if(err)
++      if(err < 0)
+               return(-errno);
+       return(0);
+ }
+@@ -315,7 +592,7 @@
+       return(new);
+ }
+-int create_unix_socket(char *file, int len)
++int os_create_unix_socket(char *file, int len, int close_on_exec)
+ {
+       struct sockaddr_un addr;
+       int sock, err;
+@@ -327,6 +604,13 @@
+               return(-errno);
+       }
++      if(close_on_exec) {
++              err = os_set_exec_close(sock, 1);
++              if(err < 0)
++                      printk("create_unix_socket : close_on_exec failed, "
++                     "err = %d", -err);
++      }
++
+       addr.sun_family = AF_UNIX;
+       /* XXX Be more careful about overflow */
+@@ -334,14 +618,45 @@
+       err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+       if (err < 0){
+-              printk("create_listening_socket - bind failed, errno = %d\n",
+-                     errno);
++              printk("create_listening_socket at '%s' - bind failed, "
++                     "errno = %d\n", file, errno);
+               return(-errno);
+       }
+       return(sock);
+ }
++void os_flush_stdout(void)
++{
++      fflush(stdout);
++}
++
++int os_lock_file(int fd, int excl)
++{
++      int type = excl ? F_WRLCK : F_RDLCK;
++      struct flock lock = ((struct flock) { .l_type   = type,
++                                            .l_whence = SEEK_SET,
++                                            .l_start  = 0,
++                                            .l_len    = 0 } );
++      int err, save;
++
++      err = fcntl(fd, F_SETLK, &lock);
++      if(!err)
++              goto out;
++
++      save = -errno;
++      err = fcntl(fd, F_GETLK, &lock);
++      if(err){
++              err = -errno;
++              goto out;
++      }
++      
++      printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid);
++      err = save;
++ out:
++      return(err);
++}
++
+ /*
+  * Overrides for Emacs so that we follow Linus's tabbing style.
+  * Emacs will notice this stuff at the end of the file and automatically
+diff -Naur a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
+--- a/arch/um/os-Linux/process.c       2004-01-08 22:14:47.000000000 -0500
++++ b/arch/um/os-Linux/process.c       2004-01-08 22:20:12.000000000 -0500
+@@ -1,5 +1,5 @@
+ /* 
+- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2002 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+@@ -7,32 +7,37 @@
+ #include <stdio.h>
+ #include <errno.h>
+ #include <signal.h>
++#include <linux/unistd.h>
+ #include <sys/mman.h>
+ #include <sys/wait.h>
+ #include "os.h"
+ #include "user.h"
++#define ARBITRARY_ADDR -1
++#define FAILURE_PID    -1
++
+ unsigned long os_process_pc(int pid)
+ {
+       char proc_stat[sizeof("/proc/#####/stat\0")], buf[256];
+       unsigned long pc;
+-      int fd;
++      int fd, err;
+       sprintf(proc_stat, "/proc/%d/stat", pid);
+       fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0);
+       if(fd < 0){
+-              printk("os_process_pc - couldn't open '%s', errno = %d\n", 
+-                     proc_stat, errno);
+-              return(-1);
++              printk("os_process_pc - couldn't open '%s', err = %d\n", 
++                     proc_stat, -fd);
++              return(ARBITRARY_ADDR);
+       }
+-      if(read(fd, buf, sizeof(buf)) < 0){
+-              printk("os_process_pc - couldn't read '%s', errno = %d\n", 
+-                     proc_stat, errno);
+-              close(fd);
+-              return(-1);
++      err = os_read_file(fd, buf, sizeof(buf));
++      if(err < 0){
++              printk("os_process_pc - couldn't read '%s', err = %d\n", 
++                     proc_stat, -err);
++              os_close_file(fd);
++              return(ARBITRARY_ADDR);
+       }
+-      close(fd);
+-      pc = -1;
++      os_close_file(fd);
++      pc = ARBITRARY_ADDR;
+       if(sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d "
+                 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
+                 "%*d %*d %*d %*d %ld", &pc) != 1){
+@@ -52,22 +57,23 @@
+       snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
+       fd = os_open_file(stat, of_read(OPENFLAGS()), 0);
+       if(fd < 0){
+-              printk("Couldn't open '%s', errno = %d\n", stat, -fd);
+-              return(-1);
++              printk("Couldn't open '%s', err = %d\n", stat, -fd);
++              return(FAILURE_PID);
+       }
+-      n = read(fd, data, sizeof(data));
+-      close(fd);
++      n = os_read_file(fd, data, sizeof(data));
++      os_close_file(fd);
+       if(n < 0){
+-              printk("Couldn't read '%s', errno = %d\n", stat);
+-              return(-1);
++              printk("Couldn't read '%s', err = %d\n", stat, -n);
++              return(FAILURE_PID);
+       }
+-      parent = -1;
++      parent = FAILURE_PID;
+       /* XXX This will break if there is a space in the command */
+       n = sscanf(data, "%*d %*s %*c %d", &parent);
+-      if(n != 1) printk("Failed to scan '%s'\n", data);
++      if(n != 1) 
++              printk("Failed to scan '%s'\n", data);
+       return(parent);
+ }
+@@ -87,7 +93,8 @@
+ void os_usr1_process(int pid)
+ {
+-      kill(pid, SIGUSR1);
++      syscall(__NR_tkill, pid, SIGUSR1); 
++      /* kill(pid, SIGUSR1); */
+ }
+ int os_getpid(void)
+@@ -95,7 +102,7 @@
+       return(getpid());
+ }
+-int os_map_memory(void *virt, int fd, unsigned long off, unsigned long len, 
++int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
+                 int r, int w, int x)
+ {
+       void *loc;
+@@ -104,8 +111,8 @@
+       prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 
+               (x ? PROT_EXEC : 0);
+-      loc = mmap((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, 
+-                 fd, off);
++      loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, 
++                   fd, off);
+       if(loc == MAP_FAILED)
+               return(-errno);
+       return(0);
+@@ -126,7 +133,8 @@
+         int err;
+         err = munmap(addr, len);
+-        if(err < 0) return(-errno);
++      if(err < 0) 
++              return(-errno);
+         return(0);
+ }
+diff -Naur a/arch/um/os-Linux/tty.c b/arch/um/os-Linux/tty.c
+--- a/arch/um/os-Linux/tty.c   2004-01-08 22:23:12.000000000 -0500
++++ b/arch/um/os-Linux/tty.c   2004-01-08 22:30:17.000000000 -0500
+@@ -28,10 +28,10 @@
+       struct grantpt_info info;
+       int fd;
+-      if((fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0)) < 0){
+-              printk("get_pty : Couldn't open /dev/ptmx - errno = %d\n",
+-                     errno);
+-              return(-1);
++      fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd);
++              return(fd);
+       }
+       info.fd = fd;
+@@ -39,7 +39,7 @@
+       if(info.res < 0){
+               printk("get_pty : Couldn't grant pty - errno = %d\n", 
+-                     info.err);
++                     -info.err);
+               return(-1);
+       }
+       if(unlockpt(fd) < 0){
+diff -Naur a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c
+--- a/arch/um/sys-i386/bugs.c  2004-01-08 22:27:56.000000000 -0500
++++ b/arch/um/sys-i386/bugs.c  2004-01-08 22:34:17.000000000 -0500
+@@ -4,20 +4,21 @@
+  */
+ #include <unistd.h>
+-#include <fcntl.h>
+ #include <errno.h>
+ #include <string.h>
+ #include <sys/signal.h>
++#include <asm/ldt.h>
+ #include "kern_util.h"
+ #include "user.h"
+ #include "sysdep/ptrace.h"
+ #include "task.h"
++#include "os.h"
+ #define MAXTOKEN 64
+ /* Set during early boot */
+-int cpu_has_cmov = 1;
+-int cpu_has_xmm = 0;
++int host_has_cmov = 1;
++int host_has_xmm = 0;
+ static char token(int fd, char *buf, int len, char stop)
+ {
+@@ -27,13 +28,15 @@
+       ptr = buf;
+       end = &buf[len];
+       do {
+-              n = read(fd, ptr, sizeof(*ptr));
++              n = os_read_file(fd, ptr, sizeof(*ptr));
+               c = *ptr++;
+-              if(n == 0) return(0);
+-              else if(n != sizeof(*ptr)){
+-                      printk("Reading /proc/cpuinfo failed, "
+-                             "errno = %d\n", errno);
+-                      return(-errno);
++              if(n != sizeof(*ptr)){
++                      if(n == 0) return(0);
++                      printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
++                      if(n < 0) 
++                              return(n);
++                      else 
++                              return(-EIO);
+               }
+       } while((c != '\n') && (c != stop) && (ptr < end));
+@@ -45,45 +48,79 @@
+       return(c);
+ }
+-static int check_cpu_feature(char *feature, int *have_it)
++static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
+ {
+-      char buf[MAXTOKEN], c;
+-      int fd, len = sizeof(buf)/sizeof(buf[0]), n;
+-
+-      printk("Checking for host processor %s support...", feature);
+-      fd = open("/proc/cpuinfo", O_RDONLY);
+-      if(fd < 0){
+-              printk("Couldn't open /proc/cpuinfo, errno = %d\n", errno);
+-              return(0);
+-      }
++      int n;
++      char c;
+-      *have_it = 0;
+-      buf[len - 1] = '\0';
++      scratch[len - 1] = '\0';
+       while(1){
+-              c = token(fd, buf, len - 1, ':');
+-              if(c <= 0) goto out;
++              c = token(fd, scratch, len - 1, ':');
++              if(c <= 0)
++                      return(0);
+               else if(c != ':'){
+                       printk("Failed to find ':' in /proc/cpuinfo\n");
+-                      goto out;
++                      return(0);
+               }
+-              if(!strncmp(buf, "flags", strlen("flags"))) break;
++              if(!strncmp(scratch, key, strlen(key))) 
++                      return(1);
+               do {
+-                      n = read(fd, &c, sizeof(c));
++                      n = os_read_file(fd, &c, sizeof(c));
+                       if(n != sizeof(c)){
+                               printk("Failed to find newline in "
+-                                     "/proc/cpuinfo, n = %d, errno = %d\n",
+-                                     n, errno);
+-                              goto out;
++                                     "/proc/cpuinfo, err = %d\n", -n);
++                              return(0);
+                       }
+               } while(c != '\n');
+       }
++      return(0);
++}
++
++int cpu_feature(char *what, char *buf, int len)
++{
++      int fd, ret = 0;
++
++      fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
++              return(0);
++      }
++
++      if(!find_cpuinfo_line(fd, what, buf, len)){
++              printk("Couldn't find '%s' line in /proc/cpuinfo\n", what);
++              goto out_close;
++      }
++
++      token(fd, buf, len, '\n');
++      ret = 1;
++
++ out_close:
++      os_close_file(fd);
++      return(ret);
++}
++
++static int check_cpu_flag(char *feature, int *have_it)
++{
++      char buf[MAXTOKEN], c;
++      int fd, len = sizeof(buf)/sizeof(buf[0]);
++
++      printk("Checking for host processor %s support...", feature);
++      fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
++      if(fd < 0){
++              printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
++              return(0);
++      }
++
++      *have_it = 0;
++      if(!find_cpuinfo_line(fd, "flags", buf, sizeof(buf) / sizeof(buf[0])))
++              goto out;
+       c = token(fd, buf, len - 1, ' ');
+       if(c < 0) goto out;
+       else if(c != ' '){
+-              printk("Failed to find ':' in /proc/cpuinfo\n");
++              printk("Failed to find ' ' in /proc/cpuinfo\n");
+               goto out;
+       }
+@@ -100,21 +137,48 @@
+  out:
+       if(*have_it == 0) printk("No\n");
+       else if(*have_it == 1) printk("Yes\n");
+-      close(fd);
++      os_close_file(fd);
+       return(1);
+ }
++#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems
++       * for some people.
++       */
++static void disable_lcall(void)
++{
++      struct modify_ldt_ldt_s ldt;
++      int err;
++
++      bzero(&ldt, sizeof(ldt));
++      ldt.entry_number = 7;
++      ldt.base_addr = 0;
++      ldt.limit = 0;
++      err = modify_ldt(1, &ldt, sizeof(ldt));
++      if(err)
++              printk("Failed to disable lcall7 - errno = %d\n", errno);
++}
++#endif
++
++void arch_init_thread(void)
++{
++#if 0
++      disable_lcall();
++#endif
++}
++
+ void arch_check_bugs(void)
+ {
+       int have_it;
+-      if(access("/proc/cpuinfo", R_OK)){
++      if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){
+               printk("/proc/cpuinfo not available - skipping CPU capability "
+                      "checks\n");
+               return;
+       }
+-      if(check_cpu_feature("cmov", &have_it)) cpu_has_cmov = have_it;
+-      if(check_cpu_feature("xmm", &have_it)) cpu_has_xmm = have_it;
++      if(check_cpu_flag("cmov", &have_it)) 
++              host_has_cmov = have_it;
++      if(check_cpu_flag("xmm", &have_it)) 
++              host_has_xmm = have_it;
+ }
+ int arch_handle_signal(int sig, union uml_pt_regs *regs)
+@@ -130,18 +194,18 @@
+       if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40))
+               return(0);
+-      if(cpu_has_cmov == 0)
++      if(host_has_cmov == 0)
+               panic("SIGILL caused by cmov, which this processor doesn't "
+                     "implement, boot a filesystem compiled for older "
+                     "processors");
+-      else if(cpu_has_cmov == 1)
++      else if(host_has_cmov == 1)
+               panic("SIGILL caused by cmov, which this processor claims to "
+                     "implement");
+-      else if(cpu_has_cmov == -1)
++      else if(host_has_cmov == -1)
+               panic("SIGILL caused by cmov, couldn't tell if this processor "
+                     "implements it, boot a filesystem compiled for older "
+                     "processors");
+-      else panic("Bad value for cpu_has_cmov (%d)", cpu_has_cmov);
++      else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
+       return(0);
+ }
+diff -Naur a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
+--- a/arch/um/sys-i386/Makefile        2004-01-08 22:15:20.000000000 -0500
++++ b/arch/um/sys-i386/Makefile        2004-01-08 22:21:10.000000000 -0500
+@@ -1,7 +1,8 @@
+-obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o module.o \
+-      ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o
++obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o ptrace.o \
++      ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o time.o
+ obj-$(CONFIG_HIGHMEM) += highmem.o
++obj-$(CONFIG_MODULES) += module.o
+ USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o
+ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
+@@ -9,6 +10,8 @@
+ SYMLINKS = semaphore.c highmem.c module.c
+ SYMLINKS := $(foreach f,$(SYMLINKS),$(src)/$f)
++clean-files := $(SYMLINKS)
++
+ semaphore.c-dir = kernel
+ highmem.c-dir = mm
+ module.c-dir = kernel
+@@ -24,8 +27,7 @@
+ $(SYMLINKS): 
+       $(call make_link,$@)
+-clean:
+-      $(MAKE) -C util clean
++subdir- := util
+ fastdep:
+diff -Naur a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c
+--- a/arch/um/sys-i386/ptrace_user.c   2004-01-08 22:16:43.000000000 -0500
++++ b/arch/um/sys-i386/ptrace_user.c   2004-01-08 22:22:45.000000000 -0500
+@@ -39,10 +39,10 @@
+       nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
+       for(i = 0; i < nregs; i++){
+               if((i == 4) || (i == 5)) continue;
+-              if(ptrace(PTRACE_POKEUSR, pid, &dummy->u_debugreg[i],
++              if(ptrace(PTRACE_POKEUSER, pid, &dummy->u_debugreg[i],
+                         regs[i]) < 0)
+-                      printk("write_debugregs - ptrace failed, "
+-                             "errno = %d\n", errno);
++                      printk("write_debugregs - ptrace failed on "
++                             "register %d, errno = %d\n", errno);
+       }
+ }
+@@ -54,7 +54,7 @@
+       dummy = NULL;
+       nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]);
+       for(i = 0; i < nregs; i++){
+-              regs[i] = ptrace(PTRACE_PEEKUSR, pid, 
++              regs[i] = ptrace(PTRACE_PEEKUSER, pid, 
+                                &dummy->u_debugreg[i], 0);
+       }
+ }
+diff -Naur a/arch/um/sys-i386/time.c b/arch/um/sys-i386/time.c
+--- a/arch/um/sys-i386/time.c  1969-12-31 19:00:00.000000000 -0500
++++ b/arch/um/sys-i386/time.c  2004-01-08 22:22:53.000000000 -0500
+@@ -0,0 +1,24 @@
++/*
++ * sys-i386/time.c 
++ * Created            25.9.2002       Sapan Bhatia
++ *
++ */
++
++unsigned long long time_stamp(void)
++{
++      unsigned long low, high;
++
++      asm("rdtsc" : "=a" (low), "=d" (high));
++      return((((unsigned long long) high) << 32) + low);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/arch/um/sys-i386/util/Makefile b/arch/um/sys-i386/util/Makefile
+--- a/arch/um/sys-i386/util/Makefile   2004-01-08 22:31:42.000000000 -0500
++++ b/arch/um/sys-i386/util/Makefile   2004-01-08 22:36:19.000000000 -0500
+@@ -6,10 +6,10 @@
+ mk_sc-objs    := mk_sc.o
+ $(obj)/mk_thread : $(obj)/mk_thread_kern.o $(obj)/mk_thread_user.o
+-      $(CC) $(CFLAGS) -o $@ $^
++      $(HOSTCC) $(CFLAGS) -o $@ $^
+ $(obj)/mk_thread_user.o : $(src)/mk_thread_user.c
+-      $(CC) $(USER_CFLAGS) -c -o $@ $<
++      $(HOSTCC) $(USER_CFLAGS) -c -o $@ $<
+ clean :
+       $(RM) -f $(build-targets)
+diff -Naur a/arch/um/sys-i386/util/mk_sc.c b/arch/um/sys-i386/util/mk_sc.c
+--- a/arch/um/sys-i386/util/mk_sc.c    2004-01-08 22:29:42.000000000 -0500
++++ b/arch/um/sys-i386/util/mk_sc.c    2004-01-08 22:35:17.000000000 -0500
+@@ -38,6 +38,7 @@
+   SC_OFFSET("SC_ERR", err);
+   SC_OFFSET("SC_CR2", cr2);
+   SC_OFFSET("SC_FPSTATE", fpstate);
++  SC_OFFSET("SC_SIGMASK", oldmask);
+   SC_FP_OFFSET("SC_FP_CW", cw);
+   SC_FP_OFFSET("SC_FP_SW", sw);
+   SC_FP_OFFSET("SC_FP_TAG", tag);
+diff -Naur a/arch/um/uml.lds.S b/arch/um/uml.lds.S
+--- a/arch/um/uml.lds.S        2004-01-08 22:20:26.000000000 -0500
++++ b/arch/um/uml.lds.S        2004-01-08 22:26:51.000000000 -0500
+@@ -9,7 +9,6 @@
+ {
+   . = START + SIZEOF_HEADERS;
+-  . = ALIGN(4096);
+   __binary_start = .;
+ #ifdef MODE_TT
+   .thread_private : {
+@@ -26,7 +25,11 @@
+   . = ALIGN(4096);            /* Init code and data */
+   _stext = .;
+   __init_begin = .;
+-  .text.init : { *(.text.init) }
++  .init.text : { 
++      _sinittext = .;
++      *(.init.text)
++      _einittext = .;
++  }
+   . = ALIGN(4096);
+   .text      :
+   {
+@@ -38,7 +41,7 @@
+   #include "asm/common.lds.S"
+-  .data.init : { *(.data.init) }
++  init.data : { *(init.data) }
+   .data    :
+   {
+     . = ALIGN(KERNEL_STACK_SIZE);             /* init_task */
+diff -Naur a/arch/um/util/Makefile b/arch/um/util/Makefile
+--- a/arch/um/util/Makefile    2004-01-08 22:32:28.000000000 -0500
++++ b/arch/um/util/Makefile    2004-01-08 22:36:33.000000000 -0500
+@@ -3,19 +3,19 @@
+                  mk_constants_user.o mk_constants_kern.o
+ $(obj)/mk_task: $(obj)/mk_task_user.o $(obj)/mk_task_kern.o
+-      $(CC) -o $@ $^
++      $(HOSTCC) -o $@ $^
+ $(obj)/mk_task_user.o: $(src)/mk_task_user.c
+-      $(CC) -o $@ -c $< 
++      $(HOSTCC) -o $@ -c $< 
+ $(obj)/mk_constants : $(obj)/mk_constants_user.o $(obj)/mk_constants_kern.o
+-      $(CC) -o $@ $^
++      $(HOSTCC) -o $@ $^
+ $(obj)/mk_constants_user.o : $(src)/mk_constants_user.c
+-      $(CC) -c $< -o $@
++      $(HOSTCC) -c $< -o $@
+ $(obj)/mk_constants_kern.o : $(src)/mk_constants_kern.c
+-      $(CC) $(CFLAGS) -c $< -o $@
++      $(HOSTCC) $(CFLAGS) -c $< -o $@
+ clean:
+       $(RM) $(build-targets)
+diff -Naur a/arch/um/util/mk_constants_kern.c b/arch/um/util/mk_constants_kern.c
+--- a/arch/um/util/mk_constants_kern.c 2004-01-08 22:14:20.000000000 -0500
++++ b/arch/um/util/mk_constants_kern.c 2004-01-08 22:19:17.000000000 -0500
+@@ -1,5 +1,6 @@
+ #include "linux/kernel.h"
+ #include "linux/stringify.h"
++#include "linux/time.h"
+ #include "asm/page.h"
+ extern void print_head(void);
+@@ -11,6 +12,7 @@
+ {
+   print_head();
+   print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE);
++
+   print_constant_str("UM_KERN_EMERG", KERN_EMERG);
+   print_constant_str("UM_KERN_ALERT", KERN_ALERT);
+   print_constant_str("UM_KERN_CRIT", KERN_CRIT);
+@@ -19,6 +21,8 @@
+   print_constant_str("UM_KERN_NOTICE", KERN_NOTICE);
+   print_constant_str("UM_KERN_INFO", KERN_INFO);
+   print_constant_str("UM_KERN_DEBUG", KERN_DEBUG);
++
++  print_constant_int("UM_NSEC_PER_SEC", NSEC_PER_SEC);
+   print_tail();
+   return(0);
+ }
+diff -Naur a/drivers/char/tty_io.c b/drivers/char/tty_io.c
+--- a/drivers/char/tty_io.c    2004-01-08 22:23:22.000000000 -0500
++++ b/drivers/char/tty_io.c    2004-01-08 22:30:52.000000000 -0500
+@@ -2419,12 +2419,18 @@
+ static struct cdev vc0_cdev;
+ #endif
++static int tty_initialized;
++
+ /*
+  * Ok, now we can initialize the rest of the tty devices and can count
+  * on memory allocations, interrupts etc..
+  */
+-static int __init tty_init(void)
++int __init tty_init(void)
+ {
++        if (tty_initialized)
++                return 0;
++      tty_initialized = 1;
++
+       strcpy(tty_cdev.kobj.name, "dev.tty");
+       cdev_init(&tty_cdev, &tty_fops);
+       if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
+diff -Naur a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h
+--- a/fs/hostfs/hostfs.h       1969-12-31 19:00:00.000000000 -0500
++++ b/fs/hostfs/hostfs.h       2004-01-08 22:17:40.000000000 -0500
+@@ -0,0 +1,79 @@
++#ifndef __UM_FS_HOSTFS
++#define __UM_FS_HOSTFS
++
++#include "os.h"
++
++/* These are exactly the same definitions as in fs.h, but the names are 
++ * changed so that this file can be included in both kernel and user files.
++ */
++
++#define HOSTFS_ATTR_MODE      1
++#define HOSTFS_ATTR_UID       2
++#define HOSTFS_ATTR_GID       4
++#define HOSTFS_ATTR_SIZE      8
++#define HOSTFS_ATTR_ATIME     16
++#define HOSTFS_ATTR_MTIME     32
++#define HOSTFS_ATTR_CTIME     64
++#define HOSTFS_ATTR_ATIME_SET 128
++#define HOSTFS_ATTR_MTIME_SET 256
++#define HOSTFS_ATTR_FORCE     512     /* Not a change, but a change it */
++#define HOSTFS_ATTR_ATTR_FLAG 1024
++
++struct hostfs_iattr {
++      unsigned int    ia_valid;
++      mode_t          ia_mode;
++      uid_t           ia_uid;
++      gid_t           ia_gid;
++      loff_t          ia_size;
++      struct timespec ia_atime;
++      struct timespec ia_mtime;
++      struct timespec ia_ctime;
++      unsigned int    ia_attr_flags;
++};
++
++extern int stat_file(const char *path, unsigned long long *inode_out, 
++                   int *mode_out, int *nlink_out, int *uid_out, int *gid_out,
++                   unsigned long long *size_out, struct timespec *atime_out, 
++                   struct timespec *mtime_out, struct timespec *ctime_out, 
++                   int *blksize_out, unsigned long long *blocks_out);
++extern int access_file(char *path, int r, int w, int x);
++extern int open_file(char *path, int r, int w, int append);
++extern int file_type(const char *path, int *rdev);
++extern void *open_dir(char *path, int *err_out);
++extern char *read_dir(void *stream, unsigned long long *pos, 
++                    unsigned long long *ino_out, int *len_out);
++extern void close_file(void *stream);
++extern void close_dir(void *stream);
++extern int read_file(int fd, unsigned long long *offset, char *buf, int len);
++extern int write_file(int fd, unsigned long long *offset, const char *buf,
++                    int len);
++extern int lseek_file(int fd, long long offset, int whence);
++extern int file_create(char *name, int ur, int uw, int ux, int gr, 
++                     int gw, int gx, int or, int ow, int ox);
++extern int set_attr(const char *file, struct hostfs_iattr *attrs);
++extern int make_symlink(const char *from, const char *to);
++extern int unlink_file(const char *file);
++extern int do_mkdir(const char *file, int mode);
++extern int do_rmdir(const char *file);
++extern int do_mknod(const char *file, int mode, int dev);
++extern int link_file(const char *from, const char *to);
++extern int do_readlink(char *file, char *buf, int size);
++extern int rename_file(char *from, char *to);
++extern int do_statfs(char *root, long *bsize_out, long long *blocks_out, 
++                   long long *bfree_out, long long *bavail_out, 
++                   long long *files_out, long long *ffree_out, 
++                   void *fsid_out, int fsid_size, long *namelen_out, 
++                   long *spare_out);
++
++#endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
+--- a/fs/hostfs/hostfs_kern.c  1969-12-31 19:00:00.000000000 -0500
++++ b/fs/hostfs/hostfs_kern.c  2004-01-08 22:18:32.000000000 -0500
+@@ -0,0 +1,1008 @@
++/* 
++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ *
++ * Ported the filesystem routines to 2.5.
++ * 2003-02-10 Petr Baudis <pasky@ucw.cz>
++ */
++
++#include <linux/stddef.h>
++#include <linux/fs.h>
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/pagemap.h>
++#include <linux/blkdev.h>
++#include <linux/list.h>
++#include <linux/buffer_head.h>
++#include <linux/root_dev.h>
++#include <linux/statfs.h>
++#include <asm/uaccess.h>
++#include "hostfs.h"
++#include "kern_util.h"
++#include "kern.h"
++#include "user_util.h"
++#include "2_5compat.h"
++#include "init.h"
++
++struct hostfs_inode_info {
++      char *host_filename;
++      int fd;
++      int mode;
++      struct inode vfs_inode;
++};
++
++static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode)
++{
++      return(list_entry(inode, struct hostfs_inode_info, vfs_inode));
++}
++
++#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_dentry->d_inode)
++
++int hostfs_d_delete(struct dentry *dentry)
++{
++      return(1);
++}
++
++struct dentry_operations hostfs_dentry_ops = {
++      .d_delete               = hostfs_d_delete,
++};
++
++/* Changed in hostfs_args before the kernel starts running */
++static char *root_ino = "/";
++static int append = 0;
++
++#define HOSTFS_SUPER_MAGIC 0x00c0ffee
++
++static struct inode_operations hostfs_iops;
++static struct inode_operations hostfs_dir_iops;
++static struct address_space_operations hostfs_link_aops;
++
++static int __init hostfs_args(char *options, int *add)
++{
++      char *ptr;
++
++      ptr = strchr(options, ',');
++      if(ptr != NULL)
++              *ptr++ = '\0';
++      if(*options != '\0')
++              root_ino = options;
++
++      options = ptr;
++      while(options){
++              ptr = strchr(options, ',');
++              if(ptr != NULL)
++                      *ptr++ = '\0';
++              if(*options != '\0'){
++                      if(!strcmp(options, "append"))
++                              append = 1;
++                      else printf("hostfs_args - unsupported option - %s\n",
++                                  options);
++              }
++              options = ptr;
++      }
++      return(0);
++}
++
++__uml_setup("hostfs=", hostfs_args,
++"hostfs=<root dir>,<flags>,...\n"
++"    This is used to set hostfs parameters.  The root directory argument\n"
++"    is used to confine all hostfs mounts to within the specified directory\n"
++"    tree on the host.  If this isn't specified, then a user inside UML can\n"
++"    mount anything on the host that's accessible to the user that's running\n"
++"    it.\n"
++"    The only flag currently supported is 'append', which specifies that all\n"
++"    files opened by hostfs will be opened in append mode.\n\n"
++);
++
++static char *dentry_name(struct dentry *dentry, int extra)
++{
++      struct dentry *parent;
++      char *root, *name;
++      int len;
++
++      len = 0;
++      parent = dentry;
++      while(parent->d_parent != parent){
++              len += parent->d_name.len + 1;
++              parent = parent->d_parent;
++      }
++      
++      root = HOSTFS_I(parent->d_inode)->host_filename;
++      len += strlen(root);
++      name = kmalloc(len + extra + 1, GFP_KERNEL);
++      if(name == NULL) return(NULL);
++
++      name[len] = '\0';
++      parent = dentry;
++      while(parent->d_parent != parent){
++              len -= parent->d_name.len + 1;
++              name[len] = '/';
++              strncpy(&name[len + 1], parent->d_name.name, 
++                      parent->d_name.len);
++              parent = parent->d_parent;
++      }
++      strncpy(name, root, strlen(root));
++      return(name);
++}
++
++static char *inode_name(struct inode *ino, int extra)
++{
++      struct dentry *dentry;
++
++      dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias);
++      return(dentry_name(dentry, extra));
++}
++
++static int read_name(struct inode *ino, char *name)
++{
++      /* The non-int inode fields are copied into ints by stat_file and
++       * then copied into the inode because passing the actual pointers
++       * in and having them treated as int * breaks on big-endian machines
++       */
++      int err;
++      int i_mode, i_nlink, i_blksize;
++      unsigned long long i_size;
++      unsigned long long i_ino;
++      unsigned long long i_blocks;
++
++      err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid, 
++                      &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime, 
++                      &ino->i_ctime, &i_blksize, &i_blocks);
++      if(err) 
++              return(err);
++
++      ino->i_ino = i_ino;
++      ino->i_mode = i_mode;
++      ino->i_nlink = i_nlink;
++      ino->i_size = i_size;
++      ino->i_blksize = i_blksize;
++      ino->i_blocks = i_blocks;
++      if((ino->i_sb->s_dev == ROOT_DEV) && (ino->i_uid == getuid()))
++              ino->i_uid = 0;
++      return(0);
++}
++
++static char *follow_link(char *link)
++{
++      int len, n;
++      char *name, *resolved, *end;
++
++      len = 64;
++      while(1){
++              n = -ENOMEM;
++              name = kmalloc(len, GFP_KERNEL);
++              if(name == NULL)
++                      goto out;
++
++              n = do_readlink(link, name, len);
++              if(n < len)
++                      break;
++              len *= 2;
++              kfree(name);
++      }
++      if(n < 0)
++              goto out_free;
++
++      if(*name == '/')
++              return(name);
++
++      end = strrchr(link, '/');
++      if(end == NULL)
++              return(name);
++
++      *(end + 1) = '\0';
++      len = strlen(link) + strlen(name) + 1;
++
++      resolved = kmalloc(len, GFP_KERNEL);
++      if(resolved == NULL){
++              n = -ENOMEM;
++              goto out_free;
++      }
++
++      sprintf(resolved, "%s%s", link, name);
++      kfree(name);
++      kfree(link);
++      return(resolved);
++
++ out_free:
++      kfree(name);
++ out:
++      return(ERR_PTR(n));
++}
++
++static int read_inode(struct inode *ino)
++{
++      char *name;
++      int err = 0;
++
++      /* Unfortunately, we are called from iget() when we don't have a dentry
++       * allocated yet.
++       */
++      if(list_empty(&ino->i_dentry))
++              goto out;
++ 
++      err = -ENOMEM;
++      name = inode_name(ino, 0);
++      if(name == NULL) 
++              goto out;
++
++      if(file_type(name, NULL) == OS_TYPE_SYMLINK){
++              name = follow_link(name);
++              if(IS_ERR(name)){
++                      err = PTR_ERR(name);
++                      goto out;
++              }
++      }
++      
++      err = read_name(ino, name);
++      kfree(name);
++ out:
++      return(err);
++}
++
++int hostfs_statfs(struct super_block *sb, struct kstatfs *sf)
++{
++      /* do_statfs uses struct statfs64 internally, but the linux kernel
++       * struct statfs still has 32-bit versions for most of these fields,
++       * so we convert them here
++       */
++      int err;
++      long long f_blocks;
++      long long f_bfree;
++      long long f_bavail;
++      long long f_files;
++      long long f_ffree;
++
++      err = do_statfs(HOSTFS_I(sb->s_root->d_inode)->host_filename,
++                      &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files,
++                      &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid), 
++                      &sf->f_namelen, sf->f_spare);
++      if(err) return(err);
++      sf->f_blocks = f_blocks;
++      sf->f_bfree = f_bfree;
++      sf->f_bavail = f_bavail;
++      sf->f_files = f_files;
++      sf->f_ffree = f_ffree;
++      sf->f_type = HOSTFS_SUPER_MAGIC;
++      return(0);
++}
++
++static struct inode *hostfs_alloc_inode(struct super_block *sb)
++{
++      struct hostfs_inode_info *hi;
++
++      hi = kmalloc(sizeof(*hi), GFP_KERNEL);
++      if(hi == NULL) 
++              return(NULL);
++
++      *hi = ((struct hostfs_inode_info) { .host_filename      = NULL,
++                                          .fd                 = -1,
++                                          .mode               = 0 });
++      inode_init_once(&hi->vfs_inode);
++      return(&hi->vfs_inode);
++}
++
++static void hostfs_destroy_inode(struct inode *inode)
++{
++      if(HOSTFS_I(inode)->host_filename) 
++              kfree(HOSTFS_I(inode)->host_filename);
++
++      if(HOSTFS_I(inode)->fd != -1) 
++              close_file(&HOSTFS_I(inode)->fd);
++
++      kfree(HOSTFS_I(inode));
++}
++
++static void hostfs_read_inode(struct inode *inode)
++{
++      read_inode(inode);
++}
++
++static struct super_operations hostfs_sbops = { 
++      .alloc_inode    = hostfs_alloc_inode,
++      .destroy_inode  = hostfs_destroy_inode,
++      .read_inode     = hostfs_read_inode,
++      .statfs         = hostfs_statfs,
++};
++
++int hostfs_readdir(struct file *file, void *ent, filldir_t filldir)
++{
++      void *dir;
++      char *name;
++      unsigned long long next, ino;
++      int error, len;
++
++      name = dentry_name(file->f_dentry, 0);
++      if(name == NULL) return(-ENOMEM);
++      dir = open_dir(name, &error);
++      kfree(name);
++      if(dir == NULL) return(-error);
++      next = file->f_pos;
++      while((name = read_dir(dir, &next, &ino, &len)) != NULL){
++              error = (*filldir)(ent, name, len, file->f_pos, 
++                                 ino, DT_UNKNOWN);
++              if(error) break;
++              file->f_pos = next;
++      }
++      close_dir(dir);
++      return(0);
++}
++
++int hostfs_file_open(struct inode *ino, struct file *file)
++{
++      char *name;
++      int mode = 0, r = 0, w = 0, fd;
++
++      mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
++      if((mode & HOSTFS_I(ino)->mode) == mode)
++              return(0);
++
++      /* The file may already have been opened, but with the wrong access,
++       * so this resets things and reopens the file with the new access.
++       */
++      if(HOSTFS_I(ino)->fd != -1){
++              close_file(&HOSTFS_I(ino)->fd);
++              HOSTFS_I(ino)->fd = -1;
++      }
++
++      HOSTFS_I(ino)->mode |= mode;
++      if(HOSTFS_I(ino)->mode & FMODE_READ) 
++              r = 1;
++      if(HOSTFS_I(ino)->mode & FMODE_WRITE) 
++              w = 1;
++      if(w) 
++              r = 1;
++
++      name = dentry_name(file->f_dentry, 0);
++      if(name == NULL) 
++              return(-ENOMEM);
++
++      fd = open_file(name, r, w, append);
++      kfree(name);
++      if(fd < 0) return(fd);
++      FILE_HOSTFS_I(file)->fd = fd;
++
++      return(0);
++}
++
++int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
++{
++      return(0);
++}
++
++static struct file_operations hostfs_file_fops = {
++      .llseek         = generic_file_llseek,
++      .read           = generic_file_read,
++      .write          = generic_file_write,
++      .mmap           = generic_file_mmap,
++      .open           = hostfs_file_open,
++      .release        = NULL,
++      .fsync          = hostfs_fsync,
++};
++
++static struct file_operations hostfs_dir_fops = {
++      .readdir        = hostfs_readdir,
++      .read           = generic_read_dir,
++};
++
++int hostfs_writepage(struct page *page, struct writeback_control *wbc)
++{
++      struct address_space *mapping = page->mapping;
++      struct inode *inode = mapping->host;
++      char *buffer;
++      unsigned long long base;
++      int count = PAGE_CACHE_SIZE;
++      int end_index = inode->i_size >> PAGE_CACHE_SHIFT;
++      int err;
++
++      if (page->index >= end_index)
++              count = inode->i_size & (PAGE_CACHE_SIZE-1);
++
++      buffer = kmap(page);
++      base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT;
++
++      err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count);
++      if(err != count){
++              ClearPageUptodate(page);
++              goto out;
++      }
++
++      if (base > inode->i_size)
++              inode->i_size = base;
++
++      if (PageError(page))
++              ClearPageError(page);   
++      err = 0;
++
++ out: 
++      kunmap(page);
++
++      unlock_page(page);
++      return err; 
++}
++
++int hostfs_readpage(struct file *file, struct page *page)
++{
++      char *buffer;
++      long long start;
++      int err = 0;
++
++      start = (long long) page->index << PAGE_CACHE_SHIFT;
++      buffer = kmap(page);
++      err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer,
++                      PAGE_CACHE_SIZE);
++      if(err < 0) goto out;
++
++      memset(&buffer[err], 0, PAGE_CACHE_SIZE - err);
++
++      flush_dcache_page(page);
++      SetPageUptodate(page);
++      if (PageError(page)) ClearPageError(page);
++      err = 0;
++ out:
++      kunmap(page);
++      unlock_page(page);
++      return(err);
++}
++
++int hostfs_prepare_write(struct file *file, struct page *page, 
++                       unsigned int from, unsigned int to)
++{
++      char *buffer;
++      long long start, tmp;
++      int err;
++
++      start = (long long) page->index << PAGE_CACHE_SHIFT;
++      buffer = kmap(page);
++      if(from != 0){
++              tmp = start;
++              err = read_file(FILE_HOSTFS_I(file)->fd, &tmp, buffer,
++                              from);
++              if(err < 0) goto out;
++      }
++      if(to != PAGE_CACHE_SIZE){
++              start += to;
++              err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer + to,
++                              PAGE_CACHE_SIZE - to);
++              if(err < 0) goto out;           
++      }
++      err = 0;
++ out:
++      kunmap(page);
++      return(err);
++}
++
++int hostfs_commit_write(struct file *file, struct page *page, unsigned from,
++               unsigned to)
++{
++      struct address_space *mapping = page->mapping;
++      struct inode *inode = mapping->host;
++      char *buffer;
++      long long start;
++      int err = 0;
++
++      start = (long long) (page->index << PAGE_CACHE_SHIFT) + from;
++      buffer = kmap(page);
++      err = write_file(FILE_HOSTFS_I(file)->fd, &start, buffer + from, 
++                       to - from);
++      if(err > 0) err = 0;
++      if(!err && (start > inode->i_size))
++              inode->i_size = start;
++
++      kunmap(page);
++      return(err);
++}
++
++static struct address_space_operations hostfs_aops = {
++      .writepage      = hostfs_writepage,
++      .readpage       = hostfs_readpage,
++/*    .set_page_dirty = __set_page_dirty_nobuffers, */
++      .prepare_write  = hostfs_prepare_write,
++      .commit_write   = hostfs_commit_write
++};
++
++static int init_inode(struct inode *inode, struct dentry *dentry)
++{
++      char *name;
++      int type, err = -ENOMEM, rdev;
++
++      if(dentry){
++              name = dentry_name(dentry, 0);
++              if(name == NULL)
++                      goto out;
++              type = file_type(name, &rdev);
++              kfree(name);
++      }
++      else type = OS_TYPE_DIR;
++
++      err = 0;
++      if(type == OS_TYPE_SYMLINK)
++              inode->i_op = &page_symlink_inode_operations;
++      else if(type == OS_TYPE_DIR)
++              inode->i_op = &hostfs_dir_iops;
++      else inode->i_op = &hostfs_iops;
++
++      if(type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops;
++      else inode->i_fop = &hostfs_file_fops;
++
++      if(type == OS_TYPE_SYMLINK) 
++              inode->i_mapping->a_ops = &hostfs_link_aops;
++      else inode->i_mapping->a_ops = &hostfs_aops;
++
++      switch (type) {
++      case OS_TYPE_CHARDEV:
++              init_special_inode(inode, S_IFCHR, rdev);
++              break;
++      case OS_TYPE_BLOCKDEV:
++              init_special_inode(inode, S_IFBLK, rdev);
++              break;
++      case OS_TYPE_FIFO:
++              init_special_inode(inode, S_IFIFO, 0);
++              break;
++      case OS_TYPE_SOCK:
++              init_special_inode(inode, S_IFSOCK, 0);
++              break;
++      }
++ out:
++      return(err);
++}
++
++int hostfs_create(struct inode *dir, struct dentry *dentry, int mode, 
++                 struct nameidata *nd)
++{
++      struct inode *inode;
++      char *name;
++      int error, fd;
++
++      error = -ENOMEM;
++      inode = iget(dir->i_sb, 0);
++      if(inode == NULL) goto out;
++
++      error = init_inode(inode, dentry);
++      if(error) 
++              goto out_put;
++      
++      error = -ENOMEM;
++      name = dentry_name(dentry, 0);
++      if(name == NULL)
++              goto out_put;
++
++      fd = file_create(name, 
++                       mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR, 
++                       mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP, 
++                       mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH);
++      if(fd < 0) 
++              error = fd;
++      else error = read_name(inode, name);
++
++      kfree(name);
++      if(error)
++              goto out_put;
++
++      HOSTFS_I(inode)->fd = fd;
++      HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE;
++      d_instantiate(dentry, inode);
++      return(0);
++
++ out_put:
++      iput(inode);
++ out:
++      return(error);
++}
++
++struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry, 
++                            struct nameidata *nd)
++{
++      struct inode *inode;
++      char *name;
++      int err;
++
++      err = -ENOMEM;
++      inode = iget(ino->i_sb, 0);
++      if(inode == NULL) 
++              goto out;
++ 
++      err = init_inode(inode, dentry);
++      if(err) 
++              goto out_put;
++
++      err = -ENOMEM;
++      name = dentry_name(dentry, 0);
++      if(name == NULL)
++              goto out_put;
++
++      err = read_name(inode, name);
++      kfree(name);
++      if(err == -ENOENT){
++              iput(inode);
++              inode = NULL;
++      }
++      else if(err)
++              goto out_put;
++
++      d_add(dentry, inode);
++      dentry->d_op = &hostfs_dentry_ops;
++      return(NULL);
++
++ out_put:
++      iput(inode);
++ out:
++      return(ERR_PTR(err));
++}
++
++static char *inode_dentry_name(struct inode *ino, struct dentry *dentry)
++{
++        char *file;
++      int len;
++
++      file = inode_name(ino, dentry->d_name.len + 1);
++      if(file == NULL) return(NULL);
++        strcat(file, "/");
++      len = strlen(file);
++        strncat(file, dentry->d_name.name, dentry->d_name.len);
++      file[len + dentry->d_name.len] = '\0';
++        return(file);
++}
++
++int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from)
++{
++        char *from_name, *to_name;
++        int err;
++
++        if((from_name = inode_dentry_name(ino, from)) == NULL) 
++                return(-ENOMEM);
++        to_name = dentry_name(to, 0);
++      if(to_name == NULL){
++              kfree(from_name);
++              return(-ENOMEM);
++      }
++        err = link_file(to_name, from_name);
++        kfree(from_name);
++        kfree(to_name);
++        return(err);
++}
++
++int hostfs_unlink(struct inode *ino, struct dentry *dentry)
++{
++      char *file;
++      int err;
++
++      if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
++      if(append)
++              return(-EPERM);
++
++      err = unlink_file(file);
++      kfree(file);
++      return(err);
++}
++
++int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to)
++{
++      char *file;
++      int err;
++
++      if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
++      err = make_symlink(file, to);
++      kfree(file);
++      return(err);
++}
++
++int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode)
++{
++      char *file;
++      int err;
++
++      if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
++      err = do_mkdir(file, mode);
++      kfree(file);
++      return(err);
++}
++
++int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
++{
++      char *file;
++      int err;
++
++      if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM);
++      err = do_rmdir(file);
++      kfree(file);
++      return(err);
++}
++
++int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
++{
++      struct inode *inode;
++      char *name;
++      int err = -ENOMEM;
++ 
++      inode = iget(dir->i_sb, 0);
++      if(inode == NULL) 
++              goto out;
++
++      err = init_inode(inode, dentry);
++      if(err) 
++              goto out_put;
++
++      err = -ENOMEM;
++      name = dentry_name(dentry, 0);
++      if(name == NULL)
++              goto out_put;
++
++      init_special_inode(inode, mode, dev);
++      err = do_mknod(name, mode, dev);
++      if(err)
++              goto out_free;
++
++      err = read_name(inode, name);
++      kfree(name);
++      if(err)
++              goto out_put;
++
++      d_instantiate(dentry, inode);
++      return(0);
++
++ out_free:
++      kfree(name);
++ out_put:
++      iput(inode);
++ out:
++      return(err);
++}
++
++int hostfs_rename(struct inode *from_ino, struct dentry *from,
++                struct inode *to_ino, struct dentry *to)
++{
++      char *from_name, *to_name;
++      int err;
++
++      if((from_name = inode_dentry_name(from_ino, from)) == NULL)
++              return(-ENOMEM);
++      if((to_name = inode_dentry_name(to_ino, to)) == NULL){
++              kfree(from_name);
++              return(-ENOMEM);
++      }
++      err = rename_file(from_name, to_name);
++      kfree(from_name);
++      kfree(to_name);
++      return(err);
++}
++
++void hostfs_truncate(struct inode *ino)
++{
++      not_implemented();
++}
++
++int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd)
++{
++      char *name;
++      int r = 0, w = 0, x = 0, err;
++
++      if(desired & MAY_READ) r = 1;
++      if(desired & MAY_WRITE) w = 1;
++      if(desired & MAY_EXEC) x = 1;
++      name = inode_name(ino, 0);
++      if(name == NULL) return(-ENOMEM);
++      err = access_file(name, r, w, x);
++      kfree(name);
++      if(!err) err = vfs_permission(ino, desired);
++      return(err);
++}
++
++int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
++{
++      struct hostfs_iattr attrs;
++      char *name;
++      int err;
++      
++      if(append) 
++              attr->ia_valid &= ~ATTR_SIZE;
++
++      attrs.ia_valid = 0;
++      if(attr->ia_valid & ATTR_MODE){
++              attrs.ia_valid |= HOSTFS_ATTR_MODE;
++              attrs.ia_mode = attr->ia_mode;
++      }
++      if(attr->ia_valid & ATTR_UID){
++              if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) && 
++                 (attr->ia_uid == 0))
++                      attr->ia_uid = getuid();
++              attrs.ia_valid |= HOSTFS_ATTR_UID;
++              attrs.ia_uid = attr->ia_uid;
++      }
++      if(attr->ia_valid & ATTR_GID){
++              if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) && 
++                 (attr->ia_gid == 0))
++                      attr->ia_gid = getuid();
++              attrs.ia_valid |= HOSTFS_ATTR_GID;
++              attrs.ia_gid = attr->ia_gid;
++      }
++      if(attr->ia_valid & ATTR_SIZE){
++              attrs.ia_valid |= HOSTFS_ATTR_SIZE;
++              attrs.ia_size = attr->ia_size;
++      }
++      if(attr->ia_valid & ATTR_ATIME){
++              attrs.ia_valid |= HOSTFS_ATTR_ATIME;
++              attrs.ia_atime = attr->ia_atime;
++      }
++      if(attr->ia_valid & ATTR_MTIME){
++              attrs.ia_valid |= HOSTFS_ATTR_MTIME;
++              attrs.ia_mtime = attr->ia_mtime;
++      }
++      if(attr->ia_valid & ATTR_CTIME){
++              attrs.ia_valid |= HOSTFS_ATTR_CTIME;
++              attrs.ia_ctime = attr->ia_ctime;
++      }
++      if(attr->ia_valid & ATTR_ATIME_SET){
++              attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET;
++      }
++      if(attr->ia_valid & ATTR_MTIME_SET){
++              attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET;
++      }
++      name = dentry_name(dentry, 0);
++      if(name == NULL) return(-ENOMEM);
++      err = set_attr(name, &attrs);
++      kfree(name);
++      if(err)
++              return(err);
++
++      return(inode_setattr(dentry->d_inode, attr));
++}
++
++int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry, 
++         struct kstat *stat)
++{
++      generic_fillattr(dentry->d_inode, stat);
++      return(0);
++}
++
++static struct inode_operations hostfs_iops = {
++      .create         = hostfs_create,
++      .link           = hostfs_link,
++      .unlink         = hostfs_unlink,
++      .symlink        = hostfs_symlink,
++      .mkdir          = hostfs_mkdir,
++      .rmdir          = hostfs_rmdir,
++      .mknod          = hostfs_mknod,
++      .rename         = hostfs_rename,
++      .truncate       = hostfs_truncate,
++      .permission     = hostfs_permission,
++      .setattr        = hostfs_setattr,
++      .getattr        = hostfs_getattr,
++};
++
++static struct inode_operations hostfs_dir_iops = {
++      .create         = hostfs_create,
++      .lookup         = hostfs_lookup,
++      .link           = hostfs_link,
++      .unlink         = hostfs_unlink,
++      .symlink        = hostfs_symlink,
++      .mkdir          = hostfs_mkdir,
++      .rmdir          = hostfs_rmdir,
++      .mknod          = hostfs_mknod,
++      .rename         = hostfs_rename,
++      .truncate       = hostfs_truncate,
++      .permission     = hostfs_permission,
++      .setattr        = hostfs_setattr,
++      .getattr        = hostfs_getattr,
++};
++
++int hostfs_link_readpage(struct file *file, struct page *page)
++{
++      char *buffer, *name;
++      long long start;
++      int err;
++
++      start = page->index << PAGE_CACHE_SHIFT;
++      buffer = kmap(page);
++      name = inode_name(page->mapping->host, 0);
++      if(name == NULL) return(-ENOMEM);
++      err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
++      kfree(name);
++      if(err == PAGE_CACHE_SIZE)
++              err = -E2BIG;
++      else if(err > 0){
++              flush_dcache_page(page);
++              SetPageUptodate(page);
++              if (PageError(page)) ClearPageError(page);
++              err = 0;
++      }
++      kunmap(page);
++      unlock_page(page);
++      return(err);
++}
++
++static struct address_space_operations hostfs_link_aops = {
++      .readpage       = hostfs_link_readpage,
++};
++
++static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
++{
++      struct inode *root_inode;
++      char *name, *data = d;
++      int err;
++
++      sb->s_blocksize = 1024;
++      sb->s_blocksize_bits = 10;
++      sb->s_magic = HOSTFS_SUPER_MAGIC;
++      sb->s_op = &hostfs_sbops;
++
++      if((data == NULL) || (*data == '\0')) 
++              data = root_ino;
++
++      err = -ENOMEM;
++      name = kmalloc(strlen(data) + 1, GFP_KERNEL);
++      if(name == NULL) 
++              goto out;
++
++      strcpy(name, data);
++
++      root_inode = iget(sb, 0);
++      if(root_inode == NULL)
++              goto out_free;
++
++      err = init_inode(root_inode, NULL);
++      if(err)
++              goto out_put;
++
++      HOSTFS_I(root_inode)->host_filename = name;
++
++      err = -ENOMEM;
++      sb->s_root = d_alloc_root(root_inode);
++      if(sb->s_root == NULL)
++              goto out_put;
++
++      err = read_inode(root_inode);
++      if(err)
++              goto out_put;
++
++      return(0);
++
++ out_put:
++      iput(root_inode);
++ out_free:
++      kfree(name);
++ out:
++      return(err);
++}
++
++static struct super_block *hostfs_read_sb(struct file_system_type *type,
++                                           int flags, const char *dev_name,
++                                           void *data)
++{
++      return(get_sb_nodev(type, flags, data, hostfs_fill_sb_common));
++}
++
++static struct file_system_type hostfs_type = {
++      .owner          = THIS_MODULE,
++      .name           = "hostfs",
++      .get_sb         = hostfs_read_sb,
++      .kill_sb        = kill_anon_super,
++      .fs_flags       = 0,
++};
++
++static int __init init_hostfs(void)
++{
++      return(register_filesystem(&hostfs_type));
++}
++
++static void __exit exit_hostfs(void)
++{
++      unregister_filesystem(&hostfs_type);
++}
++
++module_init(init_hostfs)
++module_exit(exit_hostfs)
++MODULE_LICENSE("GPL");
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c
+--- a/fs/hostfs/hostfs_user.c  1969-12-31 19:00:00.000000000 -0500
++++ b/fs/hostfs/hostfs_user.c  2004-01-08 22:21:31.000000000 -0500
+@@ -0,0 +1,361 @@
++/* 
++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <unistd.h>
++#include <stdio.h>
++#include <fcntl.h>
++#include <dirent.h>
++#include <errno.h>
++#include <utime.h>
++#include <string.h>
++#include <sys/stat.h>
++#include <sys/time.h>
++#include <sys/vfs.h>
++#include "hostfs.h"
++#include "kern_util.h"
++#include "user.h"
++
++int stat_file(const char *path, unsigned long long *inode_out, int *mode_out,
++            int *nlink_out, int *uid_out, int *gid_out, 
++            unsigned long long *size_out, struct timespec *atime_out,
++            struct timespec *mtime_out, struct timespec *ctime_out,
++            int *blksize_out, unsigned long long *blocks_out)
++{
++      struct stat64 buf;
++
++      if(lstat64(path, &buf) < 0) 
++              return(-errno);
++
++      /* See the Makefile for why STAT64_INO_FIELD is passed in
++       * by the build
++       */
++      if(inode_out != NULL) *inode_out = buf.STAT64_INO_FIELD;
++      if(mode_out != NULL) *mode_out = buf.st_mode;
++      if(nlink_out != NULL) *nlink_out = buf.st_nlink;
++      if(uid_out != NULL) *uid_out = buf.st_uid;
++      if(gid_out != NULL) *gid_out = buf.st_gid;
++      if(size_out != NULL) *size_out = buf.st_size;
++      if(atime_out != NULL) {
++              atime_out->tv_sec = buf.st_atime;
++              atime_out->tv_nsec = 0;
++      }
++      if(mtime_out != NULL) {
++              mtime_out->tv_sec = buf.st_mtime;
++              mtime_out->tv_nsec = 0;
++      }
++      if(ctime_out != NULL) {
++              ctime_out->tv_sec = buf.st_ctime;
++              ctime_out->tv_nsec = 0;
++      }
++      if(blksize_out != NULL) *blksize_out = buf.st_blksize;
++      if(blocks_out != NULL) *blocks_out = buf.st_blocks;
++      return(0);
++}
++
++int file_type(const char *path, int *rdev)
++{
++      struct stat64 buf;
++
++      if(lstat64(path, &buf) < 0) 
++              return(-errno);
++      if(rdev != NULL) 
++              *rdev = buf.st_rdev;
++
++      if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR);
++      else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK);
++      else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV);
++      else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV);
++      else if(S_ISFIFO(buf.st_mode))return(OS_TYPE_FIFO);
++      else if(S_ISSOCK(buf.st_mode))return(OS_TYPE_SOCK);
++      else return(OS_TYPE_FILE);
++}
++
++int access_file(char *path, int r, int w, int x)
++{
++      int mode = 0;
++
++      if(r) mode = R_OK;
++      if(w) mode |= W_OK;
++      if(x) mode |= X_OK;
++      if(access(path, mode) != 0) return(-errno);
++      else return(0);
++}
++
++int open_file(char *path, int r, int w, int append)
++{
++      int mode = 0, fd;
++
++      if(r && !w) 
++              mode = O_RDONLY;
++      else if(!r && w) 
++              mode = O_WRONLY;
++      else if(r && w) 
++              mode = O_RDWR;
++      else panic("Impossible mode in open_file");
++
++      if(append)
++              mode |= O_APPEND;
++      fd = open64(path, mode);
++      if(fd < 0) return(-errno);
++      else return(fd);
++}
++
++void *open_dir(char *path, int *err_out)
++{
++      DIR *dir;
++
++      dir = opendir(path);
++      *err_out = errno;
++      if(dir == NULL) return(NULL);
++      return(dir);
++}
++
++char *read_dir(void *stream, unsigned long long *pos, 
++             unsigned long long *ino_out, int *len_out)
++{
++      DIR *dir = stream;
++      struct dirent *ent;
++
++      seekdir(dir, *pos);
++      ent = readdir(dir);
++      if(ent == NULL) return(NULL);
++      *len_out = strlen(ent->d_name);
++      *ino_out = ent->d_ino;
++      *pos = telldir(dir);
++      return(ent->d_name);
++}
++
++int read_file(int fd, unsigned long long *offset, char *buf, int len)
++{
++      int n;
++
++      n = pread64(fd, buf, len, *offset);
++      if(n < 0) return(-errno);
++      *offset += n;
++      return(n);
++}
++
++int write_file(int fd, unsigned long long *offset, const char *buf, int len)
++{
++      int n;
++
++      n = pwrite64(fd, buf, len, *offset);
++      if(n < 0) return(-errno);
++      *offset += n;
++      return(n);
++}
++
++int lseek_file(int fd, long long offset, int whence)
++{
++      int ret;
++
++      ret = lseek64(fd, offset, whence);
++      if(ret < 0) return(-errno);
++      return(0);
++}
++
++void close_file(void *stream)
++{
++      close(*((int *) stream));
++}
++
++void close_dir(void *stream)
++{
++      closedir(stream);
++}
++
++int file_create(char *name, int ur, int uw, int ux, int gr, 
++              int gw, int gx, int or, int ow, int ox)
++{
++      int mode, fd;
++
++      mode = 0;
++      mode |= ur ? S_IRUSR : 0;
++      mode |= uw ? S_IWUSR : 0;
++      mode |= ux ? S_IXUSR : 0;
++      mode |= gr ? S_IRGRP : 0;
++      mode |= gw ? S_IWGRP : 0;
++      mode |= gx ? S_IXGRP : 0;
++      mode |= or ? S_IROTH : 0;
++      mode |= ow ? S_IWOTH : 0;
++      mode |= ox ? S_IXOTH : 0;
++      fd = open64(name, O_CREAT | O_RDWR, mode);
++      if(fd < 0) 
++              return(-errno);
++      return(fd);
++}
++
++int set_attr(const char *file, struct hostfs_iattr *attrs)
++{
++      struct utimbuf buf;
++      int err, ma;
++
++      if(attrs->ia_valid & HOSTFS_ATTR_MODE){
++              if(chmod(file, attrs->ia_mode) != 0) return(-errno);
++      }
++      if(attrs->ia_valid & HOSTFS_ATTR_UID){
++              if(chown(file, attrs->ia_uid, -1)) return(-errno);
++      }
++      if(attrs->ia_valid & HOSTFS_ATTR_GID){
++              if(chown(file, -1, attrs->ia_gid)) return(-errno);
++      }
++      if(attrs->ia_valid & HOSTFS_ATTR_SIZE){
++              if(truncate(file, attrs->ia_size)) return(-errno);
++      }
++      ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET;
++      if((attrs->ia_valid & ma) == ma){
++              buf.actime = attrs->ia_atime.tv_sec;
++              buf.modtime = attrs->ia_mtime.tv_sec;
++              if(utime(file, &buf) != 0) return(-errno);
++      }
++      else {
++              struct timespec ts;
++
++              if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){
++                      err = stat_file(file, NULL, NULL, NULL, NULL, NULL, 
++                                      NULL, NULL, &ts, NULL, NULL, NULL);
++                      if(err != 0) 
++                              return(err);
++                      buf.actime = attrs->ia_atime.tv_sec;
++                      buf.modtime = ts.tv_sec;
++                      if(utime(file, &buf) != 0) 
++                              return(-errno);
++              }
++              if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){
++                      err = stat_file(file, NULL, NULL, NULL, NULL, NULL, 
++                                      NULL, &ts, NULL, NULL, NULL, NULL);
++                      if(err != 0) 
++                              return(err);
++                      buf.actime = ts.tv_sec;
++                      buf.modtime = attrs->ia_mtime.tv_sec;
++                      if(utime(file, &buf) != 0) 
++                              return(-errno);
++              }
++      }
++      if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ;
++      if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){
++              err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL, 
++                              &attrs->ia_atime, &attrs->ia_mtime, NULL, 
++                              NULL, NULL);
++              if(err != 0) return(err);
++      }
++      return(0);
++}
++
++int make_symlink(const char *from, const char *to)
++{
++      int err;
++
++      err = symlink(to, from);
++      if(err) return(-errno);
++      return(0);
++}
++
++int unlink_file(const char *file)
++{
++      int err;
++
++      err = unlink(file);
++      if(err) return(-errno);
++      return(0);
++}
++
++int do_mkdir(const char *file, int mode)
++{
++      int err;
++
++      err = mkdir(file, mode);
++      if(err) return(-errno);
++      return(0);
++}
++
++int do_rmdir(const char *file)
++{
++      int err;
++
++      err = rmdir(file);
++      if(err) return(-errno);
++      return(0);
++}
++
++int do_mknod(const char *file, int mode, int dev)
++{
++      int err;
++
++      err = mknod(file, mode, dev);
++      if(err) return(-errno);
++      return(0);
++}
++
++int link_file(const char *to, const char *from)
++{
++      int err;
++
++      err = link(to, from);
++      if(err) return(-errno);
++      return(0);
++}
++
++int do_readlink(char *file, char *buf, int size)
++{
++      int n;
++
++      n = readlink(file, buf, size);
++      if(n < 0) 
++              return(-errno);
++      if(n < size) 
++              buf[n] = '\0';
++      return(n);
++}
++
++int rename_file(char *from, char *to)
++{
++      int err;
++
++      err = rename(from, to);
++      if(err < 0) return(-errno);
++      return(0);      
++}
++
++int do_statfs(char *root, long *bsize_out, long long *blocks_out, 
++            long long *bfree_out, long long *bavail_out, 
++            long long *files_out, long long *ffree_out,
++            void *fsid_out, int fsid_size, long *namelen_out, 
++            long *spare_out)
++{
++      struct statfs64 buf;
++      int err;
++
++      err = statfs64(root, &buf);
++      if(err < 0) return(-errno);
++      *bsize_out = buf.f_bsize;
++      *blocks_out = buf.f_blocks;
++      *bfree_out = buf.f_bfree;
++      *bavail_out = buf.f_bavail;
++      *files_out = buf.f_files;
++      *ffree_out = buf.f_ffree;
++      memcpy(fsid_out, &buf.f_fsid, 
++             sizeof(buf.f_fsid) > fsid_size ? fsid_size : 
++             sizeof(buf.f_fsid));
++      *namelen_out = buf.f_namelen;
++      spare_out[0] = buf.f_spare[0];
++      spare_out[1] = buf.f_spare[1];
++      spare_out[2] = buf.f_spare[2];
++      spare_out[3] = buf.f_spare[3];
++      spare_out[4] = buf.f_spare[4];
++      spare_out[5] = buf.f_spare[5];
++      return(0);
++}
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/fs/hostfs/Makefile b/fs/hostfs/Makefile
+--- a/fs/hostfs/Makefile       1969-12-31 19:00:00.000000000 -0500
++++ b/fs/hostfs/Makefile       2004-01-08 22:17:43.000000000 -0500
+@@ -0,0 +1,36 @@
++# 
++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++# struct stat64 changed the inode field name between 2.2 and 2.4 from st_ino
++# to __st_ino.  It stayed in the same place, so as long as the correct name
++# is used, hostfs compiled on 2.2 should work on 2.4 and vice versa.
++
++STAT64_INO_FIELD := $(shell grep -q __st_ino /usr/include/bits/stat.h && \
++                              echo __)st_ino
++
++hostfs-objs := hostfs_kern.o hostfs_user.o
++
++obj-y = 
++obj-$(CONFIG_HOSTFS) += hostfs.o
++
++SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
++
++USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(SINGLE_OBJS))
++USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
++
++USER_CFLAGS += -DSTAT64_INO_FIELD=$(STAT64_INO_FIELD)
++
++$(USER_OBJS) : %.o: %.c
++      $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
++
++clean:
++
++modules:
++
++fastdep:
++
++dep:
++
++archmrproper: clean
+diff -Naur a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
+--- a/fs/hppfs/hppfs_kern.c    1969-12-31 19:00:00.000000000 -0500
++++ b/fs/hppfs/hppfs_kern.c    2004-01-08 22:27:11.000000000 -0500
+@@ -0,0 +1,811 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/kernel.h>
++#include <linux/ctype.h>
++#include <linux/dcache.h>
++#include <linux/statfs.h>
++#include <asm/uaccess.h>
++#include <asm/fcntl.h>
++#include "os.h"
++
++static int init_inode(struct inode *inode, struct dentry *dentry);
++
++struct hppfs_data {
++      struct list_head list;
++      char contents[PAGE_SIZE - sizeof(struct list_head)];
++};
++
++struct hppfs_private {
++      struct file proc_file;
++      int host_fd;
++      loff_t len;
++      struct hppfs_data *contents;
++};
++
++struct hppfs_inode_info {
++        struct dentry *proc_dentry;
++      struct inode vfs_inode;
++};
++
++static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode)
++{
++      return(list_entry(inode, struct hppfs_inode_info, vfs_inode));
++}
++
++#define HPPFS_SUPER_MAGIC 0xb00000ee
++
++static struct super_operations hppfs_sbops;
++
++static int is_pid(struct dentry *dentry)
++{
++      struct super_block *sb;
++      int i;
++
++      sb = dentry->d_sb;
++      if((sb->s_op != &hppfs_sbops) || (dentry->d_parent != sb->s_root))
++              return(0);
++
++      for(i = 0; i < dentry->d_name.len; i++){
++              if(!isdigit(dentry->d_name.name[i]))
++                      return(0);
++      }
++      return(1);
++}
++
++static char *dentry_name(struct dentry *dentry, int extra)
++{
++      struct dentry *parent;
++      char *root, *name;
++      const char *seg_name;
++      int len, seg_len;
++
++      len = 0;
++      parent = dentry;
++      while(parent->d_parent != parent){
++              if(is_pid(parent))
++                      len += strlen("pid") + 1;
++              else len += parent->d_name.len + 1;
++              parent = parent->d_parent;
++      }
++      
++      root = "proc";
++      len += strlen(root);
++      name = kmalloc(len + extra + 1, GFP_KERNEL);
++      if(name == NULL) return(NULL);
++
++      name[len] = '\0';
++      parent = dentry;
++      while(parent->d_parent != parent){
++              if(is_pid(parent)){
++                      seg_name = "pid";
++                      seg_len = strlen("pid");
++              }
++              else {
++                      seg_name = parent->d_name.name;
++                      seg_len = parent->d_name.len;
++              }
++
++              len -= seg_len + 1;
++              name[len] = '/';
++              strncpy(&name[len + 1], seg_name, seg_len);
++              parent = parent->d_parent;
++      }
++      strncpy(name, root, strlen(root));
++      return(name);
++}
++
++struct dentry_operations hppfs_dentry_ops = {
++};
++
++static int file_removed(struct dentry *dentry, const char *file)
++{
++      char *host_file;
++      int extra, fd;
++
++      extra = 0;
++      if(file != NULL) extra += strlen(file) + 1;
++
++      host_file = dentry_name(dentry, extra + strlen("/remove"));
++      if(host_file == NULL){
++              printk("file_removed : allocation failed\n");
++              return(-ENOMEM);
++      }
++
++      if(file != NULL){
++              strcat(host_file, "/");
++              strcat(host_file, file);
++      }
++      strcat(host_file, "/remove");
++
++      fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
++      kfree(host_file);
++      if(fd > 0){
++              os_close_file(fd);
++              return(1);
++      }
++      return(0);
++}
++
++static void hppfs_read_inode(struct inode *ino)
++{
++      struct inode *proc_ino;
++
++      if(HPPFS_I(ino)->proc_dentry == NULL)
++              return;
++
++      proc_ino = HPPFS_I(ino)->proc_dentry->d_inode;
++      ino->i_uid = proc_ino->i_uid;
++      ino->i_gid = proc_ino->i_gid;
++      ino->i_atime = proc_ino->i_atime;
++      ino->i_mtime = proc_ino->i_mtime;
++      ino->i_ctime = proc_ino->i_ctime;
++      ino->i_ino = proc_ino->i_ino;
++      ino->i_mode = proc_ino->i_mode;
++      ino->i_nlink = proc_ino->i_nlink;
++      ino->i_size = proc_ino->i_size;
++      ino->i_blksize = proc_ino->i_blksize;
++      ino->i_blocks = proc_ino->i_blocks;
++}
++
++static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, 
++                                  struct nameidata *nd)
++{
++      struct dentry *proc_dentry, *new, *parent;
++      struct inode *inode;
++      int err, deleted;
++
++      deleted = file_removed(dentry, NULL);
++      if(deleted < 0)
++              return(ERR_PTR(deleted));
++      else if(deleted)
++              return(ERR_PTR(-ENOENT));
++
++      err = -ENOMEM;
++      parent = HPPFS_I(ino)->proc_dentry;
++      down(&parent->d_inode->i_sem);
++      proc_dentry = d_lookup(parent, &dentry->d_name);
++      if(proc_dentry == NULL){
++              proc_dentry = d_alloc(parent, &dentry->d_name);
++              if(proc_dentry == NULL){
++                      up(&parent->d_inode->i_sem);
++                      goto out;
++              }
++              new = (*parent->d_inode->i_op->lookup)(parent->d_inode, 
++                                                     proc_dentry, NULL);
++              if(new){
++                      dput(proc_dentry);
++                      proc_dentry = new;
++              }
++      }
++      up(&parent->d_inode->i_sem);
++
++      if(IS_ERR(proc_dentry))
++              return(proc_dentry);
++
++      inode = iget(ino->i_sb, 0);
++      if(inode == NULL) 
++              goto out_dput;
++
++      err = init_inode(inode, proc_dentry);
++      if(err) 
++              goto out_put;
++      
++      hppfs_read_inode(inode);
++
++      d_add(dentry, inode);
++      dentry->d_op = &hppfs_dentry_ops;
++      return(NULL);
++
++ out_put:
++      iput(inode);
++ out_dput:
++      dput(proc_dentry);
++ out:
++      return(ERR_PTR(err));
++}
++
++static struct inode_operations hppfs_file_iops = {
++};
++
++static ssize_t read_proc(struct file *file, char *buf, ssize_t count, 
++                       loff_t *ppos, int is_user)
++{
++      ssize_t (*read)(struct file *, char *, size_t, loff_t *);
++      ssize_t n;
++
++      read = file->f_dentry->d_inode->i_fop->read;
++
++      if(!is_user)
++              set_fs(KERNEL_DS);
++              
++      n = (*read)(file, buf, count, &file->f_pos);
++
++      if(!is_user)
++              set_fs(USER_DS);
++
++      if(ppos) *ppos = file->f_pos;
++      return(n);
++}
++
++static ssize_t hppfs_read_file(int fd, char *buf, ssize_t count)
++{
++      ssize_t n;
++      int cur, err;
++      char *new_buf;
++
++      n = -ENOMEM;
++      new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
++      if(new_buf == NULL){
++              printk("hppfs_read_file : kmalloc failed\n");
++              goto out;
++      }
++      n = 0;
++      while(count > 0){
++              cur = min_t(ssize_t, count, PAGE_SIZE);
++              err = os_read_file(fd, new_buf, cur);
++              if(err < 0){
++                      printk("hppfs_read : read failed, errno = %d\n",
++                             count);
++                      n = err;
++                      goto out_free;
++              }
++              else if(err == 0)
++                      break;
++
++              if(copy_to_user(buf, new_buf, err)){
++                      n = -EFAULT;
++                      goto out_free;
++              }
++              n += err;
++              count -= err;
++      }
++ out_free:
++      kfree(new_buf);
++ out:
++      return(n);
++}
++
++static ssize_t hppfs_read(struct file *file, char *buf, size_t count, 
++                        loff_t *ppos)
++{
++      struct hppfs_private *hppfs = file->private_data;
++      struct hppfs_data *data;
++      loff_t off;
++      int err;
++
++      if(hppfs->contents != NULL){
++              if(*ppos >= hppfs->len) return(0);
++
++              data = hppfs->contents;
++              off = *ppos;
++              while(off >= sizeof(data->contents)){
++                      data = list_entry(data->list.next, struct hppfs_data,
++                                        list);
++                      off -= sizeof(data->contents);
++              }
++
++              if(off + count > hppfs->len)
++                      count = hppfs->len - off;
++              copy_to_user(buf, &data->contents[off], count);
++              *ppos += count;
++      }
++      else if(hppfs->host_fd != -1){
++              err = os_seek_file(hppfs->host_fd, *ppos);
++              if(err){
++                      printk("hppfs_read : seek failed, errno = %d\n", err);
++                      return(err);
++              }
++              count = hppfs_read_file(hppfs->host_fd, buf, count);
++              if(count > 0)
++                      *ppos += count;
++      }
++      else count = read_proc(&hppfs->proc_file, buf, count, ppos, 1);
++
++      return(count);
++}
++
++static ssize_t hppfs_write(struct file *file, const char *buf, size_t len, 
++                         loff_t *ppos)
++{
++      struct hppfs_private *data = file->private_data;
++      struct file *proc_file = &data->proc_file;
++      ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
++      int err;
++
++      write = proc_file->f_dentry->d_inode->i_fop->write;
++
++      proc_file->f_pos = file->f_pos;
++      err = (*write)(proc_file, buf, len, &proc_file->f_pos);
++      file->f_pos = proc_file->f_pos;
++
++      return(err);
++}
++
++static int open_host_sock(char *host_file, int *filter_out)
++{
++      char *end;
++      int fd;
++
++      end = &host_file[strlen(host_file)];
++      strcpy(end, "/rw");
++      *filter_out = 1;
++      fd = os_connect_socket(host_file);
++      if(fd > 0)
++              return(fd);
++
++      strcpy(end, "/r");
++      *filter_out = 0;
++      fd = os_connect_socket(host_file);
++      return(fd);
++}
++
++static void free_contents(struct hppfs_data *head)
++{
++      struct hppfs_data *data;
++      struct list_head *ele, *next;
++
++      if(head == NULL) return;
++
++      list_for_each_safe(ele, next, &head->list){
++              data = list_entry(ele, struct hppfs_data, list);
++              kfree(data);
++      }
++      kfree(head);
++}
++
++static struct hppfs_data *hppfs_get_data(int fd, int filter, 
++                                       struct file *proc_file, 
++                                       struct file *hppfs_file, 
++                                       loff_t *size_out)
++{
++      struct hppfs_data *data, *new, *head;
++      int n, err;
++
++      err = -ENOMEM;
++      data = kmalloc(sizeof(*data), GFP_KERNEL);
++      if(data == NULL){
++              printk("hppfs_get_data : head allocation failed\n");
++              goto failed;
++      }
++
++      INIT_LIST_HEAD(&data->list);
++
++      head = data;
++      *size_out = 0;
++
++      if(filter){
++              while((n = read_proc(proc_file, data->contents,
++                                   sizeof(data->contents), NULL, 0)) > 0)
++                      os_write_file(fd, data->contents, n);
++              err = os_shutdown_socket(fd, 0, 1);
++              if(err){
++                      printk("hppfs_get_data : failed to shut down "
++                             "socket\n");
++                      goto failed_free;
++              }
++      }
++      while(1){
++              n = os_read_file(fd, data->contents, sizeof(data->contents));
++              if(n < 0){
++                      err = n;
++                      printk("hppfs_get_data : read failed, errno = %d\n",
++                             err);
++                      goto failed_free;
++              }
++              else if(n == 0)
++                      break;
++
++              *size_out += n;
++
++              if(n < sizeof(data->contents))
++                      break;
++
++              new = kmalloc(sizeof(*data), GFP_KERNEL);
++              if(new == 0){
++                      printk("hppfs_get_data : data allocation failed\n");
++                      err = -ENOMEM;
++                      goto failed_free;
++              }
++      
++              INIT_LIST_HEAD(&new->list);
++              list_add(&new->list, &data->list);
++              data = new;
++      }
++      return(head);
++
++ failed_free:
++      free_contents(head);
++ failed:              
++      return(ERR_PTR(err));
++}
++
++static struct hppfs_private *hppfs_data(void)
++{
++      struct hppfs_private *data;
++
++      data = kmalloc(sizeof(*data), GFP_KERNEL);
++      if(data == NULL)
++              return(data);
++
++      *data = ((struct hppfs_private ) { .host_fd             = -1,
++                                         .len                 = -1,
++                                         .contents            = NULL } );
++      return(data);
++}
++
++static int file_mode(int fmode)
++{
++      if(fmode == (FMODE_READ | FMODE_WRITE))
++              return(O_RDWR);
++      if(fmode == FMODE_READ)
++              return(O_RDONLY);
++      if(fmode == FMODE_WRITE)
++              return(O_WRONLY);
++      return(0);
++}
++
++static int hppfs_open(struct inode *inode, struct file *file)
++{
++      struct hppfs_private *data;
++      struct dentry *proc_dentry;
++      char *host_file;
++      int err, fd, type, filter;
++
++      err = -ENOMEM;
++      data = hppfs_data();
++      if(data == NULL)
++              goto out;
++
++      host_file = dentry_name(file->f_dentry, strlen("/rw"));
++      if(host_file == NULL)
++              goto out_free2;
++
++      proc_dentry = HPPFS_I(inode)->proc_dentry;
++
++      /* XXX This isn't closed anywhere */
++      err = open_private_file(&data->proc_file, proc_dentry, 
++                              file_mode(file->f_mode));
++      if(err)
++              goto out_free1;
++
++      type = os_file_type(host_file);
++      if(type == OS_TYPE_FILE){
++              fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
++              if(fd >= 0) 
++                      data->host_fd = fd;
++              else printk("hppfs_open : failed to open '%s', errno = %d\n",
++                          host_file, -fd);
++
++              data->contents = NULL;
++      }
++      else if(type == OS_TYPE_DIR){
++              fd = open_host_sock(host_file, &filter);
++              if(fd > 0){
++                      data->contents = hppfs_get_data(fd, filter, 
++                                                      &data->proc_file, 
++                                                      file, &data->len);
++                      if(!IS_ERR(data->contents))
++                              data->host_fd = fd;
++              }
++              else printk("hppfs_open : failed to open a socket in "
++                          "'%s', errno = %d\n", host_file, -fd);
++      }
++      kfree(host_file);
++
++      file->private_data = data;
++      return(0);
++
++ out_free1:
++      kfree(host_file);
++ out_free2:
++      free_contents(data->contents);
++      kfree(data);
++ out:
++      return(err);
++}
++
++static int hppfs_dir_open(struct inode *inode, struct file *file)
++{
++      struct hppfs_private *data;
++      struct dentry *proc_dentry;
++      int err;
++
++      err = -ENOMEM;
++      data = hppfs_data();
++      if(data == NULL)
++              goto out;
++
++      proc_dentry = HPPFS_I(inode)->proc_dentry;
++      err = open_private_file(&data->proc_file, proc_dentry, 
++                              file_mode(file->f_mode));
++      if(err)
++              goto out_free;
++
++      file->private_data = data;
++      return(0);
++
++ out_free:
++      kfree(data);
++ out:
++      return(err);
++}
++
++static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
++{
++      struct hppfs_private *data = file->private_data;
++      struct file *proc_file = &data->proc_file;
++      loff_t (*llseek)(struct file *, loff_t, int);
++      loff_t ret;
++
++      llseek = proc_file->f_dentry->d_inode->i_fop->llseek;
++      if(llseek != NULL){
++              ret = (*llseek)(proc_file, off, where);
++              if(ret < 0)
++                      return(ret);
++      }
++
++      return(default_llseek(file, off, where));
++}
++
++static struct file_operations hppfs_file_fops = {
++      .owner          = NULL,
++      .llseek         = hppfs_llseek,
++      .read           = hppfs_read,
++      .write          = hppfs_write,
++      .open           = hppfs_open,
++};
++
++struct hppfs_dirent {
++      void *vfs_dirent;
++      filldir_t filldir;
++      struct dentry *dentry;
++};
++
++static int hppfs_filldir(void *d, const char *name, int size, 
++                       loff_t offset, ino_t inode, unsigned int type)
++{
++      struct hppfs_dirent *dirent = d;
++
++      if(file_removed(dirent->dentry, name))
++              return(0);
++
++      return((*dirent->filldir)(dirent->vfs_dirent, name, size, offset, 
++                                inode, type));
++}
++
++static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
++{
++      struct hppfs_private *data = file->private_data;
++      struct file *proc_file = &data->proc_file;
++      int (*readdir)(struct file *, void *, filldir_t);
++      struct hppfs_dirent dirent = ((struct hppfs_dirent)
++                                    { .vfs_dirent     = ent,
++                                      .filldir        = filldir,
++                                      .dentry         = file->f_dentry } );
++      int err;
++
++      readdir = proc_file->f_dentry->d_inode->i_fop->readdir;
++
++      proc_file->f_pos = file->f_pos;
++      err = (*readdir)(proc_file, &dirent, hppfs_filldir);
++      file->f_pos = proc_file->f_pos;
++
++      return(err);
++}
++
++static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync)
++{
++      return(0);
++}
++
++static struct file_operations hppfs_dir_fops = {
++      .owner          = NULL,
++      .readdir        = hppfs_readdir,
++      .open           = hppfs_dir_open,
++      .fsync          = hppfs_fsync,
++};
++
++static int hppfs_statfs(struct super_block *sb, struct kstatfs *sf)
++{
++      sf->f_blocks = 0;
++      sf->f_bfree = 0;
++      sf->f_bavail = 0;
++      sf->f_files = 0;
++      sf->f_ffree = 0;
++      sf->f_type = HPPFS_SUPER_MAGIC;
++      return(0);
++}
++
++static struct inode *hppfs_alloc_inode(struct super_block *sb)
++{
++      struct hppfs_inode_info *hi;
++
++      hi = kmalloc(sizeof(*hi), GFP_KERNEL);
++      if(hi == NULL) 
++              return(NULL);
++
++      *hi = ((struct hppfs_inode_info) { .proc_dentry = NULL });
++      inode_init_once(&hi->vfs_inode);
++      return(&hi->vfs_inode);
++}
++
++void hppfs_delete_inode(struct inode *ino)
++{
++      clear_inode(ino);
++}
++
++static void hppfs_destroy_inode(struct inode *inode)
++{
++      kfree(HPPFS_I(inode));
++}
++
++static struct super_operations hppfs_sbops = { 
++      .alloc_inode    = hppfs_alloc_inode,
++      .destroy_inode  = hppfs_destroy_inode,
++      .read_inode     = hppfs_read_inode,
++      .delete_inode   = hppfs_delete_inode,
++      .statfs         = hppfs_statfs,
++};
++
++static int hppfs_readlink(struct dentry *dentry, char *buffer, int buflen)
++{
++      struct file proc_file;
++      struct dentry *proc_dentry;
++      int (*readlink)(struct dentry *, char *, int);
++      int err, n;
++
++      proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
++      err = open_private_file(&proc_file, proc_dentry, O_RDONLY);
++      if(err) 
++              return(err);
++
++      readlink = proc_dentry->d_inode->i_op->readlink;
++      n = (*readlink)(proc_dentry, buffer, buflen);
++
++      close_private_file(&proc_file);
++      
++      return(n);
++}
++
++static int hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
++{
++      struct file proc_file;
++      struct dentry *proc_dentry;
++      int (*follow_link)(struct dentry *, struct nameidata *);
++      int err, n;
++
++      proc_dentry = HPPFS_I(dentry->d_inode)->proc_dentry;
++      err = open_private_file(&proc_file, proc_dentry, O_RDONLY);
++      if(err) 
++              return(err);
++
++      follow_link = proc_dentry->d_inode->i_op->follow_link;
++      n = (*follow_link)(proc_dentry, nd);
++
++      close_private_file(&proc_file);
++      
++      return(n);
++}
++
++static struct inode_operations hppfs_dir_iops = {
++      .lookup         = hppfs_lookup,
++};
++
++static struct inode_operations hppfs_link_iops = {
++      .readlink       = hppfs_readlink,
++      .follow_link    = hppfs_follow_link,
++};
++
++static int init_inode(struct inode *inode, struct dentry *dentry)
++{
++      if(S_ISDIR(dentry->d_inode->i_mode)){
++              inode->i_op = &hppfs_dir_iops;
++              inode->i_fop = &hppfs_dir_fops;
++      }
++      else if(S_ISLNK(dentry->d_inode->i_mode)){
++              inode->i_op = &hppfs_link_iops;
++              inode->i_fop = &hppfs_file_fops;
++      }
++      else {
++              inode->i_op = &hppfs_file_iops;
++              inode->i_fop = &hppfs_file_fops;
++      }
++
++      HPPFS_I(inode)->proc_dentry = dentry;
++
++      return(0);
++}
++
++static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
++{
++      struct inode *root_inode;
++      struct file_system_type *procfs;
++      struct super_block *proc_sb;
++      int err;
++
++      err = -ENOENT;
++      procfs = get_fs_type("proc");
++      if(procfs == NULL) 
++              goto out;
++
++      if(list_empty(&procfs->fs_supers))
++              goto out;
++
++      proc_sb = list_entry(procfs->fs_supers.next, struct super_block,
++                           s_instances);
++      
++      sb->s_blocksize = 1024;
++      sb->s_blocksize_bits = 10;
++      sb->s_magic = HPPFS_SUPER_MAGIC;
++      sb->s_op = &hppfs_sbops;
++
++      root_inode = iget(sb, 0);
++      if(root_inode == NULL)
++              goto out;
++
++      err = init_inode(root_inode, proc_sb->s_root);
++      if(err)
++              goto out_put;
++
++      err = -ENOMEM;
++      sb->s_root = d_alloc_root(root_inode);
++      if(sb->s_root == NULL)
++              goto out_put;
++
++      hppfs_read_inode(root_inode);
++
++      return(0);
++
++ out_put:
++      iput(root_inode);
++ out:
++      return(err);
++}
++
++static struct super_block *hppfs_read_super(struct file_system_type *type,
++                                           int flags, const char *dev_name,
++                                           void *data)
++{
++      return(get_sb_nodev(type, flags, data, hppfs_fill_super));
++}
++
++static struct file_system_type hppfs_type = {
++      .owner          = THIS_MODULE,
++      .name           = "hppfs",
++      .get_sb         = hppfs_read_super,
++      .kill_sb        = kill_anon_super,
++      .fs_flags       = 0,
++};
++
++static int __init init_hppfs(void)
++{
++      return(register_filesystem(&hppfs_type));
++}
++
++static void __exit exit_hppfs(void)
++{
++      unregister_filesystem(&hppfs_type);
++}
++
++module_init(init_hppfs)
++module_exit(exit_hppfs)
++MODULE_LICENSE("GPL");
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/fs/hppfs/Makefile b/fs/hppfs/Makefile
+--- a/fs/hppfs/Makefile        1969-12-31 19:00:00.000000000 -0500
++++ b/fs/hppfs/Makefile        2004-01-08 22:28:32.000000000 -0500
+@@ -0,0 +1,19 @@
++# 
++# Copyright (C) 2002, 2003 Jeff Dike (jdike@karaya.com)
++# Licensed under the GPL
++#
++
++hppfs-objs := hppfs_kern.o
++
++obj-y = 
++obj-$(CONFIG_HPPFS) += hppfs.o
++
++clean:
++
++modules:
++
++fastdep:
++
++dep:
++
++archmrproper: clean
+diff -Naur a/fs/Makefile b/fs/Makefile
+--- a/fs/Makefile      2004-01-08 22:23:07.000000000 -0500
++++ b/fs/Makefile      2004-01-08 22:30:15.000000000 -0500
+@@ -91,3 +91,5 @@
+ obj-$(CONFIG_XFS_FS)          += xfs/
+ obj-$(CONFIG_AFS_FS)          += afs/
+ obj-$(CONFIG_BEFS_FS)         += befs/
++obj-$(CONFIG_HOSTFS)          += hostfs/
++obj-$(CONFIG_HPPFS)           += hppfs/
+diff -Naur a/include/asm-um/archparam-i386.h b/include/asm-um/archparam-i386.h
+--- a/include/asm-um/archparam-i386.h  2004-01-08 22:28:22.000000000 -0500
++++ b/include/asm-um/archparam-i386.h  2004-01-08 22:34:31.000000000 -0500
+@@ -1,5 +1,5 @@
+ /* 
+- * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
+  * Licensed under the GPL
+  */
+@@ -56,6 +56,65 @@
+       pr_reg[16] = PT_REGS_SS(regs);          \
+ } while(0);
++#define VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL))
++#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE)
++#define VSYSCALL_ENTRY        ((unsigned long) &__kernel_vsyscall)
++extern void *__kernel_vsyscall;
++
++/*
++ * Architecture-neutral AT_ values in 0-17, leave some room
++ * for more of them, start the x86-specific ones at 32.
++ */
++#define AT_SYSINFO            32
++#define AT_SYSINFO_EHDR               33
++
++#define ARCH_DLINFO                                           \
++do {                                                          \
++              NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY);        \
++              NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE);    \
++} while (0)
++
++/*
++ * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
++ * extra segments containing the vsyscall DSO contents.  Dumping its
++ * contents makes post-mortem fully interpretable later without matching up
++ * the same kernel and hardware config to see what PC values meant.
++ * Dumping its extra ELF program headers includes all the other information
++ * a debugger needs to easily find how the vsyscall DSO was being used.
++ */
++#define ELF_CORE_EXTRA_PHDRS          (VSYSCALL_EHDR->e_phnum)
++#define ELF_CORE_WRITE_EXTRA_PHDRS                                          \
++do {                                                                        \
++      const struct elf_phdr *const vsyscall_phdrs =                         \
++              (const struct elf_phdr *) (VSYSCALL_BASE                      \
++                                         + VSYSCALL_EHDR->e_phoff);         \
++      int i;                                                                \
++      Elf32_Off ofs = 0;                                                    \
++      for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) {                        \
++              struct elf_phdr phdr = vsyscall_phdrs[i];                     \
++              if (phdr.p_type == PT_LOAD) {                                 \
++                      ofs = phdr.p_offset = offset;                         \
++                      offset += phdr.p_filesz;                              \
++              }                                                             \
++              else                                                          \
++                      phdr.p_offset += ofs;                                 \
++              phdr.p_paddr = 0; /* match other core phdrs */                \
++              DUMP_WRITE(&phdr, sizeof(phdr));                              \
++      }                                                                     \
++} while (0)
++#define ELF_CORE_WRITE_EXTRA_DATA                                           \
++do {                                                                        \
++      const struct elf_phdr *const vsyscall_phdrs =                         \
++              (const struct elf_phdr *) (VSYSCALL_BASE                      \
++                                         + VSYSCALL_EHDR->e_phoff);         \
++      int i;                                                                \
++      for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) {                        \
++              if (vsyscall_phdrs[i].p_type == PT_LOAD)                      \
++                      DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr,        \
++                                 vsyscall_phdrs[i].p_filesz);               \
++      }                                                                     \
++} while (0)
++
+ /********* Bits for asm-um/delay.h **********/
+ typedef unsigned long um_udelay_t;
+diff -Naur a/include/asm-um/common.lds.S b/include/asm-um/common.lds.S
+--- a/include/asm-um/common.lds.S      2004-01-08 22:16:07.000000000 -0500
++++ b/include/asm-um/common.lds.S      2004-01-08 22:21:49.000000000 -0500
+@@ -1,3 +1,5 @@
++#include <asm-generic/vmlinux.lds.h>
++
+   .fini      : { *(.fini)    } =0x9090
+   _etext = .;
+   PROVIDE (etext = .);
+@@ -67,6 +69,10 @@
+   }
+   __initcall_end = .;
++  __con_initcall_start = .;
++  .con_initcall.init : { *(.con_initcall.init) }
++  __con_initcall_end = .;
++
+   __uml_initcall_start = .;
+   .uml.initcall.init : { *(.uml.initcall.init) }
+   __uml_initcall_end = .;
+@@ -80,7 +86,33 @@
+   .uml.exitcall : { *(.uml.exitcall.exit) }
+   __uml_exitcall_end = .;
+-  . = ALIGN(4096);
++  . = ALIGN(4);
++  __alt_instructions = .;
++  .altinstructions : { *(.altinstructions) } 
++  __alt_instructions_end = .; 
++  .altinstr_replacement : { *(.altinstr_replacement) } 
++  /* .exit.text is discard at runtime, not link time, to deal with references
++     from .altinstructions and .eh_frame */
++  .exit.text : { *(.exit.text) }
++  .exit.data : { *(.exit.data) }
++ 
++  __preinit_array_start = .;
++  .preinit_array : { *(.preinit_array) }
++  __preinit_array_end = .;
++  __init_array_start = .;
++  .init_array : { *(.init_array) }
++  __init_array_end = .;
++  __fini_array_start = .;
++  .fini_array : { *(.fini_array) }
++  __fini_array_end = .;
++
++   . = ALIGN(4096);
+   __initramfs_start = .;
+   .init.ramfs : { *(.init.ramfs) }
+   __initramfs_end = .;
++
++  /* Sections to be discarded */
++  /DISCARD/ : {
++      *(.exitcall.exit)
++  }
++ 
+diff -Naur a/include/asm-um/cpufeature.h b/include/asm-um/cpufeature.h
+--- a/include/asm-um/cpufeature.h      1969-12-31 19:00:00.000000000 -0500
++++ b/include/asm-um/cpufeature.h      2004-01-08 22:17:48.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_CPUFEATURE_H
++#define __UM_CPUFEATURE_H
++
++#include "asm/arch/cpufeature.h"
++
++#endif
+diff -Naur a/include/asm-um/current.h b/include/asm-um/current.h
+--- a/include/asm-um/current.h 2004-01-08 22:14:14.000000000 -0500
++++ b/include/asm-um/current.h 2004-01-08 22:19:07.000000000 -0500
+@@ -16,8 +16,10 @@
+ #define CURRENT_THREAD(dummy) (((unsigned long) &dummy) & \
+                               (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER))
+-#define current ({ int dummy; \
+-                   ((struct thread_info *) CURRENT_THREAD(dummy))->task; })
++#define current_thread \
++      ({ int dummy; ((struct thread_info *) CURRENT_THREAD(dummy)); })
++
++#define current (current_thread->task)
+ #endif /* __ASSEMBLY__ */
+diff -Naur a/include/asm-um/fixmap.h b/include/asm-um/fixmap.h
+--- a/include/asm-um/fixmap.h  2004-01-08 22:30:17.000000000 -0500
++++ b/include/asm-um/fixmap.h  2004-01-08 22:35:33.000000000 -0500
+@@ -34,6 +34,7 @@
+       FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
+       FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+ #endif
++      FIX_VSYSCALL,
+       __end_of_fixed_addresses
+ };
+@@ -63,6 +64,13 @@
+ #define __fix_to_virt(x)      (FIXADDR_TOP - ((x) << PAGE_SHIFT))
+ #define __virt_to_fix(x)      ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
++/*
++ * This is the range that is readable by user mode, and things
++ * acting like user mode such as get_user_pages.
++ */
++#define FIXADDR_USER_START    (__fix_to_virt(FIX_VSYSCALL))
++#define FIXADDR_USER_END      (FIXADDR_USER_START + PAGE_SIZE)
++
+ extern void __this_fixmap_does_not_exist(void);
+ /*
+diff -Naur a/include/asm-um/irq.h b/include/asm-um/irq.h
+--- a/include/asm-um/irq.h     2004-01-08 22:32:16.000000000 -0500
++++ b/include/asm-um/irq.h     2004-01-08 22:36:27.000000000 -0500
+@@ -1,15 +1,6 @@
+ #ifndef __UM_IRQ_H
+ #define __UM_IRQ_H
+-/* The i386 irq.h has a struct task_struct in a prototype without including
+- * sched.h.  This forward declaration kills the resulting warning.
+- */
+-struct task_struct;
+-
+-#include "asm/ptrace.h"
+-
+-#undef NR_IRQS
+-
+ #define TIMER_IRQ             0
+ #define UMN_IRQ                       1
+ #define CONSOLE_IRQ           2
+@@ -28,8 +19,4 @@
+ #define LAST_IRQ XTERM_IRQ
+ #define NR_IRQS (LAST_IRQ + 1)
+-extern int um_request_irq(unsigned int irq, int fd, int type,
+-                        void (*handler)(int, void *, struct pt_regs *),
+-                        unsigned long irqflags,  const char * devname,
+-                        void *dev_id);
+ #endif
+diff -Naur a/include/asm-um/local.h b/include/asm-um/local.h
+--- a/include/asm-um/local.h   1969-12-31 19:00:00.000000000 -0500
++++ b/include/asm-um/local.h   2004-01-08 22:31:28.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_LOCAL_H
++#define __UM_LOCAL_H
++
++#include "asm/arch/local.h"
++
++#endif
+diff -Naur a/include/asm-um/module-generic.h b/include/asm-um/module-generic.h
+--- a/include/asm-um/module-generic.h  1969-12-31 19:00:00.000000000 -0500
++++ b/include/asm-um/module-generic.h  2004-01-08 22:29:52.000000000 -0500
+@@ -0,0 +1,6 @@
++#ifndef __UM_MODULE_GENERIC_H
++#define __UM_MODULE_GENERIC_H
++
++#include "asm/arch/module.h"
++
++#endif
+diff -Naur a/include/asm-um/module-i386.h b/include/asm-um/module-i386.h
+--- a/include/asm-um/module-i386.h     1969-12-31 19:00:00.000000000 -0500
++++ b/include/asm-um/module-i386.h     2004-01-08 22:29:46.000000000 -0500
+@@ -0,0 +1,13 @@
++#ifndef __UM_MODULE_I386_H
++#define __UM_MODULE_I386_H
++
++/* UML is simple */
++struct mod_arch_specific
++{
++};
++
++#define Elf_Shdr Elf32_Shdr
++#define Elf_Sym Elf32_Sym
++#define Elf_Ehdr Elf32_Ehdr
++
++#endif
+diff -Naur a/include/asm-um/page.h b/include/asm-um/page.h
+--- a/include/asm-um/page.h    2004-01-08 22:23:04.000000000 -0500
++++ b/include/asm-um/page.h    2004-01-08 22:30:06.000000000 -0500
+@@ -1,10 +1,14 @@
++/* 
++ *  Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
++ * Licensed under the GPL
++ */
++
+ #ifndef __UM_PAGE_H
+ #define __UM_PAGE_H
+ struct page;
+ #include "asm/arch/page.h"
+-#include "asm/bug.h"
+ #undef __pa
+ #undef __va
+@@ -24,25 +28,36 @@
+ #define __va_space (8*1024*1024)
+-extern unsigned long region_pa(void *virt);
+-extern void *region_va(unsigned long phys);
+-
+-#define __pa(virt) region_pa((void *) (virt))
+-#define __va(phys) region_va((unsigned long) (phys))
+-
+-extern unsigned long page_to_pfn(struct page *page);
+-extern struct page *pfn_to_page(unsigned long pfn);
++extern unsigned long to_phys(void *virt);
++extern void *to_virt(unsigned long phys);
+-extern struct page *phys_to_page(unsigned long phys);
++#define __pa(virt) to_phys((void *) virt)
++#define __va(phys) to_virt((unsigned long) phys)
+-#define virt_to_page(v) (phys_to_page(__pa(v)))
++#define page_to_pfn(page) ((page) - mem_map)
++#define pfn_to_page(pfn) (mem_map + (pfn))
+-extern struct page *page_mem_map(struct page *page);
++#define phys_to_pfn(p) ((p) >> PAGE_SHIFT)
++#define pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT)
+-#define pfn_valid(pfn) (page_mem_map(pfn_to_page(pfn)) != NULL)
+-#define virt_addr_valid(v) pfn_valid(__pa(v) >> PAGE_SHIFT)
++#define pfn_valid(pfn) ((pfn) < max_mapnr)
++#define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v)))
+ extern struct page *arch_validate(struct page *page, int mask, int order);
+ #define HAVE_ARCH_VALIDATE
++extern void arch_free_page(struct page *page, int order);
++#define HAVE_ARCH_FREE_PAGE
++
+ #endif
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
+--- a/include/asm-um/pgtable.h 2004-01-08 22:33:43.000000000 -0500
++++ b/include/asm-um/pgtable.h 2004-01-08 22:36:57.000000000 -0500
+@@ -65,10 +65,10 @@
+  * area for the same reason. ;)
+  */
+-extern unsigned long high_physmem;
++extern unsigned long end_iomem;
+ #define VMALLOC_OFFSET        (__va_space)
+-#define VMALLOC_START (((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
++#define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
+ #ifdef CONFIG_HIGHMEM
+ # define VMALLOC_END  (PKMAP_BASE-2*PAGE_SIZE)
+@@ -78,12 +78,13 @@
+ #define _PAGE_PRESENT 0x001
+ #define _PAGE_NEWPAGE 0x002
+-#define _PAGE_PROTNONE        0x004   /* If not present */
+-#define _PAGE_RW      0x008
+-#define _PAGE_USER    0x010
+-#define _PAGE_ACCESSED        0x020
+-#define _PAGE_DIRTY   0x040
+-#define _PAGE_NEWPROT   0x080
++#define _PAGE_NEWPROT   0x004
++#define _PAGE_FILE    0x008   /* set:pagecache unset:swap */
++#define _PAGE_PROTNONE        0x010   /* If not present */
++#define _PAGE_RW      0x020
++#define _PAGE_USER    0x040
++#define _PAGE_ACCESSED        0x080
++#define _PAGE_DIRTY   0x100
+ #define REGION_MASK   0xf0000000
+ #define REGION_SHIFT  28
+@@ -143,7 +144,8 @@
+ #define BAD_PAGETABLE __bad_pagetable()
+ #define BAD_PAGE __bad_page()
+-#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
++
++#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page)
+ /* number of bits that fit into a memory pointer */
+ #define BITS_PER_PTR                  (8*sizeof(unsigned long))
+@@ -164,9 +166,6 @@
+ #define pte_clear(xp) do { pte_val(*(xp)) = _PAGE_NEWPAGE; } while (0)
+-#define phys_region_index(x) (((x) & REGION_MASK) >> REGION_SHIFT)
+-#define pte_region_index(x) phys_region_index(pte_val(x))
+-
+ #define pmd_none(x)   (!(pmd_val(x) & ~_PAGE_NEWPAGE))
+ #define       pmd_bad(x)      ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
+ #define pmd_present(x)        (pmd_val(x) & _PAGE_PRESENT)
+@@ -188,19 +187,25 @@
+ #define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
+-extern struct page *pte_mem_map(pte_t pte);
+-extern struct page *phys_mem_map(unsigned long phys);
+-extern unsigned long phys_to_pfn(unsigned long p);
+-extern unsigned long pfn_to_phys(unsigned long pfn);
+-
+-#define pte_page(x) pfn_to_page(pte_pfn(x))
+-#define pte_address(x) (__va(pte_val(x) & PAGE_MASK))
+-#define mk_phys(a, r) ((a) + (r << REGION_SHIFT))
+-#define phys_addr(p) ((p) & ~REGION_MASK)
+-#define phys_page(p) (phys_mem_map(p) + ((phys_addr(p)) >> PAGE_SHIFT))
++#define pte_page(pte) phys_to_page(pte_val(pte))
++#define pmd_page(pmd) phys_to_page(pmd_val(pmd) & PAGE_MASK)
++
+ #define pte_pfn(x) phys_to_pfn(pte_val(x))
+ #define pfn_pte(pfn, prot) __pte(pfn_to_phys(pfn) | pgprot_val(prot))
+-#define pfn_pmd(pfn, prot) __pmd(pfn_to_phys(pfn) | pgprot_val(prot))
++
++extern struct page *phys_to_page(const unsigned long phys);
++extern struct page *__virt_to_page(const unsigned long virt);
++#define virt_to_page(addr) __virt_to_page((const unsigned long) addr)
++  
++/*
++ * Bits 0 through 3 are taken
++ */
++#define PTE_FILE_MAX_BITS     28
++
++#define pte_to_pgoff(pte) ((pte).pte_low >> 4)
++
++#define pgoff_to_pte(off) \
++      ((pte_t) { ((off) << 4) + _PAGE_FILE })
+ static inline pte_t pte_mknewprot(pte_t pte)
+ {
+@@ -235,6 +240,12 @@
+  * The following only work if pte_present() is true.
+  * Undefined behaviour if not..
+  */
++static inline int pte_user(pte_t pte)
++{ 
++      return((pte_val(pte) & _PAGE_USER) && 
++             !(pte_val(pte) & _PAGE_PROTNONE));
++}
++
+ static inline int pte_read(pte_t pte)
+ { 
+       return((pte_val(pte) & _PAGE_USER) && 
+@@ -252,6 +263,14 @@
+              !(pte_val(pte) & _PAGE_PROTNONE));
+ }
++/*
++ * The following only works if pte_present() is not true.
++ */
++static inline int pte_file(pte_t pte)
++{ 
++      return (pte).pte_low & _PAGE_FILE; 
++}
++
+ static inline int pte_dirty(pte_t pte)        { return pte_val(pte) & _PAGE_DIRTY; }
+ static inline int pte_young(pte_t pte)        { return pte_val(pte) & _PAGE_ACCESSED; }
+ static inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; }
+@@ -334,14 +353,7 @@
+  * and a page entry and page directory to the page they refer to.
+  */
+-#define mk_pte(page, pgprot) \
+-({                                    \
+-      pte_t __pte;                    \
+-                                        \
+-      pte_val(__pte) = page_to_phys(page) + pgprot_val(pgprot);\
+-      if(pte_present(__pte)) pte_mknewprot(pte_mknewpage(__pte)); \
+-      __pte;                          \
+-})
++extern pte_t mk_pte(struct page *page, pgprot_t pgprot);
+ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+ {
+@@ -351,17 +363,27 @@
+ }
+ #define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+-#define pmd_page(pmd) (phys_mem_map(pmd_val(pmd) & PAGE_MASK) + \
+-                     ((phys_addr(pmd_val(pmd)) >> PAGE_SHIFT)))
+-/* to find an entry in a page-table-directory. */
++/*
++ * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
++ *
++ * this macro returns the index of the entry in the pgd page which would
++ * control the given virtual address
++ */
+ #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+-/* to find an entry in a page-table-directory */
++/*
++ * pgd_offset() returns a (pgd_t *)
++ * pgd_index() is used get the offset into the pgd page's array of pgd_t's;
++ */
+ #define pgd_offset(mm, address) \
+ ((mm)->pgd + ((address) >> PGDIR_SHIFT))
+-/* to find an entry in a kernel page-table-directory */
++
++/*
++ * a shortcut which implies the use of the kernel's pgd, instead
++ * of a process's
++ */
+ #define pgd_offset_k(address) pgd_offset(&init_mm, address)
+ #define pmd_index(address) \
+@@ -373,7 +395,12 @@
+       return (pmd_t *) dir;
+ }
+-/* Find an entry in the third-level page table.. */ 
++/*
++ * the pte page can be thought of an array like this: pte_t[PTRS_PER_PTE]
++ *
++ * this macro returns the index of the entry in the pte page which would
++ * control the given virtual address
++ */
+ #define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+ #define pte_offset_kernel(dir, address) \
+       ((pte_t *) pmd_page_kernel(*(dir)) +  pte_index(address))
+@@ -399,11 +426,11 @@
+ #define update_mmu_cache(vma,address,pte) do ; while (0)
+ /* Encode and de-code a swap entry */
+-#define __swp_type(x)                 (((x).val >> 3) & 0x7f)
+-#define __swp_offset(x)                       ((x).val >> 10)
++#define __swp_type(x)                 (((x).val >> 4) & 0x3f)
++#define __swp_offset(x)                       ((x).val >> 11)
+ #define __swp_entry(type, offset) \
+-      ((swp_entry_t) { ((type) << 3) | ((offset) << 10) })
++      ((swp_entry_t) { ((type) << 4) | ((offset) << 11) })
+ #define __pte_to_swp_entry(pte) \
+       ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) })
+ #define __swp_entry_to_pte(x)         ((pte_t) { (x).val })
+diff -Naur a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h
+--- a/include/asm-um/processor-generic.h       2004-01-08 22:15:51.000000000 -0500
++++ b/include/asm-um/processor-generic.h       2004-01-08 22:21:26.000000000 -0500
+@@ -11,9 +11,7 @@
+ struct task_struct;
+ #include "linux/config.h"
+-#include "linux/signal.h"
+ #include "asm/ptrace.h"
+-#include "asm/siginfo.h"
+ #include "choose-mode.h"
+ struct mm_struct;
+@@ -22,23 +20,6 @@
+ #define cpu_relax()   do ; while (0)
+-#ifdef CONFIG_MODE_TT
+-struct proc_tt_mode {
+-      int extern_pid;
+-      int tracing;
+-      int switch_pipe[2];
+-      int singlestep_syscall;
+-      int vm_seq;
+-};
+-#endif
+-
+-#ifdef CONFIG_MODE_SKAS
+-struct proc_skas_mode {
+-      void *switch_buf;
+-      void *fork_buf;
+-};
+-#endif
+-
+ struct thread_struct {
+       int forking;
+       unsigned long kernel_stack;
+@@ -46,6 +27,7 @@
+       struct pt_regs regs;
+       unsigned long cr2;
+       int err;
++      unsigned long trap_no;
+       void *fault_addr;
+       void *fault_catcher;
+       struct task_struct *prev_sched;
+@@ -54,10 +36,20 @@
+       struct arch_thread arch;
+       union {
+ #ifdef CONFIG_MODE_TT
+-              struct proc_tt_mode tt;
++              struct {
++                      int extern_pid;
++                      int tracing;
++                      int switch_pipe[2];
++                      int singlestep_syscall;
++                      int vm_seq;
++              } tt;
+ #endif
+ #ifdef CONFIG_MODE_SKAS
+-              struct proc_skas_mode skas;
++              struct {
++                      void *switch_buf;
++                      void *fork_buf;
++                      int mm_count;
++              } skas;
+ #endif
+       } mode;
+       struct {
+@@ -101,14 +93,19 @@
+ } mm_segment_t;
+ extern struct task_struct *alloc_task_struct(void);
+-extern void free_task_struct(struct task_struct *task);
+ extern void release_thread(struct task_struct *);
+ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+ extern void dump_thread(struct pt_regs *regs, struct user *u);
++extern void prepare_to_copy(struct task_struct *tsk);
+ extern unsigned long thread_saved_pc(struct task_struct *t);
++static inline void mm_copy_segments(struct mm_struct *from_mm, 
++                                  struct mm_struct *new_mm)
++{
++}
++
+ #define init_stack    (init_thread_union.stack)
+ /*
+diff -Naur a/include/asm-um/processor-i386.h b/include/asm-um/processor-i386.h
+--- a/include/asm-um/processor-i386.h  2004-01-08 22:13:50.000000000 -0500
++++ b/include/asm-um/processor-i386.h  2004-01-08 22:18:50.000000000 -0500
+@@ -6,8 +6,8 @@
+ #ifndef __UM_PROCESSOR_I386_H
+ #define __UM_PROCESSOR_I386_H
+-extern int cpu_has_xmm;
+-extern int cpu_has_cmov;
++extern int host_has_xmm;
++extern int host_has_cmov;
+ struct arch_thread {
+       unsigned long debugregs[8];
+diff -Naur a/include/asm-um/sections.h b/include/asm-um/sections.h
+--- a/include/asm-um/sections.h        1969-12-31 19:00:00.000000000 -0500
++++ b/include/asm-um/sections.h        2004-01-08 22:32:18.000000000 -0500
+@@ -0,0 +1,7 @@
++#ifndef _UM_SECTIONS_H
++#define _UM_SECTIONS_H
++
++/* nothing to see, move along */
++#include <asm-generic/sections.h>
++
++#endif
+diff -Naur a/include/asm-um/smp.h b/include/asm-um/smp.h
+--- a/include/asm-um/smp.h     2004-01-08 22:13:34.000000000 -0500
++++ b/include/asm-um/smp.h     2004-01-08 22:17:25.000000000 -0500
+@@ -10,7 +10,7 @@
+ extern cpumask_t cpu_online_map;
+-#define smp_processor_id() (current->thread_info->cpu)
++#define smp_processor_id() (current_thread->cpu)
+ #define cpu_logical_map(n) (n)
+ #define cpu_number_map(n) (n)
+ #define PROC_CHANGE_PENALTY   15 /* Pick a number, any number */
+diff -Naur a/include/asm-um/spinlock.h b/include/asm-um/spinlock.h
+--- a/include/asm-um/spinlock.h        2004-01-08 22:29:58.000000000 -0500
++++ b/include/asm-um/spinlock.h        1969-12-31 19:00:00.000000000 -0500
+@@ -1,10 +0,0 @@
+-#ifndef __UM_SPINLOCK_H
+-#define __UM_SPINLOCK_H
+-
+-#include "linux/config.h"
+-
+-#ifdef CONFIG_SMP
+-#include "asm/arch/spinlock.h"
+-#endif
+-
+-#endif
+diff -Naur a/include/asm-um/system-generic.h b/include/asm-um/system-generic.h
+--- a/include/asm-um/system-generic.h  2004-01-08 22:32:37.000000000 -0500
++++ b/include/asm-um/system-generic.h  2004-01-08 22:36:38.000000000 -0500
+@@ -23,8 +23,10 @@
+ extern void block_signals(void);
+ extern void unblock_signals(void);
+-#define local_save_flags(flags) do { (flags) = get_signals(); } while(0)
+-#define local_irq_restore(flags) do { set_signals(flags); } while(0)
++#define local_save_flags(flags) do { typecheck(unsigned long, flags); \
++                                   (flags) = get_signals(); } while(0)
++#define local_irq_restore(flags) do { typecheck(unsigned long, flags); \
++                                    set_signals(flags); } while(0)
+ #define local_irq_save(flags) do { local_save_flags(flags); \
+                                    local_irq_disable(); } while(0)
+@@ -39,4 +41,7 @@
+         (flags == 0);                   \
+ })
++extern void *_switch_to(void *prev, void *next, void *last);
++#define switch_to(prev, next, last) prev = _switch_to(prev, next, last)
++
+ #endif
+diff -Naur a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h
+--- a/include/asm-um/thread_info.h     2004-01-08 22:18:02.000000000 -0500
++++ b/include/asm-um/thread_info.h     2004-01-08 22:24:10.000000000 -0500
+@@ -9,6 +9,7 @@
+ #ifndef __ASSEMBLY__
+ #include <asm/processor.h>
++#include <asm/types.h>
+ struct thread_info {
+       struct task_struct      *task;          /* main task structure */
+@@ -43,15 +44,18 @@
+ static inline struct thread_info *current_thread_info(void)
+ {
+       struct thread_info *ti;
+-      __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~16383UL));
++      unsigned long mask = PAGE_SIZE * 
++              (1 << CONFIG_KERNEL_STACK_ORDER) - 1;
++      __asm__("andl %%esp,%0; ":"=r" (ti) : "0" (~mask));
+       return ti;
+ }
+ /* thread information allocation */
+-#define THREAD_SIZE (4*PAGE_SIZE)
+-#define alloc_thread_info(tsk) ((struct thread_info *) \
+-      __get_free_pages(GFP_KERNEL,2))
+-#define free_thread_info(ti) free_pages((unsigned long) (ti), 2)
++#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE)
++#define alloc_thread_info(tsk) \
++      ((struct thread_info *) kmalloc(THREAD_SIZE, GFP_KERNEL))
++#define free_thread_info(ti) kfree(ti)
++      
+ #define get_thread_info(ti) get_task_struct((ti)->task)
+ #define put_thread_info(ti) put_task_struct((ti)->task)
+@@ -65,11 +69,13 @@
+ #define TIF_POLLING_NRFLAG      3       /* true if poll_idle() is polling 
+                                        * TIF_NEED_RESCHED 
+                                        */
++#define TIF_RESTART_BLOCK     4
+ #define _TIF_SYSCALL_TRACE    (1 << TIF_SYSCALL_TRACE)
+ #define _TIF_SIGPENDING               (1 << TIF_SIGPENDING)
+ #define _TIF_NEED_RESCHED     (1 << TIF_NEED_RESCHED)
+ #define _TIF_POLLING_NRFLAG     (1 << TIF_POLLING_NRFLAG)
++#define _TIF_RESTART_BLOCK    (1 << TIF_RESTART_BLOCK)
+ #endif
+diff -Naur a/include/asm-um/timex.h b/include/asm-um/timex.h
+--- a/include/asm-um/timex.h   2004-01-08 22:24:16.000000000 -0500
++++ b/include/asm-um/timex.h   2004-01-08 22:31:33.000000000 -0500
+@@ -1,8 +1,6 @@
+ #ifndef __UM_TIMEX_H
+ #define __UM_TIMEX_H
+-#include "linux/time.h"
+-
+ typedef unsigned long cycles_t;
+ #define cacheflush_time (0)
+diff -Naur a/include/asm-um/uaccess.h b/include/asm-um/uaccess.h
+--- a/include/asm-um/uaccess.h 2004-01-08 22:25:21.000000000 -0500
++++ b/include/asm-um/uaccess.h 2004-01-08 22:32:41.000000000 -0500
+@@ -6,6 +6,8 @@
+ #ifndef __UM_UACCESS_H
+ #define __UM_UACCESS_H
++#include "linux/sched.h"
++
+ #define VERIFY_READ 0
+ #define VERIFY_WRITE 1
+diff -Naur a/include/asm-um/unistd.h b/include/asm-um/unistd.h
+--- a/include/asm-um/unistd.h  2004-01-08 22:28:40.000000000 -0500
++++ b/include/asm-um/unistd.h  2004-01-08 22:34:56.000000000 -0500
+@@ -33,7 +33,10 @@
+       set_fs(KERNEL_DS);                      \
+       ret = sys(args);                        \
+       set_fs(fs);                             \
+-      return ret;
++      if (ret >= 0)                           \
++              return ret;                     \
++      errno = -(long)ret;                     \
++      return -1;
+ static inline long open(const char *pathname, int flags, int mode) 
+ {
+diff -Naur a/include/linux/gfp.h b/include/linux/gfp.h
+--- a/include/linux/gfp.h      2004-01-08 22:16:45.000000000 -0500
++++ b/include/linux/gfp.h      2004-01-08 22:22:50.000000000 -0500
+@@ -63,6 +63,11 @@
+  * For the normal case of non-DISCONTIGMEM systems the NODE_DATA() gets
+  * optimized to &contig_page_data at compile-time.
+  */
++
++#ifndef HAVE_ARCH_FREE_PAGE
++static inline void arch_free_page(struct page *page, int order) { }
++#endif
++
+ extern struct page * FASTCALL(__alloc_pages(unsigned int, unsigned int, struct zonelist *));
+ static inline struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order)
+ {
+diff -Naur a/include/linux/ghash.h b/include/linux/ghash.h
+--- a/include/linux/ghash.h    1969-12-31 19:00:00.000000000 -0500
++++ b/include/linux/ghash.h    2004-01-08 22:22:33.000000000 -0500
+@@ -0,0 +1,236 @@
++/*
++ * include/linux/ghash.h -- generic hashing with fuzzy retrieval
++ *
++ * (C) 1997 Thomas Schoebel-Theuer
++ *
++ * The algorithms implemented here seem to be a completely new invention,
++ * and I'll publish the fundamentals in a paper.
++ */
++
++#ifndef _GHASH_H
++#define _GHASH_H
++/* HASHSIZE _must_ be a power of two!!! */
++
++
++#define DEF_HASH_FUZZY_STRUCTS(NAME,HASHSIZE,TYPE) \
++\
++struct NAME##_table {\
++      TYPE * hashtable[HASHSIZE];\
++      TYPE * sorted_list;\
++      int nr_entries;\
++};\
++\
++struct NAME##_ptrs {\
++      TYPE * next_hash;\
++      TYPE * prev_hash;\
++      TYPE * next_sorted;\
++      TYPE * prev_sorted;\
++};
++
++#define DEF_HASH_FUZZY(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\
++\
++LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
++{\
++      int ix = HASHFN(elem->KEY);\
++      TYPE ** base = &tbl->hashtable[ix];\
++      TYPE * ptr = *base;\
++      TYPE * prev = NULL;\
++\
++      tbl->nr_entries++;\
++      while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\
++              base = &ptr->PTRS.next_hash;\
++              prev = ptr;\
++              ptr = *base;\
++      }\
++      elem->PTRS.next_hash = ptr;\
++      elem->PTRS.prev_hash = prev;\
++      if(ptr) {\
++              ptr->PTRS.prev_hash = elem;\
++      }\
++      *base = elem;\
++\
++      ptr = prev;\
++      if(!ptr) {\
++              ptr = tbl->sorted_list;\
++              prev = NULL;\
++      } else {\
++              prev = ptr->PTRS.prev_sorted;\
++      }\
++      while(ptr) {\
++              TYPE * next = ptr->PTRS.next_hash;\
++              if(next && KEYCMP(next->KEY, elem->KEY)) {\
++                      prev = ptr;\
++                      ptr = next;\
++              } else if(KEYCMP(ptr->KEY, elem->KEY)) {\
++                      prev = ptr;\
++                      ptr = ptr->PTRS.next_sorted;\
++              } else\
++                      break;\
++      }\
++      elem->PTRS.next_sorted = ptr;\
++      elem->PTRS.prev_sorted = prev;\
++      if(ptr) {\
++              ptr->PTRS.prev_sorted = elem;\
++      }\
++      if(prev) {\
++              prev->PTRS.next_sorted = elem;\
++      } else {\
++              tbl->sorted_list = elem;\
++      }\
++}\
++\
++LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
++{\
++      TYPE * next = elem->PTRS.next_hash;\
++      TYPE * prev = elem->PTRS.prev_hash;\
++\
++      tbl->nr_entries--;\
++      if(next)\
++              next->PTRS.prev_hash = prev;\
++      if(prev)\
++              prev->PTRS.next_hash = next;\
++      else {\
++              int ix = HASHFN(elem->KEY);\
++              tbl->hashtable[ix] = next;\
++      }\
++\
++      next = elem->PTRS.next_sorted;\
++      prev = elem->PTRS.prev_sorted;\
++      if(next)\
++              next->PTRS.prev_sorted = prev;\
++      if(prev)\
++              prev->PTRS.next_sorted = next;\
++      else\
++              tbl->sorted_list = next;\
++}\
++\
++LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
++{\
++      int ix = hashfn(pos);\
++      TYPE * ptr = tbl->hashtable[ix];\
++      while(ptr && KEYCMP(ptr->KEY, pos))\
++              ptr = ptr->PTRS.next_hash;\
++      if(ptr && !KEYEQ(ptr->KEY, pos))\
++              ptr = NULL;\
++      return ptr;\
++}\
++\
++LINKAGE TYPE * find_##NAME##_hash_fuzzy(struct NAME##_table * tbl, KEYTYPE pos)\
++{\
++      int ix;\
++      int offset;\
++      TYPE * ptr;\
++      TYPE * next;\
++\
++      ptr = tbl->sorted_list;\
++      if(!ptr || KEYCMP(pos, ptr->KEY))\
++              return NULL;\
++      ix = HASHFN(pos);\
++      offset = HASHSIZE;\
++      do {\
++              offset >>= 1;\
++              next = tbl->hashtable[(ix+offset) & ((HASHSIZE)-1)];\
++              if(next && (KEYCMP(next->KEY, pos) || KEYEQ(next->KEY, pos))\
++                 && KEYCMP(ptr->KEY, next->KEY))\
++                      ptr = next;\
++      } while(offset);\
++\
++      for(;;) {\
++              next = ptr->PTRS.next_hash;\
++              if(next) {\
++                      if(KEYCMP(next->KEY, pos)) {\
++                              ptr = next;\
++                              continue;\
++                      }\
++              }\
++              next = ptr->PTRS.next_sorted;\
++              if(next && KEYCMP(next->KEY, pos)) {\
++                      ptr = next;\
++                      continue;\
++              }\
++              return ptr;\
++      }\
++      return NULL;\
++}
++
++/* LINKAGE - empty or "static", depending on whether you want the definitions to
++ *    be public or not
++ * NAME - a string to stick in names to make this hash table type distinct from
++ *    any others
++ * HASHSIZE - number of buckets
++ * TYPE - type of data contained in the buckets - must be a structure, one 
++ *    field is of type NAME_ptrs, another is the hash key
++ * PTRS - TYPE must contain a field of type NAME_ptrs, PTRS is the name of that
++ *    field
++ * KEYTYPE - type of the key field within TYPE
++ * KEY - name of the key field within TYPE
++ * KEYCMP - pointer to function that compares KEYTYPEs to each other - the
++ *    prototype is int KEYCMP(KEYTYPE, KEYTYPE), it returns zero for equal, 
++ *    non-zero for not equal
++ * HASHFN - the hash function - the prototype is int HASHFN(KEYTYPE),
++ *    it returns a number in the range 0 ... HASHSIZE - 1
++ * Call DEF_HASH_STRUCTS, define your hash table as a NAME_table, then call
++ * DEF_HASH.
++ */
++
++#define DEF_HASH_STRUCTS(NAME,HASHSIZE,TYPE) \
++\
++struct NAME##_table {\
++      TYPE * hashtable[HASHSIZE];\
++      int nr_entries;\
++};\
++\
++struct NAME##_ptrs {\
++      TYPE * next_hash;\
++      TYPE * prev_hash;\
++};
++
++#define DEF_HASH(LINKAGE,NAME,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,HASHFN)\
++\
++LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
++{\
++      int ix = HASHFN(elem->KEY);\
++      TYPE ** base = &tbl->hashtable[ix];\
++      TYPE * ptr = *base;\
++      TYPE * prev = NULL;\
++\
++      tbl->nr_entries++;\
++      while(ptr && KEYCMP(ptr->KEY, elem->KEY)) {\
++              base = &ptr->PTRS.next_hash;\
++              prev = ptr;\
++              ptr = *base;\
++      }\
++      elem->PTRS.next_hash = ptr;\
++      elem->PTRS.prev_hash = prev;\
++      if(ptr) {\
++              ptr->PTRS.prev_hash = elem;\
++      }\
++      *base = elem;\
++}\
++\
++LINKAGE void remove_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\
++{\
++      TYPE * next = elem->PTRS.next_hash;\
++      TYPE * prev = elem->PTRS.prev_hash;\
++\
++      tbl->nr_entries--;\
++      if(next)\
++              next->PTRS.prev_hash = prev;\
++      if(prev)\
++              prev->PTRS.next_hash = next;\
++      else {\
++              int ix = HASHFN(elem->KEY);\
++              tbl->hashtable[ix] = next;\
++      }\
++}\
++\
++LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\
++{\
++      int ix = HASHFN(pos);\
++      TYPE * ptr = tbl->hashtable[ix];\
++      while(ptr && KEYCMP(ptr->KEY, pos))\
++              ptr = ptr->PTRS.next_hash;\
++      return ptr;\
++}
++
++#endif
+diff -Naur a/include/linux/mm.h b/include/linux/mm.h
+--- a/include/linux/mm.h       2004-01-08 22:13:47.000000000 -0500
++++ b/include/linux/mm.h       2004-01-08 22:18:35.000000000 -0500
+@@ -487,6 +487,9 @@
+       return __set_page_dirty_buffers(page);
+ }
++extern long do_mprotect(struct mm_struct *mm, unsigned long start, 
++                      size_t len, unsigned long prot);
++
+ /*
+  * On a two-level page table, this ends up being trivial. Thus the
+  * inlining and the symmetry break with pte_alloc_map() that does all
+@@ -517,9 +520,10 @@
+ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
+-      unsigned long len, unsigned long prot,
+-      unsigned long flag, unsigned long pgoff);
++extern unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file *file, 
++                                 unsigned long addr, unsigned long len,
++                                 unsigned long prot, unsigned long flag,
++                                 unsigned long pgoff);
+ static inline unsigned long do_mmap(struct file *file, unsigned long addr,
+       unsigned long len, unsigned long prot,
+@@ -529,7 +533,8 @@
+       if ((offset + PAGE_ALIGN(len)) < offset)
+               goto out;
+       if (!(offset & ~PAGE_MASK))
+-              ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
++              ret = do_mmap_pgoff(current->mm, file, addr, len, prot, flag, 
++                                  offset >> PAGE_SHIFT);
+ out:
+       return ret;
+ }
+diff -Naur a/include/linux/proc_mm.h b/include/linux/proc_mm.h
+--- a/include/linux/proc_mm.h  1969-12-31 19:00:00.000000000 -0500
++++ b/include/linux/proc_mm.h  2004-01-08 22:16:52.000000000 -0500
+@@ -0,0 +1,48 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#ifndef __PROC_MM_H
++#define __PROC_MM_H
++
++#include "linux/sched.h"
++
++#define MM_MMAP 54
++#define MM_MUNMAP 55
++#define MM_MPROTECT 56
++#define MM_COPY_SEGMENTS 57
++
++struct mm_mmap {
++      unsigned long addr;
++      unsigned long len;
++      unsigned long prot;
++      unsigned long flags;
++      unsigned long fd;
++      unsigned long offset;
++};
++
++struct mm_munmap {
++      unsigned long addr;
++      unsigned long len;      
++};
++
++struct mm_mprotect {
++      unsigned long addr;
++      unsigned long len;
++        unsigned int prot;
++};
++
++struct proc_mm_op {
++      int op;
++      union {
++              struct mm_mmap mmap;
++              struct mm_munmap munmap;
++              struct mm_mprotect mprotect;
++              int copy_segments;
++      } u;
++};
++
++extern struct mm_struct *proc_mm_get_mm(int fd);
++
++#endif
+diff -Naur a/mm/Makefile b/mm/Makefile
+--- a/mm/Makefile      2004-01-08 22:24:14.000000000 -0500
++++ b/mm/Makefile      2004-01-08 22:31:33.000000000 -0500
+@@ -12,3 +12,5 @@
+                          slab.o swap.o truncate.o vmscan.o $(mmu-y)
+ obj-$(CONFIG_SWAP)    += page_io.o swap_state.o swapfile.o
++obj-$(CONFIG_PROC_MM) += proc_mm.o
++
+diff -Naur a/mm/memory.c b/mm/memory.c
+--- a/mm/memory.c      2004-01-08 22:20:23.000000000 -0500
++++ b/mm/memory.c      2004-01-08 22:26:51.000000000 -0500
+@@ -44,6 +44,7 @@
+ #include <linux/highmem.h>
+ #include <linux/pagemap.h>
+ #include <linux/rmap-locking.h>
++#include <linux/init.h>
+ #include <linux/module.h>
+ #include <asm/pgalloc.h>
+@@ -680,6 +681,24 @@
+ }
++static struct vm_area_struct fixmap_vma = {
++      /* Catch users - if there are any valid
++         ones, we can make this be "&init_mm" or
++         something.  */
++      .vm_mm = NULL,
++      .vm_page_prot = PAGE_READONLY,
++      .vm_flags = VM_READ | VM_EXEC,
++};
++
++static int init_fixmap_vma(void)
++{
++      fixmap_vma.vm_start = FIXADDR_START;
++      fixmap_vma.vm_end = FIXADDR_TOP;
++      return(0);
++}
++
++__initcall(init_fixmap_vma);
++
+ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
+               unsigned long start, int len, int write, int force,
+               struct page **pages, struct vm_area_struct **vmas)
+@@ -700,19 +719,8 @@
+               vma = find_extend_vma(mm, start);
+-#ifdef FIXADDR_USER_START
+-              if (!vma &&
+-                  start >= FIXADDR_USER_START && start < FIXADDR_USER_END) {
+-                      static struct vm_area_struct fixmap_vma = {
+-                              /* Catch users - if there are any valid
+-                                 ones, we can make this be "&init_mm" or
+-                                 something.  */
+-                              .vm_mm = NULL,
+-                              .vm_start = FIXADDR_USER_START,
+-                              .vm_end = FIXADDR_USER_END,
+-                              .vm_page_prot = PAGE_READONLY,
+-                              .vm_flags = VM_READ | VM_EXEC,
+-                      };
++#ifdef FIXADDR_START
++              if (!vma && start >= FIXADDR_START && start < FIXADDR_TOP) {
+                       unsigned long pg = start & PAGE_MASK;
+                       pgd_t *pgd;
+                       pmd_t *pmd;
+diff -Naur a/mm/mmap.c b/mm/mmap.c
+--- a/mm/mmap.c        2004-01-08 22:24:04.000000000 -0500
++++ b/mm/mmap.c        2004-01-08 22:31:23.000000000 -0500
+@@ -462,11 +462,11 @@
+  * The caller must hold down_write(current->mm->mmap_sem).
+  */
+-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
+-                      unsigned long len, unsigned long prot,
+-                      unsigned long flags, unsigned long pgoff)
++unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file * file, 
++                          unsigned long addr, unsigned long len,
++                          unsigned long prot, unsigned long flags,
++                          unsigned long pgoff)
+ {
+-      struct mm_struct * mm = current->mm;
+       struct vm_area_struct * vma, * prev;
+       struct inode *inode;
+       unsigned int vm_flags;
+diff -Naur a/mm/mprotect.c b/mm/mprotect.c
+--- a/mm/mprotect.c    2004-01-08 22:19:21.000000000 -0500
++++ b/mm/mprotect.c    2004-01-08 22:25:37.000000000 -0500
+@@ -222,7 +222,8 @@
+ }
+ asmlinkage long
+-sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++do_mprotect(struct mm_struct *mm, unsigned long start, size_t len, 
++           unsigned long prot)
+ {
+       unsigned long vm_flags, nstart, end, tmp;
+       struct vm_area_struct * vma, * next, * prev;
+@@ -245,9 +246,9 @@
+       vm_flags = calc_vm_prot_bits(prot);
+-      down_write(&current->mm->mmap_sem);
++      down_write(&mm->mmap_sem);
+-      vma = find_vma_prev(current->mm, start, &prev);
++      vma = find_vma_prev(mm, start, &prev);
+       error = -ENOMEM;
+       if (!vma)
+               goto out;
+@@ -326,6 +327,11 @@
+               prev->vm_mm->map_count--;
+       }
+ out:
+-      up_write(&current->mm->mmap_sem);
++      up_write(&mm->mmap_sem);
+       return error;
+ }
++
++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
++{
++        return(do_mprotect(current->mm, start, len, prot));
++}
+diff -Naur a/mm/page_alloc.c b/mm/page_alloc.c
+--- a/mm/page_alloc.c  2004-01-08 22:13:53.000000000 -0500
++++ b/mm/page_alloc.c  2004-01-08 22:19:05.000000000 -0500
+@@ -268,6 +268,8 @@
+ {
+       LIST_HEAD(list);
++      arch_free_page(page, order);
++
+       mod_page_state(pgfree, 1 << order);
+       free_pages_check(__FUNCTION__, page);
+       list_add(&page->list, &list);
+diff -Naur a/mm/proc_mm.c b/mm/proc_mm.c
+--- a/mm/proc_mm.c     1969-12-31 19:00:00.000000000 -0500
++++ b/mm/proc_mm.c     2004-01-08 22:26:26.000000000 -0500
+@@ -0,0 +1,174 @@
++/* 
++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
++ * Licensed under the GPL
++ */
++
++#include "linux/mm.h"
++#include "linux/init.h"
++#include "linux/proc_fs.h"
++#include "linux/proc_mm.h"
++#include "linux/file.h"
++#include "asm/uaccess.h"
++#include "asm/mmu_context.h"
++
++static struct file_operations proc_mm_fops;
++
++struct mm_struct *proc_mm_get_mm(int fd)
++{
++      struct mm_struct *ret = ERR_PTR(-EBADF);
++      struct file *file;
++
++      file = fget(fd);
++      if (!file)
++              goto out;
++
++      ret = ERR_PTR(-EINVAL);
++      if(file->f_op != &proc_mm_fops)
++              goto out_fput;
++
++      ret = file->private_data;
++ out_fput:
++      fput(file);
++ out:
++      return(ret);
++}
++
++extern long do_mmap2(struct mm_struct *mm, unsigned long addr, 
++                   unsigned long len, unsigned long prot, 
++                   unsigned long flags, unsigned long fd,
++                   unsigned long pgoff);
++
++static ssize_t write_proc_mm(struct file *file, const char *buffer,
++                           size_t count, loff_t *ppos)
++{
++      struct mm_struct *mm = file->private_data;
++      struct proc_mm_op req;
++      int n, ret;
++
++      if(count > sizeof(req))
++              return(-EINVAL);
++
++      n = copy_from_user(&req, buffer, count);
++      if(n != 0)
++              return(-EFAULT);
++
++      ret = count;
++      switch(req.op){
++      case MM_MMAP: {
++              struct mm_mmap *map = &req.u.mmap;
++
++              ret = do_mmap2(mm, map->addr, map->len, map->prot, 
++                             map->flags, map->fd, map->offset >> PAGE_SHIFT);
++              if((ret & ~PAGE_MASK) == 0)
++                      ret = count;
++      
++              break;
++      }
++      case MM_MUNMAP: {
++              struct mm_munmap *unmap = &req.u.munmap;
++
++              down_write(&mm->mmap_sem);
++              ret = do_munmap(mm, unmap->addr, unmap->len);
++              up_write(&mm->mmap_sem);
++
++              if(ret == 0)
++                      ret = count;
++              break;
++      }
++      case MM_MPROTECT: {
++              struct mm_mprotect *protect = &req.u.mprotect;
++
++              ret = do_mprotect(mm, protect->addr, protect->len, 
++                                protect->prot);
++              if(ret == 0)
++                      ret = count;
++              break;
++      }
++
++      case MM_COPY_SEGMENTS: {
++              struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments);
++
++              if(IS_ERR(from)){
++                      ret = PTR_ERR(from);
++                      break;
++              }
++
++              mm_copy_segments(from, mm);
++              break;
++      }
++      default:
++              ret = -EINVAL;
++              break;
++      }
++
++      return(ret);
++}
++
++static int open_proc_mm(struct inode *inode, struct file *file)
++{
++      struct mm_struct *mm = mm_alloc();
++      int ret;
++
++      ret = -ENOMEM;
++      if(mm == NULL)
++              goto out_mem;
++
++      ret = init_new_context(current, mm);
++      if(ret)
++              goto out_free;
++
++      spin_lock(&mmlist_lock);
++      list_add(&mm->mmlist, &current->mm->mmlist);
++      mmlist_nr++;
++      spin_unlock(&mmlist_lock);
++
++      file->private_data = mm;
++
++      return(0);
++
++ out_free:
++      mmput(mm);
++ out_mem:
++      return(ret);
++}
++
++static int release_proc_mm(struct inode *inode, struct file *file)
++{
++      struct mm_struct *mm = file->private_data;
++
++      mmput(mm);
++      return(0);
++}
++
++static struct file_operations proc_mm_fops = {
++      .open           = open_proc_mm,
++      .release        = release_proc_mm,
++      .write          = write_proc_mm,
++};
++
++static int make_proc_mm(void)
++{
++      struct proc_dir_entry *ent;
++
++      ent = create_proc_entry("mm", 0222, &proc_root);
++      if(ent == NULL){
++              printk("make_proc_mm : Failed to register /proc/mm\n");
++              return(0);
++      }
++      ent->proc_fops = &proc_mm_fops;
++
++      return(0);
++}
++
++__initcall(make_proc_mm);
++
++/*
++ * Overrides for Emacs so that we follow Linus's tabbing style.
++ * Emacs will notice this stuff at the end of the file and automatically
++ * adjust the settings for this buffer only.  This must remain at the end
++ * of the file.
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
diff --git a/lustre/kernel_patches/patches/vfs_nointent_2.6.0-uml1.patch b/lustre/kernel_patches/patches/vfs_nointent_2.6.0-uml1.patch
new file mode 100644 (file)
index 0000000..99c09d1
--- /dev/null
@@ -0,0 +1,423 @@
+ 0 files changed
+
+Index: linux-2.6.0/fs/namei.c
+===================================================================
+--- linux-2.6.0.orig/fs/namei.c        2004-01-04 15:22:42.000000000 +0300
++++ linux-2.6.0/fs/namei.c     2004-01-04 15:25:04.000000000 +0300
+@@ -1270,7 +1270,7 @@
+               if (!error) {
+                       DQUOT_INIT(inode);
+                       
+-                      error = do_truncate(dentry, 0);
++                      error = do_truncate(dentry, 0, 1);
+               }
+               put_write_access(inode);
+               if (error)
+@@ -1521,6 +1521,7 @@
+       char * tmp;
+       struct dentry * dentry;
+       struct nameidata nd;
++      intent_init(&nd.intent, IT_LOOKUP);
+       if (S_ISDIR(mode))
+               return -EPERM;
+@@ -1531,6 +1532,15 @@
+       error = path_lookup(tmp, LOOKUP_PARENT, &nd);
+       if (error)
+               goto out;
++
++      if (nd.dentry->d_inode->i_op->mknod_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++              error = op->mknod_raw(&nd, mode, dev);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto out2;
++      }
++
+       dentry = lookup_create(&nd, 0);
+       error = PTR_ERR(dentry);
+@@ -1557,6 +1567,7 @@
+               dput(dentry);
+       }
+       up(&nd.dentry->d_inode->i_sem);
++out2:
+       path_release(&nd);
+ out:
+       putname(tmp);
+@@ -1598,10 +1609,18 @@
+       if (!IS_ERR(tmp)) {
+               struct dentry *dentry;
+               struct nameidata nd;
++                intent_init(&nd.intent, IT_LOOKUP);
+               error = path_lookup(tmp, LOOKUP_PARENT, &nd);
+               if (error)
+                       goto out;
++              if (nd.dentry->d_inode->i_op->mkdir_raw) {
++                      struct inode_operations *op = nd.dentry->d_inode->i_op;
++                      error = op->mkdir_raw(&nd, mode);
++                      /* the file system wants to use normal vfs path now */
++                      if (error != -EOPNOTSUPP)
++                              goto out2;
++              }
+               dentry = lookup_create(&nd, 1);
+               error = PTR_ERR(dentry);
+               if (!IS_ERR(dentry)) {
+@@ -1611,6 +1630,7 @@
+                       dput(dentry);
+               }
+               up(&nd.dentry->d_inode->i_sem);
++out2:
+               path_release(&nd);
+ out:
+               putname(tmp);
+@@ -1691,6 +1711,7 @@
+       char * name;
+       struct dentry *dentry;
+       struct nameidata nd;
++        intent_init(&nd.intent, IT_LOOKUP);
+       name = getname(pathname);
+       if(IS_ERR(name))
+@@ -1711,6 +1732,16 @@
+                       error = -EBUSY;
+                       goto exit1;
+       }
++ 
++      if (nd.dentry->d_inode->i_op->rmdir_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++ 
++              error = op->rmdir_raw(&nd);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto exit1;
++      }
++ 
+       down(&nd.dentry->d_inode->i_sem);
+       dentry = lookup_hash(&nd.last, nd.dentry);
+       error = PTR_ERR(dentry);
+@@ -1769,6 +1800,7 @@
+       struct dentry *dentry;
+       struct nameidata nd;
+       struct inode *inode = NULL;
++        intent_init(&nd.intent, IT_LOOKUP);
+       name = getname(pathname);
+       if(IS_ERR(name))
+@@ -1780,6 +1812,13 @@
+       error = -EISDIR;
+       if (nd.last_type != LAST_NORM)
+               goto exit1;
++      if (nd.dentry->d_inode->i_op->unlink_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++              error = op->unlink_raw(&nd);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto exit1;
++      }
+       down(&nd.dentry->d_inode->i_sem);
+       dentry = lookup_hash(&nd.last, nd.dentry);
+       error = PTR_ERR(dentry);
+@@ -1847,10 +1886,18 @@
+       if (!IS_ERR(to)) {
+               struct dentry *dentry;
+               struct nameidata nd;
++                intent_init(&nd.intent, IT_LOOKUP);
+               error = path_lookup(to, LOOKUP_PARENT, &nd);
+               if (error)
+                       goto out;
++              if (nd.dentry->d_inode->i_op->symlink_raw) {
++                      struct inode_operations *op = nd.dentry->d_inode->i_op;
++                      error = op->symlink_raw(&nd, from);
++                      /* the file system wants to use normal vfs path now */
++                      if (error != -EOPNOTSUPP)
++                              goto out2;
++              }
+               dentry = lookup_create(&nd, 0);
+               error = PTR_ERR(dentry);
+               if (!IS_ERR(dentry)) {
+@@ -1858,6 +1905,7 @@
+                       dput(dentry);
+               }
+               up(&nd.dentry->d_inode->i_sem);
++out2:
+               path_release(&nd);
+ out:
+               putname(to);
+@@ -1921,6 +1969,8 @@
+       struct nameidata nd, old_nd;
+       int error;
+       char * to;
++        intent_init(&nd.intent, IT_LOOKUP);
++        intent_init(&old_nd.intent, IT_LOOKUP);
+       to = getname(newname);
+       if (IS_ERR(to))
+@@ -1935,6 +1985,13 @@
+       error = -EXDEV;
+       if (old_nd.mnt != nd.mnt)
+               goto out_release;
++        if (nd.dentry->d_inode->i_op->link_raw) {
++                struct inode_operations *op = nd.dentry->d_inode->i_op;
++                error = op->link_raw(&old_nd, &nd);
++                /* the file system wants to use normal vfs path now */
++                if (error != -EOPNOTSUPP)
++                        goto out_release;
++        }
+       new_dentry = lookup_create(&nd, 0);
+       error = PTR_ERR(new_dentry);
+       if (!IS_ERR(new_dentry)) {
+@@ -1985,7 +2042,7 @@
+  *       locking].
+  */
+ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
+-             struct inode *new_dir, struct dentry *new_dentry)
++                   struct inode *new_dir, struct dentry *new_dentry)
+ {
+       int error = 0;
+       struct inode *target;
+@@ -2030,7 +2087,7 @@
+ }
+ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
+-             struct inode *new_dir, struct dentry *new_dentry)
++                     struct inode *new_dir, struct dentry *new_dentry)
+ {
+       struct inode *target;
+       int error;
+@@ -2107,6 +2164,8 @@
+       struct dentry * old_dentry, *new_dentry;
+       struct dentry * trap;
+       struct nameidata oldnd, newnd;
++        intent_init(&oldnd.intent, IT_LOOKUP);
++        intent_init(&newnd.intent, IT_LOOKUP);
+       error = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
+       if (error)
+@@ -2129,6 +2188,13 @@
+       if (newnd.last_type != LAST_NORM)
+               goto exit2;
++      if (old_dir->d_inode->i_op->rename_raw) {
++              error = old_dir->d_inode->i_op->rename_raw(&oldnd, &newnd);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto exit2;
++      }
++
+       trap = lock_rename(new_dir, old_dir);
+       old_dentry = lookup_hash(&oldnd.last, old_dir);
+@@ -2160,8 +2226,7 @@
+       if (new_dentry == trap)
+               goto exit5;
+-      error = vfs_rename(old_dir->d_inode, old_dentry,
+-                                 new_dir->d_inode, new_dentry);
++      error = vfs_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry);
+ exit5:
+       dput(new_dentry);
+ exit4:
+Index: linux-2.6.0/fs/open.c
+===================================================================
+--- linux-2.6.0.orig/fs/open.c 2004-01-04 15:21:49.000000000 +0300
++++ linux-2.6.0/fs/open.c      2004-01-04 15:25:04.000000000 +0300
+@@ -180,9 +180,10 @@
+       return error;
+ }
+-int do_truncate(struct dentry *dentry, loff_t length)
++int do_truncate(struct dentry *dentry, loff_t length, int called_from_open)
+ {
+       int err;
++      struct inode_operations *op = dentry->d_inode->i_op;
+       struct iattr newattrs;
+       /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
+@@ -193,7 +194,14 @@
+       newattrs.ia_size = length;
+       newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+       down(&dentry->d_inode->i_sem);
+-      err = notify_change(dentry, &newattrs);
++      if (called_from_open)
++              newattrs.ia_valid |= ATTR_FROM_OPEN;
++      if (op->setattr_raw) {
++              newattrs.ia_valid |= ATTR_RAW;
++              newattrs.ia_ctime = CURRENT_TIME;
++              err = op->setattr_raw(dentry->d_inode, &newattrs);
++      } else 
++                err = notify_change(dentry, &newattrs);
+       up(&dentry->d_inode->i_sem);
+       return err;
+ }
+@@ -249,7 +257,7 @@
+       error = locks_verify_truncate(inode, NULL, length);
+       if (!error) {
+               DQUOT_INIT(inode);
+-              error = do_truncate(nd.dentry, length);
++              error = do_truncate(nd.dentry, length, 0);
+       }
+       put_write_access(inode);
+@@ -301,7 +309,7 @@
+       error = locks_verify_truncate(inode, file, length);
+       if (!error)
+-              error = do_truncate(dentry, length);
++              error = do_truncate(dentry, length, 0);
+ out_putf:
+       fput(file);
+ out:
+@@ -380,9 +388,19 @@
+                   (error = permission(inode,MAY_WRITE,&nd)) != 0)
+                       goto dput_and_out;
+       }
+-      down(&inode->i_sem);
+-      error = notify_change(nd.dentry, &newattrs);
+-      up(&inode->i_sem);
++      if (inode->i_op->setattr_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++
++              newattrs.ia_valid |= ATTR_RAW;
++              error = op->setattr_raw(inode, &newattrs);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto dput_and_out;
++      } else {
++                down(&inode->i_sem);
++                error = notify_change(nd.dentry, &newattrs);
++                up(&inode->i_sem);
++        }
+ dput_and_out:
+       path_release(&nd);
+ out:
+@@ -433,9 +451,19 @@
+                   (error = permission(inode,MAY_WRITE,&nd)) != 0)
+                       goto dput_and_out;
+       }
+-      down(&inode->i_sem);
+-      error = notify_change(nd.dentry, &newattrs);
+-      up(&inode->i_sem);
++      if (inode->i_op->setattr_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++
++              newattrs.ia_valid |= ATTR_RAW;
++              error = op->setattr_raw(inode, &newattrs);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto dput_and_out;
++      } else {
++                down(&inode->i_sem);
++                error = notify_change(nd.dentry, &newattrs);
++                up(&inode->i_sem);
++        }
+ dput_and_out:
+       path_release(&nd);
+ out:
+@@ -636,6 +664,18 @@
+       if (IS_RDONLY(inode))
+               goto dput_and_out;
+       
++      if (inode->i_op->setattr_raw) {
++              struct inode_operations *op = nd.dentry->d_inode->i_op;
++
++              newattrs.ia_mode = mode;
++              newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
++              newattrs.ia_valid |= ATTR_RAW;
++              error = op->setattr_raw(inode, &newattrs);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      goto dput_and_out;
++      }
++
+       error = -EPERM;
+       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+               goto dput_and_out;
+@@ -669,6 +709,18 @@
+       if (IS_RDONLY(inode))
+               goto out;
+       error = -EPERM;
++      if (inode->i_op->setattr_raw) {
++              struct inode_operations *op = dentry->d_inode->i_op;
++
++              newattrs.ia_uid = user;
++              newattrs.ia_gid = group;
++              newattrs.ia_valid = ATTR_UID | ATTR_GID;
++              newattrs.ia_valid |= ATTR_RAW;
++              error = op->setattr_raw(inode, &newattrs);
++              /* the file system wants to use normal vfs path now */
++              if (error != -EOPNOTSUPP)
++                      return error;
++      }
+       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+               goto out;
+       newattrs.ia_valid =  ATTR_CTIME;
+@@ -682,6 +734,7 @@
+       }
+       if (!S_ISDIR(inode->i_mode))
+               newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID;
++
+       down(&inode->i_sem);
+       error = notify_change(dentry, &newattrs);
+       up(&inode->i_sem);
+Index: linux-2.6.0/fs/exec.c
+===================================================================
+--- linux-2.6.0.orig/fs/exec.c 2004-01-04 15:21:49.000000000 +0300
++++ linux-2.6.0/fs/exec.c      2004-01-04 15:25:04.000000000 +0300
+@@ -1405,7 +1405,7 @@
+               goto close_fail;
+       if (!file->f_op->write)
+               goto close_fail;
+-      if (do_truncate(file->f_dentry, 0) != 0)
++      if (do_truncate(file->f_dentry, 0, 0) != 0)
+               goto close_fail;
+       retval = binfmt->core_dump(signr, regs, file);
+Index: linux-2.6.0/include/linux/fs.h
+===================================================================
+--- linux-2.6.0.orig/include/linux/fs.h        2004-01-04 15:21:49.000000000 +0300
++++ linux-2.6.0/include/linux/fs.h     2004-01-04 15:25:04.000000000 +0300
+@@ -836,13 +836,20 @@
+       int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
+       struct dentry * (*lookup) (struct inode *,struct dentry *, struct nameidata *);
+       int (*link) (struct dentry *,struct inode *,struct dentry *);
++      int (*link_raw) (struct nameidata *,struct nameidata *);
+       int (*unlink) (struct inode *,struct dentry *);
++      int (*unlink_raw) (struct nameidata *);
+       int (*symlink) (struct inode *,struct dentry *,const char *);
++      int (*symlink_raw) (struct nameidata *,const char *);
+       int (*mkdir) (struct inode *,struct dentry *,int);
++      int (*mkdir_raw) (struct nameidata *,int);
+       int (*rmdir) (struct inode *,struct dentry *);
++      int (*rmdir_raw) (struct nameidata *);
+       int (*mknod) (struct inode *,struct dentry *,int,dev_t);
++      int (*mknod_raw) (struct nameidata *,int,dev_t);
+       int (*rename) (struct inode *, struct dentry *,
+                       struct inode *, struct dentry *);
++      int (*rename_raw) (struct nameidata *, struct nameidata *);
+       int (*readlink) (struct dentry *, char __user *,int);
+       int (*follow_link) (struct dentry *, struct nameidata *);
+       void (*truncate) (struct inode *);
+@@ -1127,7 +1134,7 @@
+ asmlinkage long sys_open(const char __user *, int, int);
+ asmlinkage long sys_close(unsigned int);      /* yes, it's really unsigned */
+-extern int do_truncate(struct dentry *, loff_t start);
++extern int do_truncate(struct dentry *, loff_t start, int called_from_open);
+ extern struct file *filp_open(const char *, int, int);
+ extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
+Index: linux-2.6.0/net/unix/af_unix.c
+===================================================================
+--- linux-2.6.0.orig/net/unix/af_unix.c        2004-01-04 15:21:21.000000000 +0300
++++ linux-2.6.0/net/unix/af_unix.c     2004-01-04 15:25:18.000000000 +0300
+@@ -592,6 +592,7 @@
+       int err = 0;
+       
+       if (sunname->sun_path[0]) {
++              intent_init(&nd.intent, IT_LOOKUP);
+               err = path_lookup(sunname->sun_path, LOOKUP_FOLLOW, &nd);
+               if (err)
+                       goto fail;
diff --git a/lustre/kernel_patches/series/uml_2.6.0 b/lustre/kernel_patches/series/uml_2.6.0
new file mode 100644 (file)
index 0000000..e1e602e
--- /dev/null
@@ -0,0 +1,20 @@
+uml-patch-2.6.0-1.patch
+uml-patch-2.6.0-1-fix1.patch 
+lustre_build.patch
+lustre_version.patch
+vfs_intent_2.6.0.patch
+vfs_nointent_2.6.0-uml1.patch
+vfs_races_2.5.72_rev1.patch
+ext3-wantedi-2.6.patch 
+ext3-san-jdike-2.5.73.patch
+iopen-2.6.0-test6.patch 
+export-truncate-2.5.63.patch 
+qla2xxx-v8.00.00b1-2.5.73.patch
+export_symbols-2.6.0.patch 
+ext3-map_inode_page-2.6.0.patch 
+removepage-2.6.0.patch
+dev_read_only_2.6.0.patch 
+kernel_text_address-2.6.0.patch 
+ext3-init-generation-2.6.0.patch 
+ext3-start_this_handle-must-return-error.patch 
+ext3-ea-in-inode-2.6.0.patch