]> git.neil.brown.name Git - history.git/commitdiff
Import 2.0.31 2.0.31
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:33 +0000 (15:11 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:11:33 +0000 (15:11 -0500)
14 files changed:
arch/alpha/kernel/irq.c
drivers/pci/pci.c
fs/binfmt_aout.c
fs/binfmt_elf.c
fs/exec.c
fs/inode.c
include/linux/binfmts.h
include/linux/pci.h
kernel/fork.c
kernel/sched.c
mm/mlock.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/netlink.c

index 58c112c7ebb243e771cf301c154f30b205aa8ce8..a8d293a2eabc4b4ae7cd14fc2f3f53e34cf124fb 100644 (file)
@@ -60,6 +60,10 @@ static unsigned long irq_mask = ~0UL;
  */
 static void update_hw(unsigned long irq, unsigned long mask)
 {
+#ifdef CONFIG_ALPHA_ALCOR
+       /* always mask out 20..30 (which are unused) */
+       mask |= 0x7ff00000UL << 16;
+#endif
        switch (irq) {
 #if NR_IRQS == 48
              default:
index e3e4ab6f1d2ab39ee25128ef1b942a19c928fc76..7b267135cecba4a02cdfb6eef5a56b5a8e4caa43 100644 (file)
@@ -314,6 +314,7 @@ struct pci_dev_info dev_info[] = {
        DEVICE( S3,             S3_TRIO64V2,    "Trio64V2/DX or /GX"),
        DEVICE( S3,             S3_PLATO_PXG,   "PLATO/PX (graphics)"),
        DEVICE( S3,             S3_ViRGE_DXGX,  "ViRGE/DX or /GX"),
+       DEVICE( S3,             S3_ViRGE_GX2,   "ViRGE/GX2"),
        DEVICE( INTEL,          INTEL_82375,    "82375EB"),
        BRIDGE( INTEL,          INTEL_82424,    "82424ZX Saturn",       0x00),
        DEVICE( INTEL,          INTEL_82378,    "82378IB"),
index 360d27eefb8aa79f91cd85cf292f5beee30c6f53..c54c205b0b2f65206a0cbf0b58e7507cd27f794d 100644 (file)
@@ -298,8 +298,10 @@ do_load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        if (ex.a_data + ex.a_bss > rlim)
                return -ENOMEM;
 
+       if (flush_old_exec(bprm))
+               return -ENOMEM;
+
        /* OK, This is the point of no return */
-       flush_old_exec(bprm);
 
        current->mm->end_code = ex.a_text +
                (current->mm->start_code = N_TXTADDR(ex));
index 45fbe67c1f9a8f732daac07ab6dc757e30ee5bee..e4ebe3651f4c3a9a7d88cca059e1b27dd6a013e1 100644 (file)
@@ -549,8 +549,10 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                }
        }
        
+       if (flush_old_exec(bprm))
+               return -ENOMEM;
+
        /* OK, This is the point of no return */
-       flush_old_exec(bprm);
 
        current->mm->end_data = 0;
        current->mm->end_code = 0;
index fe9b3fdb4d338bbf4129fa67c8b0805f6412370a..2b3669563d1a03e4d8ea38a6de6431249894af3b 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -301,15 +301,30 @@ unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm)
                mpnt->vm_pte = 0;
                insert_vm_struct(current->mm, mpnt);
                current->mm->total_vm = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT;
-       }
 
-       for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-               if (bprm->page[i]) {
-                       current->mm->rss++;
-                       put_dirty_page(current,bprm->page[i],stack_base);
+               for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+                       if (bprm->page[i]) {
+                               current->mm->rss++;
+                               put_dirty_page(current,bprm->page[i],stack_base);
+                       }
+                       stack_base += PAGE_SIZE;
+               }
+       } else {
+               /*
+                * This one is tricky. We are already in the new context, so we cannot
+                * return with -ENOMEM. So we _have_ to deallocate argument pages here,
+                * if there is no VMA, they wont be freed at exit_mmap() -> memory leak.
+                *
+                * User space then gets a SIGSEGV when it tries to access argument pages.
+                */
+               for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+                       if (bprm->page[i]) {
+                               free_page(bprm->page[i]);
+                               bprm->page[i]=NULL;
+                       }
                }
-               stack_base += PAGE_SIZE;
        }
+
        return p;
 }
 
@@ -361,20 +376,17 @@ end_readexec:
        return result;
 }
 
-static void exec_mmap(void)
+static int exec_mmap(void)
 {
        /*
         * The clear_page_tables done later on exec does the right thing
         * to the page directory when shared, except for graceful abort
-        * (the oom is wrong there, too, IMHO)
         */
        if (current->mm->count > 1) {
-               struct mm_struct *mm = kmalloc(sizeof(*mm), GFP_KERNEL);
-               if (!mm) {
-                       /* this is wrong, I think. */
-                       oom(current);
-                       return;
-               }
+               struct mm_struct *old_mm, *mm = kmalloc(sizeof(*mm), GFP_KERNEL);
+               if (!mm)
+                       return -ENOMEM;
+
                *mm = *current->mm;
                mm->def_flags = 0;      /* should future lockings be kept? */
                mm->count = 1;
@@ -382,13 +394,27 @@ static void exec_mmap(void)
                mm->mmap_avl = NULL;
                mm->total_vm = 0;
                mm->rss = 0;
-               current->mm->count--;
+
+               old_mm = current->mm;
                current->mm = mm;
                new_page_tables(current);
-               return;
+
+               if ((old_mm != &init_mm) && (!--old_mm->count)) {
+                       /*
+                        * all threads exited while we were sleeping, 'old_mm' is held
+                        * by us exclusively, lets get rid of it:
+                        */
+                       exit_mmap(old_mm);
+                       free_page_tables(old_mm);
+                       kfree(old_mm);
+               }
+
+               return 0;
        }
        exit_mmap(current->mm);
        clear_page_tables(current);
+
+       return 0;
 }
 
 /*
@@ -431,7 +457,7 @@ static inline void flush_old_files(struct files_struct * files)
        }
 }
 
-void flush_old_exec(struct linux_binprm * bprm)
+int flush_old_exec(struct linux_binprm * bprm)
 {
        int i;
        int ch;
@@ -450,7 +476,8 @@ void flush_old_exec(struct linux_binprm * bprm)
        current->comm[i] = '\0';
 
        /* Release all of the old mmap stuff. */
-       exec_mmap();
+       if (exec_mmap())
+               return -ENOMEM;
 
        flush_thread();
 
@@ -460,6 +487,8 @@ void flush_old_exec(struct linux_binprm * bprm)
 
        flush_old_signals(current->sig);
        flush_old_files(current->files);
+
+       return 0;
 }
 
 /* 
index 5007f186e0ffa9ec574fd8209818be31e6b082ef..c96fb0679f891f88dffa8fe1acfcef2de4100653 100644 (file)
@@ -467,6 +467,14 @@ repeat:
        
        inode->i_count--;
 
+       if (inode->i_count)
+       /*
+        * Huoh, we were supposed to be the last user, but someone has
+        * grabbed it while we were sleeping. Dont destroy inode VM
+        * mappings, it might cause a memory leak.
+        */
+               return;
+
        if (inode->i_mmap) {
                printk("iput: inode %lu on device %s still has mappings.\n",
                        inode->i_ino, kdevname(inode->i_dev));
index f957012ba2c8090fa29470f8e1a28affb56b70d4..ae7167e35327b24f4938649085e1307cdb8147fb 100644 (file)
@@ -54,7 +54,7 @@ extern int init_java_binfmt(void);
 extern int prepare_binprm(struct linux_binprm *);
 extern void remove_arg_zero(struct linux_binprm *);
 extern int search_binary_handler(struct linux_binprm *,struct pt_regs *);
-extern void flush_old_exec(struct linux_binprm * bprm);
+extern int flush_old_exec(struct linux_binprm * bprm);
 extern unsigned long setup_arg_pages(unsigned long p, struct linux_binprm * bprm);
 extern unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
                unsigned long p, int from_kmem);
index 2a29a90f24881ab584f8778aa5940619b9eafb62..68b2e1a08a6b1950a289acaab4b863b9b13d4069 100644 (file)
 #define PCI_DEVICE_ID_S3_TRIO64V2      0x8901
 #define PCI_DEVICE_ID_S3_PLATO_PXG     0x8902
 #define PCI_DEVICE_ID_S3_ViRGE_DXGX    0x8a01
+#define PCI_DEVICE_ID_S3_ViRGE_GX2     0x8a10
 
 #define PCI_VENDOR_ID_INTEL            0x8086
 #define PCI_DEVICE_ID_INTEL_82375      0x0482
index 791d5ea5a0760041dbe4fcbc7a5e72a044614580..379942435c50ea08ce1b1cb36af19b485d7ebe9c 100644 (file)
@@ -93,6 +93,11 @@ static inline int dup_mmap(struct mm_struct * mm)
                tmp->vm_flags &= ~VM_LOCKED;
                tmp->vm_mm = mm;
                tmp->vm_next = NULL;
+               if (copy_page_range(mm, current->mm, tmp)) {
+                       kfree(tmp);
+                       exit_mmap(mm);
+                       return -ENOMEM;
+               }
                if (tmp->vm_inode) {
                        tmp->vm_inode->i_count++;
                        /* insert tmp into the share list, just after mpnt */
@@ -100,10 +105,6 @@ static inline int dup_mmap(struct mm_struct * mm)
                        mpnt->vm_next_share = tmp;
                        tmp->vm_prev_share = mpnt;
                }
-               if (copy_page_range(mm, current->mm, tmp)) {
-                       exit_mmap(mm);
-                       return -ENOMEM;
-               }
                if (tmp->vm_ops && tmp->vm_ops->open)
                        tmp->vm_ops->open(tmp);
                *p = tmp;
index f726dddaa1203ddce73237c22b8a614fd3eca85f..04ef94050f89db3cbfc159cb43819eb2a9ffbbe6 100644 (file)
@@ -116,7 +116,7 @@ static inline void add_to_runqueue(struct task_struct * p)
                return;
        }
 #endif
-       if (p->counter > current->counter + 3)
+       if (p->policy != SCHED_OTHER || p->counter > current->counter + 3)
                need_resched = 1;
        nr_running++;
        (p->prev_run = init_task.prev_run)->next_run = p;
index 30d78db8aca6571eb875546b850bc145387c7bb5..c96efe2fa7e08a6d27675f1087fd7dca8ac26a45 100644 (file)
@@ -124,9 +124,9 @@ static int mlock_fixup(struct vm_area_struct * vma,
                        pages = -pages;
                vma->vm_mm->locked_vm += pages;
 
-               if (newflags & VM_LOCKED)
+               if ((newflags & VM_LOCKED) && (newflags & VM_READ))
                        while (start < end) {
-                               char c = get_user((char *) start);
+                               int c = get_user((int *) start);
                                __asm__ __volatile__("": :"r" (c));
                                start += PAGE_SIZE;
                        }
index 550e35056d86a7b7dd43286c55f8a97d8de9f6d7..46de876c13c6ae7c1507e2a6f21f0a99dcb8e02c 100644 (file)
@@ -1389,6 +1389,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
         */
 
        for (;;) {
+               int was_locked;
                struct sk_buff * skb = sk->send_head;
                if (!skb)
                        break;
@@ -1460,10 +1461,22 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
                 *      We may need to remove this from the dev send list. 
                 */
                cli();
-               if (skb->next)
+               was_locked = skb_device_locked(skb);
+
+               if (was_locked) {
+                       /* In this case, we are relying on the fact that kfree_skb
+                        * will just set the free flag to be 3, and increment
+                        * a counter. It will not actually free anything, and 
+                        * will not take much time
+                        */
+                       kfree_skb(skb, FREE_WRITE);     
+               } else {
                        skb_unlink(skb);
+               }
                sti();
-               kfree_skb(skb, FREE_WRITE); /* write. */
+
+               if (!was_locked)
+                   kfree_skb(skb, FREE_WRITE); /* write. */
                if (!sk->dead)
                        sk->write_space(sk);
        }
index 406874275ea4c0b5aa41f762338d94b4376d7f20..756b9f7eae0aecca7b73f68c1e75f5d8c42144f0 100644 (file)
@@ -441,6 +441,7 @@ void tcp_do_retransmit(struct sock *sk, int all)
                struct tcphdr *th;
                struct iphdr *iph;
                int size;
+               unsigned long flags;
 
                dev = skb->dev;
                IS_SKB(skb);
@@ -456,8 +457,18 @@ void tcp_do_retransmit(struct sock *sk, int all)
                /*                 effect is that we'll send some unnecessary data, */
                /*                 but the alternative is disastrous...     */
                
-               if (skb_device_locked(skb))
+               save_flags(flags);
+               cli();
+
+               if (skb_device_locked(skb)) {
+                       restore_flags(flags);
                        break;
+               }
+
+               /* Unlink from any chain */
+               skb_unlink(skb);
+
+               restore_flags(flags);
 
                /*
                 *      Discard the surplus MAC header
@@ -623,14 +634,15 @@ void tcp_do_retransmit(struct sock *sk, int all)
                                 *      We still add up the counts as the round trip time wants
                                 *      adjusting.
                                 */
-                               if (sk && !skb_device_locked(skb))
+                               if (!skb_device_locked(skb))
                                {
-                                       /* Remove it from any existing driver queue first! */
-                                       skb_unlink(skb);
                                        /* Now queue it */
                                        ip_statistics.IpOutRequests++;
                                        dev_queue_xmit(skb, dev, sk->priority);
                                        sk->packets_out++;
+                               } else {
+                                       /* This shouldn't happen as we skip out above if the buffer is locked */
+                                       printk(KERN_WARNING "tcp_do_retransmit: sk_buff (%p) became locked\n", skb);
                                }
                        }
                }
index a4fe9ed5c48de772a4419532178b55eb935810ab..b00f85de7d960c5d0c346bd1f912fdd62f9293df 100644 (file)
@@ -87,6 +87,8 @@ static int netlink_write(struct inode * inode, struct file * file, const char *
        unsigned int minor = MINOR(inode->i_rdev);
        struct sk_buff *skb;
        skb=alloc_skb(count, GFP_KERNEL);
+       if (!skb)
+               return -ENOBUFS;
        skb->free=1;
        memcpy_fromfs(skb_put(skb,count),buf, count);
        return (netlink_handler[minor])(skb);