diff options
author | David Woodhouse <dwmw2@infradead.org> | 2007-07-23 10:20:10 +0100 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2007-07-23 10:20:10 +0100 |
commit | 39fe5434cb9de5da40510028b17b96bc4eb312b3 (patch) | |
tree | 7a02a317b9ad57da51ca99887c119e779ccf3f13 /arch/um | |
parent | 0fc72b81d3111d114ab378935b1cf07680ca1289 (diff) | |
parent | f695baf2df9e0413d3521661070103711545207a (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'arch/um')
43 files changed, 391 insertions, 675 deletions
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug index 09c1aca6339..c86f5eb29fd 100644 --- a/arch/um/Kconfig.debug +++ b/arch/um/Kconfig.debug @@ -47,4 +47,13 @@ config GCOV If you're involved in UML kernel development and want to use gcov, say Y. If you're unsure, say N. +config DEBUG_STACK_USAGE + bool "Stack utilization instrumentation" + default N + help + Track the maximum kernel stack usage - this will look at each + kernel stack at process exit and log it if it's the deepest + stack seen so far. + + This option will slow down process creation and destruction somewhat. endmenu diff --git a/arch/um/Makefile b/arch/um/Makefile index 5d5ed726faa..989224f2134 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -146,7 +146,7 @@ define cmd_vmlinux__ -Wl,-T,$(vmlinux-lds) $(vmlinux-init) \ -Wl,--start-group $(vmlinux-main) -Wl,--end-group \ -lutil \ - $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) \ + $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o \ FORCE ,$^) ; rm -f linux endef diff --git a/arch/um/config.release b/arch/um/config.release deleted file mode 100644 index fc68bcb9294..00000000000 --- a/arch/um/config.release +++ /dev/null @@ -1,333 +0,0 @@ -# -# Automatically generated make config: don't edit -# -CONFIG_USERMODE=y -# CONFIG_ISA is not set -# CONFIG_SBUS is not set -# CONFIG_PCI is not set -CONFIG_UID16=y -CONFIG_RWSEM_XCHGADD_ALGORITHM=y - -# -# Code maturity level options -# -CONFIG_EXPERIMENTAL=y - -# -# General Setup -# -CONFIG_STDIO_CONSOLE=y -CONFIG_NET=y -CONFIG_SYSVIPC=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_SYSCTL=y -CONFIG_BINFMT_AOUT=y -CONFIG_BINFMT_ELF=y -CONFIG_BINFMT_MISC=y -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 -CONFIG_SSL=y -CONFIG_HOSTFS=y -CONFIG_MCONSOLE=y -CONFIG_MAGIC_SYSRQ=y -# CONFIG_HOST_2G_2G is not set -# CONFIG_UML_SMP is not set -# CONFIG_SMP is not set -CONFIG_CON_ZERO_CHAN="fd:0,fd:1" -CONFIG_CON_CHAN="xterm" -CONFIG_SSL_CHAN="pty" -CONFIG_NEST_LEVEL=0 -CONFIG_KERNEL_HALF_GIGS=1 - -# -# Loadable module support -# -CONFIG_MODULES=y -CONFIG_KMOD=y - -# -# Devices -# -CONFIG_BLK_DEV_UBD=y -# CONFIG_BLK_DEV_UBD_SYNC is not set -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_NBD=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_INITRD=y -# CONFIG_MMAPPER is not set -CONFIG_UML_SOUND=y -CONFIG_SOUND=y -CONFIG_HOSTAUDIO=y -# CONFIG_UML_WATCHDOG is not set -# CONFIG_TTY_LOG is not set -CONFIG_FD_CHAN=y -# CONFIG_NULL_CHAN is not set -CONFIG_PORT_CHAN=y -CONFIG_PTY_CHAN=y -CONFIG_TTY_CHAN=y -CONFIG_XTERM_CHAN=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -# CONFIG_NETLINK_DEV is not set -# CONFIG_NETFILTER is not set -# CONFIG_FILTER is not set -CONFIG_UNIX=y -CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set -# CONFIG_IP_ADVANCED_ROUTER is not set -# CONFIG_IP_PNP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -# CONFIG_INET_ECN is not set -# CONFIG_SYN_COOKIES is not set -# CONFIG_IPV6 is not set -# CONFIG_KHTTPD is not set -# CONFIG_ATM is not set -# CONFIG_VLAN_8021Q is not set - -# -# -# -# CONFIG_IPX is not set -# CONFIG_ATALK is not set -# CONFIG_DECNET is not set -# CONFIG_BRIDGE is not set -# CONFIG_X25 is not set -# CONFIG_LAPB is not set -# CONFIG_LLC is not set -# CONFIG_NET_DIVERT is not set -# CONFIG_ECONET is not set -# CONFIG_WAN_ROUTER is not set -# CONFIG_NET_HW_FLOWCONTROL is not set - -# -# QoS and/or fair queueing -# -# CONFIG_NET_SCHED is not set - -# -# Network device support -# -CONFIG_UML_NET=y -CONFIG_UML_NET_ETHERTAP=y -CONFIG_UML_NET_TUNTAP=y -CONFIG_UML_NET_SLIP=y -CONFIG_UML_NET_DAEMON=y -CONFIG_UML_NET_MCAST=y -CONFIG_NETDEVICES=y - -# -# ARCnet devices -# -# CONFIG_ARCNET is not set -CONFIG_DUMMY=y -CONFIG_BONDING=m -CONFIG_EQUALIZER=m -CONFIG_TUN=y -# CONFIG_ETHERTAP is not set - -# -# Ethernet (10 or 100Mbit) -# -# CONFIG_NET_ETHERNET is not set - -# -# Ethernet (1000 Mbit) -# -# CONFIG_ACENIC is not set -# CONFIG_DL2K is not set -# CONFIG_MYRI_SBUS is not set -# CONFIG_NS83820 is not set -# CONFIG_HAMACHI is not set -# CONFIG_YELLOWFIN is not set -# CONFIG_SK98LIN is not set -# CONFIG_FDDI is not set -# CONFIG_HIPPI is not set -CONFIG_PLIP=m -CONFIG_PPP=m -CONFIG_PPP_MULTILINK=y -# CONFIG_PPP_FILTER is not set -# CONFIG_PPP_ASYNC is not set -CONFIG_PPP_SYNC_TTY=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPPOE=m -CONFIG_SLIP=m -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -# CONFIG_SLIP_MODE_SLIP6 is not set - -# -# Wireless LAN (non-hamradio) -# -# CONFIG_NET_RADIO is not set - -# -# Token Ring devices -# -# CONFIG_TR is not set -# CONFIG_NET_FC is not set -# CONFIG_RCPCI is not set -CONFIG_SHAPER=m - -# -# Wan interfaces -# -# CONFIG_WAN is not set - -# -# File systems -# -CONFIG_QUOTA=y -CONFIG_AUTOFS_FS=m -CONFIG_AUTOFS4_FS=m -CONFIG_REISERFS_FS=m -# CONFIG_REISERFS_CHECK is not set -# CONFIG_REISERFS_PROC_INFO is not set -CONFIG_ADFS_FS=m -# CONFIG_ADFS_FS_RW is not set -CONFIG_AFFS_FS=m -CONFIG_HFS_FS=m -CONFIG_BFS_FS=m -CONFIG_EXT3_FS=y -CONFIG_JBD=y -# CONFIG_JBD_DEBUG is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -CONFIG_UMSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_EFS_FS=m -# CONFIG_JFFS_FS is not set -# CONFIG_JFFS2_FS is not set -CONFIG_CRAMFS=m -CONFIG_TMPFS=y -CONFIG_RAMFS=m -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_ZISOFS is not set -CONFIG_MINIX_FS=m -CONFIG_VXFS_FS=m -# CONFIG_NTFS_FS is not set -# CONFIG_NTFS_RW is not set -CONFIG_HPFS_FS=m -CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y -CONFIG_DEVFS_MOUNT=y -# CONFIG_DEVFS_DEBUG is not set -CONFIG_DEVPTS_FS=y -CONFIG_QNX4FS_FS=m -# CONFIG_QNX4FS_RW is not set -CONFIG_ROMFS_FS=m -CONFIG_EXT2_FS=y -CONFIG_SYSV_FS=m -CONFIG_UDF_FS=m -CONFIG_UFS_FS=m -# CONFIG_UFS_FS_WRITE is not set - -# -# Network File Systems -# -# CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -# CONFIG_ROOT_NFS is not set -CONFIG_NFSD=y -CONFIG_NFSD_V3=y -CONFIG_SUNRPC=y -CONFIG_LOCKD=y -CONFIG_LOCKD_V4=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set -# CONFIG_NCPFS_PACKET_SIGNING is not set -# CONFIG_NCPFS_IOCTL_LOCKING is not set -# CONFIG_NCPFS_STRONG is not set -# CONFIG_NCPFS_NFS_NS is not set -# CONFIG_NCPFS_OS2_NS is not set -# CONFIG_NCPFS_SMALLDOS is not set -# CONFIG_NCPFS_NLS is not set -# CONFIG_NCPFS_EXTRAS is not set -# CONFIG_ZISOFS_FS is not set -CONFIG_ZLIB_FS_INFLATE=m - -# -# Partition Types -# -# CONFIG_PARTITION_ADVANCED is not set -CONFIG_MSDOS_PARTITION=y -# CONFIG_SMB_NLS is not set -CONFIG_NLS=y - -# -# Native Language Support -# -CONFIG_NLS_DEFAULT="iso8859-1" -# CONFIG_NLS_CODEPAGE_437 is not set -# CONFIG_NLS_CODEPAGE_737 is not set -# CONFIG_NLS_CODEPAGE_775 is not set -# CONFIG_NLS_CODEPAGE_850 is not set -# CONFIG_NLS_CODEPAGE_852 is not set -# CONFIG_NLS_CODEPAGE_855 is not set -# CONFIG_NLS_CODEPAGE_857 is not set -# CONFIG_NLS_CODEPAGE_860 is not set -# CONFIG_NLS_CODEPAGE_861 is not set -# CONFIG_NLS_CODEPAGE_862 is not set -# CONFIG_NLS_CODEPAGE_863 is not set -# CONFIG_NLS_CODEPAGE_864 is not set -# CONFIG_NLS_CODEPAGE_865 is not set -# CONFIG_NLS_CODEPAGE_866 is not set -# CONFIG_NLS_CODEPAGE_869 is not set -# CONFIG_NLS_CODEPAGE_936 is not set -# CONFIG_NLS_CODEPAGE_950 is not set -# CONFIG_NLS_CODEPAGE_932 is not set -# CONFIG_NLS_CODEPAGE_949 is not set -# CONFIG_NLS_CODEPAGE_874 is not set -# CONFIG_NLS_ISO8859_8 is not set -# CONFIG_NLS_CODEPAGE_1250 is not set -# CONFIG_NLS_CODEPAGE_1251 is not set -# CONFIG_NLS_ISO8859_1 is not set -# CONFIG_NLS_ISO8859_2 is not set -# CONFIG_NLS_ISO8859_3 is not set -# CONFIG_NLS_ISO8859_4 is not set -# CONFIG_NLS_ISO8859_5 is not set -# CONFIG_NLS_ISO8859_6 is not set -# CONFIG_NLS_ISO8859_7 is not set -# CONFIG_NLS_ISO8859_9 is not set -# CONFIG_NLS_ISO8859_13 is not set -# CONFIG_NLS_ISO8859_14 is not set -# CONFIG_NLS_ISO8859_15 is not set -# CONFIG_NLS_KOI8_R is not set -# CONFIG_NLS_KOI8_U is not set -# CONFIG_NLS_UTF8 is not set - -# -# Multi-device support (RAID and LVM) -# -# CONFIG_MD is not set -# CONFIG_BLK_DEV_MD is not set -# CONFIG_MD_LINEAR is not set -# CONFIG_MD_RAID0 is not set -# CONFIG_MD_RAID1 is not set -# CONFIG_MD_RAID5 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_LVM is not set - -# -# Memory Technology Devices (MTD) -# -# CONFIG_MTD is not set - -# -# Kernel hacking -# -# CONFIG_DEBUG_SLAB is not set -# CONFIG_DEBUG_INFO is not set -# CONFIG_PT_PROXY is not set -# CONFIG_GPROF is not set -# CONFIG_GCOV is not set diff --git a/arch/um/defconfig b/arch/um/defconfig index a54d0efecae..1e0f677c2f4 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig @@ -52,7 +52,6 @@ CONFIG_X86_WP_WORKS_OK=y CONFIG_X86_INVLPG=y CONFIG_X86_BSWAP=y CONFIG_X86_POPAD_OK=y -CONFIG_X86_CMPXCHG64=y CONFIG_X86_GOOD_APIC=y CONFIG_X86_USE_PPRO_CHECKSUM=y CONFIG_X86_TSC=y @@ -189,7 +188,7 @@ CONFIG_XTERM_CHAN=y # CONFIG_NOCONFIG_CHAN is not set CONFIG_CON_ZERO_CHAN="fd:0,fd:1" CONFIG_CON_CHAN="xterm" -CONFIG_SSL_CHAN="pty" +CONFIG_SSL_CHAN="pts" CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -527,3 +526,4 @@ CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set # CONFIG_GPROF is not set # CONFIG_GCOV is not set +# CONFIG_DEBUG_STACK_USAGE is not set diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 3aa35161176..368d3e97dfd 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -203,22 +203,37 @@ void chan_enable_winch(struct list_head *chans, struct tty_struct *tty) } } -void enable_chan(struct line *line) +int enable_chan(struct line *line) { struct list_head *ele; struct chan *chan; + int err; list_for_each(ele, &line->chan_list){ chan = list_entry(ele, struct chan, list); - if(open_one_chan(chan)) + err = open_one_chan(chan); + if (err) { + if (chan->primary) + goto out_close; + continue; + } if(chan->enabled) continue; - line_setup_irq(chan->fd, chan->input, chan->output, line, - chan); + err = line_setup_irq(chan->fd, chan->input, chan->output, line, + chan); + if (err) + goto out_close; + chan->enabled = 1; } + + return 0; + + out_close: + close_chan(&line->chan_list, 0); + return err; } /* Items are added in IRQ context, when free_irq can't be called, and diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 13f0bf852b2..4d438f36ea2 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -51,19 +51,21 @@ error: /* * UML SIGWINCH handling * - * The point of this is to handle SIGWINCH on consoles which have host ttys and - * relay them inside UML to whatever might be running on the console and cares - * about the window size (since SIGWINCH notifies about terminal size changes). + * The point of this is to handle SIGWINCH on consoles which have host + * ttys and relay them inside UML to whatever might be running on the + * console and cares about the window size (since SIGWINCH notifies + * about terminal size changes). * - * So, we have a separate thread for each host tty attached to a UML device - * (side-issue - I'm annoyed that one thread can't have multiple controlling - * ttys for purposed of handling SIGWINCH, but I imagine there are other reasons - * that doesn't make any sense). + * So, we have a separate thread for each host tty attached to a UML + * device (side-issue - I'm annoyed that one thread can't have + * multiple controlling ttys for the purpose of handling SIGWINCH, but + * I imagine there are other reasons that doesn't make any sense). * - * SIGWINCH can't be received synchronously, so you have to set up to receive it - * as a signal. That being the case, if you are going to wait for it, it is - * convenient to sit in sigsuspend() and wait for the signal to bounce you out of - * it (see below for how we make sure to exit only on SIGWINCH). + * SIGWINCH can't be received synchronously, so you have to set up to + * receive it as a signal. That being the case, if you are going to + * wait for it, it is convenient to sit in sigsuspend() and wait for + * the signal to bounce you out of it (see below for how we make sure + * to exit only on SIGWINCH). */ static void winch_handler(int sig) @@ -112,7 +114,8 @@ static int winch_thread(void *arg) err = os_new_tty_pgrp(pty_fd, os_getpid()); if(err < 0){ - printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err); + printk("winch_thread : new_tty_pgrp failed on fd %d, " + "err = %d\n", pty_fd, -err); exit(1); } @@ -126,8 +129,9 @@ static int winch_thread(void *arg) "err = %d\n", -count); while(1){ - /* This will be interrupted by SIGWINCH only, since other signals - * are blocked.*/ + /* This will be interrupted by SIGWINCH only, since + * other signals are blocked. + */ sigsuspend(&sigs); count = os_write_file(pipe_fd, &c, sizeof(c)); @@ -137,10 +141,10 @@ static int winch_thread(void *arg) } } -static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out) +static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out, + unsigned long *stack_out) { struct winch_data data; - unsigned long stack; int fds[2], n, err; char c; @@ -153,9 +157,11 @@ static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out) data = ((struct winch_data) { .pty_fd = fd, .pipe_fd = fds[1] } ); /* CLONE_FILES so this thread doesn't hold open files which are open - * now, but later closed. This is a problem with /dev/net/tun. + * now, but later closed in a different thread. This is a + * problem with /dev/net/tun, which if held open by this + * thread, prevents the TUN/TAP device from being reused. */ - err = run_helper_thread(winch_thread, &data, CLONE_FILES, &stack, 0); + err = run_helper_thread(winch_thread, &data, CLONE_FILES, stack_out); if(err < 0){ printk("fork of winch_thread failed - errno = %d\n", -err); goto out_close; @@ -170,7 +176,13 @@ static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out) err = -EINVAL; goto out_close; } - return err ; + + if (os_set_fd_block(*fd_out, 0)) { + printk("winch_tramp: failed to set thread_fd non-blocking.\n"); + goto out_close; + } + + return err; out_close: os_close_file(fds[1]); @@ -181,25 +193,25 @@ static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out) void register_winch(int fd, struct tty_struct *tty) { - int pid, thread, thread_fd = -1; - int count; + unsigned long stack; + int pid, thread, count, thread_fd = -1; char c = 1; if(!isatty(fd)) return; pid = tcgetpgrp(fd); - if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, - tty) && (pid == -1)){ - thread = winch_tramp(fd, tty, &thread_fd); - if(thread > 0){ - register_winch_irq(thread_fd, fd, thread, tty); - - count = os_write_file(thread_fd, &c, sizeof(c)); - if(count != sizeof(c)) - printk("register_winch : failed to write " - "synchronization byte, err = %d\n", - -count); - } + if (!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, tty) && + (pid == -1)) { + thread = winch_tramp(fd, tty, &thread_fd, &stack); + if (thread < 0) + return; + + register_winch_irq(thread_fd, fd, thread, tty, stack); + + count = os_write_file(thread_fd, &c, sizeof(c)); + if(count != sizeof(c)) + printk("register_winch : failed to write " + "synchronization byte, err = %d\n", -count); } } diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h index 15453845d2b..ca8c9e11a39 100644 --- a/arch/um/drivers/cow_sys.h +++ b/arch/um/drivers/cow_sys.h @@ -8,7 +8,7 @@ static inline void *cow_malloc(int size) { - return um_kmalloc(size); + return kmalloc(size, UM_GFP_KERNEL); } static inline void cow_free(void *ptr) diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c index b869e389968..8d2008f0668 100644 --- a/arch/um/drivers/daemon_user.c +++ b/arch/um/drivers/daemon_user.c @@ -35,7 +35,7 @@ static struct sockaddr_un *new_addr(void *name, int len) { struct sockaddr_un *sun; - sun = um_kmalloc(sizeof(struct sockaddr_un)); + sun = kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); if(sun == NULL){ printk("new_addr: allocation of sockaddr_un failed\n"); return NULL; @@ -83,7 +83,7 @@ static int connect_to_switch(struct daemon_data *pri) goto out_close; } - sun = um_kmalloc(sizeof(struct sockaddr_un)); + sun = kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); if(sun == NULL){ printk("new_addr: allocation of sockaddr_un failed\n"); err = -ENOMEM; diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c index 7f083ec47a4..39c01ffd45c 100644 --- a/arch/um/drivers/fd.c +++ b/arch/um/drivers/fd.c @@ -37,7 +37,7 @@ static void *fd_init(char *str, int device, const struct chan_opts *opts) printk("fd_init : couldn't parse file descriptor '%s'\n", str); return(NULL); } - data = um_kmalloc(sizeof(*data)); + data = kmalloc(sizeof(*data), UM_GFP_KERNEL); if(data == NULL) return(NULL); *data = ((struct fd_chan) { .fd = n, .raw = opts->raw }); diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c index 5eeecf8917c..1171790f742 100644 --- a/arch/um/drivers/harddog_user.c +++ b/arch/um/drivers/harddog_user.c @@ -68,7 +68,7 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) args = pid_args; } - pid = run_helper(pre_exec, &data, args, NULL); + pid = run_helper(pre_exec, &data, args); os_close_file(out_fds[0]); os_close_file(in_fds[1]); diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 4bd40bb43ec..3e0b68e297f 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -454,7 +454,10 @@ int line_open(struct line *lines, struct tty_struct *tty) tty->driver_data = line; line->tty = tty; - enable_chan(line); + err = enable_chan(line); + if (err) + return err; + INIT_DELAYED_WORK(&line->task, line_timer_cb); if(!line->sigio){ @@ -746,8 +749,24 @@ struct winch { int tty_fd; int pid; struct tty_struct *tty; + unsigned long stack; }; +static void free_winch(struct winch *winch, int free_irq_ok) +{ + list_del(&winch->list); + + if (winch->pid != -1) + os_kill_process(winch->pid, 1); + if (winch->fd != -1) + os_close_file(winch->fd); + if (winch->stack != 0) + free_stack(winch->stack, 0); + if (free_irq_ok) + free_irq(WINCH_IRQ, winch); + kfree(winch); +} + static irqreturn_t winch_interrupt(int irq, void *data) { struct winch *winch = data; @@ -764,12 +783,13 @@ static irqreturn_t winch_interrupt(int irq, void *data) "errno = %d\n", -err); printk("fd %d is losing SIGWINCH support\n", winch->tty_fd); + free_winch(winch, 0); return IRQ_HANDLED; } goto out; } } - tty = winch->tty; + tty = winch->tty; if (tty != NULL) { line = tty->driver_data; chan_window_size(&line->chan_list, &tty->winsize.ws_row, @@ -782,43 +802,44 @@ static irqreturn_t winch_interrupt(int irq, void *data) return IRQ_HANDLED; } -void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) +void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty, + unsigned long stack) { struct winch *winch; winch = kmalloc(sizeof(*winch), GFP_KERNEL); if (winch == NULL) { printk("register_winch_irq - kmalloc failed\n"); - return; + goto cleanup; } *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), .fd = fd, .tty_fd = tty_fd, .pid = pid, - .tty = tty }); + .tty = tty, + .stack = stack }); + + if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, + IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, + "winch", winch) < 0) { + printk("register_winch_irq - failed to register IRQ\n"); + goto out_free; + } spin_lock(&winch_handler_lock); list_add(&winch->list, &winch_handlers); spin_unlock(&winch_handler_lock); - if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, - IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, - "winch", winch) < 0) - printk("register_winch_irq - failed to register IRQ\n"); -} - -static void free_winch(struct winch *winch) -{ - list_del(&winch->list); - - if(winch->pid != -1) - os_kill_process(winch->pid, 1); - if(winch->fd != -1) - os_close_file(winch->fd); + return; - free_irq(WINCH_IRQ, winch); + out_free: kfree(winch); + cleanup: + os_kill_process(pid, 1); + os_close_file(fd); + if (stack != 0) + free_stack(stack, 0); } static void unregister_winch(struct tty_struct *tty) @@ -831,7 +852,7 @@ static void unregister_winch(struct tty_struct *tty) list_for_each(ele, &winch_handlers){ winch = list_entry(ele, struct winch, list); if(winch->tty == tty){ - free_winch(winch); + free_winch(winch, 1); break; } } @@ -847,7 +868,7 @@ static void winch_cleanup(void) list_for_each_safe(ele, next, &winch_handlers){ winch = list_entry(ele, struct winch, list); - free_winch(winch); + free_winch(winch, 1); } spin_unlock(&winch_handler_lock); diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c index d319db16d4e..236a3dfc297 100644 --- a/arch/um/drivers/mcast_user.c +++ b/arch/um/drivers/mcast_user.c @@ -30,7 +30,7 @@ static struct sockaddr_in *new_addr(char *addr, unsigned short port) { struct sockaddr_in *sin; - sin = um_kmalloc(sizeof(struct sockaddr_in)); + sin = kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL); if(sin == NULL){ printk("new_addr: allocation of sockaddr_in failed\n"); return NULL; diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c index 62e5ad63181..f31e71546e5 100644 --- a/arch/um/drivers/mconsole_user.c +++ b/arch/um/drivers/mconsole_user.c @@ -86,8 +86,9 @@ int mconsole_get_request(int fd, struct mc_request *req) int len; req->originlen = sizeof(req->origin); - req->len = recvfrom(fd, &req->request, sizeof(req->request), 0, - (struct sockaddr *) req->origin, &req->originlen); + req->len = recvfrom(fd, &req->request, sizeof(req->request), + MSG_DONTWAIT, (struct sockaddr *) req->origin, + &req->originlen); if (req->len < 0) return 0; diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index 3503cff867c..da946e3e1bf 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c @@ -187,7 +187,7 @@ static int change_tramp(char **argv, char *output, int output_len) } pe_data.close_me = fds[0]; pe_data.stdout = fds[1]; - pid = run_helper(change_pre_exec, &pe_data, argv, NULL); + pid = run_helper(change_pre_exec, &pe_data, argv); if (pid > 0) /* Avoid hang as we won't get data in failure case. */ read_output(fds[0], output, output_len); @@ -217,7 +217,7 @@ static void change(char *dev, char *what, unsigned char *addr, netmask[2], netmask[3]); output_len = UM_KERN_PAGE_SIZE; - output = um_kmalloc(output_len); + output = kmalloc(output_len, UM_GFP_KERNEL); if(output == NULL) printk("change : failed to allocate output buffer\n"); diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c index 483aa15222a..1316456e2a2 100644 --- a/arch/um/drivers/pcap_user.c +++ b/arch/um/drivers/pcap_user.c @@ -53,7 +53,7 @@ static int pcap_open(void *data) return -EIO; } - pri->compiled = um_kmalloc(sizeof(struct bpf_program)); + pri->compiled = kmalloc(sizeof(struct bpf_program), UM_GFP_KERNEL); if(pri->compiled == NULL){ printk(UM_KERN_ERR "pcap_open : kmalloc failed\n"); return -ENOMEM; diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c index 3f6357d24be..c799b00012c 100644 --- a/arch/um/drivers/port_user.c +++ b/arch/um/drivers/port_user.c @@ -50,7 +50,7 @@ static void *port_init(char *str, int device, const struct chan_opts *opts) if(kern_data == NULL) return NULL; - data = um_kmalloc(sizeof(*data)); + data = kmalloc(sizeof(*data), UM_GFP_KERNEL); if(data == NULL) goto err; @@ -188,7 +188,7 @@ int port_connection(int fd, int *socket, int *pid_out) { .sock_fd = new, .pipe_fd = socket[1] }); - err = run_helper(port_pre_exec, &data, argv, NULL); + err = run_helper(port_pre_exec, &data, argv); if(err < 0) goto out_shutdown; diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c index df4976c9eef..1e3fd619a83 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ @@ -7,12 +7,14 @@ #include <stdlib.h> #include <unistd.h> #include <string.h> +#include <fcntl.h> #include <errno.h> #include <termios.h> +#include <sys/stat.h> #include "chan_user.h" -#include "user.h" -#include "kern_util.h" #include "os.h" +#include "user.h" +#include "kern_constants.h" #include "um_malloc.h" struct pty_chan { @@ -27,12 +29,14 @@ static void *pty_chan_init(char *str, int device, const struct chan_opts *opts) { struct pty_chan *data; - data = um_kmalloc(sizeof(*data)); - if(data == NULL) return(NULL); + data = kmalloc(sizeof(*data), UM_GFP_KERNEL); + if (data == NULL) + return NULL; + *data = ((struct pty_chan) { .announce = opts->announce, .dev = device, .raw = opts->raw }); - return(data); + return data; } static int pts_open(int input, int output, int primary, void *d, @@ -43,31 +47,35 @@ static int pts_open(int input, int output, int primary, void *d, int fd, err; fd = get_pty(); - if(fd < 0){ + if (fd < 0) { err = -errno; - printk("open_pts : Failed to open pts\n"); + printk(UM_KERN_ERR "open_pts : Failed to open pts\n"); return err; } - if(data->raw){ + + if (data->raw) { CATCH_EINTR(err = tcgetattr(fd, &data->tt)); - if(err) - return(err); + if (err) + return err; err = raw(fd); - if(err) - return(err); + if (err) + return err; } dev = ptsname(fd); sprintf(data->dev_name, "%s", dev); *dev_out = data->dev_name; + if (data->announce) (*data->announce)(dev, data->dev); - return(fd); + + return fd; } static int getmaster(char *line) { + struct stat buf; char *pty, *bank, *cp; int master, err; @@ -75,24 +83,29 @@ static int getmaster(char *line) for (bank = "pqrs"; *bank; bank++) { line[strlen("/dev/pty")] = *bank; *pty = '0'; - if (os_stat_file(line, NULL) < 0) + /* Did we hit the end ? */ + if ((stat(line, &buf) < 0) && (errno == ENOENT)) break; + for (cp = "0123456789abcdef"; *cp; cp++) { *pty = *cp; - master = os_open_file(line, of_rdwr(OPENFLAGS()), 0); + master = open(line, O_RDWR); if (master >= 0) { char *tp = &line[strlen("/dev/")]; /* verify slave side is usable */ *tp = 't'; - err = os_access(line, OS_ACC_RW_OK); + err = access(line, R_OK | W_OK); *tp = 'p'; - if(err == 0) return(master); - (void) os_close_file(master); + if(!err) + return master; + close(master); } } } - return(-1); + + printk(UM_KERN_ERR "getmaster - no usable host pty devices\n"); + return -ENOENT; } static int pty_open(int input, int output, int primary, void *d, @@ -103,20 +116,22 @@ static int pty_open(int input, int output, int primary, void *d, char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx"; fd = getmaster(dev); - if(fd < 0) - return(-errno); + if (fd < 0) + return fd; if(data->raw){ err = raw(fd); - if(err) - return(err); + if (err) + return err; } - if(data->announce) (*data->announce)(dev, data->dev); + if (data->announce) + (*data->announce)(dev, data->dev); sprintf(data->dev_name, "%s", dev); *dev_out = data->dev_name; - return(fd); + + return fd; } const struct chan_ops pty_ops = { @@ -144,14 +159,3 @@ const struct chan_ops pts_ops = { .free = generic_free, .winch = 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/slip_user.c b/arch/um/drivers/slip_user.c index 78f0e515da8..c0b73c28cff 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c @@ -85,13 +85,13 @@ static int slip_tramp(char **argv, int fd) pe_data.stdin = fd; pe_data.stdout = fds[1]; pe_data.close_me = fds[0]; - err = run_helper(slip_pre_exec, &pe_data, argv, NULL); + err = run_helper(slip_pre_exec, &pe_data, argv); if(err < 0) goto out_close; pid = err; output_len = UM_KERN_PAGE_SIZE; - output = um_kmalloc(output_len); + output = kmalloc(output_len, UM_GFP_KERNEL); if(output == NULL){ printk("slip_tramp : failed to allocate output buffer\n"); os_kill_process(pid, 1); diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c index 39f889fe994..0e462f64f22 100644 --- a/arch/um/drivers/slirp_user.c +++ b/arch/um/drivers/slirp_user.c @@ -42,7 +42,7 @@ static int slirp_tramp(char **argv, int fd) pe_data.stdin = fd; pe_data.stdout = fd; - pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL); + pid = run_helper(slirp_pre_exec, &pe_data, argv); return(pid); } diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index fd09ad9e9c0..875d60d0c6a 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -42,8 +42,6 @@ static struct chan_opts opts = { .announce = ssl_announce, .xterm_title = "Serial Line #%d", .raw = 1, - .tramp_stack = 0, - .in_kernel = 1, }; static int ssl_config(char *str, char **error_out); @@ -99,7 +97,13 @@ static int ssl_remove(int n, char **error_out) static int ssl_open(struct tty_struct *tty, struct file *filp) { - return line_open(serial_lines, tty); + int err = line_open(serial_lines, tty); + + if (err) + printk(KERN_ERR "Failed to open serial line %d, err = %d\n", + tty->index, err); + + return err; } #if 0 diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 2bb4193ac1a..656036e90b1 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -46,8 +46,6 @@ static struct chan_opts opts = { .announce = stdio_announce, .xterm_title = "Virtual Console #%d", .raw = 1, - .tramp_stack = 0, - .in_kernel = 1, }; static int con_config(char *str, char **error_out); @@ -101,7 +99,12 @@ static int con_remove(int n, char **error_out) static int con_open(struct tty_struct *tty, struct file *filp) { - return line_open(vts, tty); + int err = line_open(vts, tty); + if (err) + printk(KERN_ERR "Failed to open console %d, err = %d\n", + tty->index, err); + + return err; } /* Set in an initcall, checked in an exitcall */ diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c index c07d0d56278..a9f87e19c5b 100644 --- a/arch/um/drivers/tty.c +++ b/arch/um/drivers/tty.c @@ -29,7 +29,7 @@ static void *tty_chan_init(char *str, int device, const struct chan_opts *opts) } str++; - data = um_kmalloc(sizeof(*data)); + data = kmalloc(sizeof(*data), UM_GFP_KERNEL); if(data == NULL) return NULL; *data = ((struct tty_chan) { .dev = str, diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 2e09f162c42..fc27f6c72b4 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -712,6 +712,8 @@ static int ubd_add(int n, char **error_out) ubd_dev->queue->queuedata = ubd_dev; blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG); + if(ubd_dev->cow.file != NULL) + blk_queue_max_sectors(ubd_dev->queue, 8 * sizeof(long)); err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]); if(err){ *error_out = "Failed to register device"; @@ -1083,7 +1085,7 @@ static void do_ubd_request(request_queue_t *q) { struct io_thread_req *io_req; struct request *req; - int n; + int n, last_sectors; while(1){ struct ubd *dev = q->queuedata; @@ -1099,9 +1101,11 @@ static void do_ubd_request(request_queue_t *q) } req = dev->request; + last_sectors = 0; while(dev->start_sg < dev->end_sg){ struct scatterlist *sg = &dev->sg[dev->start_sg]; + req->sector += last_sectors; io_req = kmalloc(sizeof(struct io_thread_req), GFP_ATOMIC); if(io_req == NULL){ @@ -1113,6 +1117,7 @@ static void do_ubd_request(request_queue_t *q) (unsigned long long) req->sector << 9, sg->offset, sg->length, sg->page); + last_sectors = sg->length >> 9; n = os_write_file(thread_fd, &io_req, sizeof(struct io_thread_req *)); if(n != sizeof(struct io_thread_req *)){ @@ -1124,7 +1129,6 @@ static void do_ubd_request(request_queue_t *q) return; } - req->sector += sg->length >> 9; dev->start_sg++; } dev->end_sg = 0; diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c index 4707b3f14c2..41d254bd38d 100644 --- a/arch/um/drivers/ubd_user.c +++ b/arch/um/drivers/ubd_user.c @@ -43,6 +43,12 @@ int start_io_thread(unsigned long sp, int *fd_out) kernel_fd = fds[0]; *fd_out = fds[1]; + err = os_set_fd_block(*fd_out, 0); + if (err) { + printk("start_io_thread - failed to set nonblocking I/O.\n"); + goto out_close; + } + pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, NULL); if(pid < 0){ diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index 571c2b3325d..fd817e54154 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -1,22 +1,20 @@ /* - * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include <stdio.h> #include <stdlib.h> +#include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <termios.h> -#include <signal.h> -#include <sched.h> -#include <sys/socket.h> -#include "kern_util.h" #include "chan_user.h" -#include "user.h" #include "os.h" +#include "init.h" +#include "user.h" #include "xterm.h" +#include "kern_constants.h" struct xterm_chan { int pid; @@ -25,25 +23,21 @@ struct xterm_chan { int device; int raw; struct termios tt; - unsigned long stack; - int direct_rcv; }; -/* Not static because it's called directly by the tt mode gdb code */ -void *xterm_init(char *str, int device, const struct chan_opts *opts) +static void *xterm_init(char *str, int device, const struct chan_opts *opts) { struct xterm_chan *data; data = malloc(sizeof(*data)); - if(data == NULL) return(NULL); - *data = ((struct xterm_chan) { .pid = -1, + if (data == NULL) + return NULL; + *data = ((struct xterm_chan) { .pid = -1, .helper_pid = -1, - .device = device, + .device = device, .title = opts->xterm_title, - .raw = opts->raw, - .stack = opts->tramp_stack, - .direct_rcv = !opts->in_kernel } ); - return(data); + .raw = opts->raw } ); + return data; } /* Only changed by xterm_setup, which is a setup */ @@ -57,16 +51,22 @@ static int __init xterm_setup(char *line, int *add) terminal_emulator = line; line = strchr(line, ','); - if(line == NULL) return(0); + if (line == NULL) + return 0; + *line++ = '\0'; - if(*line) title_switch = line; + if (*line) + title_switch = line; line = strchr(line, ','); - if(line == NULL) return(0); + if (line == NULL) + return 0; + *line++ = '\0'; - if(*line) exec_switch = line; + if (*line) + exec_switch = line; - return(0); + return 0; } __uml_setup("xterm=", xterm_setup, @@ -82,107 +82,128 @@ __uml_setup("xterm=", xterm_setup, " are 'xterm=gnome-terminal,-t,-x'.\n\n" ); -/* XXX This badly needs some cleaning up in the error paths - * Not static because it's called directly by the tt mode gdb code - */ -int xterm_open(int input, int output, int primary, void *d, +static int xterm_open(int input, int output, int primary, void *d, char **dev_out) { struct xterm_chan *data = d; - unsigned long stack; int pid, fd, new, err; char title[256], file[] = "/tmp/xterm-pipeXXXXXX"; - char *argv[] = { terminal_emulator, title_switch, title, exec_switch, + char *argv[] = { terminal_emulator, title_switch, title, exec_switch, "/usr/lib/uml/port-helper", "-uml-socket", file, NULL }; - if(os_access(argv[4], OS_ACC_X_OK) < 0) + if (access(argv[4], X_OK) < 0) argv[4] = "port-helper"; /* Check that DISPLAY is set, this doesn't guarantee the xterm * will work but w/o it we can be pretty sure it won't. */ - if (!getenv("DISPLAY")) { - printk("xterm_open: $DISPLAY not set.\n"); + if (getenv("DISPLAY") == NULL) { + printk(UM_KERN_ERR "xterm_open: $DISPLAY not set.\n"); return -ENODEV; } + /* + * This business of getting a descriptor to a temp file, + * deleting the file and closing the descriptor is just to get + * a known-unused name for the Unix socket that we really + * want. + */ fd = mkstemp(file); - if(fd < 0){ + if (fd < 0) { err = -errno; - printk("xterm_open : mkstemp failed, errno = %d\n", errno); + printk(UM_KERN_ERR "xterm_open : mkstemp failed, errno = %d\n", + errno); return err; } - if(unlink(file)){ + if (unlink(file)) { err = -errno; - printk("xterm_open : unlink failed, errno = %d\n", errno); + printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n", + errno); return err; } - os_close_file(fd); + close(fd); fd = os_create_unix_socket(file, sizeof(file), 1); - if(fd < 0){ - printk("xterm_open : create_unix_socket failed, errno = %d\n", - -fd); - return(fd); + if (fd < 0) { + printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, " + "errno = %d\n", -fd); + return fd; } sprintf(title, data->title, data->device); - stack = data->stack; - pid = run_helper(NULL, NULL, argv, &stack); - if(pid < 0){ - printk("xterm_open : run_helper failed, errno = %d\n", -pid); - return(pid); + pid = run_helper(NULL, NULL, argv); + if (pid < 0) { + err = pid; + printk(UM_KERN_ERR "xterm_open : run_helper failed, " + "errno = %d\n", -err); + goto out_close1; } - if (data->direct_rcv) { - new = os_rcv_fd(fd, &data->helper_pid); - } else { - err = os_set_fd_block(fd, 0); - if(err < 0){ - printk("xterm_open : failed to set descriptor " - "non-blocking, err = %d\n", -err); - return(err); - } - new = xterm_fd(fd, &data->helper_pid); + err = os_set_fd_block(fd, 0); + if (err < 0) { + printk(UM_KERN_ERR "xterm_open : failed to set descriptor " + "non-blocking, err = %d\n", -err); + goto out_kill; } - if(new < 0){ - printk("xterm_open : os_rcv_fd failed, err = %d\n", -new); - goto out; + + new = xterm_fd(fd, &data->helper_pid); + if (new < 0) { + err = new; + printk(UM_KERN_ERR "xterm_open : os_rcv_fd failed, err = %d\n", + -err); + goto out_kill; + } + + err = os_set_fd_block(new, 0); + if (err) { + printk(UM_KERN_ERR "xterm_open : failed to set xterm " + "descriptor non-blocking, err = %d\n", -err); + goto out_close2; } CATCH_EINTR(err = tcgetattr(new, &data->tt)); - if(err){ + if (err) { new = err; - goto out; + goto out_close2; } - if(data->raw){ + if (data->raw) { err = raw(new); - if(err){ + if (err) { new = err; - goto out; + goto out_close2; } } + unlink(file); data->pid = pid; *dev_out = NULL; - out: - unlink(file); - return(new); + + return new; + + out_close2: + close(new); + out_kill: + os_kill_process(pid, 1); + out_close1: + close(fd); + + return err; } -/* Not static because it's called directly by the tt mode gdb code */ -void xterm_close(int fd, void *d) +static void xterm_close(int fd, void *d) { struct xterm_chan *data = d; - if(data->pid != -1) + if (data->pid != -1) os_kill_process(data->pid, 1); data->pid = -1; - if(data->helper_pid != -1) + + if (data->helper_pid != -1) os_kill_process(data->helper_pid, 0); data->helper_pid = -1; + os_close_file(fd); } @@ -203,14 +224,3 @@ const struct chan_ops xterm_ops = { .free = xterm_free, .winch = 1, }; - -/* - * 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/xterm_kern.c b/arch/um/drivers/xterm_kern.c index a4ce7058e10..b646bccef37 100644 --- a/arch/um/drivers/xterm_kern.c +++ b/arch/um/drivers/xterm_kern.c @@ -1,18 +1,14 @@ /* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) * Licensed under the GPL */ -#include "linux/errno.h" -#include "linux/slab.h" -#include "linux/signal.h" -#include "linux/interrupt.h" -#include "asm/irq.h" -#include "irq_user.h" +#include <linux/slab.h> +#include <linux/completion.h> +#include <linux/irqreturn.h> +#include <asm/irq.h> #include "irq_kern.h" -#include "kern_util.h" #include "os.h" -#include "xterm.h" struct xterm_wait { struct completion ready; @@ -27,12 +23,13 @@ static irqreturn_t xterm_interrupt(int irq, void *data) int fd; fd = os_rcv_fd(xterm->fd, &xterm->pid); - if(fd == -EAGAIN) - return(IRQ_NONE); + if (fd == -EAGAIN) + return IRQ_NONE; xterm->new_fd = fd; complete(&xterm->ready); - return(IRQ_HANDLED); + + return IRQ_HANDLED; } int xterm_fd(int socket, int *pid_out) @@ -41,22 +38,21 @@ int xterm_fd(int socket, int *pid_out) int err, ret; data = kmalloc(sizeof(*data), GFP_KERNEL); - if(data == NULL){ + if (data == NULL) { printk(KERN_ERR "xterm_fd : failed to allocate xterm_wait\n"); - return(-ENOMEM); + return -ENOMEM; } /* This is a locked semaphore... */ - *data = ((struct xterm_wait) - { .fd = socket, - .pid = -1, - .new_fd = -1 }); + *data = ((struct xterm_wait) { .fd = socket, + .pid = -1, + .new_fd = -1 }); init_completion(&data->ready); - err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt, + err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt, IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM, "xterm", data); - if (err){ + if (err) { printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, " "err = %d\n", err); ret = err; @@ -76,16 +72,5 @@ int xterm_fd(int socket, int *pid_out) out: kfree(data); - return(ret); + return ret; } - -/* - * 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/chan_kern.h b/arch/um/include/chan_kern.h index c4b41bb1035..624b5100a3c 100644 --- a/arch/um/include/chan_kern.h +++ b/arch/um/include/chan_kern.h @@ -40,7 +40,7 @@ extern int console_open_chan(struct line *line, struct console *co); extern void deactivate_chan(struct list_head *chans, int irq); extern void reactivate_chan(struct list_head *chans, int irq); extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty); -extern void enable_chan(struct line *line); +extern int enable_chan(struct line *line); extern void close_chan(struct list_head *chans, int delay_free_irq); extern int chan_window_size(struct list_head *chans, unsigned short *rows_out, diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h index 38f16d812e7..5a2263e05bb 100644 --- a/arch/um/include/chan_user.h +++ b/arch/um/include/chan_user.h @@ -12,8 +12,6 @@ struct chan_opts { void (*const announce)(char *dev_name, int dev); char *xterm_title; const int raw; - const unsigned long tramp_stack; - const int in_kernel; }; enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; @@ -44,7 +42,8 @@ extern void generic_free(void *data); struct tty_struct; extern void register_winch(int fd, struct tty_struct *tty); -extern void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty); +extern void register_winch_irq(int fd, int tty_fd, int pid, + struct tty_struct *tty, unsigned long stack); #define __channel_help(fn, prefix) \ __uml_help(fn, prefix "[0-9]*=<channel description>\n" \ diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h index 7376ee44e33..6eee343e53e 100644 --- a/arch/um/include/common-offsets.h +++ b/arch/um/include/common-offsets.h @@ -27,6 +27,9 @@ DEFINE(UM_ELFCLASS64, ELFCLASS64); DEFINE(UM_NR_CPUS, NR_CPUS); +DEFINE(UM_GFP_KERNEL, GFP_KERNEL); +DEFINE(UM_GFP_ATOMIC, GFP_ATOMIC); + /* For crypto assembler code. */ DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 4d9fb26387d..930b261ea48 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -239,11 +239,9 @@ extern unsigned long __do_user_copy(void *to, const void *from, int n, /* execvp.c */ extern int execvp_noalloc(char *buf, const char *file, char *const argv[]); /* helper.c */ -extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, - unsigned long *stack_out); +extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv); extern int run_helper_thread(int (*proc)(void *), void *arg, - unsigned int flags, unsigned long *stack_out, - int stack_order); + unsigned int flags, unsigned long *stack_out); extern int helper_wait(int pid); diff --git a/arch/um/include/um_malloc.h b/arch/um/include/um_malloc.h index e6d7c5aa3f4..0ad17cb83d9 100644 --- a/arch/um/include/um_malloc.h +++ b/arch/um/include/um_malloc.h @@ -6,11 +6,17 @@ #ifndef __UM_MALLOC_H__ #define __UM_MALLOC_H__ -extern void *um_kmalloc(int size); -extern void *um_kmalloc_atomic(int size); +#include "kern_constants.h" + +extern void *__kmalloc(int size, int flags); +static inline void *kmalloc(int size, int flags) +{ + return __kmalloc(size, flags); +} + extern void kfree(const void *ptr); -extern void *um_vmalloc(int size); +extern void *vmalloc(unsigned long size); extern void vfree(void *ptr); #endif /* __UM_MALLOC_H__ */ diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c index dba04d88b43..9870febdbea 100644 --- a/arch/um/kernel/irq.c +++ b/arch/um/kernel/irq.c @@ -30,7 +30,6 @@ #include "irq_kern.h" #include "os.h" #include "sigio.h" -#include "um_malloc.h" #include "misc_constants.h" #include "as-layout.h" diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 8d2c5496532..bfa52f206bb 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -46,7 +46,6 @@ #include "mode.h" #include "mode_kern.h" #include "choose-mode.h" -#include "um_malloc.h" /* This is a per-cpu array. A processor only modifies its entry and it only * cares about its entry, so it's OK if another processor is modifying its @@ -262,21 +261,6 @@ void dump_thread(struct pt_regs *regs, struct user *u) { } -void *um_kmalloc(int size) -{ - return kmalloc(size, GFP_KERNEL); -} - -void *um_kmalloc_atomic(int size) -{ - return kmalloc(size, GFP_ATOMIC); -} - -void *um_vmalloc(int size) -{ - return vmalloc(size); -} - int __cant_sleep(void) { return in_atomic() || irqs_disabled() || in_interrupt(); /* Is in_interrupt() really needed? */ diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 627742d8943..6916c8888db 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -52,17 +52,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - int copied; - - ret = -EIO; - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp, p); + case PTRACE_PEEKDATA: + ret = generic_ptrace_peekdata(child, addr, data); break; - } /* read the word at location addr in the USER area. */ case PTRACE_PEEKUSR: @@ -72,11 +64,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) /* when I and D space are separate, this will have to be fixed. */ case PTRACE_POKETEXT: /* write the word at location addr. */ case PTRACE_POKEDATA: - ret = -EIO; - if (access_process_vm(child, addr, &data, sizeof(data), - 1) != sizeof(data)) - break; - ret = 0; + ret = generic_ptrace_pokedata(child, addr, data); break; case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c index abab90c3803..3850d53f79f 100644 --- a/arch/um/kernel/trap.c +++ b/arch/um/kernel/trap.c @@ -76,23 +76,24 @@ good_area: goto out; do { + int fault; survive: - switch (handle_mm_fault(mm, vma, address, is_write)){ - case VM_FAULT_MINOR: - current->min_flt++; - break; - case VM_FAULT_MAJOR: - current->maj_flt++; - break; - case VM_FAULT_SIGBUS: - err = -EACCES; - goto out; - case VM_FAULT_OOM: - err = -ENOMEM; - goto out_of_memory; - default: + fault = handle_mm_fault(mm, vma, address, is_write); + if (unlikely(fault & VM_FAULT_ERROR)) { + if (fault & VM_FAULT_OOM) { + err = -ENOMEM; + goto out_of_memory; + } else if (fault & VM_FAULT_SIGBUS) { + err = -EACCES; + goto out; + } BUG(); } + if (fault & VM_FAULT_MAJOR) + current->maj_flt++; + else + current->min_flt++; + pgd = pgd_offset(mm, address); pud = pud_offset(pgd, address); pmd = pmd_offset(pud, address); diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c index 9bf944f6a1d..b126df4ea16 100644 --- a/arch/um/os-Linux/aio.c +++ b/arch/um/os-Linux/aio.c @@ -177,6 +177,7 @@ static int do_not_aio(struct aio_thread_req *req) static int aio_req_fd_r = -1; static int aio_req_fd_w = -1; static int aio_pid = -1; +static unsigned long aio_stack; static int not_aio_thread(void *arg) { @@ -212,7 +213,6 @@ static int not_aio_thread(void *arg) static int init_aio_24(void) { - unsigned long stack; int fds[2], err; err = os_pipe(fds, 1, 1); @@ -227,7 +227,7 @@ static int init_aio_24(void) goto out_close_pipe; err = run_helper_thread(not_aio_thread, NULL, - CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0); + CLONE_FILES | CLONE_VM | SIGCHLD, &aio_stack); if(err < 0) goto out_close_pipe; @@ -252,7 +252,6 @@ out: #define DEFAULT_24_AIO 0 static int init_aio_26(void) { - unsigned long stack; int err; if(io_setup(256, &ctx)){ @@ -263,7 +262,7 @@ static int init_aio_26(void) } err = run_helper_thread(aio_thread, NULL, - CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0); + CLONE_FILES | CLONE_VM | SIGCHLD, &aio_stack); if(err < 0) return err; @@ -365,8 +364,10 @@ __initcall(init_aio); static void exit_aio(void) { - if(aio_pid != -1) + if (aio_pid != -1) { os_kill_process(aio_pid, 1); + free_stack(aio_stack, 0); + } } __uml_exitcall(exit_aio); diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c index acba3016128..61d3953c7ac 100644 --- a/arch/um/os-Linux/drivers/ethertap_user.c +++ b/arch/um/os-Linux/drivers/ethertap_user.c @@ -54,7 +54,7 @@ static void etap_change(int op, unsigned char *addr, unsigned char *netmask, return; } - output = um_kmalloc(UM_KERN_PAGE_SIZE); + output = kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL); if(output == NULL) printk("etap_change : Failed to allocate output buffer\n"); read_output(fd, output, UM_KERN_PAGE_SIZE); @@ -117,7 +117,7 @@ static int etap_tramp(char *dev, char *gate, int control_me, pe_data.control_remote = control_remote; pe_data.control_me = control_me; pe_data.data_me = data_me; - pid = run_helper(etap_pre_exec, &pe_data, args, NULL); + pid = run_helper(etap_pre_exec, &pe_data, args); if(pid < 0) err = pid; @@ -166,7 +166,7 @@ static int etap_open(void *data) err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], control_fds[1], data_fds[0], data_fds[1]); output_len = UM_KERN_PAGE_SIZE; - output = um_kmalloc(output_len); + output = kmalloc(output_len, UM_GFP_KERNEL); read_output(control_fds[0], output, output_len); if(output == NULL) diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c index 11a9779dc9f..f848b4ea934 100644 --- a/arch/um/os-Linux/drivers/tuntap_user.c +++ b/arch/um/os-Linux/drivers/tuntap_user.c @@ -83,7 +83,7 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, data.stdout = remote; data.close_me = me; - pid = run_helper(tuntap_pre_exec, &data, argv, NULL); + pid = run_helper(tuntap_pre_exec, &data, argv); if(pid < 0) return -pid; diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index 97bed16bf4c..d81af7b8587 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -44,17 +44,13 @@ static int helper_child(void *arg) /* Returns either the pid of the child process we run or -E* on failure. * XXX The alloc_stack here breaks if this is called in the tracing thread, so * we need to receive a preallocated stack (a local buffer is ok). */ -int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, - unsigned long *stack_out) +int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv) { struct helper_data data; unsigned long stack, sp; int pid, fds[2], ret, n; - if ((stack_out != NULL) && (*stack_out != 0)) - stack = *stack_out; - else - stack = alloc_stack(0, __cant_sleep()); + stack = alloc_stack(0, __cant_sleep()); if (stack == 0) return -ENOMEM; @@ -76,8 +72,8 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, data.pre_data = pre_data; data.argv = argv; data.fd = fds[1]; - data.buf = __cant_sleep() ? um_kmalloc_atomic(PATH_MAX) : - um_kmalloc(PATH_MAX); + data.buf = __cant_sleep() ? kmalloc(PATH_MAX, UM_GFP_ATOMIC) : + kmalloc(PATH_MAX, UM_GFP_KERNEL); pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data); if (pid < 0) { ret = -errno; @@ -113,22 +109,21 @@ out_close: close(fds[1]); close(fds[0]); out_free: - if ((stack_out == NULL) || (*stack_out == 0)) - free_stack(stack, 0); + free_stack(stack, 0); return ret; } int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, - unsigned long *stack_out, int stack_order) + unsigned long *stack_out) { unsigned long stack, sp; int pid, status, err; - stack = alloc_stack(stack_order, __cant_sleep()); + stack = alloc_stack(0, __cant_sleep()); if (stack == 0) return -ENOMEM; - sp = stack + (UM_KERN_PAGE_SIZE << stack_order) - sizeof(void *); + sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *); pid = clone(proc, (void *) sp, flags | SIGCHLD, arg); if (pid < 0) { err = -errno; @@ -147,7 +142,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) printk("run_helper_thread - thread returned status " "0x%x\n", status); - free_stack(stack, stack_order); + free_stack(stack, 0); } else *stack_out = stack; return pid; diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index fb510d40480..e85f4995a01 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c @@ -235,8 +235,8 @@ void *__wrap_malloc(int size) return __real_malloc(size); else if(size <= UM_KERN_PAGE_SIZE) /* finding contiguous pages can be hard*/ - ret = um_kmalloc(size); - else ret = um_vmalloc(size); + ret = kmalloc(size, UM_GFP_KERNEL); + else ret = vmalloc(size); /* glibc people insist that if malloc fails, errno should be * set by malloc as well. So we do. diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c index 8d4e0c6b8c9..dc03e9cccb6 100644 --- a/arch/um/os-Linux/sigio.c +++ b/arch/um/os-Linux/sigio.c @@ -26,6 +26,7 @@ * exitcall. */ static int write_sigio_pid = -1; +static unsigned long write_sigio_stack; /* These arrays are initialized before the sigio thread is started, and * the descriptors closed after it is killed. So, it can't see them change. @@ -104,7 +105,7 @@ static int need_poll(struct pollfds *polls, int n) if(n <= polls->size) return 0; - new = um_kmalloc_atomic(n * sizeof(struct pollfd)); + new = kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC); if(new == NULL){ printk("need_poll : failed to allocate new pollfds\n"); return -ENOMEM; @@ -144,8 +145,10 @@ static void update_thread(void) return; fail: /* Critical section start */ - if(write_sigio_pid != -1) + if (write_sigio_pid != -1) { os_kill_process(write_sigio_pid, 1); + free_stack(write_sigio_stack, 0); + } write_sigio_pid = -1; close(sigio_private[0]); close(sigio_private[1]); @@ -230,7 +233,7 @@ static struct pollfd *setup_initial_poll(int fd) { struct pollfd *p; - p = um_kmalloc(sizeof(struct pollfd)); + p = kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL); if (p == NULL) { printk("setup_initial_poll : failed to allocate poll\n"); return NULL; @@ -243,7 +246,6 @@ static struct pollfd *setup_initial_poll(int fd) static void write_sigio_workaround(void) { - unsigned long stack; struct pollfd *p; int err; int l_write_sigio_fds[2]; @@ -293,7 +295,8 @@ static void write_sigio_workaround(void) memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, - CLONE_FILES | CLONE_VM, &stack, 0); + CLONE_FILES | CLONE_VM, + &write_sigio_stack); if (write_sigio_pid < 0) goto out_clear; @@ -356,10 +359,12 @@ out: static void sigio_cleanup(void) { - if(write_sigio_pid != -1){ - os_kill_process(write_sigio_pid, 1); - write_sigio_pid = -1; - } + if (write_sigio_pid == -1) + return; + + os_kill_process(write_sigio_pid, 1); + free_stack(write_sigio_stack, 0); + write_sigio_pid = -1; } __uml_exitcall(sigio_cleanup); diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index 46c00cc429b..ba9af8d6205 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c @@ -41,7 +41,7 @@ int is_skas_winch(int pid, int fd, void *data) if(pid != os_getpgrp()) return(0); - register_winch_irq(-1, fd, -1, data); + register_winch_irq(-1, fd, -1, data, 0); return(1); } diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c index 3f33165ada6..419b2d5ff6d 100644 --- a/arch/um/os-Linux/user_syms.c +++ b/arch/um/os-Linux/user_syms.c @@ -5,7 +5,8 @@ * so I *must* declare good prototypes for them and then EXPORT them. * The kernel code uses the macro defined by include/linux/string.h, * so I undef macros; the userspace code does not include that and I - * add an EXPORT for the glibc one.*/ + * add an EXPORT for the glibc one. + */ #undef strlen #undef strstr @@ -61,12 +62,18 @@ EXPORT_SYMBOL_PROTO(dup2); EXPORT_SYMBOL_PROTO(__xstat); EXPORT_SYMBOL_PROTO(__lxstat); EXPORT_SYMBOL_PROTO(__lxstat64); +EXPORT_SYMBOL_PROTO(__fxstat64); EXPORT_SYMBOL_PROTO(lseek); EXPORT_SYMBOL_PROTO(lseek64); EXPORT_SYMBOL_PROTO(chown); +EXPORT_SYMBOL_PROTO(fchown); EXPORT_SYMBOL_PROTO(truncate); +EXPORT_SYMBOL_PROTO(ftruncate64); EXPORT_SYMBOL_PROTO(utime); +EXPORT_SYMBOL_PROTO(utimes); +EXPORT_SYMBOL_PROTO(futimes); EXPORT_SYMBOL_PROTO(chmod); +EXPORT_SYMBOL_PROTO(fchmod); EXPORT_SYMBOL_PROTO(rename); EXPORT_SYMBOL_PROTO(__xmknod); @@ -102,14 +109,3 @@ EXPORT_SYMBOL(__stack_smash_handler); extern long __guard __attribute__((weak)); EXPORT_SYMBOL(__guard); - -/* - * 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: - */ |