--- /dev/null
+diff -Naur a/arch/um/Kconfig b/arch/um/Kconfig
+--- a/arch/um/Kconfig Tue Sep 9 16:43:10 2003
++++ b/arch/um/Kconfig Tue Sep 9 16:48:54 2003
+@@ -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
+@@ -239,6 +279,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 Tue Sep 9 16:44:02 2003
++++ b/arch/um/Kconfig_block Tue Sep 9 16:49:30 2003
+@@ -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 Tue Sep 9 16:43:43 2003
++++ b/arch/um/Kconfig_net Tue Sep 9 16:49:20 2003
+@@ -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/Makefile b/arch/um/Makefile
+--- a/arch/um/Makefile Tue Sep 9 16:43:50 2003
++++ b/arch/um/Makefile Tue Sep 9 16:49:24 2003
+@@ -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,14 @@
+
+ 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
+
+ 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 +103,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,6 +121,7 @@
+
+ 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)
+
+@@ -123,9 +129,10 @@
+ USER_CFLAGS += -D_GNU_SOURCE
+
+ 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 +168,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 Tue Sep 9 16:45:38 2003
++++ b/arch/um/Makefile-i386 Tue Sep 9 16:50:11 2003
+@@ -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 Tue Sep 9 16:43:05 2003
++++ b/arch/um/Makefile-skas Tue Sep 9 16:48:52 2003
+@@ -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/config.release b/arch/um/config.release
+--- a/arch/um/config.release Tue Sep 9 16:46:07 2003
++++ b/arch/um/config.release Tue Sep 9 16:51:08 2003
+@@ -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 Tue Sep 9 16:43:55 2003
++++ b/arch/um/defconfig Tue Sep 9 16:49:28 2003
+@@ -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
+@@ -38,10 +28,38 @@
+ CONFIG_KERNEL_STACK_ORDER=2
+
+ #
++# 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 +87,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 +97,7 @@
+ CONFIG_NETDEVICES=y
+
+ #
+-# Network Devices
++# UML Network Devices
+ #
+ CONFIG_UML_NET=y
+ CONFIG_UML_NET_ETHERTAP=y
+@@ -88,22 +107,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 +118,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 +131,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)
+@@ -141,8 +145,6 @@
+ # 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_X25 is not set
+ # CONFIG_LAPB is not set
+ # CONFIG_NET_DIVERT is not set
+@@ -160,6 +162,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,6 +177,22 @@
+ #
+
+ #
++# 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
+@@ -188,66 +210,82 @@
+ #
+ # 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_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_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 +355,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 +377,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 +392,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/Makefile b/arch/um/drivers/Makefile
+--- a/arch/um/drivers/Makefile Tue Sep 9 16:43:32 2003
++++ b/arch/um/drivers/Makefile Tue Sep 9 16:49:19 2003
+@@ -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/chan_kern.c b/arch/um/drivers/chan_kern.c
+--- a/arch/um/drivers/chan_kern.c Tue Sep 9 16:46:09 2003
++++ b/arch/um/drivers/chan_kern.c Tue Sep 9 16:51:12 2003
+@@ -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"
+diff -Naur a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
+--- a/arch/um/drivers/chan_user.c Tue Sep 9 16:41:10 2003
++++ b/arch/um/drivers/chan_user.c Tue Sep 9 16:47:22 2003
+@@ -188,8 +188,8 @@
+ 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);
+diff -Naur a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h
+--- a/arch/um/drivers/cow.h Wed Dec 31 19:00:00 1969
++++ b/arch/um/drivers/cow.h Tue Sep 9 16:47:42 2003
+@@ -0,0 +1,40 @@
++#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 *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 *magic_out,
++ char **backing_file_out, time_t *mtime_out,
++ __u64 *size_out, int *sectorsize_out,
++ int *bitmap_offset_out);
++
++extern int write_cow_header(char *cow_file, int fd, char *backing_file,
++ int sectorsize, long long *size);
++
++extern void cow_sizes(__u64 size, int sectorsize, 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 Wed Dec 31 19:00:00 1969
++++ b/arch/um/drivers/cow_kern.c Tue Sep 9 16:51:12 2003
+@@ -0,0 +1,628 @@
++#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(¤t->sigmask_lock);
++ sigfillset(¤t->blocked);
++ flush_signals(current);
++ spin_unlock_irq(¤t->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 magic;
++ 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, &magic,
++ &backing_file, &mtime, &size,
++ &dev->sectorsize, &dev->bitmap_offset);
++ if(err){
++ printk(KERN_ERR "cow_open - read_cow_header failed, "
++ "err = %d\n", err);
++ goto out;
++ }
++
++ cow_sizes(size, dev->sectorsize, 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 Wed Dec 31 19:00:00 1969
++++ b/arch/um/drivers/cow_sys.h Tue Sep 9 16:49:10 2003
+@@ -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 Wed Dec 31 19:00:00 1969
++++ b/arch/um/drivers/cow_user.c Tue Sep 9 16:49:06 2003
+@@ -0,0 +1,296 @@
++#include <stddef.h>
++#include <string.h>
++#include <errno.h>
++#include <unistd.h>
++#include <byteswap.h>
++#include <sys/stat.h>
++#include <sys/time.h>
++#include <sys/param.h>
++#include <netinet/in.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;
++};
++
++union cow_header {
++ struct cow_header_v1 v1;
++ struct cow_header_v2 v2;
++};
++
++#define COW_MAGIC 0x4f4f4f4d /* MOOO */
++#define COW_VERSION 2
++
++void cow_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 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, long long *size)
++{
++ struct cow_header_v2 *header;
++ struct stat64 buf;
++ int err;
++
++ err = cow_seek_file(fd, 0);
++ if(err != 0){
++ cow_printf("write_cow_header - lseek failed, errno = %d\n",
++ errno);
++ return(-errno);
++ }
++
++ err = -ENOMEM;
++ header = cow_malloc(sizeof(*header));
++ if(header == NULL){
++ cow_printf("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){
++ 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 = stat64(header->backing_file, &buf);
++ if(err < 0){
++ cow_printf("Stat of backing file '%s' failed, errno = %d\n",
++ header->backing_file, errno);
++ err = -errno;
++ goto out_free;
++ }
++
++ err = cow_file_size(header->backing_file, size);
++ if(err){
++ cow_printf("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)){
++ cow_printf("Write of header to new COW file '%s' failed, "
++ "errno = %d\n", cow_file, errno);
++ 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));
++}
++
++int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg,
++ __u32 *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 = 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;
++
++ *magic_out = COW_MAGIC;
++
++ 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);
++ 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);
++ file = header->v2.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 *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, &size);
++ if(err)
++ goto out;
++
++ cow_sizes(size, sectorsize, sizeof(struct cow_header_v2),
++ bitmap_len_out, data_offset_out);
++ *bitmap_offset_out = sizeof(struct cow_header_v2);
++
++ offset = *data_offset_out + size - sizeof(zero);
++ err = cow_seek_file(fd, offset);
++ if(err != 0){
++ cow_printf("cow bitmap lseek failed : errno = %d\n", errno);
++ 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)){
++ err = -EINVAL;
++ cow_printf("Write of bitmap to new COW file '%s' failed, "
++ "errno = %d\n", cow_file, errno);
++ goto out;
++ }
++
++ return(0);
++
++ out:
++ return(err);
++}
++
++/*
++ * ---------------------------------------------------------------------------
++ * Local variables:
++ * c-file-style: "linux"
++ * End:
++ */
+diff -Naur a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
+--- a/arch/um/drivers/hostaudio_kern.c Tue Sep 9 16:46:07 2003
++++ b/arch/um/drivers/hostaudio_kern.c Tue Sep 9 16:51:08 2003
+@@ -11,6 +11,7 @@
+ #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"
+@@ -22,7 +23,7 @@
+ #ifndef MODULE
+ static int set_dsp(char *name, int *add)
+ {
+- dsp = uml_strdup(name);
++ dsp = name;
+ return(0);
+ }
+
+@@ -34,7 +35,7 @@
+
+ static int set_mixer(char *name, int *add)
+ {
+- mixer = uml_strdup(name);
++ mixer = name;
+ return(0);
+ }
+
+@@ -51,23 +52,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 +119,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 +289,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/line.c b/arch/um/drivers/line.c
+--- a/arch/um/drivers/line.c Tue Sep 9 16:45:58 2003
++++ b/arch/um/drivers/line.c Tue Sep 9 16:50:27 2003
+@@ -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,16 +16,18 @@
+ #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)
++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)
+@@ -136,20 +138,22 @@
+ return(len);
+ }
+
+-void line_write_interrupt(int irq, void *data, struct pt_regs *unused)
++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,9 +165,9 @@
+ * writes.
+ */
+
+- if (waitqueue_active(&tty->write_wait))
++ if(waitqueue_active(&tty->write_wait))
+ wake_up_interruptible(&tty->write_wait);
+-
++ return(IRQ_HANDLED);
+ }
+
+ int line_write_room(struct tty_struct *tty)
+@@ -369,7 +373,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 +383,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);
+ }
+
+@@ -412,7 +416,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 +437,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 +470,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 +498,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 +537,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);
++ close(winch->fd);
++ }
+ if(winch->pid != -1)
+ os_kill_process(winch->pid, 1);
+ }
+diff -Naur a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
+--- a/arch/um/drivers/mconsole_kern.c Tue Sep 9 16:41:12 2003
++++ b/arch/um/drivers/mconsole_kern.c Tue Sep 9 16:47:22 2003
+@@ -27,6 +27,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 +68,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;
+@@ -88,6 +89,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 +102,34 @@
+ 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 = ptr - req->request.data;
++ printk("%.*s", len, ptr);
++ mconsole_reply(req, "", 0, 0);
++}
++
+ #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\
+ "
+
+ void mconsole_help(struct mc_request *req)
+@@ -302,7 +318,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 = create_unix_socket(file, sizeof(file), 1);
+ if (sock < 0){
+ printk("Failed to initialize management console\n");
+ return(1);
+diff -Naur a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
+--- a/arch/um/drivers/mconsole_user.c Tue Sep 9 16:41:40 2003
++++ b/arch/um/drivers/mconsole_user.c Tue Sep 9 16:47:42 2003
+@@ -28,6 +28,7 @@
+ { "cad", mconsole_cad, 1 },
+ { "stop", mconsole_stop, 0 },
+ { "go", mconsole_go, 1 },
++ { "log", mconsole_log, 1 },
+ };
+
+ /* Initialized in mconsole_init, which is an initcall */
+@@ -139,6 +140,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 Tue Sep 9 16:41:34 2003
++++ b/arch/um/drivers/mmapper_kern.c Tue Sep 9 16:47:40 2003
+@@ -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 Tue Sep 9 16:43:06 2003
++++ b/arch/um/drivers/net_kern.c Tue Sep 9 16:48:52 2003
+@@ -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);
+@@ -61,14 +62,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 +84,7 @@
+
+ out:
+ spin_unlock(&lp->lock);
++ return(IRQ_HANDLED);
+ }
+
+ static int uml_net_open(struct net_device *dev)
+@@ -252,37 +254,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 +263,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 +305,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 +327,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 +582,8 @@
+ unregister_netdev(dev);
+
+ list_del(&device->list);
+- free_netdev(device);
++ kfree(device);
++ free_netdev(dev);
+ return(0);
+ }
+
+diff -Naur a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
+--- a/arch/um/drivers/port_kern.c Tue Sep 9 16:41:19 2003
++++ b/arch/um/drivers/port_kern.c Tue Sep 9 16:47:28 2003
+@@ -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/ssl.c b/arch/um/drivers/ssl.c
+--- a/arch/um/drivers/ssl.c Tue Sep 9 16:43:21 2003
++++ b/arch/um/drivers/ssl.c Tue Sep 9 16:48:57 2003
+@@ -53,8 +53,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,
+diff -Naur a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
+--- a/arch/um/drivers/stdio_console.c Tue Sep 9 16:41:51 2003
++++ b/arch/um/drivers/stdio_console.c Tue Sep 9 16:47:57 2003
+@@ -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,6 +160,15 @@
+
+ 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,
++};
++
+ int stdio_init(void)
+ {
+ char *new_title;
+@@ -166,7 +176,8 @@
+ printk(KERN_INFO "Initializing stdio console driver\n");
+
+ 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]));
+
+@@ -188,15 +199,6 @@
+ if(con_init_done) up(&vts[console->index].sem);
+ }
+
+-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,
+-};
+-
+ static struct tty_driver *console_device(struct console *c, int *index)
+ {
+ *index = c->index;
+@@ -212,12 +214,14 @@
+ console_device, console_setup,
+ CON_PRINTBUFFER);
+
+-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)
+diff -Naur a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
+--- a/arch/um/drivers/ubd_kern.c Tue Sep 9 16:43:08 2003
++++ b/arch/um/drivers/ubd_kern.c Tue Sep 9 16:48:54 2003
+@@ -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,6 +47,7 @@
+ #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"
+@@ -67,7 +75,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,12 +104,12 @@
+
+ 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;
+ };
+
+@@ -115,12 +123,12 @@
+
+ #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, \
+ }
+
+@@ -128,8 +136,10 @@
+
+ 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 +206,39 @@
+ " 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, "sync")){
+ global_openflags.s = 1;
+ return(0);
+@@ -220,20 +250,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 +267,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 +298,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 +311,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 +351,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;
+ }
+@@ -391,9 +420,10 @@
+ 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,16 +459,18 @@
+ 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->cow.bitmap_offset,
+@@ -455,7 +487,10 @@
+ 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,
+@@ -481,17 +516,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%d", 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,10 +555,7 @@
+ 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))
+@@ -523,7 +569,7 @@
+ 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 +607,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 +650,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 +713,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);
+@@ -714,15 +758,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",
+@@ -796,15 +834,6 @@
+
+ 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);
+diff -Naur a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
+--- a/arch/um/drivers/ubd_user.c Tue Sep 9 16:41:52 2003
++++ b/arch/um/drivers/ubd_user.c Tue Sep 9 16:47:57 2003
+@@ -24,142 +24,24 @@
+ #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 stat64 buf1, buf2;
+
+ if(from_cmdline == NULL) return(1);
+ if(!strcmp(from_cmdline, from_cow)) return(1);
+
+- if(stat(from_cmdline, &buf1) < 0){
++ if(stat64(from_cmdline, &buf1) < 0){
+ printk("Couldn't stat '%s', errno = %d\n", from_cmdline,
+ errno);
+ return(1);
+ }
+- if(stat(from_cow, &buf2) < 0){
++ if(stat64(from_cow, &buf2) < 0){
+ printk("Couldn't stat '%s', errno = %d\n", from_cow, errno);
+ return(1);
+ }
+@@ -215,118 +97,6 @@
+ return(0);
+ }
+
+-static int absolutize(char *to, int size, char *from)
+-{
+- char save_cwd[256], *slash;
+- int remaining;
+-
+- 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,
+@@ -346,10 +116,17 @@
+ if((fd = os_open_file(file, *openflags, mode)) < 0)
+ return(fd);
+ }
++
++ err = os_lock_file(fd, openflags->w);
++ if(err){
++ printk("Failed to lock '%s', errno = %d\n", file, -err);
++ goto error;
++ }
++
+ if(backing_file_out == NULL) return(fd);
+
+- err = read_cow_header(fd, &magic, &backing_file, &mtime, &size,
+- §orsize, bitmap_offset_out);
++ err = read_cow_header(file_reader, &fd, &magic, &backing_file, &mtime,
++ &size, §orsize, bitmap_offset_out);
+ if(err && (*backing_file_out != NULL)){
+ printk("Failed to read COW header from COW file \"%s\", "
+ "errno = %d\n", file, err);
+@@ -376,12 +153,12 @@
+ if(err) goto error;
+ }
+
+- sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out,
+- data_offset_out);
++ cow_sizes(size, sectorsize, *bitmap_offset_out, bitmap_len_out,
++ data_offset_out);
+
+ return(fd);
+ error:
+- close(fd);
++ os_close_file(fd);
+ return(err);
+ }
+
+@@ -389,10 +166,7 @@
+ int sectorsize, 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,29 +177,12 @@
+ 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,
++ bitmap_offset_out, bitmap_len_out,
++ data_offset_out);
++ if(!err)
++ return(fd);
++ os_close_file(fd);
+ out:
+ return(err);
+ }
+@@ -448,14 +205,6 @@
+ else return(n);
+ }
+
+-int ubd_is_dir(char *file)
+-{
+- struct stat64 buf;
+-
+- if(stat64(file, &buf) < 0) return(0);
+- return(S_ISDIR(buf.st_mode));
+-}
+-
+ void do_io(struct io_thread_req *req)
+ {
+ char *buf;
+diff -Naur a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
+--- a/arch/um/drivers/xterm.c Tue Sep 9 16:41:17 2003
++++ b/arch/um/drivers/xterm.c Tue Sep 9 16:47:27 2003
+@@ -108,7 +108,7 @@
+ }
+ close(fd);
+
+- fd = create_unix_socket(file, sizeof(file));
++ fd = create_unix_socket(file, sizeof(file), 1);
+ if(fd < 0){
+ printk("xterm_open : create_unix_socket failed, errno = %d\n",
+ -fd);
+diff -Naur a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
+--- a/arch/um/drivers/xterm_kern.c Tue Sep 9 16:45:16 2003
++++ b/arch/um/drivers/xterm_kern.c Tue Sep 9 16:50:00 2003
+@@ -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)
+diff -Naur a/arch/um/dyn.lds.S b/arch/um/dyn.lds.S
+--- a/arch/um/dyn.lds.S Tue Sep 9 16:43:23 2003
++++ b/arch/um/dyn.lds.S Tue Sep 9 16:49:04 2003
+@@ -15,7 +15,11 @@
+ . = ALIGN(4096); /* Init code and data */
+ _stext = .;
+ __init_begin = .;
+- .text.init : { *(.text.init) }
++ .init.text : {
++ _sinittext = .;
++ *(.init.text)
++ _einittext = .;
++ }
+
+ . = ALIGN(4096);
+
+@@ -67,7 +71,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/irq_kern.h b/arch/um/include/irq_kern.h
+--- a/arch/um/include/irq_kern.h Wed Dec 31 19:00:00 1969
++++ b/arch/um/include/irq_kern.h Tue Sep 9 16:48:56 2003
+@@ -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 Tue Sep 9 16:42:24 2003
++++ b/arch/um/include/kern_util.h Tue Sep 9 16:48:18 2003
+@@ -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);
+diff -Naur a/arch/um/include/line.h b/arch/um/include/line.h
+--- a/arch/um/include/line.h Tue Sep 9 16:45:29 2003
++++ b/arch/um/include/line.h Tue Sep 9 16:50:05 2003
+@@ -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,9 @@
+
+ #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 irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused);
++extern irqreturn_t 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 Tue Sep 9 16:42:56 2003
++++ b/arch/um/include/mconsole.h Tue Sep 9 16:48:27 2003
+@@ -77,6 +77,7 @@
+ 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 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 Tue Sep 9 16:46:13 2003
++++ b/arch/um/include/mem.h Tue Sep 9 16:51:14 2003
+@@ -13,7 +13,6 @@
+ };
+
+ extern void set_usable_vm(unsigned long start, unsigned long end);
+-extern void set_kmem_end(unsigned long new);
+
+ #endif
+
+diff -Naur a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h
+--- a/arch/um/include/mem_user.h Tue Sep 9 16:43:56 2003
++++ b/arch/um/include/mem_user.h Tue Sep 9 16:49:29 2003
+@@ -51,9 +51,6 @@
+
+ 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);
+diff -Naur a/arch/um/include/os.h b/arch/um/include/os.h
+--- a/arch/um/include/os.h Tue Sep 9 16:41:47 2003
++++ b/arch/um/include/os.h Tue Sep 9 16:47:55 2003
+@@ -103,10 +103,11 @@
+ 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);
+@@ -120,6 +121,7 @@
+ 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 Tue Sep 9 16:45:13 2003
++++ b/arch/um/include/sysdep-i386/sigcontext.h Tue Sep 9 16:49:58 2003
+@@ -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 Tue Sep 9 16:43:28 2003
++++ b/arch/um/include/ubd_user.h Tue Sep 9 16:49:08 2003
+@@ -39,7 +39,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/user.h b/arch/um/include/user.h
+--- a/arch/um/include/user.h Tue Sep 9 16:41:16 2003
++++ b/arch/um/include/user.h Tue Sep 9 16:47:26 2003
+@@ -14,7 +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 Tue Sep 9 16:41:34 2003
++++ b/arch/um/include/user_util.h Tue Sep 9 16:47:39 2003
+@@ -59,7 +59,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);
+@@ -90,7 +89,8 @@
+ 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/kernel/Makefile b/arch/um/kernel/Makefile
+--- a/arch/um/kernel/Makefile Tue Sep 9 16:44:02 2003
++++ b/arch/um/kernel/Makefile Tue Sep 9 16:49:30 2003
+@@ -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/config.c.in b/arch/um/kernel/config.c.in
+--- a/arch/um/kernel/config.c.in Tue Sep 9 16:45:16 2003
++++ b/arch/um/kernel/config.c.in Tue Sep 9 16:50:00 2003
+@@ -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 Tue Sep 9 16:41:55 2003
++++ b/arch/um/kernel/exec_kern.c Tue Sep 9 16:48:00 2003
+@@ -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, ¤t->thread.regs);
+ if (error == 0){
+ current->ptrace &= ~PT_DTRACE;
+diff -Naur a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
+--- a/arch/um/kernel/init_task.c Tue Sep 9 16:46:17 2003
++++ b/arch/um/kernel/init_task.c Tue Sep 9 16:51:23 2003
+@@ -17,6 +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);
+
+ /*
+ * Initial task structure.
+@@ -38,26 +39,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 Tue Sep 9 16:45:47 2003
++++ b/arch/um/kernel/irq.c Tue Sep 9 16:50:14 2003
+@@ -28,6 +28,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);
+
+@@ -82,65 +83,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;
+ }
+
+ /*
+@@ -281,13 +269,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);
+ /*
+@@ -384,7 +371,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)
+@@ -430,15 +417,19 @@
+ }
+
+ 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 */
+@@ -654,7 +645,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/mem.c b/arch/um/kernel/mem.c
+--- a/arch/um/kernel/mem.c Tue Sep 9 16:42:54 2003
++++ b/arch/um/kernel/mem.c Tue Sep 9 16:48:27 2003
+@@ -119,11 +119,6 @@
+ return(kmem_top);
+ }
+
+-void set_kmem_end(unsigned long new)
+-{
+- kmem_top = new;
+-}
+-
+ #ifdef CONFIG_HIGHMEM
+ /* Changed during early boot */
+ pte_t *kmap_pte;
+@@ -218,7 +213,7 @@
+ if(regions[i] == NULL) break;
+ }
+ if(i == NREGIONS){
+- printk("setup_range : no free regions\n");
++ printk("setup_one_range : no free regions\n");
+ i = -1;
+ goto out;
+ }
+@@ -227,7 +222,9 @@
+ fd = create_mem_file(len);
+
+ if(region == NULL){
+- region = alloc_bootmem_low_pages(sizeof(*region));
++ if(kmalloc_ok)
++ region = kmalloc(sizeof(*region), GFP_KERNEL);
++ else region = alloc_bootmem_low_pages(sizeof(*region));
+ if(region == NULL)
+ panic("Failed to allocating mem_region");
+ }
+@@ -528,9 +525,9 @@
+ 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)
++static 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;
+
+diff -Naur a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c
+--- a/arch/um/kernel/mem_user.c Tue Sep 9 16:43:27 2003
++++ b/arch/um/kernel/mem_user.c Tue Sep 9 16:49:07 2003
+@@ -111,6 +111,11 @@
+ offset = 0;
+ }
+
++ if(offset >= region->len){
++ printf("%ld bytes of physical memory is insufficient\n",
++ region->len);
++ exit(1);
++ }
+ loc = mmap(start, region->len - offset, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FIXED, region->fd, offset);
+ if(loc != start){
+@@ -122,26 +127,26 @@
+
+ static int __init parse_iomem(char *str, int *add)
+ {
+- struct stat buf;
++ struct stat64 buf;
+ char *file, *driver;
+ int fd;
+
+ driver = str;
+ file = strchr(str,',');
+ if(file == NULL){
+- printk("parse_iomem : failed to parse iomem\n");
++ printf("parse_iomem : failed to parse iomem\n");
+ return(1);
+ }
+ *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",
++ printf("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);
++ if(fstat64(fd, &buf) < 0) {
++ printf("parse_iomem - cannot fstat file, errno = %d\n", errno);
+ return(1);
+ }
+ add_iomem(driver, fd, buf.st_size);
+diff -Naur a/arch/um/kernel/process.c b/arch/um/kernel/process.c
+--- a/arch/um/kernel/process.c Tue Sep 9 16:45:56 2003
++++ b/arch/um/kernel/process.c Tue Sep 9 16:50:22 2003
+@@ -72,7 +72,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);
+@@ -127,7 +126,8 @@
+ 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);
+ }
+diff -Naur a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
+--- a/arch/um/kernel/process_kern.c Tue Sep 9 16:43:24 2003
++++ b/arch/um/kernel/process_kern.c Tue Sep 9 16:49:06 2003
+@@ -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);
+ }
+@@ -103,13 +98,14 @@
+
+ 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 | 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 +125,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 +145,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 +153,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 +190,7 @@
+
+ void default_idle(void)
+ {
+- idle_timer();
++ uml_idle_timer();
+
+ atomic_inc(&init_mm.mm_count);
+ current->mm = &init_mm;
+@@ -363,10 +363,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);
+@@ -381,7 +386,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 Tue Sep 9 16:41:35 2003
++++ b/arch/um/kernel/ptrace.c Tue Sep 9 16:47:40 2003
+@@ -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/sigio_kern.c b/arch/um/kernel/sigio_kern.c
+--- a/arch/um/kernel/sigio_kern.c Tue Sep 9 16:41:54 2003
++++ b/arch/um/kernel/sigio_kern.c Tue Sep 9 16:47:58 2003
+@@ -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/signal_kern.c b/arch/um/kernel/signal_kern.c
+--- a/arch/um/kernel/signal_kern.c Tue Sep 9 16:43:31 2003
++++ b/arch/um/kernel/signal_kern.c Tue Sep 9 16:49:19 2003
+@@ -36,7 +36,7 @@
+ if(sig == SIGSEGV){
+ struct k_sigaction *ka;
+
+- ka = ¤t->sig->action[SIGSEGV - 1];
++ ka = ¤t->sighand->action[SIGSEGV - 1];
+ ka->sa.sa_handler = SIG_DFL;
+ }
+ force_sig(SIGSEGV, current);
+@@ -142,7 +142,7 @@
+ return(0);
+
+ /* Whee! Actually deliver the signal. */
+- ka = ¤t->sig->action[sig -1 ];
++ ka = ¤t->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,6 +227,42 @@
+ }
+ }
+
++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(¤t->thread.regs)));
++}
++
+ static int copy_sc_from_user(struct pt_regs *to, void *from,
+ struct arch_frame_data *arch)
+ {
+@@ -239,8 +275,8 @@
+
+ int sys_sigreturn(struct pt_regs regs)
+ {
+- void *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs));
+- void *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs));
++ void __user *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs));
++ void __user *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs));
+ int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
+
+ spin_lock_irq(¤t->sighand->siglock);
+@@ -257,7 +293,8 @@
+
+ int sys_rt_sigreturn(struct pt_regs regs)
+ {
+- struct ucontext *uc = sp_to_uc(PT_REGS_SP(¤t->thread.regs));
++ unsigned long sp = PT_REGS_SP(¤t->thread.regs);
++ struct ucontext __user *uc = sp_to_uc(sp);
+ void *fp;
+ int sig_size = _NSIG_WORDS * sizeof(unsigned long);
+
+diff -Naur a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
+--- a/arch/um/kernel/skas/Makefile Tue Sep 9 16:42:00 2003
++++ b/arch/um/kernel/skas/Makefile Tue Sep 9 16:48:10 2003
+@@ -7,18 +7,22 @@
+ process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.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/include/mode.h b/arch/um/kernel/skas/include/mode.h
+--- a/arch/um/kernel/skas/include/mode.h Tue Sep 9 16:43:28 2003
++++ b/arch/um/kernel/skas/include/mode.h Tue Sep 9 16:49:08 2003
+@@ -20,6 +20,7 @@
+ 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/uaccess.h b/arch/um/kernel/skas/include/uaccess.h
+--- a/arch/um/kernel/skas/include/uaccess.h Tue Sep 9 16:42:57 2003
++++ b/arch/um/kernel/skas/include/uaccess.h Tue Sep 9 16:48:51 2003
+@@ -19,7 +19,7 @@
+ #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)
+diff -Naur a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
+--- a/arch/um/kernel/skas/process.c Tue Sep 9 16:46:01 2003
++++ b/arch/um/kernel/skas/process.c Tue Sep 9 16:51:06 2003
+@@ -4,6 +4,7 @@
+ */
+
+ #include <stdlib.h>
++#include <unistd.h>
+ #include <errno.h>
+ #include <signal.h>
+ #include <setjmp.h>
+@@ -24,6 +25,16 @@
+ #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);
++}
+
+ unsigned long exec_regs[FRAME_SIZE];
+ unsigned long exec_fp_regs[HOST_FP_SIZE];
+@@ -48,11 +59,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 +83,6 @@
+ handle_syscall(regs);
+ }
+
+-int userspace_pid;
+-
+ static int userspace_tramp(void *arg)
+ {
+ init_new_thread_signals(0);
+@@ -83,6 +92,8 @@
+ return(0);
+ }
+
++int userspace_pid;
++
+ void start_userspace(void)
+ {
+ void *stack;
+@@ -149,6 +160,7 @@
+ case SIGILL:
+ case SIGBUS:
+ case SIGFPE:
++ case SIGWINCH:
+ user_signal(WSTOPSIG(status), regs);
+ break;
+ default:
+@@ -328,7 +340,8 @@
+ 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);
+@@ -342,6 +355,7 @@
+ printk("new_mm : /proc/mm copy_segments failed, "
+ "errno = %d\n", errno);
+ }
++
+ return(fd);
+ }
+
+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 Tue Sep 9 16:41:52 2003
++++ b/arch/um/kernel/skas/process_kern.c Tue Sep 9 16:47:57 2003
+@@ -61,9 +61,8 @@
+ thread_wait(¤t->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;
+
+ n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf);
+@@ -93,9 +92,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 +134,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();
+ }
+
+@@ -164,7 +162,7 @@
+ capture_signal_stack();
+
+ init_new_thread_signals(1);
+- idle_timer();
++ uml_idle_timer();
+
+ init_task.thread.request.u.thread.proc = start_kernel_proc;
+ init_task.thread.request.u.thread.arg = NULL;
+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 Tue Sep 9 16:42:54 2003
++++ b/arch/um/kernel/skas/util/mk_ptregs.c Tue Sep 9 16:48:27 2003
+@@ -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 Tue Sep 9 16:41:48 2003
++++ b/arch/um/kernel/smp.c Tue Sep 9 16:47:56 2003
+@@ -22,7 +22,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;
+
+ /* Per CPU bogomips and other parameters
+ * The only piece used here is the ipi pipe, which is set before SMP is
+@@ -97,15 +97,15 @@
+
+ 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);
+ }
+ 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)
+ {
+@@ -120,12 +120,12 @@
+ 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);
+@@ -140,8 +140,11 @@
+
+ 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,
+@@ -150,6 +153,7 @@
+ CHOOSE_MODE(write(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);
+ }
+
+@@ -157,15 +161,16 @@
+ {
+ 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);
++ err = os_pipe(cpu_data[me].ipi_pipe, 1, 1);
+ if(err) 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++){
+@@ -177,10 +182,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");
+ }
+@@ -270,7 +275,7 @@
+ 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);
+
+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 Tue Sep 9 16:45:55 2003
++++ b/arch/um/kernel/sys_call_table.c Tue Sep 9 16:50:22 2003
+@@ -219,15 +219,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 +250,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 +275,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_fadvise64_64
+
+ #if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
+ #define LAST_SYSCALL LAST_GENERIC_SYSCALL
+@@ -455,32 +484,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 +522,20 @@
+ [ __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,
+
+ ARCH_SYSCALLS
+ [ LAST_SYSCALL + 1 ... NR_syscalls ] =
+diff -Naur a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
+--- a/arch/um/kernel/syscall_kern.c Tue Sep 9 16:45:13 2003
++++ b/arch/um/kernel/syscall_kern.c Tue Sep 9 16:49:58 2003
+@@ -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(¤t->mm->mmap_sem);
+- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+- up_write(¤t->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;
+ }
+@@ -141,37 +143,6 @@
+ 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(¤t->thread.regs)));
+-}
+-
+ long execute_syscall(void *r)
+ {
+ return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r));
+diff -Naur a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
+--- a/arch/um/kernel/sysrq.c Tue Sep 9 16:42:22 2003
++++ b/arch/um/kernel/sysrq.c Tue Sep 9 16:48:13 2003
+@@ -53,6 +53,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/time.c b/arch/um/kernel/time.c
+--- a/arch/um/kernel/time.c Tue Sep 9 16:41:45 2003
++++ b/arch/um/kernel/time.c Tue Sep 9 16:47:55 2003
+@@ -15,12 +15,16 @@
+ #include "process.h"
+ #include "signal_user.h"
+ #include "time_user.h"
++#include "kern_constants.h"
+
+ 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)
+@@ -65,7 +69,7 @@
+ errno);
+ }
+
+-void idle_timer(void)
++void uml_idle_timer(void)
+ {
+ if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR)
+ panic("Couldn't unset SIGVTALRM handler");
+@@ -82,8 +86,6 @@
+ set_interval(ITIMER_VIRTUAL);
+ }
+
+-struct timeval local_offset = { 0, 0 };
+-
+ void do_gettimeofday(struct timeval *tv)
+ {
+ unsigned long flags;
+@@ -100,7 +102,7 @@
+ 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;
+@@ -110,6 +112,8 @@
+ gettimeofday(&now, NULL);
+ timersub(&tv_in, &now, &local_offset);
+ time_unlock(flags);
++
++ 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 Tue Sep 9 16:43:50 2003
++++ b/arch/um/kernel/time_kern.c Tue Sep 9 16:49:26 2003
+@@ -38,7 +38,7 @@
+
+ void timer_irq(union uml_pt_regs *regs)
+ {
+- int cpu = current->thread_info->cpu, ticks = missed_ticks[cpu];
++ int cpu = current_thread->cpu, ticks = missed_ticks[cpu];
+
+ if(!timer_irq_inited) return;
+ missed_ticks[cpu] = 0;
+@@ -55,12 +55,13 @@
+ do_timer(®s);
+ }
+
+-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)
+@@ -78,12 +79,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;
+ }
+@@ -122,9 +123,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);
+ }
+
+diff -Naur a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c
+--- a/arch/um/kernel/trap_kern.c Tue Sep 9 16:41:19 2003
++++ b/arch/um/kernel/trap_kern.c Tue Sep 9 16:47:27 2003
+@@ -16,6 +16,7 @@
+ #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"
+@@ -51,7 +52,7 @@
+ 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);
+@@ -180,6 +181,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 Tue Sep 9 16:43:06 2003
++++ b/arch/um/kernel/trap_user.c Tue Sep 9 16:48:52 2003
+@@ -82,6 +82,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,
+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 Tue Sep 9 16:41:43 2003
++++ b/arch/um/kernel/tt/exec_kern.c Tue Sep 9 16:47:53 2003
+@@ -47,17 +47,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/uaccess.h b/arch/um/kernel/tt/include/uaccess.h
+--- a/arch/um/kernel/tt/include/uaccess.h Tue Sep 9 16:43:54 2003
++++ b/arch/um/kernel/tt/include/uaccess.h Tue Sep 9 16:49:28 2003
+@@ -46,18 +46,20 @@
+
+ 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,
+- ¤t->thread.fault_addr,
+- ¤t->thread.fault_catcher) : n);
++ if(!access_ok_tt(VERIFY_READ, from, n))
++ return(n);
++
++ return(__do_copy_from_user(to, from, n, ¤t->thread.fault_addr,
++ ¤t->thread.fault_catcher));
+ }
+
+ 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,
+- ¤t->thread.fault_addr,
+- ¤t->thread.fault_catcher) : n);
++ if(!access_ok_tt(VERIFY_WRITE, to, n))
++ return(n);
++
++ return(__do_copy_to_user(to, from, n, ¤t->thread.fault_addr,
++ ¤t->thread.fault_catcher));
+ }
+
+ extern int __do_strncpy_from_user(char *dst, const char *src, size_t n,
+@@ -67,7 +69,9 @@
+ {
+ int n;
+
+- if(!access_ok_tt(VERIFY_READ, src, 1)) return(-EFAULT);
++ if(!access_ok_tt(VERIFY_READ, src, 1))
++ return(-EFAULT);
++
+ n = __do_strncpy_from_user(dst, src, count,
+ ¤t->thread.fault_addr,
+ ¤t->thread.fault_catcher);
+@@ -87,10 +91,11 @@
+
+ static inline int clear_user_tt(void *mem, int len)
+ {
+- return(access_ok_tt(VERIFY_WRITE, mem, len) ?
+- __do_clear_user(mem, len,
+- ¤t->thread.fault_addr,
+- ¤t->thread.fault_catcher) : len);
++ if(!access_ok_tt(VERIFY_WRITE, mem, len))
++ return(len);
++
++ return(__do_clear_user(mem, len, ¤t->thread.fault_addr,
++ ¤t->thread.fault_catcher));
+ }
+
+ extern int __do_strnlen_user(const char *str, unsigned long n,
+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 Tue Sep 9 16:45:54 2003
++++ b/arch/um/kernel/tt/process_kern.c Tue Sep 9 16:50:21 2003
+@@ -104,7 +104,10 @@
+
+ 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)
+@@ -125,27 +128,27 @@
+ UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1);
+ 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, ¤t->thread.exec_buf))
+ do_exit(0);
+ }
+
+ static int new_thread_proc(void *stack)
+ {
++ local_irq_disable();
+ init_new_thread_stack(stack, new_thread_handler);
+ os_usr1_process(os_getpid());
+ return(0);
+@@ -165,35 +168,32 @@
+ UPT_SC(¤t->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);
+ }
+
+@@ -377,8 +377,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);
+
+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 Tue Sep 9 16:43:48 2003
++++ b/arch/um/kernel/tt/ptproxy/proxy.c Tue Sep 9 16:49:22 2003
+@@ -293,10 +293,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)
+diff -Naur a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c
+--- a/arch/um/kernel/tt/tracer.c Tue Sep 9 16:41:14 2003
++++ b/arch/um/kernel/tt/tracer.c Tue Sep 9 16:47:25 2003
+@@ -39,7 +39,7 @@
+ return(0);
+
+ register_winch_irq(tracer_winch[0], fd, -1, data);
+- return(0);
++ return(1);
+ }
+
+ static void tracer_winch_handler(int sig)
+@@ -401,7 +401,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_user.c b/arch/um/kernel/tt/uaccess_user.c
+--- a/arch/um/kernel/tt/uaccess_user.c Tue Sep 9 16:42:02 2003
++++ b/arch/um/kernel/tt/uaccess_user.c Tue Sep 9 16:48:11 2003
+@@ -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,6 +69,7 @@
+ 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;
+@@ -71,6 +83,8 @@
+ }
+ *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 Tue Sep 9 16:43:49 2003
++++ b/arch/um/kernel/tty_log.c Tue Sep 9 16:49:22 2003
+@@ -13,6 +13,7 @@
+ #include <sys/time.h>
+ #include "init.h"
+ #include "user.h"
++#include "kern_util.h"
+ #include "os.h"
+
+ #define TTY_LOG_DIR "./"
+@@ -24,29 +25,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 });
++ 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 } );
+ write(tty_log_fd, &data, sizeof(data));
++ write(tty_log_fd, ¤t_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 +74,114 @@
+ 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 });
++ 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 } );
+ write(tty_log_fd, &data, sizeof(data));
+ return;
+ }
+ close(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 = write(fd, chunk, try);
++ if(n != try)
++ return(-errno);
++ 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 });
++ 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 } );
+ write(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 } );
++ write(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 +200,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/um_arch.c b/arch/um/kernel/um_arch.c
+--- a/arch/um/kernel/um_arch.c Tue Sep 9 16:45:38 2003
++++ b/arch/um/kernel/um_arch.c Tue Sep 9 16:50:11 2003
+@@ -38,13 +38,18 @@
+ #include "mode_kern.h"
+ #include "mode.h"
+
+-#define DEFAULT_COMMAND_LINE "root=6200"
++#define DEFAULT_COMMAND_LINE "root=ubd0"
+
+ 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,
+@@ -61,10 +66,14 @@
+ 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);
+ }
+
+@@ -369,6 +378,7 @@
+ 2 * PAGE_SIZE;
+
+ task_protections((unsigned long) &init_thread_info);
++ os_flush_stdout();
+
+ return(CHOOSE_MODE(start_uml_tt(), start_uml_skas()));
+ }
+diff -Naur a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c
+--- a/arch/um/kernel/umid.c Tue Sep 9 16:46:00 2003
++++ b/arch/um/kernel/umid.c Tue Sep 9 16:51:03 2003
+@@ -33,18 +33,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 +55,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 +68,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){
+@@ -92,14 +93,14 @@
+ fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))),
+ 0644);
+ if(fd < 0){
+- printk("Open of machine pid file \"%s\" failed - "
++ printf("Open of machine pid file \"%s\" failed - "
+ "errno = %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);
++ printf("Write of pid file failed - errno = %d\n", errno);
+ close(fd);
+ return 0;
+ }
+@@ -197,7 +198,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 +218,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);
+ }
+@@ -239,25 +240,25 @@
+ 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);
+ }
+
+@@ -267,7 +268,7 @@
+ * 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);
+@@ -275,14 +276,14 @@
+ if((err = mkdir(tmp, 0777)) < 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 +296,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_util.c b/arch/um/kernel/user_util.c
+--- a/arch/um/kernel/user_util.c Tue Sep 9 16:41:41 2003
++++ b/arch/um/kernel/user_util.c Tue Sep 9 16:47:43 2003
+@@ -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/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
+--- a/arch/um/os-Linux/drivers/tuntap_user.c Tue Sep 9 16:46:16 2003
++++ b/arch/um/os-Linux/drivers/tuntap_user.c Tue Sep 9 16:51:17 2003
+@@ -142,7 +142,7 @@
+ return(-errno);
+ }
+ 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);
+diff -Naur a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
+--- a/arch/um/os-Linux/file.c Tue Sep 9 16:46:10 2003
++++ b/arch/um/os-Linux/file.c Tue Sep 9 16:51:13 2003
+@@ -315,7 +315,7 @@
+ return(new);
+ }
+
+-int create_unix_socket(char *file, int len)
++int create_unix_socket(char *file, int len, int close_on_exec)
+ {
+ struct sockaddr_un addr;
+ int sock, err;
+@@ -327,6 +327,10 @@
+ return(-errno);
+ }
+
++ if(close_on_exec && fcntl(sock, F_SETFD, 1) < 0)
++ printk("create_unix_socket : Setting FD_CLOEXEC failed, "
++ "errno = %d", errno);
++
+ addr.sun_family = AF_UNIX;
+
+ /* XXX Be more careful about overflow */
+@@ -342,6 +346,37 @@
+ 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/sys-i386/Makefile b/arch/um/sys-i386/Makefile
+--- a/arch/um/sys-i386/Makefile Tue Sep 9 16:41:38 2003
++++ b/arch/um/sys-i386/Makefile Tue Sep 9 16:47:42 2003
+@@ -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
+
+ 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/bugs.c b/arch/um/sys-i386/bugs.c
+--- a/arch/um/sys-i386/bugs.c Tue Sep 9 16:45:37 2003
++++ b/arch/um/sys-i386/bugs.c Tue Sep 9 16:50:09 2003
+@@ -8,6 +8,7 @@
+ #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"
+@@ -16,8 +17,8 @@
+ #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)
+ {
+@@ -104,6 +105,25 @@
+ return(1);
+ }
+
++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);
++}
++
++void arch_init_thread(void)
++{
++ disable_lcall();
++}
++
+ void arch_check_bugs(void)
+ {
+ int have_it;
+@@ -113,8 +133,8 @@
+ "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_feature("cmov", &have_it)) host_has_cmov = have_it;
++ if(check_cpu_feature("xmm", &have_it)) host_has_xmm = have_it;
+ }
+
+ int arch_handle_signal(int sig, union uml_pt_regs *regs)
+@@ -130,18 +150,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/uml.lds.S b/arch/um/uml.lds.S
+--- a/arch/um/uml.lds.S Tue Sep 9 16:43:03 2003
++++ b/arch/um/uml.lds.S Tue Sep 9 16:48:52 2003
+@@ -26,7 +26,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 +42,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/mk_constants_kern.c b/arch/um/util/mk_constants_kern.c
+--- a/arch/um/util/mk_constants_kern.c Tue Sep 9 16:41:24 2003
++++ b/arch/um/util/mk_constants_kern.c Tue Sep 9 16:47:30 2003
+@@ -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/fs/Makefile b/fs/Makefile
+--- a/fs/Makefile Tue Sep 9 16:43:32 2003
++++ b/fs/Makefile Tue Sep 9 16:49:19 2003
+@@ -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/fs/hostfs/Makefile b/fs/hostfs/Makefile
+--- a/fs/hostfs/Makefile Wed Dec 31 19:00:00 1969
++++ b/fs/hostfs/Makefile Tue Sep 9 16:47:22 2003
+@@ -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/hostfs/hostfs.h b/fs/hostfs/hostfs.h
+--- a/fs/hostfs/hostfs.h Wed Dec 31 19:00:00 1969
++++ b/fs/hostfs/hostfs.h Tue Sep 9 16:47:21 2003
+@@ -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 Wed Dec 31 19:00:00 1969
++++ b/fs/hostfs/hostfs_kern.c Tue Sep 9 16:47:25 2003
+@@ -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 Wed Dec 31 19:00:00 1969
++++ b/fs/hostfs/hostfs_user.c Tue Sep 9 16:47:43 2003
+@@ -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/hppfs/Makefile b/fs/hppfs/Makefile
+--- a/fs/hppfs/Makefile Wed Dec 31 19:00:00 1969
++++ b/fs/hppfs/Makefile Tue Sep 9 16:49:04 2003
+@@ -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/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
+--- a/fs/hppfs/hppfs_kern.c Wed Dec 31 19:00:00 1969
++++ b/fs/hppfs/hppfs_kern.c Tue Sep 9 16:48:52 2003
+@@ -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/include/asm-um/archparam-i386.h b/include/asm-um/archparam-i386.h
+--- a/include/asm-um/archparam-i386.h Tue Sep 9 16:45:45 2003
++++ b/include/asm-um/archparam-i386.h Tue Sep 9 16:50:12 2003
+@@ -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 Tue Sep 9 16:41:45 2003
++++ b/include/asm-um/common.lds.S Tue Sep 9 16:47:55 2003
+@@ -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 Wed Dec 31 19:00:00 1969
++++ b/include/asm-um/cpufeature.h Tue Sep 9 16:47:22 2003
+@@ -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 Tue Sep 9 16:41:22 2003
++++ b/include/asm-um/current.h Tue Sep 9 16:47:29 2003
+@@ -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 Tue Sep 9 16:46:00 2003
++++ b/include/asm-um/fixmap.h Tue Sep 9 16:51:02 2003
+@@ -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 Tue Sep 9 16:46:09 2003
++++ b/include/asm-um/irq.h Tue Sep 9 16:51:12 2003
+@@ -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 Wed Dec 31 19:00:00 1969
++++ b/include/asm-um/local.h Tue Sep 9 16:49:26 2003
+@@ -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 Wed Dec 31 19:00:00 1969
++++ b/include/asm-um/module-generic.h Tue Sep 9 16:49:17 2003
+@@ -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 Wed Dec 31 19:00:00 1969
++++ b/include/asm-um/module-i386.h Tue Sep 9 16:49:10 2003
+@@ -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 Tue Sep 9 16:43:32 2003
++++ b/include/asm-um/page.h Tue Sep 9 16:49:19 2003
+@@ -4,7 +4,6 @@
+ struct page;
+
+ #include "asm/arch/page.h"
+-#include "asm/bug.h"
+
+ #undef __pa
+ #undef __va
+diff -Naur a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
+--- a/include/asm-um/pgtable.h Tue Sep 9 16:46:25 2003
++++ b/include/asm-um/pgtable.h Tue Sep 9 16:51:24 2003
+@@ -79,12 +79,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
+@@ -203,6 +204,16 @@
+ #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))
+
++/*
++ * 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)
+ {
+ pte_val(pte) |= _PAGE_NEWPROT;
+@@ -236,6 +247,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) &&
+@@ -253,6 +270,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; }
+@@ -355,14 +380,26 @@
+ #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) \
+@@ -374,7 +411,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))
+@@ -400,11 +442,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 Tue Sep 9 16:41:42 2003
++++ b/include/asm-um/processor-generic.h Tue Sep 9 16:47:43 2003
+@@ -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;
+@@ -101,14 +99,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 Tue Sep 9 16:41:17 2003
++++ b/include/asm-um/processor-i386.h Tue Sep 9 16:47:27 2003
+@@ -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 Wed Dec 31 19:00:00 1969
++++ b/include/asm-um/sections.h Tue Sep 9 16:49:28 2003
+@@ -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 Tue Sep 9 16:41:04 2003
++++ b/include/asm-um/smp.h Tue Sep 9 16:47:18 2003
+@@ -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/system-generic.h b/include/asm-um/system-generic.h
+--- a/include/asm-um/system-generic.h Tue Sep 9 16:46:13 2003
++++ b/include/asm-um/system-generic.h Tue Sep 9 16:51:14 2003
+@@ -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 Tue Sep 9 16:42:02 2003
++++ b/include/asm-um/thread_info.h Tue Sep 9 16:48:12 2003
+@@ -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 Tue Sep 9 16:43:51 2003
++++ b/include/asm-um/timex.h Tue Sep 9 16:49:27 2003
+@@ -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/linux/mm.h b/include/linux/mm.h
+--- a/include/linux/mm.h Tue Sep 9 16:41:15 2003
++++ b/include/linux/mm.h Tue Sep 9 16:47:26 2003
+@@ -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 Wed Dec 31 19:00:00 1969
++++ b/include/linux/proc_mm.h Tue Sep 9 16:47:15 2003
+@@ -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 Tue Sep 9 16:43:50 2003
++++ b/mm/Makefile Tue Sep 9 16:49:26 2003
+@@ -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 Tue Sep 9 16:43:03 2003
++++ b/mm/memory.c Tue Sep 9 16:48:52 2003
+@@ -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>
+@@ -673,6 +674,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)
+@@ -693,19 +712,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 Tue Sep 9 16:43:49 2003
++++ b/mm/mmap.c Tue Sep 9 16:49:24 2003
+@@ -434,11 +434,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 Tue Sep 9 16:42:54 2003
++++ b/mm/mprotect.c Tue Sep 9 16:48:27 2003
+@@ -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;
+@@ -241,9 +242,9 @@
+
+ vm_flags = calc_vm_prot_bits(prot);
+
+- down_write(¤t->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 || vma->vm_start > start)
+ goto out;
+@@ -304,6 +305,11 @@
+ prev->vm_mm->map_count--;
+ }
+ out:
+- up_write(¤t->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/proc_mm.c b/mm/proc_mm.c
+--- a/mm/proc_mm.c Wed Dec 31 19:00:00 1969
++++ b/mm/proc_mm.c Tue Sep 9 16:48:51 2003
+@@ -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, ¤t->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:
++ */