From: Alan Cox Date: Fri, 23 Nov 2007 20:23:26 +0000 (-0500) Subject: Linux 2.2.19pre15 X-Git-Tag: 2.2.19pre15 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=b2ace18484a30dfd5a4c87963e1dbbcff0337555;p=history.git Linux 2.2.19pre15 o Hugh Blemings has moved (Hugh Blemings) o Add support for usb hubs with many ports (Randy Dunlap) o Reapply make xconfig isdn fix (Andrzej Krzysztofowicz) o Fix the tcp problems (Alexey Kuznetsov) o Kai Petzke has moved (Kai Petzke) o Add BUG() to S/390 (Ulrich Weigand) o Further S/390 fixes (Ulrich Weigand) o Add keventd from 2.4 to 2.2 (Ulrich Weigand) | Needed for S/390 drivers o Remove dead isdn_init call (Andrzej Krzysztofowicz) o Remove bogus aha1542/aha1740 sense check (Nick Holloway) o FPU emu fix (Ulrich Weigand) o EEpro100 posted writes fix (Andrey Savochkin, Don Becker) --- diff --git a/CREDITS b/CREDITS index 6d4ec34b3e9b..b3b008770fdf 100644 --- a/CREDITS +++ b/CREDITS @@ -241,8 +241,8 @@ S: Marrickville NSW 2204 S: Australia N: Hugh Blemings -E: hugh@linuxcare.com -W: http://www.linuxcare.com.au/hugh/ +E: hugh@misc.nu +W: http://misc.nu/hugh D: Author and maintainer of the Keyspan USB to Serial drivers S: Po Box 234 S: Belconnen ACT 2616 @@ -1744,15 +1744,15 @@ S: Harrison, Arkansas 72602-1815 S: USA N: Kai Petzke -E: wpp@marie.physik.tu-berlin.de -W: http://physik.tu-berlin.de/~wpp -P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38 2E 3E 31 79 C3 65 5D E1 +E: petzke@teltarif.de +W: http://www.teltarif.de/ +P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38 2E 3E 31 79 C3 65 5D E1 D: Driver for Laser Magnetic Storage CD-ROM D: Some kernel bug fixes D: Port of the database Postgres -D: "Unix fuer Jedermann" a German introduction to linux (see my web page) -S: M"ullerstr. 69 -S: 13349 Berlin +D: Book: "Linux verstehen und anwenden" (Hanser-Verlag) +S: Triftstra=DFe 55 +S: 13353 Berlin S: Germany N: Ken Pizzini diff --git a/Makefile b/Makefile index 3bdb8ac3b516..f1f7b16ec1c9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 19 -EXTRAVERSION = pre13 +EXTRAVERSION = pre15 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff --git a/arch/s390/kernel/s390io.c b/arch/s390/kernel/s390io.c index e8cacde4720d..0d62ca7fd298 100644 --- a/arch/s390/kernel/s390io.c +++ b/arch/s390/kernel/s390io.c @@ -2179,7 +2179,11 @@ int s390_process_IRQ( unsigned int irq ) chnchk = 1; } /* endif */ - if ( (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND) + if( dp->ii.irb.scsw.ectl==0) + { + issense=0; + } + else if ( (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND) && (dp->ii.irb.scsw.eswf == 0 )) { issense = 0; diff --git a/drivers/char/mem.c b/drivers/char/mem.c index f0d7b690b939..dfab308263c5 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -34,9 +34,6 @@ void dmasound_init(void); #ifdef CONFIG_SPARCAUDIO extern int sparcaudio_init(void); #endif -#ifdef CONFIG_ISDN -int isdn_init(void); -#endif #ifdef CONFIG_PHONE extern int telephony_init(void); #endif @@ -647,9 +644,6 @@ __initfunc(int chr_dev_init(void)) #if CONFIG_QIC02_TAPE qic02_tape_init(); #endif -#if CONFIG_ISDN - isdn_init(); -#endif #ifdef CONFIG_FTAPE ftape_init(); #endif diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in index 982f93ad78d3..5bdf9196b184 100644 --- a/drivers/isdn/Config.in +++ b/drivers/isdn/Config.in @@ -16,7 +16,9 @@ bool ' Support audio via ISDN' CONFIG_ISDN_AUDIO if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then bool ' Support AT-Fax Class 1 and 2 commands' CONFIG_ISDN_TTY_FAX fi -if [ "$CONFIG_X25" != "n" ]; then + +# CONFIG_X25 is defined only when CONFIG_EXPERIMENTAL=y +if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X25" != "n" ]; then bool ' X.25 PLP on top of ISDN' CONFIG_ISDN_X25 fi diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index a630988ae195..4ab70619d3e0 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -751,6 +751,7 @@ static struct net_device *speedo_found1(struct pci_dev *pdev, int pci_bus, This takes less than 10usec and will easily finish before the next action. */ outl(PortReset, ioaddr + SCBPort); + inl(ioaddr + SCBPort); /* Honor PortReset timing. */ udelay(10); @@ -839,6 +840,7 @@ static struct net_device *speedo_found1(struct pci_dev *pdev, int pci_bus, #endif /* kernel_bloat */ outl(PortReset, ioaddr + SCBPort); + inl(ioaddr + SCBPort); /* Honor PortReset timing. */ udelay(10); @@ -1062,6 +1064,9 @@ static void speedo_resume(struct net_device *dev) /* Set the segment registers to '0'. */ wait_for_cmd_done(ioaddr + SCBCmd); outl(0, ioaddr + SCBPointer); + /* impose a delay to avoid a bug */ + inl(ioaddr + SCBPointer); + udelay(10); outb(RxAddrLoad, ioaddr + SCBCmd); wait_for_cmd_done(ioaddr + SCBCmd); outb(CUCmdBase, ioaddr + SCBCmd); diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 1f9ee7a97610..72cdccf71dff 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -40,6 +40,8 @@ * 01/17/01 fixed PL020234MVE problem accessing DASD 68-127, 133-191,... * 01/23/01 fixed sleep_on_request to terminate when signal_pending * 01/25/01 added code for error recovery with PAC'0x1D' = long busy + * 02/08/01 fixed PL020237RMI + * 02/08/01 fixed PL020265TDI */ #include @@ -1213,7 +1215,7 @@ dasd_do_chanq (void) delta = cqr->expires - cqr->startclk; printk (KERN_ERR PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" - " I/O operation outstanding longer than 0x%08x%08x usecs on req %p\n", + " I/O operation outstanding longer than 0x%08lx%08lx usecs on req %p\n", devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr); cqr->expires += delta; #if 0 @@ -1842,7 +1844,7 @@ dasd_format (dasd_device_t * device, format_data_t * fdata) while ((!rc ) && ((req = device->discipline->format_device (device, &temp)) != NULL ) ) { - if ( rc=sleep_on_req(req) ) { + if ( (rc=sleep_on_req(req)) != 0 ) { printk (KERN_WARNING PRINTK_HEADER " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)" " Formatting failed with rc = %d\n", @@ -2620,7 +2622,7 @@ dasd_set_device_level (unsigned int irq, int desired_level, if (major_info->blksize_size[minor + i] < 1024 ) major_info->blksize_size[minor + i] = 1024; - major_info->max_sectors[minor + i] = 200 << device->sizes.s2b_shift; /* FIXME !!! */ + major_info->max_sectors[minor + i] = device->discipline->max_blocks << device->sizes.s2b_shift; } atomic_compare_and_swap_debug (&device->level, DASD_DEVICE_LEVEL_ANALYSIS_PREPARED, @@ -3081,9 +3083,7 @@ dasd_init (void) dasd_unregister_major(major_info); } } - emergency_failed: dasd_cleanup_emergency_req(); - failed: printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n"); out: printk (KERN_INFO PRINTK_HEADER "initialization finished\n"); diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index daeca010893a..b7be0b107dbf 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -533,6 +533,7 @@ dasd_diag_dump_sense(struct dasd_device_t *device, ccw_req_t *req) dasd_discipline_t dasd_diag_discipline = { name : "DIAG", ebcname : "DIAG", + max_blocks: PAGE_SIZE/sizeof(diag_bio_t), check_characteristics: dasd_diag_check_characteristics, do_analysis: dasd_diag_do_analysis, fill_geometry: dasd_diag_fill_geometry, diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index f36fbd5d8c40..98eb5da5847b 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -898,6 +898,7 @@ dasd_eckd_dump_sense(struct dasd_device_t *device, ccw_req_t *req) dasd_discipline_t dasd_eckd_discipline = { name : "ECKD", ebcname : "ECKD", + max_blocks: 255, id_check: dasd_eckd_id_check, check_characteristics: dasd_eckd_check_characteristics, init_analysis: dasd_eckd_init_analysis, diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 43f6ddcdaf88..829af5b63007 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -353,6 +353,7 @@ dasd_fba_dump_sense(struct dasd_device_t *device, ccw_req_t *req) dasd_discipline_t dasd_fba_discipline = { name : "FBA ", ebcname : "FBA ", + max_blocks: PAGE_SIZE/sizeof(ccw1_t), id_check: dasd_fba_id_check, check_characteristics: dasd_fba_check_characteristics, do_analysis: dasd_fba_do_analysis, diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index 8879f716a6b1..ecc8a2b6cb36 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -560,7 +560,9 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) done(SCpnt); return 0;}); if(*cmd == REQUEST_SENSE){ -#ifndef DEBUG +#if 0 + /* scsi_request_sense() provides a buffer of size 256, + so there is no reason to expect equality */ if (bufflen != sizeof(SCpnt->sense_buffer)) { printk("Wrong buffer length supplied for request sense (%d)\n",bufflen); }; diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index 96812a0ec9f0..8cd523ca3c25 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -324,11 +324,13 @@ int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) if(*cmd == REQUEST_SENSE) { +#if 0 if (bufflen != sizeof(SCpnt->sense_buffer)) { printk("Wrong buffer length supplied for request sense (%d)\n", bufflen); } +#endif SCpnt->result = 0; done(SCpnt); return 0; diff --git a/drivers/scsi/i60uscsi.h b/drivers/scsi/i60uscsi.h index 6fff823cc2fd..f5fa801708a7 100644 --- a/drivers/scsi/i60uscsi.h +++ b/drivers/scsi/i60uscsi.h @@ -78,6 +78,14 @@ #define U32 unsigned long #endif +#ifndef VIRT_TO_BUS +#define VIRT_TO_BUS(x) (unsigned long)virt_to_bus((void *) x) +#endif + +#ifndef VIRT_TO_BUS +#define VIRT_TO_BUS(x) (unsigned int)virt_to_bus((void *) x) +#endif + #ifndef NULL #define NULL 0 /* zero */ #endif diff --git a/drivers/usb/hub.h b/drivers/usb/hub.h index 1be8422dae7e..b2c3dffeb091 100644 --- a/drivers/usb/hub.h +++ b/drivers/usb/hub.h @@ -111,7 +111,8 @@ struct usb_hub { /* Interrupt polling pipe */ struct urb *urb; - char buffer[USB_MAXCHILDREN / 8]; + char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; /* add 1 bit for hub status change */ + /* and add 7 bits to round up to byte boundary */ /* List of hubs */ struct list_head hub_list; diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h index 0e5c1538c152..1b02b6c0cf48 100644 --- a/include/asm-s390/dasd.h +++ b/include/asm-s390/dasd.h @@ -125,6 +125,7 @@ typedef char *(*dasd_dump_sense_fn_t)(struct dasd_device_t *,ccw_req_t *); typedef struct dasd_discipline_t { char ebcname[8]; /* a name used for tagging and printks */ char name[8]; /* a name used for tagging and printks */ + int max_blocks; /* how many blocks are allowed to be chained */ struct dasd_discipline_t *next; /* used for list of disciplines */ diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h index 434f5cc1cd57..043eebc529be 100644 --- a/include/asm-s390/page.h +++ b/include/asm-s390/page.h @@ -26,6 +26,11 @@ #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + __asm__ __volatile__(".word 0x0000"); \ +} while (0) + extern __inline__ int get_order(unsigned long size) { int order; @@ -104,7 +109,6 @@ typedef unsigned long pgprot_t; #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) #define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) - #endif /* __KERNEL__ */ #endif /* _S390_PAGE_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 52da83b1986e..33471421add2 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -120,6 +120,11 @@ extern void trap_init(void); extern signed long FASTCALL(schedule_timeout(signed long timeout)); asmlinkage void schedule(void); +extern int schedule_task(struct tq_struct *task); +extern void flush_scheduled_tasks(void); +extern int start_context_thread(void); +extern int current_is_keventd(void); + /* * The default fd array needs to be at least BITS_PER_LONG, * as this is the granularity returned by copy_fdset(). @@ -516,6 +521,13 @@ extern void FASTCALL(wake_up_process(struct task_struct * tsk)); #define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE | TASK_EXCLUSIVE) #define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE | TASK_EXCLUSIVE) +#define __set_task_state(tsk, state_value) do { (tsk)->state = state_value; } while (0) +#ifdef __SMP__ +#define set_task_state(tsk, state_value) do { __set_task_state(tsk, state_value); mb(); } while (0) +#else +#define set_task_state(tsk, state_value) __set_task_state(tsk, state_value) +#endif + #define __set_current_state(state_value) do { current->state = state_value; } while (0) #ifdef __SMP__ #define set_current_state(state_value) do { __set_current_state(state_value); mb(); } while (0) diff --git a/include/linux/tqueue.h b/include/linux/tqueue.h index d886f7533e95..f6558752007b 100644 --- a/include/linux/tqueue.h +++ b/include/linux/tqueue.h @@ -50,6 +50,7 @@ struct tq_struct { typedef struct tq_struct * task_queue; #define DECLARE_TASK_QUEUE(q) task_queue q = NULL +#define TQ_ACTIVE(q) ((q) != NULL) extern task_queue tq_timer, tq_immediate, tq_scheduler, tq_disk; @@ -78,20 +79,25 @@ extern task_queue tq_timer, tq_immediate, tq_scheduler, tq_disk; extern spinlock_t tqueue_lock; /* - * queue_task + * Queue a task on a tq. Return non-zero if it was successfully + * added. */ -extern __inline__ void queue_task(struct tq_struct *bh_pointer, +extern __inline__ int queue_task(struct tq_struct *bh_pointer, task_queue *bh_list) { + int ret = 0; if (!test_and_set_bit(0,&bh_pointer->sync)) { unsigned long flags; spin_lock_irqsave(&tqueue_lock, flags); bh_pointer->next = *bh_list; *bh_list = bh_pointer; spin_unlock_irqrestore(&tqueue_lock, flags); + ret = 1; } + return ret; } + /* * Call all "bottom halfs" on a given list. */ diff --git a/include/linux/usb.h b/include/linux/usb.h index 71431cccb398..1cb1c475fece 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -510,7 +510,7 @@ struct usb_bus { struct list_head inodes; }; -#define USB_MAXCHILDREN (8) /* This is arbitrary */ +#define USB_MAXCHILDREN (16) /* This is arbitrary */ struct usb_device { int devnum; /* Device number on USB bus */ diff --git a/include/linux/wait.h b/include/linux/wait.h index 995f28111043..cbb4d61d9621 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -4,7 +4,8 @@ #define WNOHANG 0x00000001 #define WUNTRACED 0x00000002 -#define __WCLONE 0x80000000 +#define __WALL 0x40000000 /* Wait on all children, regardless of type */ +#define __WCLONE 0x80000000 /* Wait only on non-SIGCHLD children */ #ifdef __KERNEL__ diff --git a/include/math-emu/op-2.h b/include/math-emu/op-2.h index ad3fbc538a00..8273e41561db 100644 --- a/include/math-emu/op-2.h +++ b/include/math-emu/op-2.h @@ -79,7 +79,7 @@ else \ { \ X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) | \ - (((X##_f1 << (sz - (N))) | X##_f0) != 0)); \ + (((X##_f1 << (2*_FP_W_TYPE_SIZE - (N))) | X##_f0) != 0)); \ X##_f1 = 0; \ } \ } while (0) diff --git a/init/main.c b/init/main.c index df269c22afa7..13955227edd7 100644 --- a/init/main.c +++ b/init/main.c @@ -1595,6 +1595,9 @@ static void __init do_basic_setup(void) else mount_initrd =0; #endif + /* Start the event daemon thread */ + start_context_thread(); + /* Set up devices .. */ device_setup(); diff --git a/kernel/Makefile b/kernel/Makefile index abd520d4499d..d0b2cd308cea 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -15,7 +15,7 @@ O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o sys.o \ module.o exit.o itimer.o info.o time.o softirq.o resource.o \ sysctl.o acct.o capability.o -OX_OBJS += signal.o +OX_OBJS += context.o signal.o ifeq ($(CONFIG_KMOD),y) O_OBJS += kmod.o diff --git a/kernel/context.c b/kernel/context.c new file mode 100644 index 000000000000..6bfaaca920da --- /dev/null +++ b/kernel/context.c @@ -0,0 +1,157 @@ +/* + * linux/kernel/context.c + * + * Mechanism for running arbitrary tasks in process context + * + * dwmw2@redhat.com: Genesis + * + * andrewm@uow.edu.au: 2.4.0-test12 + * - Child reaping + * - Support for tasks which re-add themselves + * - flush_scheduled_tasks. + */ + +#define __KERNEL_SYSCALLS__ + +#include +#include +#include +#include +#include +#include + +static DECLARE_TASK_QUEUE(tq_context); +static DECLARE_WAIT_QUEUE_HEAD(context_task_wq); +static DECLARE_WAIT_QUEUE_HEAD(context_task_done); +static int keventd_running; +static struct task_struct *keventd_task; + +static int need_keventd(const char *who) +{ + if (keventd_running == 0) + printk(KERN_ERR "%s(): keventd has not started\n", who); + return keventd_running; +} + +int current_is_keventd(void) +{ + int ret = 0; + if (need_keventd(__FUNCTION__)) + ret = (current == keventd_task); + return ret; +} + +/** + * schedule_task - schedule a function for subsequent execution in process context. + * @task: pointer to a &tq_struct which defines the function to be scheduled. + * + * May be called from interrupt context. The scheduled function is run at some + * time in the near future by the keventd kernel thread. If it can sleep, it + * should be designed to do so for the minimum possible time, as it will be + * stalling all other scheduled tasks. + * + * schedule_task() returns non-zero if the task was successfully scheduled. + * If @task is already residing on a task queue then schedule_task() fails + * to schedule your task and returns zero. + */ +int schedule_task(struct tq_struct *task) +{ + int ret; + need_keventd(__FUNCTION__); + ret = queue_task(task, &tq_context); + wake_up(&context_task_wq); + return ret; +} + +static int context_thread(void *dummy) +{ + struct task_struct *curtask = current; + DECLARE_WAITQUEUE(wait, curtask); + struct k_sigaction sa; + + daemonize(); + strcpy(curtask->comm, "keventd"); + keventd_running = 1; + keventd_task = curtask; + + spin_lock_irq(&curtask->sigmask_lock); + siginitsetinv(&curtask->blocked, sigmask(SIGCHLD)); + recalc_sigpending(curtask); + spin_unlock_irq(&curtask->sigmask_lock); + + /* Install a handler so SIGCLD is delivered */ + sa.sa.sa_handler = SIG_IGN; + sa.sa.sa_flags = 0; + siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD)); + do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0); + + /* + * If one of the functions on a task queue re-adds itself + * to the task queue we call schedule() in state TASK_RUNNING + */ + for (;;) { + set_task_state(curtask, TASK_INTERRUPTIBLE); + add_wait_queue(&context_task_wq, &wait); + if (TQ_ACTIVE(tq_context)) + set_task_state(curtask, TASK_RUNNING); + schedule(); + remove_wait_queue(&context_task_wq, &wait); + run_task_queue(&tq_context); + wake_up(&context_task_done); + if (signal_pending(curtask)) { + while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0) + ; + flush_signals(curtask); + recalc_sigpending(curtask); + } + } +} + +/** + * flush_scheduled_tasks - ensure that any scheduled tasks have run to completion. + * + * Forces execution of the schedule_task() queue and blocks until its completion. + * + * If a kernel subsystem uses schedule_task() and wishes to flush any pending + * tasks, it should use this function. This is typically used in driver shutdown + * handlers. + * + * The caller should hold no spinlocks and should hold no semaphores which could + * cause the scheduled tasks to block. + */ +static struct tq_struct dummy_task; + +void flush_scheduled_tasks(void) +{ + int count; + DECLARE_WAITQUEUE(wait, current); + + /* + * Do it twice. It's possible, albeit highly unlikely, that + * the caller queued a task immediately before calling us, + * and that the eventd thread was already past the run_task_queue() + * but not yet into wake_up(), so it woke us up before completing + * the caller's queued task or our new dummy task. + */ + add_wait_queue(&context_task_done, &wait); + for (count = 0; count < 2; count++) { + set_current_state(TASK_UNINTERRUPTIBLE); + + /* Queue a dummy task to make sure we get kicked */ + schedule_task(&dummy_task); + + /* Wait for it to complete */ + schedule(); + } + remove_wait_queue(&context_task_done, &wait); +} + +int start_context_thread(void) +{ + kernel_thread(context_thread, NULL, CLONE_FS | CLONE_FILES); + return 0; +} + +EXPORT_SYMBOL(schedule_task); +EXPORT_SYMBOL(flush_scheduled_tasks); + diff --git a/kernel/exit.c b/kernel/exit.c index 8343731c951f..98437d30c6de 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -437,7 +437,7 @@ asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct struct wait_queue wait = { current, NULL }; struct task_struct *p; - if (options & ~(WNOHANG|WUNTRACED|__WCLONE)) + if (options & ~(WNOHANG|WUNTRACED|__WCLONE|__WALL)) return -EINVAL; add_wait_queue(¤t->wait_chldexit,&wait); @@ -462,8 +462,13 @@ repeat: if (p->pgrp != -pid) continue; } - /* wait for cloned processes iff the __WCLONE flag is set */ - if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) + /* Wait for all children (clone and not) if __WALL is set; + * otherwise, wait for clone children *only* if __WCLONE is + * set; otherwise, wait for non-clone children *only*. (Note: + * A "clone" child here is one that reports to its parent + * using a signal other than SIGCHLD.) */ + if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) + && !(options & __WALL)) continue; flag = 1; switch (p->state) { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c8107f2c5c3f..3e73b0a29b22 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5,7 +5,7 @@ * * Implementation of the Transmission Control Protocol(TCP). * - * Version: $Id: tcp_input.c,v 1.164.2.19 2001/02/02 01:50:39 davem Exp $ + * Version: $Id: tcp_input.c,v 1.164.2.20 2001/02/23 20:20:22 davem Exp $ * * Authors: Ross Biro, * Fred N. van Kempen, @@ -253,14 +253,14 @@ extern __inline__ int tcp_paws_discard(struct tcp_opt *tp, struct tcphdr *th, un * of data (and SYN, FIN, of course) is checked separately. * See tcp_data_queue(), for example. * - * Also, controls (RST is main one) are accepted using RCV.WUP instead + * Also, controls (RST is main one) are accepted using last_ack_sent instead * of RCV.NXT. Peer still did not advance his SND.UNA when we - * delayed ACK, so that hisSND.UNA<=ourRCV.WUP. + * delayed ACK, so that hisSND.UNA<=last_ack_sent. * (borrowed from freebsd) */ static inline int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq) { - return !before(end_seq, tp->rcv_wup) && + return !before(end_seq, tp->last_ack_sent) && !after(seq, tp->rcv_nxt + tcp_receive_window(tp)); } @@ -1443,6 +1443,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) SOCK_DEBUG(sk, "retransmit received: seq %X\n", TCP_SKB_CB(skb)->seq); tcp_enter_quickack_mode(tp); out_of_window: + tp->delayed_acks++; kfree_skb(skb); return; } @@ -1683,6 +1684,9 @@ static void tcp_check_urg(struct sock * sk, struct tcphdr * th) if (after(tp->copied_seq, ptr)) return; + if (before(ptr, tp->rcv_nxt)) + return; + /* Do we already have a newer (or duplicate) urgent pointer? */ if (tp->urg_data && !after(ptr, tp->urg_seq)) return; @@ -1701,8 +1705,10 @@ static void tcp_check_urg(struct sock * sk, struct tcphdr * th) * as data, nor can we alter copied_seq until this data arrives * or we break the sematics of SIOCATMARK (and thus sockatmark()) */ - if (tp->urg_seq == tp->copied_seq) - tp->copied_seq++; /* Move the copied sequence on correctly */ + if (tp->urg_seq == tp->copied_seq && tp->urg_data && + !sk->urginline && + tp->copied_seq != tp->rcv_nxt) + tp->copied_seq++; tp->urg_data = URG_NOTYET; tp->urg_seq = ptr; @@ -1721,7 +1727,7 @@ static inline void tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long len /* Do we wait for any urgent data? - normally not... */ if (tp->urg_data == URG_NOTYET) { - u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4); + u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4) - th->syn; /* Is the urgent pointer pointing into this packet? */ if (ptr < len) {