From ead318cbcd7e332e750ce4f3d18929f63f6acddc Mon Sep 17 00:00:00 2001 From: Mark Huang Date: Fri, 21 Jan 2005 03:34:14 +0000 Subject: [PATCH] uml-patch-2.6.7-2 --- arch/um/Kconfig | 7 + arch/um/Kconfig_char | 52 +++- arch/um/Makefile | 20 +- arch/um/Makefile-i386 | 11 + arch/um/defconfig | 66 +++--- arch/um/drivers/Makefile | 2 +- arch/um/drivers/chan_kern.c | 49 ++++ arch/um/drivers/chan_user.c | 63 +---- arch/um/drivers/cow_user.c | 4 +- arch/um/drivers/fd.c | 17 +- arch/um/drivers/hostaudio_kern.c | 44 ++-- arch/um/drivers/mconsole_kern.c | 16 +- arch/um/drivers/net_kern.c | 27 ++- arch/um/drivers/net_user.c | 5 +- arch/um/drivers/port_user.c | 19 +- arch/um/drivers/pty.c | 23 +- arch/um/drivers/slip_user.c | 6 +- arch/um/drivers/slirp_user.c | 8 +- arch/um/drivers/tty.c | 11 +- arch/um/drivers/ubd_kern.c | 12 +- arch/um/drivers/ubd_user.c | 5 +- arch/um/drivers/xterm.c | 16 +- arch/um/dyn.lds.S | 3 - arch/um/include/init.h | 10 + arch/um/include/irq_user.h | 1 + arch/um/include/mem.h | 2 +- arch/um/include/mem_kern.h | 2 +- arch/um/include/os.h | 45 +++- arch/um/include/time_user.h | 1 + arch/um/include/user.h | 2 + arch/um/include/user_util.h | 6 +- arch/um/kernel/Makefile | 19 +- arch/um/kernel/frame.c | 8 +- arch/um/kernel/helper.c | 17 +- arch/um/kernel/irq_user.c | 14 ++ arch/um/kernel/ksyms.c | 3 + arch/um/kernel/mem_user.c | 39 ++- arch/um/kernel/physmem.c | 27 ++- arch/um/kernel/process.c | 40 ++-- arch/um/kernel/process_kern.c | 11 +- arch/um/kernel/sigio_kern.c | 14 +- arch/um/kernel/sigio_user.c | 12 +- arch/um/kernel/skas/exec_user.c | 6 +- arch/um/kernel/skas/include/mode.h | 2 + arch/um/kernel/skas/process.c | 42 +--- arch/um/kernel/skas/process_kern.c | 31 ++- arch/um/kernel/skas/trap_user.c | 3 + arch/um/kernel/skas/uaccess.c | 59 +++-- arch/um/kernel/smp.c | 46 +--- arch/um/kernel/time.c | 46 +--- arch/um/kernel/time_kern.c | 26 +- arch/um/kernel/trap_kern.c | 15 +- arch/um/kernel/trap_user.c | 11 +- arch/um/kernel/tt/exec_kern.c | 6 +- arch/um/kernel/tt/exec_user.c | 9 +- arch/um/kernel/tt/process_kern.c | 48 +++- arch/um/kernel/tt/ptproxy/proxy.c | 4 +- arch/um/kernel/tt/tracer.c | 4 +- arch/um/kernel/tt/trap_user.c | 9 +- arch/um/kernel/tt/uaccess_user.c | 2 +- arch/um/kernel/tty_log.c | 2 + arch/um/kernel/uaccess_user.c | 2 +- arch/um/kernel/um_arch.c | 16 +- arch/um/kernel/umid.c | 10 +- arch/um/kernel/user_util.c | 48 +++- arch/um/main.c | 60 ++++- arch/um/os-Linux/Makefile | 10 +- arch/um/os-Linux/drivers/ethertap_user.c | 4 +- arch/um/os-Linux/drivers/tuntap_user.c | 3 +- arch/um/os-Linux/file.c | 288 ++++++++++++++++++++++- arch/um/os-Linux/process.c | 20 +- arch/um/sys-i386/Makefile | 2 +- arch/um/sys-i386/bugs.c | 7 +- arch/um/sys-i386/ldt.c | 2 + arch/um/sys-i386/ptrace_user.c | 3 +- arch/um/util/Makefile | 3 + fs/Makefile | 3 +- fs/hostfs/Makefile | 15 +- fs/hostfs/hostfs.h | 207 ++++++++++++---- include/asm-um/bug.h | 2 - include/asm-um/irq.h | 5 +- include/asm-um/processor-generic.h | 4 +- 82 files changed, 1318 insertions(+), 526 deletions(-) diff --git a/arch/um/Kconfig b/arch/um/Kconfig index d8356bc15..92fe9130b 100644 --- a/arch/um/Kconfig +++ b/arch/um/Kconfig @@ -78,6 +78,9 @@ config NET source "fs/Kconfig.binfmt" +config EXTERNFS + tristate "Support for host-based filesystems" + config HOSTFS tristate "Host filesystem" help @@ -99,6 +102,10 @@ config HOSTFS If you'd like to be able to work with files stored on the host, say Y or M here; otherwise say N. +config HUMFS + tristate 'Usable host filesystem' + depends on EXTERNFS + config HPPFS tristate "HoneyPot ProcFS" help diff --git a/arch/um/Kconfig_char b/arch/um/Kconfig_char index a21cbbc7e..8a6afe659 100644 --- a/arch/um/Kconfig_char +++ b/arch/um/Kconfig_char @@ -108,11 +108,55 @@ config SSL_CHAN config UNIX98_PTYS bool "Unix98 PTY support" - -config UNIX98_PTY_COUNT - int "Maximum number of Unix98 PTYs in use (0-2048)" - depends on UNIX98_PTYS + ---help--- + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. + + Linux has traditionally used the BSD-like names /dev/ptyxx for + masters and /dev/ttyxx for slaves of pseudo terminals. This scheme + has a number of problems. The GNU C library glibc 2.1 and later, + however, supports the Unix98 naming standard: in order to acquire a + pseudo terminal, a process opens /dev/ptmx; the number of the pseudo + terminal is then made available to the process and the pseudo + terminal slave can be accessed as /dev/pts/. What was + traditionally /dev/ttyp2 will then be /dev/pts/2, for example. + + All modern Linux systems use the Unix98 ptys. Say Y unless + you're on an embedded system and want to conserve memory. + +config LEGACY_PTYS + bool "Legacy (BSD) PTY support" + default y + ---help--- + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. + + Linux has traditionally used the BSD-like names /dev/ptyxx + for masters and /dev/ttyxx for slaves of pseudo + terminals. This scheme has a number of problems, including + security. This option enables these legacy devices; on most + systems, it is safe to say N. + + +config LEGACY_PTY_COUNT + int "Maximum number of legacy PTY in use" + depends on LEGACY_PTYS default "256" + ---help--- + The maximum number of legacy PTYs that can be used at any one time. + The default is 256, and should be more than enough. Embedded + systems may want to reduce this to save memory. + + When not in use, each legacy PTY occupies 12 bytes on 32-bit + architectures and 24 bytes on 64-bit architectures. config WATCHDOG bool "Watchdog Timer Support" diff --git a/arch/um/Makefile b/arch/um/Makefile index 4e9bbefe4..5dfc32025 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -48,7 +48,7 @@ endif include $(ARCH_DIR)/Makefile-$(SUBARCH) include $(ARCH_DIR)/Makefile-os-$(OS) -EXTRAVERSION := $(EXTRAVERSION)-1um +EXTRAVERSION := $(EXTRAVERSION)-2um ARCH_INCLUDE = -I$(ARCH_DIR)/include @@ -61,13 +61,17 @@ CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \ -Dsigprocmask=kernel_sigprocmask $(MODE_INCLUDE) +check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi) + +CFLAGS += $(call check_gcc,-fno-unit-at-a-time,) + LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc # These are needed for clean and mrproper, since in that case .config is not # included; the values here are meaningless CONFIG_NEST_LEVEL ?= 0 -CONFIG_KERNEL_HALF_GIGS ?= 0 +CONFIG_KERNEL_HALF_GIGS ?= 0 SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000) @@ -111,8 +115,12 @@ CPP_MODE_TT := $(shell [ "$(CONFIG_MODE_TT)" = "y" ] && echo -DMODE_TT) CONFIG_KERNEL_STACK_ORDER ?= 2 STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] ) +ifndef START + START = $$(($(TOP_ADDR) - $(SIZE))) +endif + AFLAGS_vmlinux.lds.o = $(shell echo -U$(SUBARCH) \ - -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \ + -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \ -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \ -DKERNEL_STACK_SIZE=$(STACK_SIZE)) @@ -207,3 +215,9 @@ $(ARCH_DIR)/util: FORCE $(Q)$(MAKE) $(build)=$@ export SUBARCH USER_CFLAGS OS + +all: linux + +define archhelp + echo '* linux - Binary kernel image (./linux)' +endef diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386 index 36b1f692e..1b7e1639d 100644 --- a/arch/um/Makefile-i386 +++ b/arch/um/Makefile-i386 @@ -4,7 +4,18 @@ else TOP_ADDR = 0xc0000000 endif +ifeq ($(CONFIG_MODE_SKAS),y) + ifneq ($(CONFIG_MODE_TT),y) + START = 0x8048000 + endif +endif + CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) + +ifneq ($(CONFIG_GPROF),y) +ARCH_CFLAGS += -DUM_FASTCALL +endif + ELF_ARCH = $(SUBARCH) ELF_FORMAT = elf32-$(SUBARCH) diff --git a/arch/um/defconfig b/arch/um/defconfig index 1ea71f4d6..ce75425b2 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -14,7 +14,9 @@ CONFIG_MODE_SKAS=y CONFIG_NET=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=y +CONFIG_EXTERNFS=y CONFIG_HOSTFS=y +CONFIG_HUMFS=y CONFIG_HPPFS=y CONFIG_MCONSOLE=y CONFIG_MAGIC_SYSRQ=y @@ -41,8 +43,10 @@ CONFIG_BROKEN_ON_SMP=y # CONFIG_SWAP=y CONFIG_SYSVIPC=y +# CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y CONFIG_SYSCTL=y +# CONFIG_AUDIT is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_HOTPLUG is not set # CONFIG_IKCONFIG is not set @@ -53,6 +57,7 @@ CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # @@ -79,7 +84,8 @@ CONFIG_CON_ZERO_CHAN="fd:0,fd:1" CONFIG_CON_CHAN="xterm" CONFIG_SSL_CHAN="pty" CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_WATCHDOG is not set CONFIG_UML_SOUND=y CONFIG_SOUND=y @@ -130,23 +136,21 @@ CONFIG_INET=y # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set # CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set # CONFIG_INET_AH is not set # CONFIG_INET_ESP 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) # -CONFIG_IPV6_SCTP__=y # CONFIG_IP_SCTP is not set # CONFIG_ATM is not set +# CONFIG_BRIDGE is not set # CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set # CONFIG_LLC2 is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set @@ -167,6 +171,11 @@ CONFIG_IPV6_SCTP__=y # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_HAMRADIO is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set CONFIG_DUMMY=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set @@ -184,6 +193,20 @@ CONFIG_TUN=y # # Ethernet (10000 Mbit) # + +# +# Token Ring devices +# + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set CONFIG_PPP=y # CONFIG_PPP_MULTILINK is not set # CONFIG_PPP_FILTER is not set @@ -196,36 +219,8 @@ CONFIG_SLIP=y # CONFIG_SLIP_COMPRESSED is not set # CONFIG_SLIP_SMART is not set # CONFIG_SLIP_MODE_SLIP6 is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# # CONFIG_SHAPER is not set - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# Amateur Radio support -# -# CONFIG_HAMRADIO is not set - -# -# IrDA (infrared) support -# -# CONFIG_IRDA is not set - -# -# Bluetooth support -# -# CONFIG_BT is not set +# CONFIG_NETCONSOLE is not set # # File systems @@ -237,6 +232,7 @@ CONFIG_EXT2_FS=y CONFIG_REISERFS_FS=y # CONFIG_REISERFS_CHECK is not set # CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_REISERFS_FS_XATTR is not set # CONFIG_JFS_FS is not set # CONFIG_XFS_FS is not set CONFIG_MINIX_FS=y @@ -269,6 +265,7 @@ CONFIG_VFAT_FS=y # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +CONFIG_SYSFS=y CONFIG_DEVFS_FS=y CONFIG_DEVFS_MOUNT=y # CONFIG_DEVFS_DEBUG is not set @@ -372,6 +369,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" # Library routines # # CONFIG_CRC32 is not set +# CONFIG_LIBCRC32C is not set # # SCSI support diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile index 7dd15474b..ba1aabbd7 100644 --- a/arch/um/drivers/Makefile +++ b/arch/um/drivers/Makefile @@ -15,7 +15,7 @@ mcast-objs := mcast_kern.o mcast_user.o #pcap-objs := pcap_kern.o pcap_user.o $(PCAP) net-objs := net_kern.o net_user.o mconsole-objs := mconsole_kern.o mconsole_user.o -hostaudio-objs := hostaudio_kern.o hostaudio_user.o +hostaudio-objs := hostaudio_kern.o ubd-objs := ubd_kern.o ubd_user.o port-objs := port_kern.o port_user.o harddog-objs := harddog_kern.o harddog_user.o diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 56e19fa7b..9ffd30050 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -17,6 +17,7 @@ #include "irq_user.h" #include "sigio.h" #include "line.h" +#include "os.h" static void *not_configged_init(char *str, int device, struct chan_opts *opts) { @@ -87,6 +88,54 @@ static struct chan_ops not_configged_ops = { .winch = 0, }; +void generic_close(int fd, void *unused) +{ + os_close_file(fd); +} + +int generic_read(int fd, char *c_out, void *unused) +{ + int n; + + n = os_read_file(fd, c_out, sizeof(*c_out)); + + if(n == -EAGAIN) + return(0); + else if(n == 0) + return(-EIO); + return(n); +} + +/* XXX Trivial wrapper around os_write_file */ + +int generic_write(int fd, const char *buf, int n, void *unused) +{ + return(os_write_file(fd, buf, n)); +} + +int generic_window_size(int fd, void *unused, unsigned short *rows_out, + unsigned short *cols_out) +{ + int rows, cols; + int ret; + + ret = os_window_size(fd, &rows, &cols); + if(ret < 0) + return(ret); + + ret = ((*rows_out != rows) || (*cols_out != cols)); + + *rows_out = rows; + *cols_out = cols; + + return(ret); +} + +void generic_free(void *data) +{ + kfree(data); +} + static void tty_receive_char(struct tty_struct *tty, char ch) { if(tty == NULL) return; diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 7319ddd17..bbc5b4c28 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -21,31 +21,19 @@ #include "choose-mode.h" #include "mode.h" -void generic_close(int fd, void *unused) +static void winch_handler(int sig) { - os_close_file(fd); } -int generic_read(int fd, char *c_out, void *unused) -{ - int n; - - n = os_read_file(fd, c_out, sizeof(*c_out)); - - if(n == -EAGAIN) - return(0); - else if(n == 0) - return(-EIO); - return(n); -} - -/* XXX Trivial wrapper around os_write_file */ - -int generic_write(int fd, const char *buf, int n, void *unused) -{ - return(os_write_file(fd, buf, n)); -} +struct winch_data { + int pty_fd; + int pipe_fd; + int close_me; +}; +/* XXX This breaks horribly (by hanging UML) when moved to chan_kern.c - + * needs investigation + */ int generic_console_write(int fd, const char *buf, int n, void *unused) { struct termios save, new; @@ -62,39 +50,6 @@ int generic_console_write(int fd, const char *buf, int n, void *unused) return(err); } -int generic_window_size(int fd, void *unused, unsigned short *rows_out, - unsigned short *cols_out) -{ - int rows, cols; - int ret; - - ret = os_window_size(fd, &rows, &cols); - if(ret < 0) - return(ret); - - ret = ((*rows_out != rows) || (*cols_out != cols)); - - *rows_out = rows; - *cols_out = cols; - - return(ret); -} - -void generic_free(void *data) -{ - kfree(data); -} - -static void winch_handler(int sig) -{ -} - -struct winch_data { - int pty_fd; - int pipe_fd; - int close_me; -}; - static int winch_thread(void *arg) { struct winch_data *data = arg; diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c index 014c2c853..9627e3fad 100644 --- a/arch/um/drivers/cow_user.c +++ b/arch/um/drivers/cow_user.c @@ -27,8 +27,8 @@ struct cow_header_v1 { #define PATH_LEN_V2 MAXPATHLEN struct cow_header_v2 { - unsigned long magic; - unsigned long version; + __u32 magic; + __u32 version; char backing_file[PATH_LEN_V2]; time_t mtime; __u64 size; diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c index 33c6c7868..42cba3fe6 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "user.h" #include "user_util.h" #include "chan_user.h" @@ -45,10 +46,16 @@ void *fd_init(char *str, int device, struct chan_opts *opts) int fd_open(int input, int output, int primary, void *d, char **dev_out) { struct fd_chan *data = d; + int err; if(data->raw && isatty(data->fd)){ - tcgetattr(data->fd, &data->tt); - raw(data->fd, 0); + CATCH_EINTR(err = tcgetattr(data->fd, &data->tt)); + if(err) + return(err); + + err = raw(data->fd); + if(err) + return(err); } sprintf(data->str, "%d", data->fd); *dev_out = data->str; @@ -58,9 +65,13 @@ int fd_open(int input, int output, int primary, void *d, char **dev_out) void fd_close(int fd, void *d) { struct fd_chan *data = d; + int err; if(data->raw && isatty(fd)){ - tcsetattr(fd, TCSAFLUSH, &data->tt); + CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &data->tt)); + if(err) + printk("Failed to restore terminal state - " + "errno = %d\n", -err); data->raw = 0; } } diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index 9f9ae2730..7f965c832 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c @@ -13,7 +13,18 @@ #include "asm/uaccess.h" #include "kern_util.h" #include "init.h" -#include "hostaudio.h" +#include "os.h" + +struct hostaudio_state { + int fd; +}; + +struct hostmixer_state { + int fd; +}; + +#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp" +#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer" /* Only changed from linux_main at boot time */ char *dsp = HOSTAUDIO_DEV_DSP; @@ -24,7 +35,7 @@ char *mixer = HOSTAUDIO_DEV_MIXER; " The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n" #define MIXER_HELP \ -" This is used to specify the host mixer device to the hostaudio driver.\n" \ +" This is used to specify the host mixer device to the hostaudio driver.\n"\ " The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n" #ifndef MODULE @@ -71,7 +82,7 @@ static ssize_t hostaudio_read(struct file *file, char *buffer, size_t count, if(kbuf == NULL) return(-ENOMEM); - err = hostaudio_read_user(state, kbuf, count, ppos); + err = os_read_file(state->fd, kbuf, count); if(err < 0) goto out; @@ -102,9 +113,10 @@ static ssize_t hostaudio_write(struct file *file, const char *buffer, if(copy_from_user(kbuf, buffer, count)) goto out; - err = hostaudio_write_user(state, kbuf, count, ppos); + err = os_write_file(state->fd, kbuf, count); if(err < 0) goto out; + *ppos += err; out: kfree(kbuf); @@ -147,7 +159,7 @@ static int hostaudio_ioctl(struct inode *inode, struct file *file, break; } - err = hostaudio_ioctl_user(state, cmd, (unsigned long) &data); + err = os_ioctl_generic(state->fd, cmd, (unsigned long) &data); switch(cmd){ case SNDCTL_DSP_SPEED: @@ -177,17 +189,19 @@ static int hostaudio_open(struct inode *inode, struct file *file) #endif state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL); - if(state == NULL) return(-ENOMEM); + if(state == NULL) + return(-ENOMEM); if(file->f_mode & FMODE_READ) r = 1; if(file->f_mode & FMODE_WRITE) w = 1; - ret = hostaudio_open_user(state, r, w, dsp); + ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); if(ret < 0){ kfree(state); return(ret); } + state->fd = ret; file->private_data = state; return(0); } @@ -195,16 +209,15 @@ static int hostaudio_open(struct inode *inode, struct file *file) static int hostaudio_release(struct inode *inode, struct file *file) { struct hostaudio_state *state = file->private_data; - int ret; #ifdef DEBUG printk("hostaudio: release called\n"); #endif - ret = hostaudio_release_user(state); + os_close_file(state->fd); kfree(state); - return(ret); + return(0); } /* /dev/mixer file operations */ @@ -218,7 +231,7 @@ static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file, printk("hostmixer: ioctl called\n"); #endif - return(hostmixer_ioctl_mixdev_user(state, cmd, arg)); + return(os_ioctl_generic(state->fd, cmd, arg)); } static int hostmixer_open_mixdev(struct inode *inode, struct file *file) @@ -237,9 +250,11 @@ static int hostmixer_open_mixdev(struct inode *inode, struct file *file) if(file->f_mode & FMODE_READ) r = 1; if(file->f_mode & FMODE_WRITE) w = 1; - ret = hostmixer_open_mixdev_user(state, r, w, mixer); + ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); if(ret < 0){ + printk("hostaudio_open_mixdev failed to open '%s', err = %d\n", + dsp, -ret); kfree(state); return(ret); } @@ -251,16 +266,15 @@ static int hostmixer_open_mixdev(struct inode *inode, struct file *file) static int hostmixer_release(struct inode *inode, struct file *file) { struct hostmixer_state *state = file->private_data; - int ret; #ifdef DEBUG printk("hostmixer: release called\n"); #endif - ret = hostmixer_release_mixdev_user(state); + os_close_file(state->fd); kfree(state); - return(ret); + return(0); } diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index d8af1449e..3396ba494 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -51,27 +51,26 @@ static struct notifier_block reboot_notifier = { LIST_HEAD(mc_requests); -void mc_work_proc(void *unused) +static void mc_work_proc(void *unused) { struct mconsole_entry *req; unsigned long flags; - int done; - do { + while(!list_empty(&mc_requests)){ local_save_flags(flags); req = list_entry(mc_requests.next, struct mconsole_entry, list); list_del(&req->list); - done = list_empty(&mc_requests); local_irq_restore(flags); req->request.cmd->handler(&req->request); kfree(req); - } while(!done); + } } DECLARE_WORK(mconsole_work, mc_work_proc, NULL); -irqreturn_t mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t mconsole_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { int fd; struct mconsole_entry *new; @@ -91,7 +90,8 @@ irqreturn_t mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) } } } - if(!list_empty(&mc_requests)) schedule_work(&mconsole_work); + if(!list_empty(&mc_requests)) + schedule_work(&mconsole_work); reactivate_fd(fd, MCONSOLE_IRQ); return(IRQ_HANDLED); } @@ -374,8 +374,8 @@ void mconsole_sysrq(struct mc_request *req) ptr += strlen("sysrq"); while(isspace(*ptr)) ptr++; - handle_sysrq(*ptr, ¤t->thread.regs, NULL); mconsole_reply(req, "", 0, 0); + handle_sysrq(*ptr, ¤t->thread.regs, NULL); } #else void mconsole_sysrq(struct mc_request *req) diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index c97dbe0ee..20c473221 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -19,6 +19,8 @@ #include "linux/inetdevice.h" #include "linux/ctype.h" #include "linux/bootmem.h" +#include "linux/ethtool.h" +#include "asm/uaccess.h" #include "user_util.h" #include "kern_util.h" #include "net_kern.h" @@ -240,7 +242,30 @@ static int uml_net_change_mtu(struct net_device *dev, int new_mtu) static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - return(-EINVAL); + static const struct ethtool_drvinfo info = { + .cmd = ETHTOOL_GDRVINFO, + .driver = "uml virtual ethernet", + .version = "42", + }; + void *useraddr; + u32 ethcmd; + + switch (cmd) { + case SIOCETHTOOL: + useraddr = ifr->ifr_data; + if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) + return -EFAULT; + switch (ethcmd) { + case ETHTOOL_GDRVINFO: + if (copy_to_user(useraddr, &info, sizeof(info))) + return -EFAULT; + return 0; + default: + return -EOPNOTSUPP; + } + default: + return -EINVAL; + } } void uml_net_user_timer_expire(unsigned long _conn) diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index c9fc2862e..8753188a5 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c @@ -173,9 +173,10 @@ static int change_tramp(char **argv, char *output, int output_len) pe_data.stdout = fds[1]; pid = run_helper(change_pre_exec, &pe_data, argv, NULL); - os_close_file(fds[1]); read_output(fds[0], output, output_len); - waitpid(pid, NULL, 0); + os_close_file(fds[0]); + os_close_file(fds[1]); + CATCH_EINTR(waitpid(pid, NULL, 0)); return(pid); } diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index 8dbad9412..92a6d4e79 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -76,12 +76,17 @@ void port_free(void *d) int port_open(int input, int output, int primary, void *d, char **dev_out) { struct port_chan *data = d; - int fd; + int fd, err; fd = port_wait(data->kernel_data); if((fd >= 0) && data->raw){ - tcgetattr(fd, &data->tt); - raw(fd, 0); + CATCH_EINTR(err = tcgetattr(fd, &data->tt)); + if(err) + return(err); + + err = raw(fd); + if(err) + return(err); } *dev_out = data->dev; return(fd); @@ -118,12 +123,18 @@ struct chan_ops port_ops = { int port_listen_fd(int port) { struct sockaddr_in addr; - int fd, err; + int fd, err, arg; fd = socket(PF_INET, SOCK_STREAM, 0); if(fd == -1) return(-errno); + arg = 1; + if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){ + err = -errno; + goto out; + } + addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c index bfa08d812..d67417150 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -38,7 +38,7 @@ int pts_open(int input, int output, int primary, void *d, char **dev_out) { struct pty_chan *data = d; char *dev; - int fd; + int fd, err; fd = get_pty(); if(fd < 0){ @@ -46,8 +46,13 @@ int pts_open(int input, int output, int primary, void *d, char **dev_out) return(-errno); } if(data->raw){ - tcgetattr(fd, &data->tt); - raw(fd, 0); + CATCH_EINTR(err = tcgetattr(fd, &data->tt)); + if(err) + return(err); + + err = raw(fd); + if(err) + return(err); } dev = ptsname(fd); @@ -89,13 +94,19 @@ int getmaster(char *line) int pty_open(int input, int output, int primary, void *d, char **dev_out) { struct pty_chan *data = d; - int fd; + int fd, err; char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx"; fd = getmaster(dev); - if(fd < 0) return(-errno); + if(fd < 0) + return(-errno); + + if(data->raw){ + err = raw(fd); + if(err) + return(err); + } - if(data->raw) raw(fd, 0); if(data->announce) (*data->announce)(dev, data->dev); sprintf(data->dev_name, "%s", dev); diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index 1a5255925..3d8d4ca36 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include @@ -100,7 +100,9 @@ static int slip_tramp(char **argv, int fd) printk("%s", output); kfree(output); } - if(waitpid(pid, &status, 0) < 0) err = errno; + CATCH_EINTR(err = waitpid(pid, &status, 0)); + if(err < 0) + err = errno; else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ printk("'%s' didn't exit with status 0\n", argv[0]); err = -EINVAL; diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c index edb45d9b0..e95fcabbb 100644 --- a/arch/um/drivers/slirp_user.c +++ b/arch/um/drivers/slirp_user.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include #include "user_util.h" @@ -113,13 +113,13 @@ static void slirp_close(int fd, void *data) } #endif - err = waitpid(pri->pid, &status, WNOHANG); - if(err<0) { + CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG)); + if(err < 0) { printk("slirp_close: waitpid returned %d\n", errno); return; } - if(err==0) { + if(err == 0) { printk("slirp_close: process %d has not exited\n"); return; } diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c index b3676e9dc..54aadefe2 100644 --- a/arch/um/drivers/tty.c +++ b/arch/um/drivers/tty.c @@ -41,13 +41,18 @@ void *tty_chan_init(char *str, int device, struct chan_opts *opts) int tty_open(int input, int output, int primary, void *d, char **dev_out) { struct tty_chan *data = d; - int fd; + int fd, err; fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0); if(fd < 0) return(fd); if(data->raw){ - tcgetattr(fd, &data->tt); - raw(fd, 0); + CATCH_EINTR(err = tcgetattr(fd, &data->tt)); + if(err) + return(err); + + err = raw(fd); + if(err) + return(err); } *dev_out = data->dev; diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index ee47b820f..bad209bf2 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -1004,7 +1004,7 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req) * to write the data to disk first, then we can map the disk * page in and continue normally from there. */ - if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){ + if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer, dev->fd, io_req->offset + dev->cow.data_offset)){ io_req->map_fd = dev->fd; io_req->map_offset = io_req->offset + dev->cow.data_offset; @@ -1134,12 +1134,20 @@ static int ubd_ioctl(struct inode * inode, struct file * file, } static int ubd_check_remapped(int fd, unsigned long address, int is_write, - __u64 offset) + __u64 offset, int is_user) { __u64 bitmap_offset; unsigned long new_bitmap[2]; int i, err, n; + /* This can only fix kernelspace faults */ + if(is_user) + return(0); + + /* ubd-mmap is only enabled in skas mode */ + if(CHOOSE_MODE(1, 0)) + return(0); + /* If it's not a write access, we can't do anything about it */ if(!is_write) return(0); diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c index 28458a6e6..400c2a08d 100644 --- a/arch/um/drivers/ubd_user.c +++ b/arch/um/drivers/ubd_user.c @@ -44,7 +44,9 @@ static int same_backing_files(char *from_cmdline, char *from_cow, char *cow) printk("Couldn't stat '%s', err = %d\n", from_cow, -err); return(1); } - if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) + if((buf1.ust_major == buf2.ust_major) && + (buf1.ust_minor == buf2.ust_minor) && + (buf1.ust_ino == buf2.ust_ino)) return(1); printk("Backing file mismatch - \"%s\" requested,\n" @@ -189,6 +191,7 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, data_offset_out); if(!err) return(fd); + os_close_file(fd); out: return(err); diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index dccdf3e90..f417b3b66 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -83,6 +83,7 @@ __uml_setup("xterm=", xterm_setup, " are 'xterm=gnome-terminal,-t,-x'.\n\n" ); +/* XXX This badly needs some cleaning up in the error paths */ int xterm_open(int input, int output, int primary, void *d, char **dev_out) { struct xterm_chan *data = d; @@ -141,8 +142,19 @@ int xterm_open(int input, int output, int primary, void *d, char **dev_out) goto out; } - tcgetattr(new, &data->tt); - if(data->raw) raw(new, 0); + CATCH_EINTR(err = tcgetattr(new, &data->tt)); + if(err){ + new = err; + goto out; + } + + if(data->raw){ + err = raw(new); + if(err){ + new = err; + goto out; + } + } data->pid = pid; *dev_out = NULL; diff --git a/arch/um/dyn.lds.S b/arch/um/dyn.lds.S index f1df3485f..a331e2bde 100644 --- a/arch/um/dyn.lds.S +++ b/arch/um/dyn.lds.S @@ -5,9 +5,6 @@ OUTPUT_ARCH(ELF_ARCH) ENTRY(_start) jiffies = jiffies_64; -SEARCH_DIR("/usr/local/i686-pc-linux-gnu/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); -/* Do we need any of these for elf? - __DYNAMIC = 0; */ SECTIONS { . = START + SIZEOF_HEADERS; diff --git a/arch/um/include/init.h b/arch/um/include/init.h index f1d82e025..52c393fa3 100644 --- a/arch/um/include/init.h +++ b/arch/um/include/init.h @@ -100,6 +100,16 @@ extern struct uml_param __uml_setup_start, __uml_setup_end; #define __uml_postsetup_call __attribute__ ((unused,__section__ (".uml.postsetup.init"))) #define __uml_exit_call __attribute__ ((unused,__section__ (".uml.exitcall.exit"))) +#ifndef __KERNEL__ + +#define __initcall(fn) static initcall_t __initcall_##fn __init_call = fn +#define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn + +#define __init_call __attribute__ ((unused,__section__ (".initcall.init"))) +#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit"))) + +#endif + #endif /* _LINUX_UML_INIT_H */ /* diff --git a/arch/um/include/irq_user.h b/arch/um/include/irq_user.h index 087bd39d0..0df4076ac 100644 --- a/arch/um/include/irq_user.h +++ b/arch/um/include/irq_user.h @@ -14,6 +14,7 @@ extern void free_irq_by_irq_and_dev(int irq, void *dev_id); extern void free_irq_by_fd(int fd); extern void reactivate_fd(int fd, int irqnum); extern void deactivate_fd(int fd, int irqnum); +extern int deactivate_all_fds(void); extern void forward_interrupts(int pid); extern void init_irq_signals(int on_sigstack); extern void forward_ipi(int fd, int pid); diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h index 10c46c389..7d3bc63dd 100644 --- a/arch/um/include/mem.h +++ b/arch/um/include/mem.h @@ -10,7 +10,7 @@ extern int phys_mapping(unsigned long phys, __u64 *offset_out); extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w); -extern int is_remapped(void *virt); +extern int is_remapped(const void *virt, int fd, __u64 offset); extern int physmem_remove_mapping(void *virt); extern void physmem_forget_descriptor(int fd); diff --git a/arch/um/include/mem_kern.h b/arch/um/include/mem_kern.h index b39f03d94..699d46d87 100644 --- a/arch/um/include/mem_kern.h +++ b/arch/um/include/mem_kern.h @@ -11,7 +11,7 @@ struct remapper { struct list_head list; - int (*proc)(int, unsigned long, int, __u64); + int (*proc)(int, unsigned long, int, __u64, int); }; extern void register_remapper(struct remapper *info); diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 269156ede..08a174e9a 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -29,7 +29,8 @@ * (if they are wrong here, they are wrong there...). */ struct uml_stat { - int ust_dev; /* device */ + int ust_major; /* device */ + int ust_minor; unsigned long long ust_ino; /* inode */ int ust_mode; /* protection */ int ust_nlink; /* number of hard links */ @@ -41,6 +42,8 @@ struct uml_stat { unsigned long ust_atime; /* time of last access */ unsigned long ust_mtime; /* time of last modification */ unsigned long ust_ctime; /* time of last change */ + int ust_rmajor; + int ust_rminor; }; struct openflags { @@ -52,10 +55,12 @@ struct openflags { unsigned int a : 1; /* O_APPEND */ unsigned int e : 1; /* O_EXCL */ unsigned int cl : 1; /* FD_CLOEXEC */ + unsigned int d : 1; /* O_DIRECT */ }; #define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \ - .t = 0, .a = 0, .e = 0, .cl = 0 }) + .t = 0, .a = 0, .e = 0, .cl = 0, \ + .d = 0 }) static inline struct openflags of_read(struct openflags flags) { @@ -117,9 +122,20 @@ static inline struct openflags of_cloexec(struct openflags flags) return(flags); } +static inline struct openflags of_direct(struct openflags flags) +{ + flags.d = 1; + return(flags); +} + extern int os_stat_file(const char *file_name, struct uml_stat *buf); +extern int os_lstat_file(const char *file_name, struct uml_stat *ubuf); extern int os_stat_fd(const int fd, struct uml_stat *buf); extern int os_access(const char *file, int mode); +extern int os_set_file_time(const char *file, unsigned long access, + unsigned long mod); +extern int os_set_file_perms(const char *file, int mode); +extern int os_set_file_owner(const char *file, int owner, int group); extern void os_print_error(int error, const char* str); extern int os_get_exec_close(int fd, int *close_on_exec); extern int os_set_exec_close(int fd, int close_on_exec); @@ -134,15 +150,33 @@ extern int os_mode_fd(int fd, int mode); extern int os_seek_file(int fd, __u64 offset); extern int os_open_file(char *file, struct openflags flags, int mode); +extern void *os_open_dir(char *dir, int *err_out); +extern int os_seek_dir(void *stream, unsigned long long pos); +extern int os_read_dir(void *stream, unsigned long long *ino_out, + char **name_out); +extern int os_tell_dir(void *stream); +extern int os_close_dir(void *stream); +extern int os_remove_file(const char *file); +extern int os_move_file(const char *from, const char *to); +extern int os_truncate_file(const char *file, unsigned long long len); +extern int os_truncate_fd(int fd, unsigned long long len); extern int os_read_file(int fd, void *buf, int len); extern int os_write_file(int fd, const void *buf, int count); extern int os_file_size(char *file, long long *size_out); +extern int os_fd_size(int fd, long long *size_out); extern int os_file_modtime(char *file, unsigned long *modtime); extern int os_pipe(int *fd, int stream, int close_on_exec); extern int os_set_fd_async(int fd, int owner); +extern int os_clear_fd_async(int fd); extern int os_set_fd_block(int fd, int blocking); extern int os_accept_connection(int fd); extern int os_create_unix_socket(char *file, int len, int close_on_exec); +extern int os_make_symlink(const char *to, const char *from); +extern int os_read_symlink(const char *file, char *buf, int size); +extern int os_link_file(const char *to, const char *from); +extern int os_make_dir(const char *dir, int mode); +extern int os_remove_dir(const char *dir); +extern int os_make_dev(const char *name, int mode, int major, int minor); 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); @@ -165,6 +199,13 @@ 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); +extern int os_stat_filesystem(char *path, 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); +extern unsigned long long os_usecs(void); #endif diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h index 9ddb749f7..6793a2fcd 100644 --- a/arch/um/include/time_user.h +++ b/arch/um/include/time_user.h @@ -11,6 +11,7 @@ extern void switch_timers(int to_real); extern void set_interval(int timer_type); extern void idle_sleep(int secs); extern void enable_timer(void); +extern void disable_timer(void); extern unsigned long time_lock(void); extern void time_unlock(unsigned long); diff --git a/arch/um/include/user.h b/arch/um/include/user.h index e9cf19eb1..57ee9e261 100644 --- a/arch/um/include/user.h +++ b/arch/um/include/user.h @@ -15,6 +15,8 @@ extern void kfree(void *ptr); extern int in_aton(char *str); extern int open_gdb_chan(void); extern int strlcpy(char *, const char *, int); +extern void *um_vmalloc(int size); +extern void vfree(void *ptr); #endif diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h index 588012843..ab089d7a7 100644 --- a/arch/um/include/user_util.h +++ b/arch/um/include/user_util.h @@ -8,6 +8,8 @@ #include "sysdep/ptrace.h" +#define CATCH_EINTR(expr) while (((expr) < 0) && (errno == EINTR)) + extern int mode_tt; extern int grantpt(int __fd); @@ -62,7 +64,6 @@ extern void set_cmdline(char *cmd); extern void input_cb(void (*proc)(void *), void *arg, int arg_len); extern int get_pty(void); extern void *um_kmalloc(int size); -extern int raw(int fd, int complain); extern int switcheroo(int fd, int prot, void *from, void *to, int size); extern void setup_machinename(char *machine_out); extern void setup_hostinfo(void); @@ -73,7 +74,6 @@ extern void do_exec(int old_pid, int new_pid); extern void tracer_panic(char *msg, ...); extern char *get_umid(int only_if_set); extern void do_longjmp(void *p, int val); -extern void suspend_new_thread(int fd); extern int detach(int pid, int sig); extern int attach(int pid); extern void kill_child_dead(int pid); @@ -89,6 +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); +extern int setjmp_wrapper(void (*proc)(void *, void *), ...); +extern int raw(int fd); #endif diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 70da5fa16..6cce2669d 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -5,13 +5,18 @@ extra-y := vmlinux.lds.s -obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o \ - helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \ - physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \ - sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \ - syscall_kern.o syscall_user.o sysrq.o sys_call_table.o tempfile.o \ - time.o time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o \ - um_arch.o umid.o user_util.o +# Descend into ../util for make clean. This is here because it doesn't work +# in arch/um/Makefile. + +subdir- = ../util + +obj-y = checksum.o config.o exec_kern.o exitcode.o filehandle.o frame_kern.o \ + frame.o helper.o init_task.o irq.o irq_user.o ksyms.o mem.o \ + mem_user.o physmem.o process.o process_kern.o ptrace.o reboot.o \ + resource.o sigio_user.o sigio_kern.o signal_kern.o signal_user.o \ + smp.o syscall_kern.o syscall_user.o sysrq.o sys_call_table.o \ + tempfile.o time.o time_kern.o tlb.o trap_kern.o trap_user.o \ + uaccess_user.o um_arch.o umid.o user_util.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o obj-$(CONFIG_GPROF) += gprof_syms.o diff --git a/arch/um/kernel/frame.c b/arch/um/kernel/frame.c index c18386af5..4b349f207 100644 --- a/arch/um/kernel/frame.c +++ b/arch/um/kernel/frame.c @@ -21,6 +21,7 @@ #include "sysdep/sigcontext.h" #include "frame_user.h" #include "kern_util.h" +#include "user_util.h" #include "ptrace_user.h" #include "os.h" @@ -40,7 +41,7 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp, /* Wait for it to stop itself and continue it with a SIGUSR1 to force * it into the signal handler. */ - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0){ printf("capture_stack : waitpid failed - errno = %d\n", errno); exit(1); @@ -60,7 +61,7 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp, * At this point, the handler has stuffed the addresses of * sig, sc, and SA_RESTORER in raw. */ - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0){ printf("capture_stack : waitpid failed - errno = %d\n", errno); exit(1); @@ -82,7 +83,8 @@ static int capture_stack(int (*child)(void *arg), void *arg, void *sp, errno); exit(1); } - if(waitpid(pid, &status, 0) < 0){ + CATCH_EINTR(n = waitpid(pid, &status, 0)); + if(n < 0){ printf("capture_stack : waitpid failed - errno = %d\n", errno); exit(1); } diff --git a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c index 6d0a1f969..29cceb012 100644 --- a/arch/um/kernel/helper.c +++ b/arch/um/kernel/helper.c @@ -12,6 +12,7 @@ #include #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "os.h" struct helper_data { @@ -93,24 +94,20 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, if(n < 0){ printk("run_helper : read on pipe failed, err = %d\n", -n); err = n; - goto out_kill; + os_kill_process(pid, 1); } else if(n != 0){ - waitpid(pid, NULL, 0); + CATCH_EINTR(n = waitpid(pid, NULL, 0)); pid = -errno; } + err = pid; - if(stack_out == NULL) free_stack(stack, 0); - else *stack_out = stack; - return(pid); - - out_kill: - os_kill_process(pid, 1); out_close: os_close_file(fds[0]); - os_close_file(fds[1]); out_free: - free_stack(stack, 0); + if(stack_out == NULL) + free_stack(stack, 0); + else *stack_out = stack; return(err); } diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c index 87ac2b038..38e66ac84 100644 --- a/arch/um/kernel/irq_user.c +++ b/arch/um/kernel/irq_user.c @@ -364,6 +364,20 @@ void deactivate_fd(int fd, int irqnum) irq_unlock(flags); } +int deactivate_all_fds(void) +{ + struct irq_fd *irq; + int err; + + for(irq=active_fds;irq != NULL;irq = irq->next){ + err = os_clear_fd_async(irq->fd); + if(err) + return(err); + } + + return(0); +} + void forward_ipi(int fd, int pid) { int err; diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c index 4ed2807bc..74c9c2203 100644 --- a/arch/um/kernel/ksyms.c +++ b/arch/um/kernel/ksyms.c @@ -50,11 +50,13 @@ EXPORT_SYMBOL(handle_page_fault); EXPORT_SYMBOL(find_iomem); #ifdef CONFIG_MODE_TT +EXPORT_SYMBOL(strncpy_from_user_tt); EXPORT_SYMBOL(copy_from_user_tt); EXPORT_SYMBOL(copy_to_user_tt); #endif #ifdef CONFIG_MODE_SKAS +EXPORT_SYMBOL(strncpy_from_user_skas); EXPORT_SYMBOL(copy_to_user_skas); EXPORT_SYMBOL(copy_from_user_skas); #endif @@ -85,6 +87,7 @@ EXPORT_SYMBOL(os_shutdown_socket); EXPORT_SYMBOL(os_create_unix_socket); EXPORT_SYMBOL(os_connect_socket); EXPORT_SYMBOL(os_accept_connection); +EXPORT_SYMBOL(os_ioctl_generic); EXPORT_SYMBOL(os_rcv_fd); EXPORT_SYMBOL(run_helper); EXPORT_SYMBOL(start_thread); diff --git a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c index c52744b01..b6d6a61b4 100644 --- a/arch/um/kernel/mem_user.c +++ b/arch/um/kernel/mem_user.c @@ -143,7 +143,7 @@ static int __init parse_iomem(char *str, int *add) struct iomem_region *new; struct uml_stat buf; char *file, *driver; - int fd, err; + int fd, err, size; driver = str; file = strchr(str,','); @@ -171,10 +171,12 @@ static int __init parse_iomem(char *str, int *add) goto out_close; } + size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); + *new = ((struct iomem_region) { .next = iomem_regions, .driver = driver, .fd = fd, - .size = buf.ust_size, + .size = size, .phys = 0, .virt = 0 }); iomem_regions = new; @@ -206,6 +208,39 @@ int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, return(0); } +#if 0 +/* Debugging facility for dumping stuff out to the host, avoiding the timing + * problems that come with printf and breakpoints. + * Enable in case of emergency. + */ + +int logging = 1; +int logging_fd = -1; + +int logging_line = 0; +char logging_buf[512]; + +void log(char *fmt, ...) +{ + va_list ap; + struct timeval tv; + struct openflags flags; + + if(logging == 0) return; + if(logging_fd < 0){ + flags = of_create(of_trunc(of_rdwr(OPENFLAGS()))); + logging_fd = os_open_file("log", flags, 0644); + } + gettimeofday(&tv, NULL); + sprintf(logging_buf, "%d\t %u.%u ", logging_line++, tv.tv_sec, + tv.tv_usec); + va_start(ap, fmt); + vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap); + va_end(ap); + write(logging_fd, logging_buf, strlen(logging_buf)); +} +#endif + /* * 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 --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c index d0e0f50dc..258e158a5 100644 --- a/arch/um/kernel/physmem.c +++ b/arch/um/kernel/physmem.c @@ -122,14 +122,19 @@ int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) unsigned long phys; int err; + phys = __pa(virt); + desc = find_virtmem_hash(&virtmem_hash, (void *) virt); + if(desc != NULL){ + if((virt != desc->virt) || (fd != desc->fd) || + (offset != desc->offset)) + panic("Address 0x%p is already substituted\n", virt); + return(0); + } + fd_maps = descriptor_mapping(fd); if(fd_maps == NULL) return(-ENOMEM); - phys = __pa(virt); - if(find_virtmem_hash(&virtmem_hash, virt) != NULL) - panic("Address 0x%p is already substituted\n", virt); - err = -ENOMEM; desc = kmalloc(sizeof(*desc), GFP_ATOMIC); if(desc == NULL) @@ -200,6 +205,9 @@ void physmem_forget_descriptor(int fd) if(desc == NULL) return; + if(!list_empty(&desc->pages)) + printk("Still have mapped pages on fd %d\n", fd); + list_for_each_safe(ele, next, &desc->pages){ page = list_entry(ele, struct phys_desc, list); offset = page->offset; @@ -232,9 +240,16 @@ void arch_free_page(struct page *page, int order) } } -int is_remapped(void *virt) +int is_remapped(const void *virt, int fd, __u64 offset) { - return(find_virtmem_hash(&virtmem_hash, virt) != NULL); + struct phys_desc *desc; + + desc = find_virtmem_hash(&virtmem_hash, (void *) virt); + if(desc == NULL) + return(0); + if(offset != desc->offset) + printk("offset mismatch\n"); + return(find_virtmem_hash(&virtmem_hash, (void *) virt) != NULL); } /* Changed during early boot */ diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 01ad09884..694a9c9f4 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -45,7 +45,7 @@ void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) int flags = 0, pages; if(sig_stack != NULL){ - pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2; + pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER); set_sigstack(sig_stack, pages * page_size()); flags = SA_ONSTACK; } @@ -56,11 +56,7 @@ void init_new_thread_signals(int altstack) { int flags = altstack ? SA_ONSTACK : 0; - /* NODEFER is set here because SEGV isn't turned back on when the - * handler is ready to receive signals. This causes any segfault - * during a copy_user to kill the process because the fault is blocked. - */ - set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags | SA_NODEFER, + set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); @@ -73,7 +69,7 @@ void init_new_thread_signals(int altstack) set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); set_handler(SIGUSR2, (__sighandler_t) sig_handler, - SA_NOMASK | flags, -1); + flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); signal(SIGHUP, SIG_IGN); init_irq_signals(altstack); @@ -123,10 +119,14 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack, /* Start the process and wait for it to kill itself */ new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg); - if(new_pid < 0) return(-errno); - while(((err = waitpid(new_pid, &status, 0)) < 0) && (errno == EINTR)) ; - if(err < 0) panic("Waiting for outer trampoline failed - errno = %d", - errno); + if(new_pid < 0) + return(new_pid); + + CATCH_EINTR(err = waitpid(new_pid, &status, 0)); + 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, " "status = %d", status); @@ -134,16 +134,6 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack, return(arg.pid); } -void suspend_new_thread(int fd) -{ - char c; - - os_stop_process(os_getpid()); - - if(os_read_file(fd, &c, sizeof(c)) != sizeof(c)) - panic("read failed in suspend_new_thread"); -} - static int ptrace_child(void *arg) { int pid = os_getpid(); @@ -170,7 +160,7 @@ static int start_ptraced_child(void **stack_out) pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); if(pid < 0) panic("check_ptrace : clone failed, errno = %d", errno); - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("check_ptrace : wait failed, errno = %d", errno); if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) @@ -187,7 +177,7 @@ static void stop_ptraced_child(int pid, void *stack, int exitcode) if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) panic("check_ptrace : ptrace failed, errno = %d", errno); - n = waitpid(pid, &status, 0); + CATCH_EINTR(n = waitpid(pid, &status, 0)); if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) panic("check_ptrace : child exited with status 0x%x", status); @@ -207,7 +197,7 @@ void __init check_ptrace(void) if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) panic("check_ptrace : ptrace failed, errno = %d", errno); - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("check_ptrace : wait failed, errno = %d", errno); if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) @@ -231,7 +221,7 @@ void __init check_ptrace(void) int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) { - jmp_buf buf; + sigjmp_buf buf; int n; *jmp_ptr = &buf; diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index ea000e6bc..8eb2d3b47 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -16,6 +16,7 @@ #include "linux/module.h" #include "linux/init.h" #include "linux/capability.h" +#include "linux/vmalloc.h" #include "linux/spinlock.h" #include "asm/unistd.h" #include "asm/mman.h" @@ -164,8 +165,6 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, struct pt_regs *regs) { p->thread = (struct thread_struct) INIT_THREAD; - p->thread.kernel_stack = - (unsigned long) p->thread_info + 2 * PAGE_SIZE; return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, clone_flags, sp, stack_top, p, regs)); } @@ -301,6 +300,11 @@ void *um_kmalloc_atomic(int size) return(kmalloc(size, GFP_ATOMIC)); } +void *um_vmalloc(int size) +{ + return(vmalloc(size)); +} + unsigned long get_fault_addr(void) { return((unsigned long) current->thread.fault_addr); @@ -320,8 +324,7 @@ int user_context(unsigned long sp) unsigned long stack; stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER); - stack += 2 * PAGE_SIZE; - return(stack != current->thread.kernel_stack); + return(stack != (unsigned long) current_thread); } extern void remove_umid_dir(void); diff --git a/arch/um/kernel/sigio_kern.c b/arch/um/kernel/sigio_kern.c index 92658eaa4..2cb3911ad 100644 --- a/arch/um/kernel/sigio_kern.c +++ b/arch/um/kernel/sigio_kern.c @@ -16,7 +16,7 @@ /* Protected by sigio_lock() called from write_sigio_workaround */ static int sigio_irq_fd = -1; -irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused) +static 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); @@ -25,10 +25,14 @@ irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused) int write_sigio_irq(int fd) { - if(um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, - SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", - NULL)){ - printk("write_sigio_irq : um_request_irq failed\n"); + int err; + + err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, + SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", + NULL); + if(err){ + printk("write_sigio_irq : um_request_irq failed, err = %d\n", + err); return(-1); } sigio_irq_fd = fd; diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index 6a9b38978..80fe2cd76 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c @@ -16,6 +16,7 @@ #include "init.h" #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "sigio.h" #include "helper.h" #include "os.h" @@ -50,7 +51,6 @@ static void openpty_cb(void *arg) void __init check_one_sigio(void (*proc)(int, int)) { struct sigaction old, new; - struct termios tt; struct openpty_arg pty = { .master = -1, .slave = -1 }; int master, slave, err; @@ -68,12 +68,10 @@ void __init check_one_sigio(void (*proc)(int, int)) return; } - /* XXX These can fail with EINTR */ - if(tcgetattr(master, &tt) < 0) - panic("check_sigio : tcgetattr failed, errno = %d\n", errno); - cfmakeraw(&tt); - if(tcsetattr(master, TCSADRAIN, &tt) < 0) - panic("check_sigio : tcsetattr failed, errno = %d\n", errno); + /* Not now, but complain so we now where we failed. */ + err = raw(master); + if (err < 0) + panic("check_sigio : __raw failed, errno = %d\n", -err); err = os_sigio_async(master, slave); if(err < 0) diff --git a/arch/um/kernel/skas/exec_user.c b/arch/um/kernel/skas/exec_user.c index c9942b6fc..d50633a70 100644 --- a/arch/um/kernel/skas/exec_user.c +++ b/arch/um/kernel/skas/exec_user.c @@ -11,6 +11,7 @@ #include #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "os.h" #include "time_user.h" @@ -26,7 +27,7 @@ static int user_thread_tramp(void *arg) int user_thread(unsigned long stack, int flags) { - int pid, status; + int pid, status, err; pid = clone(user_thread_tramp, (void *) stack_sp(stack), flags | CLONE_FILES | SIGCHLD, NULL); @@ -35,7 +36,8 @@ int user_thread(unsigned long stack, int flags) return(pid); } - if(waitpid(pid, &status, WUNTRACED) < 0){ + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); + if(err < 0){ printk("user_thread - waitpid failed, errno = %d\n", errno); return(-errno); } diff --git a/arch/um/kernel/skas/include/mode.h b/arch/um/kernel/skas/include/mode.h index aa16dc0d8..ca5b84058 100644 --- a/arch/um/kernel/skas/include/mode.h +++ b/arch/um/kernel/skas/include/mode.h @@ -6,6 +6,8 @@ #ifndef __MODE_SKAS_H__ #define __MODE_SKAS_H__ +#include + extern unsigned long exec_regs[]; extern unsigned long exec_fp_regs[]; extern unsigned long exec_fpx_regs[]; diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c index 7e489869d..a1a6b8d90 100644 --- a/arch/um/kernel/skas/process.c +++ b/arch/um/kernel/skas/process.c @@ -78,7 +78,7 @@ static void handle_trap(int pid, union uml_pt_regs *regs) panic("handle_trap - continuing to end of syscall failed, " "errno = %d\n", errno); - err = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) panic("handle_trap - failed to wait at end of syscall, " "errno = %d, status = %d\n", errno, status); @@ -117,7 +117,7 @@ void start_userspace(int cpu) panic("start_userspace : clone failed, errno = %d", errno); do { - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("start_userspace : wait failed, errno = %d", errno); @@ -144,7 +144,7 @@ void userspace(union uml_pt_regs *regs) panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", errno); while(1){ - err = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); if(err < 0) panic("userspace - waitpid failed, errno = %d\n", errno); @@ -190,7 +190,7 @@ void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, void (*handler)(int)) { unsigned long flags; - jmp_buf switch_buf, fork_buf; + sigjmp_buf switch_buf, fork_buf; *switch_buf_ptr = &switch_buf; *fork_buf_ptr = &fork_buf; @@ -214,7 +214,7 @@ void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, void thread_wait(void *sw, void *fb) { - jmp_buf buf, **switch_buf = sw, *fork_buf; + sigjmp_buf buf, **switch_buf = sw, *fork_buf; *switch_buf = &buf; fork_buf = fb; @@ -276,23 +276,23 @@ void restore_registers(union uml_pt_regs *regs) void switch_threads(void *me, void *next) { - jmp_buf my_buf, **me_ptr = me, *next_buf = next; + sigjmp_buf my_buf, **me_ptr = me, *next_buf = next; *me_ptr = &my_buf; if(sigsetjmp(my_buf, 1) == 0) siglongjmp(*next_buf, 1); } -static jmp_buf initial_jmpbuf; +static sigjmp_buf initial_jmpbuf; /* XXX Make these percpu */ static void (*cb_proc)(void *arg); static void *cb_arg; -static jmp_buf *cb_back; +static sigjmp_buf *cb_back; int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) { - jmp_buf **switch_buf = switch_buf_ptr; + sigjmp_buf **switch_buf = switch_buf_ptr; int n; *fork_buf_ptr = &initial_jmpbuf; @@ -328,7 +328,7 @@ void remove_sigstack(void) void initial_thread_cb_skas(void (*proc)(void *), void *arg) { - jmp_buf here; + sigjmp_buf here; cb_proc = proc; cb_arg = arg; @@ -356,28 +356,6 @@ void reboot_skas(void) siglongjmp(initial_jmpbuf, 4); } -int new_mm(int from) -{ - struct proc_mm_op copy; - int n, fd = os_open_file("/proc/mm", - of_cloexec(of_write(OPENFLAGS())), 0); - - if(fd < 0) - return(fd); - - if(from != -1){ - copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, - .u = - { .copy_segments = from } } ); - n = os_write_file(fd, ©, sizeof(copy)); - if(n != sizeof(copy)) - printk("new_mm : /proc/mm copy_segments failed, " - "err = %d\n", -n); - } - - return(fd); -} - void switch_mm_skas(int mm_fd) { int err; diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index ec62366ac..e16309d53 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c @@ -16,6 +16,8 @@ #include "frame.h" #include "kern.h" #include "mode.h" +#include "filehandle.h" +#include "proc_mm.h" int singlestepping_skas(void) { @@ -130,12 +132,33 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, handler = new_thread_handler; } - new_thread((void *) p->thread.kernel_stack, - &p->thread.mode.skas.switch_buf, + new_thread(p->thread_info, &p->thread.mode.skas.switch_buf, &p->thread.mode.skas.fork_buf, handler); return(0); } +int new_mm(int from) +{ + struct proc_mm_op copy; + int n, fd; + + fd = open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0); + if(fd < 0) + return(fd); + + if(from != -1){ + copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, + .u = + { .copy_segments = from } } ); + n = os_write_file(fd, ©, sizeof(copy)); + if(n != sizeof(copy)) + printk("new_mm : /proc/mm copy_segments failed, " + "err = %d\n", -n); + } + + return(fd); +} + void init_idle_skas(void) { cpu_tasks[current_thread->cpu].pid = os_getpid(); @@ -164,13 +187,13 @@ int start_uml_skas(void) { start_userspace(0); capture_signal_stack(); - uml_idle_timer(); init_new_thread_signals(1); + uml_idle_timer(); init_task.thread.request.u.thread.proc = start_kernel_proc; init_task.thread.request.u.thread.arg = NULL; - return(start_idle_thread((void *) init_task.thread.kernel_stack, + return(start_idle_thread(init_task.thread_info, &init_task.thread.mode.skas.switch_buf, &init_task.thread.mode.skas.fork_buf)); } diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c index 2c47e78c1..96593709a 100644 --- a/arch/um/kernel/skas/trap_user.c +++ b/arch/um/kernel/skas/trap_user.c @@ -19,8 +19,10 @@ void sig_handler_common_skas(int sig, void *sc_ptr) struct skas_regs *r; struct signal_info *info; int save_errno = errno; + int save_user; r = &TASK_REGS(get_current())->skas; + save_user = r->is_user; r->is_user = 0; r->fault_addr = SC_FAULT_ADDR(sc); r->fault_type = SC_FAULT_TYPE(sc); @@ -33,6 +35,7 @@ void sig_handler_common_skas(int sig, void *sc_ptr) (*info->handler)(sig, (union uml_pt_regs *) r); errno = save_errno; + r->is_user = save_user; } void user_signal(int sig, union uml_pt_regs *regs) diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index ea82f19b2..d7ff0b914 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c @@ -12,6 +12,7 @@ #include "asm/pgtable.h" #include "asm/uaccess.h" #include "kern_util.h" +#include "user_util.h" extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, pte_t *pte_out); @@ -25,7 +26,7 @@ static unsigned long maybe_map(unsigned long virt, int is_write) int dummy_code; if(IS_ERR(phys) || (is_write && !pte_write(pte))){ - err = handle_page_fault(virt, 0, is_write, 0, &dummy_code); + err = handle_page_fault(virt, 0, is_write, 1, &dummy_code); if(err) return(0); phys = um_virt_to_phys(current, virt, NULL); @@ -51,37 +52,67 @@ static int do_op(unsigned long addr, int len, int is_write, return(n); } -static int buffer_op(unsigned long addr, int len, int is_write, - int (*op)(unsigned long addr, int len, void *arg), - void *arg) +static void do_buffer_op(void *jmpbuf, void *arg_ptr) { + va_list args = *((va_list *) arg_ptr); + unsigned long addr = va_arg(args, unsigned long); + int len = va_arg(args, int); + int is_write = va_arg(args, int); + int (*op)(unsigned long, int, void *) = va_arg(args, void *); + void *arg = va_arg(args, void *); + int *res = va_arg(args, int *); int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); int remain = len, n; + current->thread.fault_catcher = jmpbuf; n = do_op(addr, size, is_write, op, arg); - if(n != 0) - return(n < 0 ? remain : 0); + if(n != 0){ + *res = (n < 0 ? remain : 0); + goto out; + } addr += size; remain -= size; - if(remain == 0) - return(0); + if(remain == 0){ + *res = 0; + goto out; + } while(addr < ((addr + remain) & PAGE_MASK)){ n = do_op(addr, PAGE_SIZE, is_write, op, arg); - if(n != 0) - return(n < 0 ? remain : 0); + if(n != 0){ + *res = (n < 0 ? remain : 0); + goto out; + } addr += PAGE_SIZE; remain -= PAGE_SIZE; } - if(remain == 0) - return(0); + if(remain == 0){ + *res = 0; + goto out; + } n = do_op(addr, remain, is_write, op, arg); if(n != 0) - return(n < 0 ? remain : 0); - return(0); + *res = (n < 0 ? remain : 0); + else *res = 0; + out: + current->thread.fault_catcher = NULL; +} + +static int buffer_op(unsigned long addr, int len, int is_write, + int (*op)(unsigned long addr, int len, void *arg), + void *arg) +{ + int faulted, res; + + faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg, + &res); + if(!faulted) + return(res); + + return(addr + len - (unsigned long) current->thread.fault_addr); } static int copy_chunk_from_user(unsigned long from, int len, void *arg) diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c index 7c9737c74..6ffb4d046 100644 --- a/arch/um/kernel/smp.c +++ b/arch/um/kernel/smp.c @@ -39,14 +39,6 @@ EXPORT_SYMBOL(cpu_online_map); */ struct cpuinfo_um cpu_data[NR_CPUS]; -spinlock_t um_bh_lock = SPIN_LOCK_UNLOCKED; - -atomic_t global_bh_count; - -/* Not used by UML */ -unsigned char global_irq_holder = NO_PROC_ID; -unsigned volatile long global_irq_lock; - /* Set when the idlers are all forked */ int smp_threads_ready = 0; @@ -65,41 +57,6 @@ void smp_send_reschedule(int cpu) num_reschedules_sent++; } -static void show(char * str) -{ - int cpu = smp_processor_id(); - - printk(KERN_INFO "\n%s, CPU %d:\n", str, cpu); -} - -#define MAXCOUNT 100000000 - -static inline void wait_on_bh(void) -{ - int count = MAXCOUNT; - do { - if (!--count) { - show("wait_on_bh"); - count = ~0; - } - /* nothing .. wait for the other bh's to go away */ - } while (atomic_read(&global_bh_count) != 0); -} - -/* - * This is called when we want to synchronize with - * bottom half handlers. We need to wait until - * no other CPU is executing any bottom half handler. - * - * Don't wait if we're already running in an interrupt - * context or are inside a bh handler. - */ -void synchronize_bh(void) -{ - if (atomic_read(&global_bh_count) && !in_interrupt()) - wait_on_bh(); -} - void smp_send_stop(void) { int i; @@ -159,8 +116,7 @@ static struct task_struct *idle_thread(int cpu) .task = new_task } ); idle_threads[cpu] = new_task; CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c, - sizeof(c)), - ({ panic("skas mode doesn't support SMP"); })); + sizeof(c)), wake_up_forked_process(new_task); return(new_task); } diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c index fa0b710b5..a6e7ff3c5 100644 --- a/arch/um/kernel/time.c +++ b/arch/um/kernel/time.c @@ -53,6 +53,15 @@ void enable_timer(void) errno); } +void disable_timer(void) +{ + struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); + if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) || + (setitimer(ITIMER_REAL, &disable, NULL) < 0)) + printk("disnable_timer - setitimer failed, errno = %d\n", + errno); +} + void switch_timers(int to_real) { struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); @@ -85,49 +94,12 @@ void uml_idle_timer(void) set_interval(ITIMER_REAL); } -static unsigned long long get_host_hz(void) -{ - char mhzline[16], *end; - unsigned long long mhz; - int ret, mult, rest, len; - - ret = cpu_feature("cpu MHz", mhzline, - sizeof(mhzline) / sizeof(mhzline[0])); - if(!ret) - panic ("Could not get host MHZ"); - - mhz = strtoul(mhzline, &end, 10); - - /* This business is to parse a floating point number without using - * floating types. - */ - - rest = 0; - mult = 0; - if(*end == '.'){ - end++; - len = strlen(end); - if(len < 6) - mult = 6 - len; - else if(len > 6) - end[6] = '\0'; - rest = strtoul(end, NULL, 10); - while(mult-- > 0) - rest *= 10; - } - - return(1000000 * mhz + rest); -} - -unsigned long long host_hz = 0; - extern int do_posix_clock_monotonic_gettime(struct timespec *tp); void time_init(void) { struct timespec now; - host_hz = get_host_hz(); if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) panic("Couldn't set SIGVTALRM handler"); set_interval(ITIMER_VIRTUAL); diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c index 7209ba578..c36bff0a9 100644 --- a/arch/um/kernel/time_kern.c +++ b/arch/um/kernel/time_kern.c @@ -20,6 +20,7 @@ #include "user_util.h" #include "time_user.h" #include "mode.h" +#include "os.h" u64 jiffies_64; @@ -42,10 +43,10 @@ unsigned long long sched_clock(void) int timer_irq_inited = 0; static int first_tick; -static unsigned long long prev_tsc; +static unsigned long long prev_usecs; static long long delta; /* Deviation per interval */ -extern unsigned long long host_hz; +#define MILLION 1000000 void timer_irq(union uml_pt_regs *regs) { @@ -60,21 +61,24 @@ void timer_irq(union uml_pt_regs *regs) if(first_tick){ #if defined(CONFIG_UML_REAL_TIME_CLOCK) - unsigned long long tsc; /* We've had 1 tick */ - tsc = time_stamp(); + unsigned long long usecs = os_usecs(); - delta += tsc - prev_tsc; - prev_tsc = tsc; + delta += usecs - prev_usecs; + prev_usecs = usecs; - ticks += (delta * HZ) / host_hz; - delta -= (ticks * host_hz) / HZ; + /* Protect against the host clock being set backwards */ + if(delta < 0) + delta = 0; + + ticks += (delta * HZ) / MILLION; + delta -= (ticks * MILLION) / HZ; #else ticks = 1; #endif } else { - prev_tsc = time_stamp(); + prev_usecs = os_usecs(); first_tick = 1; } @@ -149,7 +153,7 @@ void __udelay(um_udelay_t usecs) { int i, n; - n = (loops_per_jiffy * HZ * usecs) / 1000000; + n = (loops_per_jiffy * HZ * usecs) / MILLION; for(i=0;ipid == 1) { - up_read(&mm->mmap_sem); - yield(); - down_read(&mm->mmap_sem); - goto survive; - } - goto out; + BUG(); } pte = pte_offset_kernel(pmd, page); } while(!pte_present(*pte)); @@ -103,7 +97,6 @@ out_of_memory: down_read(&mm->mmap_sem); goto survive; } - err = -ENOMEM; goto out; } @@ -114,7 +107,7 @@ void register_remapper(struct remapper *info) list_add(&info->list, &physmem_remappers); } -static int check_remapped_addr(unsigned long address, int is_write) +static int check_remapped_addr(unsigned long address, int is_write, int is_user) { struct remapper *remapper; struct list_head *ele; @@ -127,7 +120,7 @@ static int check_remapped_addr(unsigned long address, int is_write) list_for_each(ele, &physmem_remappers){ remapper = list_entry(ele, struct remapper, list); - if((*remapper->proc)(fd, address, is_write, offset)) + if((*remapper->proc)(fd, address, is_write, offset, is_user)) return(1); } @@ -145,7 +138,7 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write, flush_tlb_kernel_vm(); return(0); } - else if(check_remapped_addr(address & PAGE_MASK, is_write)) + else if(check_remapped_addr(address & PAGE_MASK, is_write, is_user)) return(0); else if(current->mm == NULL) panic("Segfault with no mm"); diff --git a/arch/um/kernel/trap_user.c b/arch/um/kernel/trap_user.c index 6744ca60d..d12eac64a 100644 --- a/arch/um/kernel/trap_user.c +++ b/arch/um/kernel/trap_user.c @@ -32,7 +32,14 @@ void kill_child_dead(int pid) { kill(pid, SIGKILL); kill(pid, SIGCONT); - while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT); + do { + int n; + CATCH_EINTR(n = waitpid(pid, NULL, 0)); + if (n > 0) + kill(pid, SIGCONT); + else + break; + } while(1); } /* Unlocked - don't care if this is a bit off */ @@ -120,7 +127,7 @@ void alarm_handler(int sig, struct sigcontext sc) void do_longjmp(void *b, int val) { - jmp_buf *buf = b; + sigjmp_buf *buf = b; siglongjmp(*buf, val); } diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c index d8e3bfe6b..065b504a6 100644 --- a/arch/um/kernel/tt/exec_kern.c +++ b/arch/um/kernel/tt/exec_kern.c @@ -14,6 +14,7 @@ #include "kern_util.h" #include "irq_user.h" #include "time_user.h" +#include "signal_user.h" #include "mem_user.h" #include "os.h" #include "tlb.h" @@ -39,8 +40,7 @@ void flush_thread_tt(void) do_exit(SIGKILL); } - new_pid = start_fork_tramp((void *) current->thread.kernel_stack, - stack, 0, exec_tramp); + new_pid = start_fork_tramp(current->thread_info, stack, 0, exec_tramp); if(new_pid < 0){ printk(KERN_ERR "flush_thread : new thread failed, errno = %d\n", @@ -54,7 +54,9 @@ void flush_thread_tt(void) current->thread.request.u.exec.pid = new_pid; unprotect_stack((unsigned long) current_thread); os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); + change_sig(SIGUSR1, 0); enable_timer(); free_page(stack); protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); diff --git a/arch/um/kernel/tt/exec_user.c b/arch/um/kernel/tt/exec_user.c index 35d108266..6d5fa825a 100644 --- a/arch/um/kernel/tt/exec_user.c +++ b/arch/um/kernel/tt/exec_user.c @@ -19,13 +19,18 @@ void do_exec(int old_pid, int new_pid) { unsigned long regs[FRAME_SIZE]; + int err; if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) || - (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0) || - (waitpid(new_pid, 0, WUNTRACED) < 0)) + (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0)) tracer_panic("do_exec failed to attach proc - errno = %d", errno); + CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED)); + if (err < 0) + tracer_panic("do_exec failed to attach proc in waitpid - errno = %d", + errno); + if(ptrace_getregs(old_pid, regs) < 0) tracer_panic("do_exec failed to get registers - errno = %d", errno); diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index 2bdbdab87..177cb2461 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -116,6 +116,17 @@ void exit_thread_tt(void) os_close_file(current->thread.mode.tt.switch_pipe[1]); } +void suspend_new_thread(int fd) +{ + int err; + char c; + + os_stop_process(os_getpid()); + err = os_read_file(fd, &c, sizeof(c)); + if(err != sizeof(c)) + panic("read failed in suspend_new_thread, err = %d", -err); +} + void schedule_tail(task_t *prev); static void new_thread_handler(int sig) @@ -150,6 +161,12 @@ static void new_thread_handler(int sig) local_irq_enable(); if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) do_exit(0); + + /* XXX No set_user_mode here because a newly execed process will + * immediately segfault on its non-existent IP, coming straight back + * to the signal handler, which will call set_user_mode on its way + * out. This should probably change since it's confusing. + */ } static int new_thread_proc(void *stack) @@ -172,6 +189,7 @@ static int new_thread_proc(void *stack) local_irq_disable(); init_new_thread_stack(stack, new_thread_handler); os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); return(0); } @@ -215,6 +233,7 @@ int fork_tramp(void *stack) init_new_thread_stack(stack, finish_fork_handler); os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); return(0); } @@ -236,7 +255,7 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1); if(err < 0){ printk("copy_thread : pipe failed, err = %d\n", -err); - return(err); + goto out; } stack = alloc_stack(0, 0); @@ -248,8 +267,7 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, clone_flags &= CLONE_VM; p->thread.temp_stack = stack; - new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack, - clone_flags, tramp); + new_pid = start_fork_tramp(p->thread_info, stack, clone_flags, tramp); if(new_pid < 0){ printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", -new_pid); @@ -267,19 +285,30 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, current->thread.request.op = OP_FORK; current->thread.request.u.fork.pid = new_pid; os_usr1_process(os_getpid()); - return(0); + + /* Enable the signal and then disable it to ensure that it is handled + * here, and nowhere else. + */ + change_sig(SIGUSR1, 1); + + change_sig(SIGUSR1, 0); + err = 0; + out: + return(err); } void reboot_tt(void) { current->thread.request.op = OP_REBOOT; os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); } void halt_tt(void) { current->thread.request.op = OP_HALT; os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); } void kill_off_processes_tt(void) @@ -306,6 +335,9 @@ void initial_thread_cb_tt(void (*proc)(void *), void *arg) current->thread.request.u.cb.proc = proc; current->thread.request.u.cb.arg = arg; os_usr1_process(os_getpid()); + change_sig(SIGUSR1, 1); + + change_sig(SIGUSR1, 0); } } @@ -475,7 +507,7 @@ void set_init_pid(int pid) init_task.thread.mode.tt.extern_pid = pid; err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1); - if(err) + if(err) panic("Can't create switch pipe for init_task, errno = %d", -err); } @@ -501,9 +533,9 @@ int start_uml_tt(void) void *sp; int pages; - pages = (1 << CONFIG_KERNEL_STACK_ORDER) - 2; - sp = (void *) init_task.thread.kernel_stack + pages * PAGE_SIZE - - sizeof(unsigned long); + pages = (1 << CONFIG_KERNEL_STACK_ORDER); + sp = (void *) ((unsigned long) init_task.thread_info) + + pages * PAGE_SIZE - sizeof(unsigned long); return(tracer(start_kernel_proc, sp)); } diff --git a/arch/um/kernel/tt/ptproxy/proxy.c b/arch/um/kernel/tt/ptproxy/proxy.c index de417c49d..458ecf9a4 100644 --- a/arch/um/kernel/tt/ptproxy/proxy.c +++ b/arch/um/kernel/tt/ptproxy/proxy.c @@ -272,7 +272,7 @@ void fake_child_exit(void) child_proxy(1, W_EXITCODE(0, 0)); while(debugger.waiting == 1){ - pid = waitpid(debugger.pid, &status, WUNTRACED); + CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED)); if(pid != debugger.pid){ printk("fake_child_exit - waitpid failed, " "errno = %d\n", errno); @@ -280,7 +280,7 @@ void fake_child_exit(void) } debugger_proxy(status, debugger.pid); } - pid = waitpid(debugger.pid, &status, WUNTRACED); + CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED)); if(pid != debugger.pid){ printk("fake_child_exit - waitpid failed, " "errno = %d\n", errno); diff --git a/arch/um/kernel/tt/tracer.c b/arch/um/kernel/tt/tracer.c index 3271e6a63..1b5477412 100644 --- a/arch/um/kernel/tt/tracer.c +++ b/arch/um/kernel/tt/tracer.c @@ -192,7 +192,7 @@ int tracer(int (*init_proc)(void *), void *sp) printf("tracing thread pid = %d\n", tracing_pid); pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); - n = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0){ printf("waitpid on idle thread failed, errno = %d\n", errno); exit(1); @@ -233,7 +233,7 @@ int tracer(int (*init_proc)(void *), void *sp) } set_cmdline("(tracing thread)"); while(1){ - pid = waitpid(-1, &status, WUNTRACED); + CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED)); if(pid <= 0){ if(errno != ECHILD){ printf("wait failed - errno = %d\n", errno); diff --git a/arch/um/kernel/tt/trap_user.c b/arch/um/kernel/tt/trap_user.c index 7a6dbf5f9..00bacacfc 100644 --- a/arch/um/kernel/tt/trap_user.c +++ b/arch/um/kernel/tt/trap_user.c @@ -23,6 +23,13 @@ void sig_handler_common_tt(int sig, void *sc_ptr) unprotect_kernel_mem(); + /* This is done because to allow SIGSEGV to be delivered inside a SEGV + * handler. This can happen in copy_user, and if SEGV is disabled, + * the process will die. + */ + if(sig == SIGSEGV) + change_sig(SIGSEGV, 1); + r = &TASK_REGS(get_current())->tt; save_regs = *r; is_user = user_context(SC_SP(sc)); @@ -30,7 +37,6 @@ void sig_handler_common_tt(int sig, void *sc_ptr) if(sig != SIGUSR2) r->syscall = -1; - change_sig(SIGUSR1, 1); info = &sig_info[sig]; if(!info->is_irq) unblock_signals(); @@ -39,7 +45,6 @@ void sig_handler_common_tt(int sig, void *sc_ptr) if(is_user){ interrupt_end(); block_signals(); - change_sig(SIGUSR1, 0); set_user_mode(NULL); } *r = save_regs; diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c index f084f0c2b..f01475512 100644 --- a/arch/um/kernel/tt/uaccess_user.c +++ b/arch/um/kernel/tt/uaccess_user.c @@ -72,7 +72,7 @@ int __do_strnlen_user(const char *str, unsigned long n, struct tt_regs save = TASK_REGS(get_current())->tt; int ret; unsigned long *faddrp = (unsigned long *)fault_addr; - jmp_buf jbuf; + sigjmp_buf jbuf; *fault_catcher = &jbuf; if(sigsetjmp(jbuf, 1) == 0) diff --git a/arch/um/kernel/tty_log.c b/arch/um/kernel/tty_log.c index be0dec54b..148b86a87 100644 --- a/arch/um/kernel/tty_log.c +++ b/arch/um/kernel/tty_log.c @@ -205,6 +205,8 @@ static int __init set_tty_log_fd(char *name, int *add) printf("set_tty_log_fd - strtoul failed on '%s'\n", name); tty_log_fd = -1; } + + *add = 0; return 0; } diff --git a/arch/um/kernel/uaccess_user.c b/arch/um/kernel/uaccess_user.c index fc079512a..d035257ed 100644 --- a/arch/um/kernel/uaccess_user.c +++ b/arch/um/kernel/uaccess_user.c @@ -18,7 +18,7 @@ unsigned long __do_user_copy(void *to, const void *from, int n, { unsigned long *faddrp = (unsigned long *) fault_addr, ret; - jmp_buf jbuf; + sigjmp_buf jbuf; *fault_catcher = &jbuf; if(sigsetjmp(jbuf, 1) == 0){ (*op)(to, from, n); diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 18a4a7607..802b7fb53 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -27,7 +27,6 @@ #include "user_util.h" #include "kern_util.h" #include "kern.h" -#include "mprot.h" #include "mem_user.h" #include "mem.h" #include "umid.h" @@ -306,7 +305,7 @@ unsigned long end_iomem; int linux_main(int argc, char **argv) { - unsigned long avail; + unsigned long avail, diff; unsigned long virtmem_size, max_physmem; unsigned int i, add; @@ -324,6 +323,16 @@ int linux_main(int argc, char **argv) brk_start = (unsigned long) sbrk(0); CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); + /* Increase physical memory size for exec-shield users + so they actually get what they asked for. This should + add zero for non-exec shield users */ + + diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); + if(diff > 1024 * 1024){ + printf("Adding %ld bytes to physical memory to account for " + "exec-shield gap\n", diff); + physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); + } uml_physmem = uml_start; @@ -380,9 +389,6 @@ int linux_main(int argc, char **argv) uml_postsetup(); - init_task.thread.kernel_stack = (unsigned long) &init_thread_info + - 2 * PAGE_SIZE; - task_protections((unsigned long) &init_thread_info); os_flush_stdout(); diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c index 645fbfe51..f609e11c0 100644 --- a/arch/um/kernel/umid.c +++ b/arch/um/kernel/umid.c @@ -43,7 +43,7 @@ static int __init set_umid(char *name, int is_random, } if(strlen(name) > UMID_LEN - 1) - (*printer)("Unique machine name is being truncated to %s " + (*printer)("Unique machine name is being truncated to %d " "characters\n", UMID_LEN); strlcpy(umid, name, sizeof(umid)); @@ -54,6 +54,7 @@ static int __init set_umid(char *name, int is_random, static int __init set_umid_arg(char *name, int *add) { + *add = 0; return(set_umid(name, 0, printf)); } @@ -199,17 +200,20 @@ int not_dead_yet(char *dir) static int __init set_uml_dir(char *name, int *add) { if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){ - uml_dir = malloc(strlen(name) + 1); + uml_dir = malloc(strlen(name) + 2); if(uml_dir == NULL){ printf("Failed to malloc uml_dir - error = %d\n", errno); uml_dir = name; + /* Return 0 here because do_initcalls doesn't look at + * the return value. + */ return(0); } sprintf(uml_dir, "%s/", name); } else uml_dir = name; - return 0; + return(0); } static int __init make_uml_dir(void) diff --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c index b15d79c3b..c977750a0 100644 --- a/arch/um/kernel/user_util.c +++ b/arch/um/kernel/user_util.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -81,20 +82,19 @@ int wait_for_stop(int pid, int sig, int cont_type, void *relay) int status, ret; while(1){ - ret = waitpid(pid, &status, WUNTRACED); + CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED)); if((ret < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){ if(ret < 0){ - if(errno == EINTR) continue; printk("wait failed, errno = %d\n", errno); } else if(WIFEXITED(status)) - printk("process exited with status %d\n", - WEXITSTATUS(status)); + printk("process %d exited with status %d\n", + pid, WEXITSTATUS(status)); else if(WIFSIGNALED(status)) - printk("process exited with signal %d\n", - WTERMSIG(status)); + printk("process %d exited with signal %d\n", + pid, WTERMSIG(status)); else if((WSTOPSIG(status) == SIGVTALRM) || (WSTOPSIG(status) == SIGALRM) || (WSTOPSIG(status) == SIGIO) || @@ -110,8 +110,8 @@ int wait_for_stop(int pid, int sig, int cont_type, void *relay) ptrace(cont_type, pid, 0, WSTOPSIG(status)); continue; } - else printk("process stopped with signal %d\n", - WSTOPSIG(status)); + else printk("process %d stopped with signal %d\n", + pid, WSTOPSIG(status)); panic("wait_for_stop failed to wait for %d to stop " "with %d\n", pid, sig); } @@ -119,18 +119,27 @@ int wait_for_stop(int pid, int sig, int cont_type, void *relay) } } -int raw(int fd, int complain) +int raw(int fd) { struct termios tt; int err; - tcgetattr(fd, &tt); + CATCH_EINTR(err = tcgetattr(fd, &tt)); + if (err < 0) { + printk("tcgetattr failed, errno = %d\n", errno); + return(-errno); + } + cfmakeraw(&tt); - err = tcsetattr(fd, TCSANOW, &tt); - if((err < 0) && complain){ + + CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); + if (err < 0) { printk("tcsetattr failed, errno = %d\n", errno); return(-errno); } + + /* XXX tcsetattr could have applied only some changes + * (and cfmakeraw() is a set of changes) */ return(0); } @@ -153,6 +162,21 @@ void setup_hostinfo(void) host.release, host.version, host.machine); } +int setjmp_wrapper(void (*proc)(void *, void *), ...) +{ + va_list args; + sigjmp_buf buf; + int n; + + n = sigsetjmp(buf, 1); + if(n == 0){ + va_start(args, proc); + (*proc)(&buf, &args); + } + va_end(args); + return(n); +} + /* * 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 --git a/arch/um/main.c b/arch/um/main.c index ead5e2cf0..9d06171f6 100644 --- a/arch/um/main.c +++ b/arch/um/main.c @@ -17,6 +17,8 @@ #include "kern_util.h" #include "mem_user.h" #include "signal_user.h" +#include "time_user.h" +#include "irq_user.h" #include "user.h" #include "init.h" #include "mode.h" @@ -147,7 +149,20 @@ int main(int argc, char **argv, char **envp) /* Reboot */ if(ret){ + int err; + printf("\n"); + + /* Let any pending signals fire, then disable them. This + * ensures that they won't be delivered after the exec, when + * they are definitely not expected. + */ + unblock_signals(); + disable_timer(); + err = deactivate_all_fds(); + if(err) + printf("deactivate_all_fds failed, errno = %d\n", -err); + execvp(new_argv[0], new_argv); perror("Failed to exec kernel"); ret = 1; @@ -163,10 +178,21 @@ extern void *__real_malloc(int); void *__wrap_malloc(int size) { - if(CAN_KMALLOC()) - return(um_kmalloc(size)); - else + void *ret; + + if(!CAN_KMALLOC()) return(__real_malloc(size)); + else if(size <= PAGE_SIZE) /* finding contiguos pages is hard */ + ret = um_kmalloc(size); + else ret = um_vmalloc(size); + + /* glibc people insist that if malloc fails, errno should be + * set by malloc as well. So we do. + */ + if(ret == NULL) + errno = ENOMEM; + + return(ret); } void *__wrap_calloc(int n, int size) @@ -180,9 +206,35 @@ void *__wrap_calloc(int n, int size) extern void __real_free(void *); +extern unsigned long high_physmem; + void __wrap_free(void *ptr) { - if(CAN_KMALLOC()) kfree(ptr); + unsigned long addr = (unsigned long) ptr; + + /* We need to know how the allocation happened, so it can be correctly + * freed. This is done by seeing what region of memory the pointer is + * in - + * physical memory - kmalloc/kfree + * kernel virtual memory - vmalloc/vfree + * anywhere else - malloc/free + * If kmalloc is not yet possible, then the kernel memory regions + * may not be set up yet, and the variables not set up. So, + * free is called. + * + * CAN_KMALLOC is checked because it would be bad to free a buffer + * with kmalloc/vmalloc after they have been turned off during + * shutdown. + */ + + if((addr >= uml_physmem) && (addr < high_physmem)){ + if(CAN_KMALLOC()) + kfree(ptr); + } + else if((addr >= start_vm) && (addr < end_vm)){ + if(CAN_KMALLOC()) + vfree(ptr); + } else __real_free(ptr); } diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 4fa03137a..a6665dd42 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -3,9 +3,15 @@ # Licensed under the GPL # -obj-y = file.o process.o tty.o user_syms.o drivers/ +obj-y = aio.o file.o process.o time.o tty.o user_syms.o drivers/ -USER_OBJS := $(foreach file,file.o process.o tty.o,$(obj)/$(file)) +USER_OBJS := $(foreach file,aio.o file.o process.o time.o tty.o,$(obj)/$(file)) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< + +HAVE_AIO_ABI = $(shell [ -e /usr/include/linux/aio_abi.h ] && \ + echo -DHAVE_AIO_ABI) +HAVE_AIO_LIBC = $(shell objdump -T /lib/libc-*.so | grep io_submit && \ + echo -DHAVE_AIO_LIBC) +CFLAGS_aio.o = $(HAVE_AIO_ABI) $(HAVE_AIO_LIBC) diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c index d4bb21467..cd4d6544d 100644 --- a/arch/um/os-Linux/drivers/ethertap_user.c +++ b/arch/um/os-Linux/drivers/ethertap_user.c @@ -16,6 +16,7 @@ #include #include "user.h" #include "kern_util.h" +#include "user_util.h" #include "net_user.h" #include "etap.h" #include "helper.h" @@ -125,7 +126,8 @@ static int etap_tramp(char *dev, char *gate, int control_me, if(c != 1){ printk("etap_tramp : uml_net failed\n"); err = -EINVAL; - if(waitpid(pid, &status, 0) < 0) + CATCH_EINTR(n = waitpid(pid, &status, 0)); + if(n < 0) err = -errno; else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)) printk("uml_net didn't exit with status 1\n"); diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c index 054874d75..f40c627ef 100644 --- a/arch/um/os-Linux/drivers/tuntap_user.c +++ b/arch/um/os-Linux/drivers/tuntap_user.c @@ -18,6 +18,7 @@ #include "net_user.h" #include "tuntap.h" #include "kern_util.h" +#include "user_util.h" #include "user.h" #include "helper.h" #include "os.h" @@ -108,7 +109,7 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, errno); return(-errno); } - waitpid(pid, NULL, 0); + CATCH_EINTR(waitpid(pid, NULL, 0)); cmsg = CMSG_FIRSTHDR(&msg); if(cmsg == NULL){ diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index 4083bf96c..bda79c182 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -15,6 +18,8 @@ #include #include #include +#include +#include #include "os.h" #include "user.h" #include "kern_util.h" @@ -22,7 +27,8 @@ static void copy_stat(struct uml_stat *dst, struct stat64 *src) { *dst = ((struct uml_stat) { - .ust_dev = src->st_dev, /* device */ + .ust_major = MAJOR(src->st_dev), /* device */ + .ust_minor = MINOR(src->st_dev), .ust_ino = src->st_ino, /* inode */ .ust_mode = src->st_mode, /* protection */ .ust_nlink = src->st_nlink, /* number of hard links */ @@ -34,6 +40,8 @@ static void copy_stat(struct uml_stat *dst, struct stat64 *src) .ust_atime = src->st_atime, /* time of last access */ .ust_mtime = src->st_mtime, /* time of last modification */ .ust_ctime = src->st_ctime, /* time of last change */ + .ust_rmajor = MAJOR(src->st_rdev), + .ust_rminor = MINOR(src->st_rdev), }); } @@ -71,12 +79,29 @@ int os_stat_file(const char *file_name, struct uml_stat *ubuf) return(err); } -int os_access(const char* file, int mode) +int os_lstat_file(const char *file_name, struct uml_stat *ubuf) +{ + struct stat64 sbuf; + int err; + + do { + err = lstat64(file_name, &sbuf); + } while((err < 0) && (errno == EINTR)) ; + + if(err < 0) + return(-errno); + + if(ubuf != NULL) + copy_stat(ubuf, &sbuf); + return(err); +} + +int os_access(const char *file, int mode) { int amode, err; - amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) | - (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ; + amode=(mode& OS_ACC_R_OK ? R_OK : 0) | (mode& OS_ACC_W_OK ? W_OK : 0) | + (mode& OS_ACC_X_OK ? X_OK : 0) | (mode& OS_ACC_F_OK ? F_OK : 0) ; err = access(file, amode); if(err < 0) @@ -85,6 +110,41 @@ int os_access(const char* file, int mode) return(0); } +int os_set_file_time(const char *file, unsigned long access, unsigned long mod) +{ + struct utimbuf buf = ((struct utimbuf){ .actime = access, + .modtime = mod }); + int err; + + err = utime(file, &buf); + if(err < 0) + return(-errno); + + return(0); +} + +int os_set_file_perms(const char *file, int mode) +{ + int err; + + err = chmod(file, mode); + if(err < 0) + return(-errno); + + return(0); +} + +int os_set_file_owner(const char *file, int owner, int group) +{ + int err; + + err = chown(file, owner, group); + if(err < 0) + return(-errno); + + return(0); +} + void os_print_error(int error, const char* str) { errno = error < 0 ? -error : error; @@ -187,7 +247,8 @@ int os_sigio_async(int master, int slave) if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || (fcntl(master, F_SETOWN, os_getpid()) < 0)){ - printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n", errno); + printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n", + errno); return(-errno); } @@ -218,7 +279,7 @@ int os_file_type(char *file) struct uml_stat buf; int err; - err = os_stat_file(file, &buf); + err = os_lstat_file(file, &buf); if(err < 0) return(err); @@ -265,6 +326,7 @@ int os_open_file(char *file, struct openflags flags, int mode) if(flags.c) f |= O_CREAT; if(flags.t) f |= O_TRUNC; if(flags.e) f |= O_EXCL; + if(flags.d) f |= O_DIRECT; fd = open64(file, f, mode); if(fd < 0) @@ -278,6 +340,96 @@ int os_open_file(char *file, struct openflags flags, int mode) return(fd); } +void *os_open_dir(char *path, int *err_out) +{ + void *dir; + + dir = opendir(path); + *err_out = -errno; + return(dir); +} + +int os_seek_dir(void *stream, unsigned long long pos) +{ + seekdir(stream, pos); + return(0); +} + +int os_read_dir(void *stream, unsigned long long *ino_out, char **name_out) +{ + struct dirent *ent; + + errno = 0; + ent = readdir(stream); + if(ent == NULL){ + if(errno != 0) + return(-errno); + *name_out = NULL; + return(0); + } + + *ino_out = ent->d_ino; + *name_out = ent->d_name; + return(0); +} + +int os_tell_dir(void *stream) +{ + return(telldir(stream)); +} + +int os_close_dir(void *stream) +{ + int err; + + err = closedir(stream); + if(err < 0) + return(-errno); + return(0); +} + +int os_remove_file(const char *file) +{ + int err; + + err = unlink(file); + if(err) + return(-errno); + + return(0); +} + +int os_move_file(const char *from, const char *to) +{ + int err; + + err = rename(from, to); + if(err) + return(-errno); + + return(0); +} + +int os_truncate_fd(int fd, unsigned long long len) +{ + int err; + + err = ftruncate(fd, len); + if(err) + return(-errno); + return(0); +} + +int os_truncate_file(const char *file, unsigned long long len) +{ + int err; + + err = truncate(file, len); + if(err) + return(-errno); + return(0); +} + int os_connect_socket(char *name) { struct sockaddr_un sock; @@ -307,7 +459,8 @@ int os_seek_file(int fd, __u64 offset) __u64 actual; actual = lseek64(fd, offset, SEEK_SET); - if(actual != offset) return(-errno); + if(actual != offset) + return(-errno); return(0); } @@ -395,6 +548,19 @@ int os_file_size(char *file, long long *size_out) return(0); } +int os_fd_size(int fd, long long *size_out) +{ + struct stat buf; + int err; + + err = fstat(fd, &buf); + if(err) + return(-errno); + + *size_out = buf.st_size; + return(0); +} + int os_file_modtime(char *file, unsigned long *modtime) { struct uml_stat buf; @@ -495,6 +661,16 @@ int os_set_fd_async(int fd, int owner) return(0); } +int os_clear_fd_async(int fd) +{ + int flags = fcntl(fd, F_GETFL); + + flags &= ~(O_ASYNC | O_NONBLOCK); + if(fcntl(fd, F_SETFL, flags) < 0) + return(-errno); + return(0); +} + int os_set_fd_block(int fd, int blocking) { int flags; @@ -625,6 +801,72 @@ int os_create_unix_socket(char *file, int len, int close_on_exec) return(sock); } +int os_make_symlink(const char *to, const char *from) +{ + int err; + + err = symlink(to, from); + if(err) + return(-errno); + + return(0); +} + +int os_read_symlink(const char *file, char *buf, int size) +{ + int err; + + err = readlink(file, buf, size); + if(err < 0) + return(-errno); + + return(err); +} + +int os_link_file(const char *to, const char *from) +{ + int err; + + err = link(to, from); + if(err) + return(-errno); + + return(0); +} + +int os_make_dir(const char *dir, int mode) +{ + int err; + + err = mkdir(dir, mode); + if(err) + return(-errno); + + return(0); +} + +int os_make_dev(const char *name, int mode, int major, int minor) +{ + int err; + + err = mknod(name, mode, MKDEV(major, minor)); + if(err) + return(-errno); + + return(0); +} + +int os_remove_dir(const char *dir) +{ + int err; + + err = rmdir(dir); + if(err) + return(-errno); + + return(0); +} + void os_flush_stdout(void) { fflush(stdout); @@ -656,6 +898,38 @@ int os_lock_file(int fd, int excl) return(err); } +int os_stat_filesystem(char *path, 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(path, &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 diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index f1b178cb3..ce1b5f15e 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -12,13 +12,17 @@ #include #include "os.h" #include "user.h" +#include "user_util.h" #define ARBITRARY_ADDR -1 #define FAILURE_PID -1 +#define STAT_PATH_LEN sizeof("/proc/#######/stat\0") +#define COMM_SCANF "%*[^)])" + unsigned long os_process_pc(int pid) { - char proc_stat[sizeof("/proc/#####/stat\0")], buf[256]; + char proc_stat[STAT_PATH_LEN], buf[256]; unsigned long pc; int fd, err; @@ -38,9 +42,9 @@ unsigned long os_process_pc(int pid) } os_close_file(fd); pc = ARBITRARY_ADDR; - if(sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d " + if(sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " - "%*d %*d %*d %*d %ld", &pc) != 1){ + "%*d %*d %*d %*d %*d %lu", &pc) != 1){ printk("os_process_pc - couldn't find pc in '%s'\n", buf); } return(pc); @@ -48,7 +52,7 @@ unsigned long os_process_pc(int pid) int os_process_parent(int pid) { - char stat[sizeof("/proc/nnnnn/stat\0")]; + char stat[STAT_PATH_LEN]; char data[256]; int parent, n, fd; @@ -70,8 +74,7 @@ int os_process_parent(int pid) } parent = FAILURE_PID; - /* XXX This will break if there is a space in the command */ - n = sscanf(data, "%*d %*s %*c %d", &parent); + n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent); if(n != 1) printk("Failed to scan '%s'\n", data); @@ -87,14 +90,13 @@ void os_kill_process(int pid, int reap_child) { kill(pid, SIGKILL); if(reap_child) - waitpid(pid, NULL, 0); + CATCH_EINTR(waitpid(pid, NULL, 0)); } void os_usr1_process(int pid) { - syscall(__NR_tkill, pid, SIGUSR1); - /* kill(pid, SIGUSR1); */ + kill(pid, SIGUSR1); } int os_getpid(void) diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index c9c539fe4..2ce4cb714 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile @@ -1,5 +1,5 @@ obj-y = bugs.o checksum.o fault.o ksyms.o ldt.o ptrace.o ptrace_user.o \ - semaphore.o sigcontext.o syscalls.o sysrq.o time.o + semaphore.o sigcontext.o syscalls.o sysrq.o obj-$(CONFIG_HIGHMEM) += highmem.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c index b453e2f76..d5e0ba90a 100644 --- a/arch/um/sys-i386/bugs.c +++ b/arch/um/sys-i386/bugs.c @@ -183,15 +183,16 @@ void arch_check_bugs(void) int arch_handle_signal(int sig, union uml_pt_regs *regs) { - unsigned long ip; + unsigned char tmp[2]; /* This is testing for a cmov (0x0f 0x4x) instruction causing a * SIGILL in init. */ if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0); - ip = UPT_IP(regs); - if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40)) + if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) + panic("SIGILL in init, could not read instructions!\n"); + if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40)) return(0); if(host_has_cmov == 0) diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index 33e302160..ba77ccaa8 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -13,6 +13,8 @@ #ifdef CONFIG_MODE_TT extern int modify_ldt(int func, void *ptr, unsigned long bytecount); +/* XXX this needs copy_to_user and copy_from_user */ + int sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) { if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT); diff --git a/arch/um/sys-i386/ptrace_user.c b/arch/um/sys-i386/ptrace_user.c index 6b9ba0845..4c7d37517 100644 --- a/arch/um/sys-i386/ptrace_user.c +++ b/arch/um/sys-i386/ptrace_user.c @@ -42,7 +42,8 @@ static void write_debugregs(int pid, unsigned long *regs) if(ptrace(PTRACE_POKEUSER, pid, &dummy->u_debugreg[i], regs[i]) < 0) printk("write_debugregs - ptrace failed on " - "register %d, errno = %d\n", errno); + "register %d, value = 0x%x, errno = %d\n", i, + regs[i], errno); } } diff --git a/arch/um/util/Makefile b/arch/um/util/Makefile index f480f42bd..2fa9136ee 100644 --- a/arch/um/util/Makefile +++ b/arch/um/util/Makefile @@ -6,3 +6,6 @@ mk_constants-objs := mk_constants_user.o mk_constants_kern.o HOSTCFLAGS_mk_task_kern.o := $(CFLAGS) $(CPPFLAGS) HOSTCFLAGS_mk_constants_kern.o := $(CFLAGS) $(CPPFLAGS) + +clean: + $(RM) -f $(host-progs) diff --git a/fs/Makefile b/fs/Makefile index e68e9f5bd..e5d6eee9a 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -91,5 +91,4 @@ obj-$(CONFIG_JFS_FS) += jfs/ obj-$(CONFIG_XFS_FS) += xfs/ obj-$(CONFIG_AFS_FS) += afs/ obj-$(CONFIG_BEFS_FS) += befs/ -obj-$(CONFIG_HOSTFS) += hostfs/ -obj-$(CONFIG_HPPFS) += hppfs/ +obj-$(CONFIG_EXTERNFS) += hostfs/ diff --git a/fs/hostfs/Makefile b/fs/hostfs/Makefile index 794292e0a..a1b3c63b3 100644 --- a/fs/hostfs/Makefile +++ b/fs/hostfs/Makefile @@ -3,24 +3,15 @@ # 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 +obj-$(CONFIG_EXTERNFS) += externfs.o +obj-$(CONFIG_HOSTFS) += host_fs.o host_file.o +obj-$(CONFIG_HUMFS) += humfs.o meta_fs.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 $@ $< diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h index d1f6c339f..e80b6f836 100644 --- a/fs/hostfs/hostfs.h +++ b/fs/hostfs/hostfs.h @@ -1,69 +1,178 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + #ifndef __UM_FS_HOSTFS #define __UM_FS_HOSTFS +#include "linux/fs.h" +#include "filehandle.h" #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 { +#define EXTERNFS_ATTR_MODE 1 +#define EXTERNFS_ATTR_UID 2 +#define EXTERNFS_ATTR_GID 4 +#define EXTERNFS_ATTR_SIZE 8 +#define EXTERNFS_ATTR_ATIME 16 +#define EXTERNFS_ATTR_MTIME 32 +#define EXTERNFS_ATTR_CTIME 64 +#define EXTERNFS_ATTR_ATIME_SET 128 +#define EXTERNFS_ATTR_MTIME_SET 256 +#define EXTERNFS_ATTR_FORCE 512 /* Not a change, but a change it */ +#define EXTERNFS_ATTR_ATTR_FLAG 1024 + +struct externfs_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; + time_t ia_atime; + time_t ia_mtime; + time_t 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); +struct externfs_data { + struct externfs_file_ops *file_ops; + struct externfs_mount_ops *mount_ops; +}; + +struct externfs_inode { + struct inode vfs_inode; + struct externfs_file_ops *ops; +}; + +struct externfs_mount_ops { + struct externfs_data *(*mount)(char *mount_arg); + struct externfs_inode *(*init_file)(struct externfs_data *ed); +}; + +struct externfs_file_ops { + int (*stat_file)(const char *path, struct externfs_data *ed, + dev_t *dev_out, unsigned long long *inode_out, + int *mode_out, int *nlink_out, int *uid_out, + int *gid_out, unsigned long long *size_out, + unsigned long *atime_out, unsigned long *mtime_out, + unsigned long *ctime_out, int *blksize_out, + unsigned long long *blocks_out); + int (*file_type)(const char *path, int *rdev, + struct externfs_data *ed); + int (*access_file)(char *path, int r, int w, int x, int uid, int gid, + struct externfs_data *ed); + int (*open_file)(struct externfs_inode *ext, char *file, + int uid, int gid, struct inode *inode, + struct externfs_data *ed); + void (*close_file)(struct externfs_inode *ext, + unsigned long long size); + void *(*open_dir)(char *path, int uid, int gid, + struct externfs_data *ed); + char *(*read_dir)(void *stream, unsigned long long *pos, + unsigned long long *ino_out, int *len_out, + struct externfs_data *ed); + int (*read_file)(struct externfs_inode *ext, + unsigned long long offset, char *buf, int len, + int ignore_start, int ignore_end, + void (*completion)(char *, int, void *), void *arg, + struct externfs_data *ed); + int (*write_file)(struct externfs_inode *ext, + unsigned long long offset, const char *buf, + int start, int len, + void (*completion)(char *, int, void *), void *arg, + struct externfs_data *ed); + int (*map_file_page)(struct externfs_inode *ext, + unsigned long long offset, char *buf, int w, + struct externfs_data *ed); + void (*close_dir)(void *stream, struct externfs_data *ed); + void (*invisible)(struct externfs_inode *ext); + int (*create_file)(struct externfs_inode *ext, char *path, + int mode, int uid, int gid, struct inode *inode, + struct externfs_data *ed); + int (*set_attr)(const char *path, struct externfs_iattr *attrs, + struct externfs_data *ed); + int (*make_symlink)(const char *from, const char *to, int uid, int gid, + struct externfs_data *ed); + int (*unlink_file)(const char *path, struct externfs_data *ed); + int (*make_dir)(const char *path, int mode, int uid, int gid, + struct externfs_data *ed); + int (*remove_dir)(const char *path, int uid, int gid, + struct externfs_data *ed); + int (*make_node)(const char *path, int mode, int uid, int gid, + int type, int maj, int min, struct externfs_data *ed); + int (*link_file)(const char *to, const char *from, int uid, int gid, + struct externfs_data *ed); + int (*read_link)(char *path, int uid, int gid, char *buf, int size, + struct externfs_data *ed); + int (*rename_file)(char *from, char *to, struct externfs_data *ed); + int (*statfs)(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 externfs_data *ed); + int (*truncate_file)(struct externfs_inode *ext, __u64 size, + struct externfs_data *ed); +}; + +#define HOSTFS_BUFSIZE 64 + +extern int register_externfs(char *name, struct externfs_mount_ops *mount_ops); +extern void unregister_externfs(char *name); +extern void init_externfs(struct externfs_data *ed, + struct externfs_file_ops *ops); +struct externfs_data *inode_externfs_info(struct inode *inode); + +extern char *generic_root_filename(char *mount_arg); +extern void host_close_file(void *stream); +extern int host_read_file(int fd, unsigned long long offset, char *buf, + int len); +extern int host_open_file(const char *path[], int r, int w, + struct file_handle *fh); +extern void *host_open_dir(const char *path[]); +extern char *host_read_dir(void *stream, unsigned long long *pos, + unsigned long long *ino_out, int *len_out); +extern int host_file_type(const char *path[], int *rdev); +extern char *host_root_filename(char *mount_arg); +extern char *get_path(const char *path[], char *buf, int size); +extern void free_path(const char *buf, char *tmp); +extern int host_create_file(const char *path[], int mode, + struct file_handle *fh); +extern int host_set_attr(const char *path[], struct externfs_iattr *attrs); +extern int host_make_symlink(const char *from[], const char *to); +extern int host_unlink_file(const char *path[]); +extern int host_make_dir(const char *path[], int mode); +extern int host_remove_dir(const char *path[]); +extern int host_link_file(const char *to[], const char *from[]); +extern int host_read_link(const char *path[], char *buf, int size); +extern int host_rename_file(const char *from[], const char *to[]); +extern int host_stat_fs(const char *path[], 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); +extern int host_stat_file(const char *path[], int *dev_out, + unsigned long long *inode_out, int *mode_out, + int *nlink_out, int *uid_out, int *gid_out, + unsigned long long *size_out, + unsigned long *atime_out, unsigned long *mtime_out, + unsigned long *ctime_out, int *blksize_out, + unsigned long long *blocks_out); + +extern char *generic_host_read_dir(void *stream, unsigned long long *pos, + unsigned long long *ino_out, int *len_out, + void *mount); +extern int generic_host_read_file(int fd, unsigned long long offset, char *buf, + int len, void *mount); +extern void generic_host_close_file(void *stream, unsigned long long size, + void *mount); +extern int generic_host_truncate_file(struct file_handle *fh, __u64 size, + void *m); + +extern char *inode_name_prefix(struct inode *inode, char *prefix); #endif diff --git a/include/asm-um/bug.h b/include/asm-um/bug.h index f5836c5ae..9a244ca5d 100644 --- a/include/asm-um/bug.h +++ b/include/asm-um/bug.h @@ -23,8 +23,6 @@ } \ } while (0) -extern int foo; - #endif #endif diff --git a/include/asm-um/irq.h b/include/asm-um/irq.h index de389a477..bccf537ec 100644 --- a/include/asm-um/irq.h +++ b/include/asm-um/irq.h @@ -15,8 +15,9 @@ #define SIGIO_WRITE_IRQ 11 #define TELNETD_IRQ 12 #define XTERM_IRQ 13 - -#define LAST_IRQ XTERM_IRQ +#define HUMFS_IRQ 14 + +#define LAST_IRQ HUMFS_IRQ #define NR_IRQS (LAST_IRQ + 1) #endif diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h index ff157c59e..084bb64a8 100644 --- a/include/asm-um/processor-generic.h +++ b/include/asm-um/processor-generic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -22,7 +22,6 @@ struct mm_struct; struct thread_struct { int forking; - unsigned long kernel_stack; int nsyscalls; struct pt_regs regs; unsigned long cr2; @@ -73,7 +72,6 @@ struct thread_struct { #define INIT_THREAD \ { \ .forking = 0, \ - .kernel_stack = 0, \ .nsyscalls = 0, \ .regs = EMPTY_REGS, \ .cr2 = 0, \ -- 2.47.0