]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.19pre15 2.2.19pre15
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:23:26 +0000 (15:23 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:23:26 +0000 (15:23 -0500)
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)

26 files changed:
CREDITS
Makefile
arch/s390/kernel/s390io.c
drivers/char/mem.c
drivers/isdn/Config.in
drivers/net/eepro100.c
drivers/s390/block/dasd.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_fba.c
drivers/scsi/aha1542.c
drivers/scsi/aha1740.c
drivers/scsi/i60uscsi.h
drivers/usb/hub.h
include/asm-s390/dasd.h
include/asm-s390/page.h
include/linux/sched.h
include/linux/tqueue.h
include/linux/usb.h
include/linux/wait.h
include/math-emu/op-2.h
init/main.c
kernel/Makefile
kernel/context.c [new file with mode: 0644]
kernel/exit.c
net/ipv4/tcp_input.c

diff --git a/CREDITS b/CREDITS
index 6d4ec34b3e9bb7e31002bd77ba25041897db919b..b3b008770fdf4f2539d06e542a28ad019d5dc0e8 100644 (file)
--- 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
index 3bdb8ac3b516936e13d4d538be230ca12438ffaf..f1f7b16ec1c9c7ec5262863ef3a612eaec34430e 100644 (file)
--- 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/)
 
index e8cacde4720d6b83773db315dbceb3ac1d805ad0..0d62ca7fd29877b6360977d22572c067daef0cf0 100644 (file)
@@ -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;
index f0d7b690b939a97c7701bf2a1ce26223fc9d51e3..dfab308263c5b7f6e7473c41610a438336a31575 100644 (file)
@@ -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
index 982f93ad78d341e24d64561222729e16e1dc3237..5bdf9196b1848b34db4cc8a5d9d3d70ac46f4b36 100644 (file)
@@ -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
 
index a630988ae195138379ee64d3c2bb3a8ef69d3de0..4ab70619d3e0bcf5af34f992521a34b8b684e454 100644 (file)
@@ -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);
index 1f9ee7a976101344961366ff231a547162853524..72cdccf71dfffc3089c182b503ef90a96d628451 100644 (file)
@@ -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 <linux/module.h>
@@ -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");
index daeca010893ae62255e3f4241e10c652ce313857..b7be0b107dbff877ae9ad9963d842b7c406f8e69 100644 (file)
@@ -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,
index f36fbd5d8c4077b264af79a115ca9f6f74522b97..98eb5da5847b9ac25279fe627da20c0f311e93ea 100644 (file)
@@ -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,
index 43f6ddcdaf88402807bc77ccd73f4197466718da..829af5b63007e9237774d80293c82b3d80b68390 100644 (file)
@@ -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,          
index 8879f716a6b16b09daec2bcbdbc5a5ad71b700bc..ecc8a2b6cb36aedaf1abf3992ac2bc9c5ac22c81 100644 (file)
@@ -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);
       };
index 96812a0ec9f0c0fda3cec542913777afa79eb50b..8cd523ca3c253375c6ac841777b1fe463eb41306 100644 (file)
@@ -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;
index 6fff823cc2fd2619b2b206f7303563a3324c17ec..f5fa801708a7aa215d2462cdd3aff971f77ca6ef 100644 (file)
 #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
index 1be8422dae7eb0455aa07b1a0e3888a04c25e60f..b2c3dffeb09197360377e302cfc941db518c2309 100644 (file)
@@ -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;
index 0e5c1538c152d8f0c0e6bc40702f961b55d1c330..1b02b6c0cf48c586abaf56e593958c60d142d80e 100644 (file)
@@ -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 */
 
index 434f5cc1cd57cfce4c294cee146d22477338d8f7..043eebc529be7e08680ba55357deb1586e05571a 100644 (file)
 #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                     */
index 52da83b1986ec91efb6834226f2838c19c28af7c..33471421add273204569da989b2de07b1b3c36ca 100644 (file)
@@ -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)
index d886f7533e9524bd787a33a3a1f82f312d6673cf..f6558752007b354951308046d9af62f9ff7e4df7 100644 (file)
@@ -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.
  */
index 71431cccb398f8c67ed6d965f5044b2abb91e845..1cb1c475fece269c2a85e8d9f3d917a19ec3669b 100644 (file)
@@ -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 */
index 995f28111043a0ef0ef771672e5bd5b6d87446f6..cbb4d61d9621f142e5048bd144085e0812486166 100644 (file)
@@ -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__
 
index ad3fbc538a0049dc77f2501b360ef8a208f33c3c..8273e41561dbcc04d24356c656ea004f412ccac1 100644 (file)
@@ -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)
index df269c22afa79f410ee6ddd2001573f25b15dd51..13955227edd7f0952ac3511cea2cfda5ab12b219 100644 (file)
@@ -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();
 
index abd520d4499d51a6eb283e4e686bb73bf488a5b5..d0b2cd308cea026349ef7d7ca869b9cde43d4c96 100644 (file)
@@ -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 (file)
index 0000000..6bfaaca
--- /dev/null
@@ -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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/unistd.h>
+#include <linux/signal.h>
+
+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);
+
index 8343731c951f3e332f9528bd4d8dde116d244b5f..98437d30c6deef4acb9c34567157b4c68034c200 100644 (file)
@@ -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(&current->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) {
index c8107f2c5c3f3ec62d2a89bc600740ced5928a7b..3e73b0a29b22a85199f372f2b9f0c42c76e3c9c6 100644 (file)
@@ -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, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -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) {