From: Mark Huang Date: Fri, 20 Aug 2004 19:33:57 +0000 (+0000) Subject: Merge to uml-2.6.7-2um X-Git-Tag: after-ipod-patch~6 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=fdab6e4619766173e9cc6c4c93a3866e20f690b6;p=linux-2.6.git Merge to uml-2.6.7-2um --- diff --git a/arch/um/Kconfig b/arch/um/Kconfig index 48a634167..e47207391 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 06fe817ca..825e49541 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,15 +43,23 @@ CONFIG_BROKEN_ON_SMP=y # CONFIG_SWAP=y CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y +# CONFIG_POSIX_MQUEUE is not set CONFIG_BSD_PROCESS_ACCT=y + +# +# Class Based Kernel Resource Management +# +# CONFIG_CKRM is not set +# CONFIG_BSD_PROCESS_ACCT_V3 is not set CONFIG_SYSCTL=y -CONFIG_AUDIT=y +# CONFIG_AUDIT is not set CONFIG_LOG_BUF_SHIFT=14 # CONFIG_HOTPLUG is not set # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set +# CONFIG_DELAY_ACCT is not set CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set CONFIG_FUTEX=y CONFIG_EPOLL=y CONFIG_IOSCHED_NOOP=y @@ -66,6 +76,7 @@ CONFIG_IOSCHED_CFQ=y # # Generic Driver Options # +CONFIG_PREVENT_FIRMWARE_BUILD=y # # Character Devices @@ -82,7 +93,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 @@ -163,6 +175,7 @@ CONFIG_INET=y # QoS and/or fair queueing # # CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE is not set # # Network testing @@ -173,7 +186,6 @@ CONFIG_INET=y # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set -# CONFIG_TUX is not set CONFIG_DUMMY=y # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set @@ -231,11 +243,8 @@ 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=y -CONFIG_REISERFS_FS_POSIX_ACL=y -CONFIG_REISERFS_FS_SECURITY=y +# CONFIG_REISERFS_FS_XATTR is not set # CONFIG_JFS_FS is not set -CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set CONFIG_MINIX_FS=y # CONFIG_ROMFS_FS is not set @@ -260,6 +269,8 @@ CONFIG_ISO9660_FS=y CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" # CONFIG_NTFS_FS is not set # @@ -275,6 +286,7 @@ CONFIG_DEVFS_MOUNT=y CONFIG_TMPFS=y # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -288,7 +300,9 @@ CONFIG_RAMFS=y # CONFIG_EFS_FS is not set CONFIG_JFFS_FS=y CONFIG_JFFS_FS_VERBOSE=0 +# CONFIG_JFFS_PROC_FS is not set # CONFIG_JFFS2_FS is not set +# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -342,6 +356,7 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_CODEPAGE_1250 is not set # CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ASCII is not set # CONFIG_NLS_ISO8859_1 is not set # CONFIG_NLS_ISO8859_2 is not set # CONFIG_NLS_ISO8859_3 is not set @@ -382,6 +397,7 @@ CONFIG_INOXID_GID24=y # # Library routines # +# CONFIG_CRC_CCITT is not set # CONFIG_CRC32 is not set # CONFIG_LIBCRC32C is not set @@ -417,6 +433,16 @@ CONFIG_MTD_BLOCK=y # # CONFIG_MTD_CFI is not set # CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set # CONFIG_MTD_RAM is not set # CONFIG_MTD_ROM is not set # CONFIG_MTD_ABSENT is not set @@ -431,6 +457,7 @@ CONFIG_MTD_BLOCK=y # Self-contained MTD device drivers # # CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set # CONFIG_MTD_MTDRAM is not set CONFIG_MTD_BLKMTD=y 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/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/hostaudio_user.c b/arch/um/drivers/hostaudio_user.c deleted file mode 100644 index b89fefb4a..000000000 --- a/arch/um/drivers/hostaudio_user.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2002 Steve Schmidtke - * Licensed under the GPL - */ - -#include -#include -#include -#include "hostaudio.h" -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "os.h" - -/* /dev/dsp file operations */ - -ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, - size_t count, loff_t *ppos) -{ -#ifdef DEBUG - printk("hostaudio: read_user called, count = %d\n", count); -#endif - - return(os_read_file(state->fd, buffer, count)); -} - -ssize_t hostaudio_write_user(struct hostaudio_state *state, const char *buffer, - size_t count, loff_t *ppos) -{ -#ifdef DEBUG - printk("hostaudio: write_user called, count = %d\n", count); -#endif - - return(os_write_file(state->fd, buffer, count)); -} - -int hostaudio_ioctl_user(struct hostaudio_state *state, unsigned int cmd, - unsigned long arg) -{ -#ifdef DEBUG - printk("hostaudio: ioctl_user called, cmd = %u\n", cmd); -#endif - - return(os_ioctl_generic(state->fd, cmd, arg)); -} - -int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp) -{ -#ifdef DEBUG - printk("hostaudio: open_user called\n"); -#endif - - state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); - - if(state->fd < 0) { - printk("hostaudio_open_user failed to open '%s', err = %d\n", - dsp, -state->fd); - return(state->fd); - } - - return(0); -} - -int hostaudio_release_user(struct hostaudio_state *state) -{ -#ifdef DEBUG - printk("hostaudio: release called\n"); -#endif - if(state->fd >= 0){ - os_close_file(state->fd); - state->fd = -1; - } - - return(0); -} - -/* /dev/mixer file operations */ - -int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, - unsigned int cmd, unsigned long arg) -{ -#ifdef DEBUG - printk("hostmixer: ioctl_user called cmd = %u\n",cmd); -#endif - - return(os_ioctl_generic(state->fd, cmd, arg)); -} - -int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w, - char *mixer) -{ -#ifdef DEBUG - printk("hostmixer: open_user called\n"); -#endif - - state->fd = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); - - if(state->fd < 0) { - printk("hostaudio_open_mixdev_user failed to open '%s', " - "err = %d\n", mixer, state->fd); - return(state->fd); - } - - return(0); -} - -int hostmixer_release_mixdev_user(struct hostmixer_state *state) -{ -#ifdef DEBUG - printk("hostmixer: release_user called\n"); -#endif - - if(state->fd >= 0){ - os_close_file(state->fd); - state->fd = -1; - } - - return 0; -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --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/hostaudio.h b/arch/um/include/hostaudio.h deleted file mode 100644 index 797b3f24e..000000000 --- a/arch/um/include/hostaudio.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2002 Steve Schmidtke - * Licensed under the GPL - */ - -#ifndef HOSTAUDIO_H -#define HOSTAUDIO_H - -#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp" -#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer" - -struct hostaudio_state { - int fd; -}; - -struct hostmixer_state { - int fd; -}; - -/* UML user-side protoypes */ -extern ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, - size_t count, loff_t *ppos); -extern ssize_t hostaudio_write_user(struct hostaudio_state *state, - const char *buffer, size_t count, - loff_t *ppos); -extern int hostaudio_ioctl_user(struct hostaudio_state *state, - unsigned int cmd, unsigned long arg); -extern int hostaudio_open_user(struct hostaudio_state *state, int r, int w, - char *dsp); -extern int hostaudio_release_user(struct hostaudio_state *state); -extern int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, - unsigned int cmd, unsigned long arg); -extern int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, - int w, char *mixer); -extern int hostmixer_release_mixdev_user(struct hostmixer_state *state); - -#endif /* HOSTAUDIO_H */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/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/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..cb12aa824 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 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/mprot.h b/arch/um/kernel/mprot.h deleted file mode 100644 index 83dc8ccee..000000000 --- a/arch/um/kernel/mprot.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __MPROT_H__ -#define __MPROT_H__ - -extern void no_access(unsigned long addr, unsigned int len); - -#endif 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/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 d646f1daf..1e7c1f1a8 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 @@ -80,20 +81,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) || @@ -109,8 +109,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); } @@ -118,18 +118,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); } @@ -152,6 +161,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 47f90448e..6e351e41a 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 bitops.o sigcontext.o syscalls.o sysrq.o time.o + semaphore.o bitops.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/sys-i386/time.c b/arch/um/sys-i386/time.c deleted file mode 100644 index a6a5ba755..000000000 --- a/arch/um/sys-i386/time.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * sys-i386/time.c - * Created 25.9.2002 Sapan Bhatia - * - */ - -unsigned long long time_stamp(void) -{ - unsigned long low, high; - - asm("rdtsc" : "=a" (low), "=d" (high)); - return((((unsigned long long) high) << 32) + low); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --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/arch/um/util/mk_constants b/arch/um/util/mk_constants deleted file mode 100644 index 2cc984204..000000000 Binary files a/arch/um/util/mk_constants and /dev/null differ diff --git a/arch/um/util/mk_task b/arch/um/util/mk_task deleted file mode 100644 index 1f4f75021..000000000 Binary files a/arch/um/util/mk_task and /dev/null differ diff --git a/fs/Makefile b/fs/Makefile index e39e43f35..9911572f2 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -92,6 +92,5 @@ 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/ obj-$(CONFIG_RCFS_FS) += rcfs/ diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c deleted file mode 100644 index ef5d5d1bf..000000000 --- a/fs/hostfs/hostfs_kern.c +++ /dev/null @@ -1,1008 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - * - * Ported the filesystem routines to 2.5. - * 2003-02-10 Petr Baudis - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hostfs.h" -#include "kern_util.h" -#include "kern.h" -#include "user_util.h" -#include "2_5compat.h" -#include "init.h" - -struct hostfs_inode_info { - char *host_filename; - int fd; - int mode; - struct inode vfs_inode; -}; - -static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode) -{ - return(list_entry(inode, struct hostfs_inode_info, vfs_inode)); -} - -#define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_dentry->d_inode) - -int hostfs_d_delete(struct dentry *dentry) -{ - return(1); -} - -struct dentry_operations hostfs_dentry_ops = { - .d_delete = hostfs_d_delete, -}; - -/* Changed in hostfs_args before the kernel starts running */ -static char *root_ino = "/"; -static int append = 0; - -#define HOSTFS_SUPER_MAGIC 0x00c0ffee - -static struct inode_operations hostfs_iops; -static struct inode_operations hostfs_dir_iops; -static struct address_space_operations hostfs_link_aops; - -static int __init hostfs_args(char *options, int *add) -{ - char *ptr; - - ptr = strchr(options, ','); - if(ptr != NULL) - *ptr++ = '\0'; - if(*options != '\0') - root_ino = options; - - options = ptr; - while(options){ - ptr = strchr(options, ','); - if(ptr != NULL) - *ptr++ = '\0'; - if(*options != '\0'){ - if(!strcmp(options, "append")) - append = 1; - else printf("hostfs_args - unsupported option - %s\n", - options); - } - options = ptr; - } - return(0); -} - -__uml_setup("hostfs=", hostfs_args, -"hostfs=,,...\n" -" This is used to set hostfs parameters. The root directory argument\n" -" is used to confine all hostfs mounts to within the specified directory\n" -" tree on the host. If this isn't specified, then a user inside UML can\n" -" mount anything on the host that's accessible to the user that's running\n" -" it.\n" -" The only flag currently supported is 'append', which specifies that all\n" -" files opened by hostfs will be opened in append mode.\n\n" -); - -static char *dentry_name(struct dentry *dentry, int extra) -{ - struct dentry *parent; - char *root, *name; - int len; - - len = 0; - parent = dentry; - while(parent->d_parent != parent){ - len += parent->d_name.len + 1; - parent = parent->d_parent; - } - - root = HOSTFS_I(parent->d_inode)->host_filename; - len += strlen(root); - name = kmalloc(len + extra + 1, GFP_KERNEL); - if(name == NULL) return(NULL); - - name[len] = '\0'; - parent = dentry; - while(parent->d_parent != parent){ - len -= parent->d_name.len + 1; - name[len] = '/'; - strncpy(&name[len + 1], parent->d_name.name, - parent->d_name.len); - parent = parent->d_parent; - } - strncpy(name, root, strlen(root)); - return(name); -} - -static char *inode_name(struct inode *ino, int extra) -{ - struct dentry *dentry; - - dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias); - return(dentry_name(dentry, extra)); -} - -static int read_name(struct inode *ino, char *name) -{ - /* The non-int inode fields are copied into ints by stat_file and - * then copied into the inode because passing the actual pointers - * in and having them treated as int * breaks on big-endian machines - */ - int err; - int i_mode, i_nlink, i_blksize; - unsigned long long i_size; - unsigned long long i_ino; - unsigned long long i_blocks; - - err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid, - &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime, - &ino->i_ctime, &i_blksize, &i_blocks); - if(err) - return(err); - - ino->i_ino = i_ino; - ino->i_mode = i_mode; - ino->i_nlink = i_nlink; - ino->i_size = i_size; - ino->i_blksize = i_blksize; - ino->i_blocks = i_blocks; - if((ino->i_sb->s_dev == ROOT_DEV) && (ino->i_uid == getuid())) - ino->i_uid = 0; - return(0); -} - -static char *follow_link(char *link) -{ - int len, n; - char *name, *resolved, *end; - - len = 64; - while(1){ - n = -ENOMEM; - name = kmalloc(len, GFP_KERNEL); - if(name == NULL) - goto out; - - n = do_readlink(link, name, len); - if(n < len) - break; - len *= 2; - kfree(name); - } - if(n < 0) - goto out_free; - - if(*name == '/') - return(name); - - end = strrchr(link, '/'); - if(end == NULL) - return(name); - - *(end + 1) = '\0'; - len = strlen(link) + strlen(name) + 1; - - resolved = kmalloc(len, GFP_KERNEL); - if(resolved == NULL){ - n = -ENOMEM; - goto out_free; - } - - sprintf(resolved, "%s%s", link, name); - kfree(name); - kfree(link); - return(resolved); - - out_free: - kfree(name); - out: - return(ERR_PTR(n)); -} - -static int read_inode(struct inode *ino) -{ - char *name; - int err = 0; - - /* Unfortunately, we are called from iget() when we don't have a dentry - * allocated yet. - */ - if(list_empty(&ino->i_dentry)) - goto out; - - err = -ENOMEM; - name = inode_name(ino, 0); - if(name == NULL) - goto out; - - if(file_type(name, NULL) == OS_TYPE_SYMLINK){ - name = follow_link(name); - if(IS_ERR(name)){ - err = PTR_ERR(name); - goto out; - } - } - - err = read_name(ino, name); - kfree(name); - out: - return(err); -} - -int hostfs_statfs(struct super_block *sb, struct kstatfs *sf) -{ - /* do_statfs uses struct statfs64 internally, but the linux kernel - * struct statfs still has 32-bit versions for most of these fields, - * so we convert them here - */ - int err; - long long f_blocks; - long long f_bfree; - long long f_bavail; - long long f_files; - long long f_ffree; - - err = do_statfs(HOSTFS_I(sb->s_root->d_inode)->host_filename, - &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files, - &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid), - &sf->f_namelen, sf->f_spare); - if(err) return(err); - sf->f_blocks = f_blocks; - sf->f_bfree = f_bfree; - sf->f_bavail = f_bavail; - sf->f_files = f_files; - sf->f_ffree = f_ffree; - sf->f_type = HOSTFS_SUPER_MAGIC; - return(0); -} - -static struct inode *hostfs_alloc_inode(struct super_block *sb) -{ - struct hostfs_inode_info *hi; - - hi = kmalloc(sizeof(*hi), GFP_KERNEL); - if(hi == NULL) - return(NULL); - - *hi = ((struct hostfs_inode_info) { .host_filename = NULL, - .fd = -1, - .mode = 0 }); - inode_init_once(&hi->vfs_inode); - return(&hi->vfs_inode); -} - -static void hostfs_destroy_inode(struct inode *inode) -{ - if(HOSTFS_I(inode)->host_filename) - kfree(HOSTFS_I(inode)->host_filename); - - if(HOSTFS_I(inode)->fd != -1) - close_file(&HOSTFS_I(inode)->fd); - - kfree(HOSTFS_I(inode)); -} - -static void hostfs_read_inode(struct inode *inode) -{ - read_inode(inode); -} - -static struct super_operations hostfs_sbops = { - .alloc_inode = hostfs_alloc_inode, - .destroy_inode = hostfs_destroy_inode, - .read_inode = hostfs_read_inode, - .statfs = hostfs_statfs, -}; - -int hostfs_readdir(struct file *file, void *ent, filldir_t filldir) -{ - void *dir; - char *name; - unsigned long long next, ino; - int error, len; - - name = dentry_name(file->f_dentry, 0); - if(name == NULL) return(-ENOMEM); - dir = open_dir(name, &error); - kfree(name); - if(dir == NULL) return(-error); - next = file->f_pos; - while((name = read_dir(dir, &next, &ino, &len)) != NULL){ - error = (*filldir)(ent, name, len, file->f_pos, - ino, DT_UNKNOWN); - if(error) break; - file->f_pos = next; - } - close_dir(dir); - return(0); -} - -int hostfs_file_open(struct inode *ino, struct file *file) -{ - char *name; - int mode = 0, r = 0, w = 0, fd; - - mode = file->f_mode & (FMODE_READ | FMODE_WRITE); - if((mode & HOSTFS_I(ino)->mode) == mode) - return(0); - - /* The file may already have been opened, but with the wrong access, - * so this resets things and reopens the file with the new access. - */ - if(HOSTFS_I(ino)->fd != -1){ - close_file(&HOSTFS_I(ino)->fd); - HOSTFS_I(ino)->fd = -1; - } - - HOSTFS_I(ino)->mode |= mode; - if(HOSTFS_I(ino)->mode & FMODE_READ) - r = 1; - if(HOSTFS_I(ino)->mode & FMODE_WRITE) - w = 1; - if(w) - r = 1; - - name = dentry_name(file->f_dentry, 0); - if(name == NULL) - return(-ENOMEM); - - fd = open_file(name, r, w, append); - kfree(name); - if(fd < 0) return(fd); - FILE_HOSTFS_I(file)->fd = fd; - - return(0); -} - -int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync) -{ - return(0); -} - -static struct file_operations hostfs_file_fops = { - .llseek = generic_file_llseek, - .read = generic_file_read, - .write = generic_file_write, - .mmap = generic_file_mmap, - .open = hostfs_file_open, - .release = NULL, - .fsync = hostfs_fsync, -}; - -static struct file_operations hostfs_dir_fops = { - .readdir = hostfs_readdir, - .read = generic_read_dir, -}; - -int hostfs_writepage(struct page *page, struct writeback_control *wbc) -{ - struct address_space *mapping = page->mapping; - struct inode *inode = mapping->host; - char *buffer; - unsigned long long base; - int count = PAGE_CACHE_SIZE; - int end_index = inode->i_size >> PAGE_CACHE_SHIFT; - int err; - - if (page->index >= end_index) - count = inode->i_size & (PAGE_CACHE_SIZE-1); - - buffer = kmap(page); - base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT; - - err = write_file(HOSTFS_I(inode)->fd, &base, buffer, count); - if(err != count){ - ClearPageUptodate(page); - goto out; - } - - if (base > inode->i_size) - inode->i_size = base; - - if (PageError(page)) - ClearPageError(page); - err = 0; - - out: - kunmap(page); - - unlock_page(page); - return err; -} - -int hostfs_readpage(struct file *file, struct page *page) -{ - char *buffer; - long long start; - int err = 0; - - start = (long long) page->index << PAGE_CACHE_SHIFT; - buffer = kmap(page); - err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer, - PAGE_CACHE_SIZE); - if(err < 0) goto out; - - memset(&buffer[err], 0, PAGE_CACHE_SIZE - err); - - flush_dcache_page(page); - SetPageUptodate(page); - if (PageError(page)) ClearPageError(page); - err = 0; - out: - kunmap(page); - unlock_page(page); - return(err); -} - -int hostfs_prepare_write(struct file *file, struct page *page, - unsigned int from, unsigned int to) -{ - char *buffer; - long long start, tmp; - int err; - - start = (long long) page->index << PAGE_CACHE_SHIFT; - buffer = kmap(page); - if(from != 0){ - tmp = start; - err = read_file(FILE_HOSTFS_I(file)->fd, &tmp, buffer, - from); - if(err < 0) goto out; - } - if(to != PAGE_CACHE_SIZE){ - start += to; - err = read_file(FILE_HOSTFS_I(file)->fd, &start, buffer + to, - PAGE_CACHE_SIZE - to); - if(err < 0) goto out; - } - err = 0; - out: - kunmap(page); - return(err); -} - -int hostfs_commit_write(struct file *file, struct page *page, unsigned from, - unsigned to) -{ - struct address_space *mapping = page->mapping; - struct inode *inode = mapping->host; - char *buffer; - long long start; - int err = 0; - - start = (long long) (page->index << PAGE_CACHE_SHIFT) + from; - buffer = kmap(page); - err = write_file(FILE_HOSTFS_I(file)->fd, &start, buffer + from, - to - from); - if(err > 0) err = 0; - if(!err && (start > inode->i_size)) - inode->i_size = start; - - kunmap(page); - return(err); -} - -static struct address_space_operations hostfs_aops = { - .writepage = hostfs_writepage, - .readpage = hostfs_readpage, -/* .set_page_dirty = __set_page_dirty_nobuffers, */ - .prepare_write = hostfs_prepare_write, - .commit_write = hostfs_commit_write -}; - -static int init_inode(struct inode *inode, struct dentry *dentry) -{ - char *name; - int type, err = -ENOMEM, rdev; - - if(dentry){ - name = dentry_name(dentry, 0); - if(name == NULL) - goto out; - type = file_type(name, &rdev); - kfree(name); - } - else type = OS_TYPE_DIR; - - err = 0; - if(type == OS_TYPE_SYMLINK) - inode->i_op = &page_symlink_inode_operations; - else if(type == OS_TYPE_DIR) - inode->i_op = &hostfs_dir_iops; - else inode->i_op = &hostfs_iops; - - if(type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops; - else inode->i_fop = &hostfs_file_fops; - - if(type == OS_TYPE_SYMLINK) - inode->i_mapping->a_ops = &hostfs_link_aops; - else inode->i_mapping->a_ops = &hostfs_aops; - - switch (type) { - case OS_TYPE_CHARDEV: - init_special_inode(inode, S_IFCHR, rdev); - break; - case OS_TYPE_BLOCKDEV: - init_special_inode(inode, S_IFBLK, rdev); - break; - case OS_TYPE_FIFO: - init_special_inode(inode, S_IFIFO, 0); - break; - case OS_TYPE_SOCK: - init_special_inode(inode, S_IFSOCK, 0); - break; - } - out: - return(err); -} - -int hostfs_create(struct inode *dir, struct dentry *dentry, int mode, - struct nameidata *nd) -{ - struct inode *inode; - char *name; - int error, fd; - - error = -ENOMEM; - inode = iget(dir->i_sb, 0); - if(inode == NULL) goto out; - - error = init_inode(inode, dentry); - if(error) - goto out_put; - - error = -ENOMEM; - name = dentry_name(dentry, 0); - if(name == NULL) - goto out_put; - - fd = file_create(name, - mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR, - mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP, - mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH); - if(fd < 0) - error = fd; - else error = read_name(inode, name); - - kfree(name); - if(error) - goto out_put; - - HOSTFS_I(inode)->fd = fd; - HOSTFS_I(inode)->mode = FMODE_READ | FMODE_WRITE; - d_instantiate(dentry, inode); - return(0); - - out_put: - iput(inode); - out: - return(error); -} - -struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry, - struct nameidata *nd) -{ - struct inode *inode; - char *name; - int err; - - err = -ENOMEM; - inode = iget(ino->i_sb, 0); - if(inode == NULL) - goto out; - - err = init_inode(inode, dentry); - if(err) - goto out_put; - - err = -ENOMEM; - name = dentry_name(dentry, 0); - if(name == NULL) - goto out_put; - - err = read_name(inode, name); - kfree(name); - if(err == -ENOENT){ - iput(inode); - inode = NULL; - } - else if(err) - goto out_put; - - d_add(dentry, inode); - dentry->d_op = &hostfs_dentry_ops; - return(NULL); - - out_put: - iput(inode); - out: - return(ERR_PTR(err)); -} - -static char *inode_dentry_name(struct inode *ino, struct dentry *dentry) -{ - char *file; - int len; - - file = inode_name(ino, dentry->d_name.len + 1); - if(file == NULL) return(NULL); - strcat(file, "/"); - len = strlen(file); - strncat(file, dentry->d_name.name, dentry->d_name.len); - file[len + dentry->d_name.len] = '\0'; - return(file); -} - -int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from) -{ - char *from_name, *to_name; - int err; - - if((from_name = inode_dentry_name(ino, from)) == NULL) - return(-ENOMEM); - to_name = dentry_name(to, 0); - if(to_name == NULL){ - kfree(from_name); - return(-ENOMEM); - } - err = link_file(to_name, from_name); - kfree(from_name); - kfree(to_name); - return(err); -} - -int hostfs_unlink(struct inode *ino, struct dentry *dentry) -{ - char *file; - int err; - - if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); - if(append) - return(-EPERM); - - err = unlink_file(file); - kfree(file); - return(err); -} - -int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to) -{ - char *file; - int err; - - if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); - err = make_symlink(file, to); - kfree(file); - return(err); -} - -int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode) -{ - char *file; - int err; - - if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); - err = do_mkdir(file, mode); - kfree(file); - return(err); -} - -int hostfs_rmdir(struct inode *ino, struct dentry *dentry) -{ - char *file; - int err; - - if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); - err = do_rmdir(file); - kfree(file); - return(err); -} - -int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) -{ - struct inode *inode; - char *name; - int err = -ENOMEM; - - inode = iget(dir->i_sb, 0); - if(inode == NULL) - goto out; - - err = init_inode(inode, dentry); - if(err) - goto out_put; - - err = -ENOMEM; - name = dentry_name(dentry, 0); - if(name == NULL) - goto out_put; - - init_special_inode(inode, mode, dev); - err = do_mknod(name, mode, dev); - if(err) - goto out_free; - - err = read_name(inode, name); - kfree(name); - if(err) - goto out_put; - - d_instantiate(dentry, inode); - return(0); - - out_free: - kfree(name); - out_put: - iput(inode); - out: - return(err); -} - -int hostfs_rename(struct inode *from_ino, struct dentry *from, - struct inode *to_ino, struct dentry *to) -{ - char *from_name, *to_name; - int err; - - if((from_name = inode_dentry_name(from_ino, from)) == NULL) - return(-ENOMEM); - if((to_name = inode_dentry_name(to_ino, to)) == NULL){ - kfree(from_name); - return(-ENOMEM); - } - err = rename_file(from_name, to_name); - kfree(from_name); - kfree(to_name); - return(err); -} - -void hostfs_truncate(struct inode *ino) -{ - not_implemented(); -} - -int hostfs_permission(struct inode *ino, int desired, struct nameidata *nd) -{ - char *name; - int r = 0, w = 0, x = 0, err; - - if(desired & MAY_READ) r = 1; - if(desired & MAY_WRITE) w = 1; - if(desired & MAY_EXEC) x = 1; - name = inode_name(ino, 0); - if(name == NULL) return(-ENOMEM); - err = access_file(name, r, w, x); - kfree(name); - if(!err) err = vfs_permission(ino, desired); - return(err); -} - -int hostfs_setattr(struct dentry *dentry, struct iattr *attr) -{ - struct hostfs_iattr attrs; - char *name; - int err; - - if(append) - attr->ia_valid &= ~ATTR_SIZE; - - attrs.ia_valid = 0; - if(attr->ia_valid & ATTR_MODE){ - attrs.ia_valid |= HOSTFS_ATTR_MODE; - attrs.ia_mode = attr->ia_mode; - } - if(attr->ia_valid & ATTR_UID){ - if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) && - (attr->ia_uid == 0)) - attr->ia_uid = getuid(); - attrs.ia_valid |= HOSTFS_ATTR_UID; - attrs.ia_uid = attr->ia_uid; - } - if(attr->ia_valid & ATTR_GID){ - if((dentry->d_inode->i_sb->s_dev == ROOT_DEV) && - (attr->ia_gid == 0)) - attr->ia_gid = getuid(); - attrs.ia_valid |= HOSTFS_ATTR_GID; - attrs.ia_gid = attr->ia_gid; - } - if(attr->ia_valid & ATTR_SIZE){ - attrs.ia_valid |= HOSTFS_ATTR_SIZE; - attrs.ia_size = attr->ia_size; - } - if(attr->ia_valid & ATTR_ATIME){ - attrs.ia_valid |= HOSTFS_ATTR_ATIME; - attrs.ia_atime = attr->ia_atime; - } - if(attr->ia_valid & ATTR_MTIME){ - attrs.ia_valid |= HOSTFS_ATTR_MTIME; - attrs.ia_mtime = attr->ia_mtime; - } - if(attr->ia_valid & ATTR_CTIME){ - attrs.ia_valid |= HOSTFS_ATTR_CTIME; - attrs.ia_ctime = attr->ia_ctime; - } - if(attr->ia_valid & ATTR_ATIME_SET){ - attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET; - } - if(attr->ia_valid & ATTR_MTIME_SET){ - attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET; - } - name = dentry_name(dentry, 0); - if(name == NULL) return(-ENOMEM); - err = set_attr(name, &attrs); - kfree(name); - if(err) - return(err); - - return(inode_setattr(dentry->d_inode, attr)); -} - -int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - generic_fillattr(dentry->d_inode, stat); - return(0); -} - -static struct inode_operations hostfs_iops = { - .create = hostfs_create, - .link = hostfs_link, - .unlink = hostfs_unlink, - .symlink = hostfs_symlink, - .mkdir = hostfs_mkdir, - .rmdir = hostfs_rmdir, - .mknod = hostfs_mknod, - .rename = hostfs_rename, - .truncate = hostfs_truncate, - .permission = hostfs_permission, - .setattr = hostfs_setattr, - .getattr = hostfs_getattr, -}; - -static struct inode_operations hostfs_dir_iops = { - .create = hostfs_create, - .lookup = hostfs_lookup, - .link = hostfs_link, - .unlink = hostfs_unlink, - .symlink = hostfs_symlink, - .mkdir = hostfs_mkdir, - .rmdir = hostfs_rmdir, - .mknod = hostfs_mknod, - .rename = hostfs_rename, - .truncate = hostfs_truncate, - .permission = hostfs_permission, - .setattr = hostfs_setattr, - .getattr = hostfs_getattr, -}; - -int hostfs_link_readpage(struct file *file, struct page *page) -{ - char *buffer, *name; - long long start; - int err; - - start = page->index << PAGE_CACHE_SHIFT; - buffer = kmap(page); - name = inode_name(page->mapping->host, 0); - if(name == NULL) return(-ENOMEM); - err = do_readlink(name, buffer, PAGE_CACHE_SIZE); - kfree(name); - if(err == PAGE_CACHE_SIZE) - err = -E2BIG; - else if(err > 0){ - flush_dcache_page(page); - SetPageUptodate(page); - if (PageError(page)) ClearPageError(page); - err = 0; - } - kunmap(page); - unlock_page(page); - return(err); -} - -static struct address_space_operations hostfs_link_aops = { - .readpage = hostfs_link_readpage, -}; - -static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) -{ - struct inode *root_inode; - char *name, *data = d; - int err; - - sb->s_blocksize = 1024; - sb->s_blocksize_bits = 10; - sb->s_magic = HOSTFS_SUPER_MAGIC; - sb->s_op = &hostfs_sbops; - - if((data == NULL) || (*data == '\0')) - data = root_ino; - - err = -ENOMEM; - name = kmalloc(strlen(data) + 1, GFP_KERNEL); - if(name == NULL) - goto out; - - strcpy(name, data); - - root_inode = iget(sb, 0); - if(root_inode == NULL) - goto out_free; - - err = init_inode(root_inode, NULL); - if(err) - goto out_put; - - HOSTFS_I(root_inode)->host_filename = name; - - err = -ENOMEM; - sb->s_root = d_alloc_root(root_inode); - if(sb->s_root == NULL) - goto out_put; - - err = read_inode(root_inode); - if(err) - goto out_put; - - return(0); - - out_put: - iput(root_inode); - out_free: - kfree(name); - out: - return(err); -} - -static struct super_block *hostfs_read_sb(struct file_system_type *type, - int flags, const char *dev_name, - void *data) -{ - return(get_sb_nodev(type, flags, data, hostfs_fill_sb_common)); -} - -static struct file_system_type hostfs_type = { - .owner = THIS_MODULE, - .name = "hostfs", - .get_sb = hostfs_read_sb, - .kill_sb = kill_anon_super, - .fs_flags = 0, -}; - -static int __init init_hostfs(void) -{ - return(register_filesystem(&hostfs_type)); -} - -static void __exit exit_hostfs(void) -{ - unregister_filesystem(&hostfs_type); -} - -module_init(init_hostfs) -module_exit(exit_hostfs) -MODULE_LICENSE("GPL"); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c deleted file mode 100644 index c40626609..000000000 --- a/fs/hostfs/hostfs_user.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hostfs.h" -#include "kern_util.h" -#include "user.h" - -int stat_file(const char *path, unsigned long long *inode_out, int *mode_out, - int *nlink_out, int *uid_out, int *gid_out, - unsigned long long *size_out, struct timespec *atime_out, - struct timespec *mtime_out, struct timespec *ctime_out, - int *blksize_out, unsigned long long *blocks_out) -{ - struct stat64 buf; - - if(lstat64(path, &buf) < 0) - return(-errno); - - /* See the Makefile for why STAT64_INO_FIELD is passed in - * by the build - */ - if(inode_out != NULL) *inode_out = buf.STAT64_INO_FIELD; - if(mode_out != NULL) *mode_out = buf.st_mode; - if(nlink_out != NULL) *nlink_out = buf.st_nlink; - if(uid_out != NULL) *uid_out = buf.st_uid; - if(gid_out != NULL) *gid_out = buf.st_gid; - if(size_out != NULL) *size_out = buf.st_size; - if(atime_out != NULL) { - atime_out->tv_sec = buf.st_atime; - atime_out->tv_nsec = 0; - } - if(mtime_out != NULL) { - mtime_out->tv_sec = buf.st_mtime; - mtime_out->tv_nsec = 0; - } - if(ctime_out != NULL) { - ctime_out->tv_sec = buf.st_ctime; - ctime_out->tv_nsec = 0; - } - if(blksize_out != NULL) *blksize_out = buf.st_blksize; - if(blocks_out != NULL) *blocks_out = buf.st_blocks; - return(0); -} - -int file_type(const char *path, int *rdev) -{ - struct stat64 buf; - - if(lstat64(path, &buf) < 0) - return(-errno); - if(rdev != NULL) - *rdev = buf.st_rdev; - - if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR); - else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK); - else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV); - else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV); - else if(S_ISFIFO(buf.st_mode))return(OS_TYPE_FIFO); - else if(S_ISSOCK(buf.st_mode))return(OS_TYPE_SOCK); - else return(OS_TYPE_FILE); -} - -int access_file(char *path, int r, int w, int x) -{ - int mode = 0; - - if(r) mode = R_OK; - if(w) mode |= W_OK; - if(x) mode |= X_OK; - if(access(path, mode) != 0) return(-errno); - else return(0); -} - -int open_file(char *path, int r, int w, int append) -{ - int mode = 0, fd; - - if(r && !w) - mode = O_RDONLY; - else if(!r && w) - mode = O_WRONLY; - else if(r && w) - mode = O_RDWR; - else panic("Impossible mode in open_file"); - - if(append) - mode |= O_APPEND; - fd = open64(path, mode); - if(fd < 0) return(-errno); - else return(fd); -} - -void *open_dir(char *path, int *err_out) -{ - DIR *dir; - - dir = opendir(path); - *err_out = errno; - if(dir == NULL) return(NULL); - return(dir); -} - -char *read_dir(void *stream, unsigned long long *pos, - unsigned long long *ino_out, int *len_out) -{ - DIR *dir = stream; - struct dirent *ent; - - seekdir(dir, *pos); - ent = readdir(dir); - if(ent == NULL) return(NULL); - *len_out = strlen(ent->d_name); - *ino_out = ent->d_ino; - *pos = telldir(dir); - return(ent->d_name); -} - -int read_file(int fd, unsigned long long *offset, char *buf, int len) -{ - int n; - - n = pread64(fd, buf, len, *offset); - if(n < 0) return(-errno); - *offset += n; - return(n); -} - -int write_file(int fd, unsigned long long *offset, const char *buf, int len) -{ - int n; - - n = pwrite64(fd, buf, len, *offset); - if(n < 0) return(-errno); - *offset += n; - return(n); -} - -int lseek_file(int fd, long long offset, int whence) -{ - int ret; - - ret = lseek64(fd, offset, whence); - if(ret < 0) return(-errno); - return(0); -} - -void close_file(void *stream) -{ - close(*((int *) stream)); -} - -void close_dir(void *stream) -{ - closedir(stream); -} - -int file_create(char *name, int ur, int uw, int ux, int gr, - int gw, int gx, int or, int ow, int ox) -{ - int mode, fd; - - mode = 0; - mode |= ur ? S_IRUSR : 0; - mode |= uw ? S_IWUSR : 0; - mode |= ux ? S_IXUSR : 0; - mode |= gr ? S_IRGRP : 0; - mode |= gw ? S_IWGRP : 0; - mode |= gx ? S_IXGRP : 0; - mode |= or ? S_IROTH : 0; - mode |= ow ? S_IWOTH : 0; - mode |= ox ? S_IXOTH : 0; - fd = open64(name, O_CREAT | O_RDWR, mode); - if(fd < 0) - return(-errno); - return(fd); -} - -int set_attr(const char *file, struct hostfs_iattr *attrs) -{ - struct utimbuf buf; - int err, ma; - - if(attrs->ia_valid & HOSTFS_ATTR_MODE){ - if(chmod(file, attrs->ia_mode) != 0) return(-errno); - } - if(attrs->ia_valid & HOSTFS_ATTR_UID){ - if(chown(file, attrs->ia_uid, -1)) return(-errno); - } - if(attrs->ia_valid & HOSTFS_ATTR_GID){ - if(chown(file, -1, attrs->ia_gid)) return(-errno); - } - if(attrs->ia_valid & HOSTFS_ATTR_SIZE){ - if(truncate(file, attrs->ia_size)) return(-errno); - } - ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET; - if((attrs->ia_valid & ma) == ma){ - buf.actime = attrs->ia_atime.tv_sec; - buf.modtime = attrs->ia_mtime.tv_sec; - if(utime(file, &buf) != 0) return(-errno); - } - else { - struct timespec ts; - - if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){ - err = stat_file(file, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, &ts, NULL, NULL, NULL); - if(err != 0) - return(err); - buf.actime = attrs->ia_atime.tv_sec; - buf.modtime = ts.tv_sec; - if(utime(file, &buf) != 0) - return(-errno); - } - if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){ - err = stat_file(file, NULL, NULL, NULL, NULL, NULL, - NULL, &ts, NULL, NULL, NULL, NULL); - if(err != 0) - return(err); - buf.actime = ts.tv_sec; - buf.modtime = attrs->ia_mtime.tv_sec; - if(utime(file, &buf) != 0) - return(-errno); - } - } - if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ; - if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){ - err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL, - &attrs->ia_atime, &attrs->ia_mtime, NULL, - NULL, NULL); - if(err != 0) return(err); - } - return(0); -} - -int make_symlink(const char *from, const char *to) -{ - int err; - - err = symlink(to, from); - if(err) return(-errno); - return(0); -} - -int unlink_file(const char *file) -{ - int err; - - err = unlink(file); - if(err) return(-errno); - return(0); -} - -int do_mkdir(const char *file, int mode) -{ - int err; - - err = mkdir(file, mode); - if(err) return(-errno); - return(0); -} - -int do_rmdir(const char *file) -{ - int err; - - err = rmdir(file); - if(err) return(-errno); - return(0); -} - -int do_mknod(const char *file, int mode, int dev) -{ - int err; - - err = mknod(file, mode, dev); - if(err) return(-errno); - return(0); -} - -int link_file(const char *to, const char *from) -{ - int err; - - err = link(to, from); - if(err) return(-errno); - return(0); -} - -int do_readlink(char *file, char *buf, int size) -{ - int n; - - n = readlink(file, buf, size); - if(n < 0) - return(-errno); - if(n < size) - buf[n] = '\0'; - return(n); -} - -int rename_file(char *from, char *to) -{ - int err; - - err = rename(from, to); - if(err < 0) return(-errno); - return(0); -} - -int do_statfs(char *root, long *bsize_out, long long *blocks_out, - long long *bfree_out, long long *bavail_out, - long long *files_out, long long *ffree_out, - void *fsid_out, int fsid_size, long *namelen_out, - long *spare_out) -{ - struct statfs64 buf; - int err; - - err = statfs64(root, &buf); - if(err < 0) return(-errno); - *bsize_out = buf.f_bsize; - *blocks_out = buf.f_blocks; - *bfree_out = buf.f_bfree; - *bavail_out = buf.f_bavail; - *files_out = buf.f_files; - *ffree_out = buf.f_ffree; - memcpy(fsid_out, &buf.f_fsid, - sizeof(buf.f_fsid) > fsid_size ? fsid_size : - sizeof(buf.f_fsid)); - *namelen_out = buf.f_namelen; - spare_out[0] = buf.f_spare[0]; - spare_out[1] = buf.f_spare[1]; - spare_out[2] = buf.f_spare[2]; - spare_out[3] = buf.f_spare[3]; - spare_out[4] = buf.f_spare[4]; - spare_out[5] = buf.f_spare[5]; - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --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 b2a2bd404..2f06a7bdb 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 */ @@ -24,7 +24,6 @@ struct mm_struct; struct thread_struct { int forking; - unsigned long kernel_stack; int nsyscalls; struct pt_regs regs; unsigned long cr2; @@ -75,7 +74,6 @@ struct thread_struct { #define INIT_THREAD \ { \ .forking = 0, \ - .kernel_stack = 0, \ .nsyscalls = 0, \ .regs = EMPTY_REGS, \ .cr2 = 0, \