]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.91pre2 2.1.91pre2
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:00 +0000 (15:15 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:15:00 +0000 (15:15 -0500)
14 files changed:
Makefile
arch/i386/kernel/process.c
fs/buffer.c
include/linux/swap.h
kernel/sysctl.c
mm/filemap.c
mm/page_alloc.c
mm/swap.c
mm/vmscan.c
net/core/datagram.c
net/core/iovec.c
net/packet/af_packet.c
net/socket.c
net/unix/af_unix.c

index f934b3ed69145dc28c162cc7ee6247cbc737b54f..6d9f5e584d7628ce819a6bc6f32b95e5d22f0761 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -242,7 +242,7 @@ newversion:
 
 include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion
        @echo -n \#define UTS_VERSION \"\#`cat .version` > .ver
-       @if [ -z "$(SMP)" ] ; then echo -n " SMP" >> .ver; fi
+       @if [ -n "$(SMP)" ] ; then echo -n " SMP" >> .ver; fi
        @if [ -f .name ]; then  echo -n \-`cat .name` >> .ver; fi
        @echo ' '`date`'"' >> .ver
        @echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> .ver
index 6f22457902c657e795c1b300c39c4d44ab5bdece..6ba4e0ff8db5847d78d92eff738f22007e3d4fee 100644 (file)
@@ -171,6 +171,8 @@ int cpu_idle(void *unused)
 
 asmlinkage int sys_idle(void)
 {
+       if (current->pid != 0)
+               return -EPERM;
        cpu_idle(NULL);
        return 0;
 }
index ec844de9f490a77df5b2106613d86489a1c6385b..1d58146ae2a59b816c99f7faca2c83760b3755b8 100644 (file)
@@ -55,12 +55,9 @@ static char buffersize_index[17] =
                                             number of unused buffer heads */
 
 /*
- * How large a hash table do we need?
+ * Hash table mask..
  */
-#define HASH_PAGES_ORDER       4
-#define HASH_PAGES             (1UL << HASH_PAGES_ORDER)
-#define NR_HASH                        (HASH_PAGES*PAGE_SIZE/sizeof(struct buffer_head *))
-#define HASH_MASK              (NR_HASH-1)
+static unsigned long bh_hash_mask = 0;
 
 static int grow_buffers(int pri, int size);
 
@@ -421,7 +418,7 @@ void invalidate_buffers(kdev_t dev)
        }
 }
 
-#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block))&HASH_MASK)
+#define _hashfn(dev,block) (((unsigned)(HASHDEV(dev)^block)) & bh_hash_mask)
 #define hash(dev,block) hash_table[_hashfn(dev,block)]
 
 static inline void remove_from_hash_queue(struct buffer_head * bh)
@@ -732,7 +729,7 @@ static void refill_freelist(int size)
        needed = bdf_prm.b_un.nrefill * size;  
 
        while ((nr_free_pages > freepages.min*2) &&
-               BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) &&
+               (buffermem >> PAGE_SHIFT) * 100 < (buffer_mem.max_percent * num_physpages) &&
                grow_buffers(GFP_BUFFER, size)) {
                obtained += PAGE_SIZE;
                if (obtained >= needed)
@@ -817,7 +814,6 @@ repeat:
         */
        while (obtained < (needed >> 1) &&
               nr_free_pages > freepages.min + 5 &&
-              BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) &&
               grow_buffers(GFP_BUFFER, size))
                obtained += PAGE_SIZE;
 
@@ -1707,11 +1703,16 @@ void show_buffers(void)
  */
 void buffer_init(void)
 {
-       hash_table = (struct buffer_head **)
-               __get_free_pages(GFP_ATOMIC, HASH_PAGES_ORDER);
+       int order = 5;          /* Currently maximum order.. */
+       unsigned int nr_hash;
+
+       nr_hash = (1UL << order) * PAGE_SIZE / sizeof(struct buffer_head *);
+       hash_table = (struct buffer_head **) __get_free_pages(GFP_ATOMIC, order);
+       
        if (!hash_table)
                panic("Failed to allocate buffer hash table\n");
-       memset(hash_table,0,NR_HASH*sizeof(struct buffer_head *));
+       memset(hash_table, 0, nr_hash * sizeof(struct buffer_head *));
+       bh_hash_mask = nr_hash-1;
 
        bh_cachep = kmem_cache_create("buffer_head",
                                      sizeof(struct buffer_head),
index 494490c32eac968c52d367f1458c2e2d7d1b54da..f4822bc8f1a82405735c62a4a17ed3adc8757f31 100644 (file)
@@ -39,7 +39,6 @@ extern atomic_t nr_async_pages;
 extern struct inode swapper_inode;
 extern unsigned long page_cache_size;
 extern int buffermem;
-#define BUFFER_MEM ((buffermem >> PAGE_SHIFT) + page_cache_size)
 
 /* Incomplete types for prototype declarations: */
 struct task_struct;
index e6864541f985e322ed05d3270198f5ab2c863bd4..ea3b98c9401fc70457b39c435abb2881edd836d2 100644 (file)
@@ -191,7 +191,7 @@ static ctl_table vm_table[] = {
        {VM_SWAPCTL, "swapctl", 
         &swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec},
        {VM_SWAPOUT, "swapout_interval",
-        &swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec_jiffies},
+        &swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec},
        {VM_FREEPG, "freepages", 
         &freepages, sizeof(freepages_t), 0600, NULL, &proc_dointvec},
        {VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
index 7a4e20e21902c860b11d0bd7f80fe372d0557257..cb76c5592dbd0d55bd98a07d7d4ac1f9fbb294c8 100644 (file)
@@ -150,6 +150,10 @@ int shrink_mmap(int priority, int gfp_mask)
                                }
                                tmp = tmp->b_this_page;
                        } while (tmp != bh);
+
+                       /* Refuse to swap out all buffer pages */
+                       if ((buffermem >> PAGE_SHIFT) * 100 > (buffer_mem.min_percent * num_physpages))
+                               goto next;
                }
 
                /* We can't throw away shared pages, but we do mark
index 55e4cf3d6b6e4fde1be03a6ab0cfbe7c2a80c862..5138eb0481cbe251fff92dd4b02c9ab590ab1465 100644 (file)
@@ -124,6 +124,7 @@ static spinlock_t page_alloc_lock;
  */
 int free_memory_available(int nr)
 {
+       int retval = 0;
        unsigned long flags;
        struct free_area_struct * list = NULL;
 
@@ -141,10 +142,11 @@ int free_memory_available(int nr)
                if (list->next->next == memory_head(list))
                        continue;
                /* More than one item? We're ok */
+               retval = nr + 1;
                break;
        } while (--nr >= 0);
        spin_unlock_irqrestore(&page_alloc_lock, flags);
-       return nr + 1;
+       return retval;
 }
 
 static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
index 0ccf96dc84c742686b5575475cf60d7871313c50..d607db93b88ca52793e429a72c8f7aff9fd953c3 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -67,8 +67,8 @@ swap_control_t swap_control = {
 swapstat_t swapstats = {0};
 
 buffer_mem_t buffer_mem = {
-       6,      /* minimum percent buffer + cache memory */
-       20,     /* borrow percent buffer + cache memory */
-       90      /* maximum percent buffer + cache memory */
+       3,      /* minimum percent buffer */
+       10,     /* borrow percent buffer */
+       30      /* maximum percent buffer */
 };
 
index 5492296097d8536cb85997b4eafca517c6bf35ec..e6d325509b519df9be792bb4f9eb456e0e573bf4 100644 (file)
@@ -31,7 +31,7 @@
 /* 
  * When are we next due for a page scan? 
  */
-static int next_swap_jiffies = 0;
+static unsigned long next_swap_jiffies = 0;
 
 /* 
  * How often do we do a pageout scan during normal conditions?
@@ -451,14 +451,13 @@ static inline int do_try_to_free_page(int gfp_mask)
        stop = 3;
        if (gfp_mask & __GFP_WAIT)
                stop = 0;
-       if (BUFFER_MEM > buffer_mem.borrow_percent * num_physpages / 100)
+       if ((buffermem >> PAGE_SHIFT) * 100 > buffer_mem.borrow_percent * num_physpages)
                state = 0;
 
        switch (state) {
                do {
                case 0:
-                       if (BUFFER_MEM > (buffer_mem.min_percent * num_physpages /100) &&
-                                       shrink_mmap(i, gfp_mask))
+                       if (shrink_mmap(i, gfp_mask))
                                return 1;
                        state = 1;
                case 1:
@@ -547,18 +546,30 @@ int kswapd(void *unused)
                run_task_queue(&tq_disk);
                schedule();
                swapstats.wakeups++;
-               /* Do the background pageout: 
-                * When we've got loads of memory, we try
-                * (freepages.high - nr_free_pages) times to
-                * free memory. As memory gets tighter, kswapd
-                * gets more and more agressive. -- Rik.
+       
+               /*
+                * Do the background pageout: be
+                * more aggressive if we're really
+                * low on free memory.
+                *
+                * Normally this is called 4 times
+                * a second if we need more memory,
+                * so this has a normal rate of
+                * X*4 pages of memory free'd per
+                * second. That rate goes up when
+                *
+                * - we're really low on memory (we get woken
+                *   up a lot more)
+                * - other processes fail to allocate memory,
+                *   at which time they try to do their own
+                *   freeing.
+                *
+                * A "tries" value of 50 means up to 200 pages
+                * per second (1.6MB/s). This should be a /proc
+                * thing.
                 */
-               tries = freepages.high - nr_free_pages;
-               if (tries < freepages.min) {
-                       tries = freepages.min;
-               }
-               if (nr_free_pages < freepages.low)
-                       tries <<= 1;
+               tries = 50;
+       
                while (tries--) {
                        int gfp_mask;
 
@@ -583,7 +594,6 @@ int kswapd(void *unused)
 /* 
  * The swap_tick function gets called on every clock tick.
  */
-
 void swap_tick(void)
 {
        unsigned long now, want;
@@ -604,13 +614,13 @@ void swap_tick(void)
        case 0:
                want = now;
                /* Fall through */
-       case 1 ... 2:
+       case 1 ... 3:
                want_wakeup = 1;
        default:
        }
  
        if ((long) (now - want) >= 0) {
-               if (want_wakeup || (num_physpages * buffer_mem.max_percent / 100) < BUFFER_MEM) {
+               if (want_wakeup || (num_physpages * buffer_mem.max_percent) < (buffermem >> PAGE_SHIFT) * 100) {
                        /* Set the next wake-up time */
                        next_swap_jiffies = now + swapout_interval;
                        wake_up(&kswapd_wait);
index cdab70abafd2d9b11d0284bffdc538ad34b21541..186ccf81b9535e6413926039de80500ee2b1250d 100644 (file)
@@ -132,15 +132,13 @@ restart:
                unsigned long flags;
                save_flags(flags);
                cli();
-               skb=skb_peek(&sk->receive_queue);
+               skb = skb_peek(&sk->receive_queue);
                if(skb!=NULL)
                        atomic_inc(&skb->users);
                restore_flags(flags);
-               if(skb==NULL)           /* shouldn't happen but .. */
-                       goto restart;
-               return skb;
-       }
-       skb = skb_dequeue(&sk->receive_queue);
+       } else
+               skb = skb_dequeue(&sk->receive_queue);
+
        if (!skb)       /* Avoid race if someone beats us to the data */
                goto restart;
        return skb;
@@ -163,30 +161,23 @@ void skb_free_datagram(struct sock * sk, struct sk_buff *skb)
 
 int skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
 {
-       int err;
-       err = copy_to_user(to, skb->h.raw+offset, size);
-       if (err)
-       {
-               err = -EFAULT;
-       }
+       int err = -EFAULT;
+
+       if (!copy_to_user(to, skb->h.raw + offset, size))
+               err = 0;
        return err;
 }
 
 
 /*
  *     Copy a datagram to an iovec.
+ *     Note: the iovec is modified during the copy.
  */
  
 int skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to,
                            int size)
 {
-       int err;
-       err = memcpy_toiovec(to, skb->h.raw+offset, size);
-       if (err)
-       {
-               err = -EFAULT;
-       }
-       return err;
+       return memcpy_toiovec(to, skb->h.raw + offset, size);
 }
 
 /*
index 9e8873646909f43da9c48fe6759f44a205e28094..5b684a48f246b5e7724395ada93fc5393c8d909e 100644 (file)
@@ -30,7 +30,6 @@
 
 /*
  *     Verify iovec
- *     verify area does a simple check for completly bogus addresses
  *
  *     Save time not doing verify_area. copy_*_user will make this work
  *     in any case.
@@ -79,22 +78,21 @@ out_free:
 }
 
 /*
- *     Copy kernel to iovec.
+ *     Copy kernel to iovec. Returns -EFAULT on error.
  *
  *     Note: this modifies the original iovec.
  */
  
 int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
 {
-       int err;
+       int err = -EFAULT; 
 
        while(len>0)
        {
                if(iov->iov_len)
                {
                        int copy = min(iov->iov_len, len);
-                       err = copy_to_user(iov->iov_base, kdata, copy);
-                       if (err)
+                       if (copy_to_user(iov->iov_base, kdata, copy))
                                goto out;
                        kdata+=copy;
                        len-=copy;
@@ -109,7 +107,7 @@ out:
 }
 
 /*
- *     Copy iovec to kernel.
+ *     Copy iovec to kernel. Returns -EFAULT on error.
  *
  *     Note: this modifies the original iovec.
  */
@@ -147,35 +145,23 @@ int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
 {
        int err = -EFAULT;
 
-       while(offset>0)
+       /* Skip over the finished iovecs */
+       while(offset >= iov->iov_len)
        {
-               if (offset > iov->iov_len)
-               {
-                       offset -= iov->iov_len;
-               }
-               else
-               {
-                       u8 *base = iov->iov_base + offset;
-                       int copy = min(len, iov->iov_len - offset);
-
-                       offset = 0;
-
-                       if (copy_from_user(kdata, base, copy))
-                               goto out;
-                       len-=copy;
-                       kdata+=copy;
-               }
+               offset -= iov->iov_len;
                iov++;
        }
 
-       while (len>0)
+       while (len > 0)
        {
-               int copy = min(len, iov->iov_len);
+               u8 *base = iov->iov_base + offset;
+               int copy = min(len, iov->iov_len - offset);
 
-               if (copy_from_user(kdata, iov->iov_base, copy))
+               offset = 0;
+               if (copy_from_user(kdata, base, copy))
                        goto out;
-               len-=copy;
-               kdata+=copy;
+               len   -= copy;
+               kdata += copy;
                iov++;
        }
        err = 0;
@@ -195,51 +181,22 @@ out:
 int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
                                 int offset, unsigned int len, int *csump)
 {
-       int partial_cnt = 0;
-       int err = 0;
-       int csum;
+       int csum = *csump;
+       int partial_cnt = 0, err = 0;
 
-       do {
-               int copy = iov->iov_len - offset;
-
-               if (copy > 0) {
-                       u8 *base = iov->iov_base + offset;
-
-                       /* Normal case (single iov component) is fastly detected */
-                       if (len <= copy) {
-                               *csump = csum_and_copy_from_user(base, kdata, 
-                                                                len, *csump, &err);
-                               goto out;
-                       }
-
-                       partial_cnt = copy % 4;
-                       if (partial_cnt) {
-                               copy -= partial_cnt;
-                               if (copy_from_user(kdata + copy, base + copy,
-                                               partial_cnt))
-                                       goto out_fault;
-                       }
-
-                       *csump = csum_and_copy_from_user(base, kdata, copy,
-                                                        *csump, &err);
-                       if (err)
-                               goto out;
-                       len   -= copy + partial_cnt;
-                       kdata += copy + partial_cnt;
-                       iov++;
-                       break;
-               }
+       /* Skip over the finished iovecs */
+       while (offset >= iov->iov_len)
+       {
+               offset -= iov->iov_len;
                iov++;
-               offset = -copy;
-       } while (offset > 0);
-
-       csum = *csump;
+       }
 
        while (len > 0)
        {
-               u8 *base = iov->iov_base;
-               unsigned int copy = min(len, iov->iov_len);
+               u8 *base = iov->iov_base + offset;
+               unsigned int copy = min(len, iov->iov_len - offset);
 
+               offset = 0;
                /* There is a remnant from previous iov. */
                if (partial_cnt)
                {
index 74fc7af82594343fa31cc090cf1718c509d24917..858ea0e73f1f4cd8c6849196a9468c6946b9ed0d 100644 (file)
@@ -262,9 +262,9 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg, int len,
                               struct scm_cookie *scm)
 {
        struct sock *sk = sock->sk;
+       struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name;
        struct sk_buff *skb;
        struct device *dev;
-       struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name;
        unsigned short proto=0;
        int err;
        
@@ -309,6 +309,7 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg, int len,
                return -EMSGSIZE;
 
        dev_lock_list();
+       err = -ENOBUFS;
        skb = sock_wmalloc(sk, len+dev->hard_header_len+15, 0, GFP_KERNEL);
 
        /*
@@ -318,10 +319,7 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg, int len,
         */
         
        if (skb == NULL) 
-       {
-               dev_unlock_list();
-               return(-ENOBUFS);
-       }
+               goto out_unlock;
        
        /*
         *      Fill it in 
@@ -339,36 +337,32 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg, int len,
                skb->data -= dev->hard_header_len;
                skb->tail -= dev->hard_header_len;
        }
+
+       /* Returns -EFAULT on error */
        err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
        skb->protocol = proto;
        skb->dev = dev;
        skb->priority = sk->priority;
-       dev_unlock_list();
+       if (err)
+               goto out_free;
+
+       err = -ENETDOWN;
+       if (!(dev->flags & IFF_UP))
+               goto out_free;
 
        /*
         *      Now send it
         */
 
-       if (err)
-       {
-               err = -EFAULT;
-       }
-       else
-       {
-               if (!(dev->flags & IFF_UP))
-               {
-                       err = -ENETDOWN;
-               }
-       }
-
-       if (err) 
-       {
-               kfree_skb(skb);
-               return err;
-       }
-
+       dev_unlock_list();
        dev_queue_xmit(skb);
        return(len);
+
+out_free:
+       kfree_skb(skb);
+out_unlock:
+       dev_unlock_list();
+       return err;
 }
 #endif
 
@@ -434,13 +428,12 @@ static int packet_sendmsg(struct socket *sock, struct msghdr *msg, int len,
                          struct scm_cookie *scm)
 {
        struct sock *sk = sock->sk;
+       struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;
        struct sk_buff *skb;
        struct device *dev;
-       struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;
        unsigned short proto;
-       int ifindex;
-       int err;
-       int reserve = 0;
+       unsigned char *addr;
+       int ifindex, err, reserve = 0;
        
        /*
         *      Check the flags. 
@@ -454,13 +447,15 @@ static int packet_sendmsg(struct socket *sock, struct msghdr *msg, int len,
         */
         
        if (saddr == NULL) {
-               ifindex = sk->protinfo.af_packet->ifindex;
-               proto = sk->num;
+               ifindex = sk->protinfo.af_packet->ifindex;
+               proto   = sk->num;
+               addr    = NULL;
        } else {
                if (msg->msg_namelen < sizeof(struct sockaddr_ll)) 
                        return -EINVAL;
-               ifindex = saddr->sll_ifindex;
-               proto = saddr->sll_protocol;
+               ifindex = saddr->sll_ifindex;
+               proto   = saddr->sll_protocol;
+               addr    = saddr->sll_addr;
        }
 
        dev = dev_get_by_index(ifindex);
@@ -474,55 +469,50 @@ static int packet_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 
        dev_lock_list();
 
-       skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, msg->msg_flags&MSG_DONTWAIT, &err);
-
-       if (skb==NULL) {
-               dev_unlock_list();
-               return err;
-       }
+       skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, 
+                               msg->msg_flags & MSG_DONTWAIT, &err);
+       if (skb==NULL)
+               goto out_unlock;
 
        skb_reserve(skb, (dev->hard_header_len+15)&~15);
        skb->nh.raw = skb->data;
 
        if (dev->hard_header) {
-               if (dev->hard_header(skb, dev, ntohs(proto),
-                                    saddr ? saddr->sll_addr : NULL,
-                                    NULL, len) < 0
-                   && sock->type == SOCK_DGRAM) {
-                       kfree_skb(skb);
-                       dev_unlock_list();
-                       return -EINVAL;
-               }
+               int res;
+               err = -EINVAL;
+               res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len);
                if (sock->type != SOCK_DGRAM) {
                        skb->tail = skb->data;
                        skb->len = 0;
-               }
+               } else if (res < 0)
+                       goto out_free;
        }
 
+       /* Returns -EFAULT on error */
        err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
        skb->protocol = proto;
        skb->dev = dev;
        skb->priority = sk->priority;
-       dev_unlock_list();
+       if (err)
+               goto out_free;
+
+       err = -ENETDOWN;
+       if (!(dev->flags & IFF_UP))
+               goto out_free;
 
        /*
         *      Now send it
         */
 
-       if (err) {
-               err = -EFAULT;
-       } else {
-               if (!(dev->flags & IFF_UP))
-                       err = -ENETDOWN;
-       }
-
-       if (err) {
-               kfree_skb(skb);
-               return err;
-       }
-
+       dev_unlock_list();
        dev_queue_xmit(skb);
        return(len);
+
+out_free:
+       kfree_skb(skb);
+out_unlock:
+       dev_unlock_list();
+       return err;
 }
 
 static void packet_destroy_timer(unsigned long data)
@@ -699,6 +689,7 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len
 static int packet_create(struct socket *sock, int protocol)
 {
        struct sock *sk;
+       int err;
 
        if (!suser())
                return -EPERM;
@@ -711,27 +702,23 @@ static int packet_create(struct socket *sock, int protocol)
 
        sock->state = SS_UNCONNECTED;
        MOD_INC_USE_COUNT;
+
+       err = -ENOBUFS;
        sk = sk_alloc(AF_PACKET, GFP_KERNEL, 1);
-       if (sk == NULL) {
-               MOD_DEC_USE_COUNT;
-               return -ENOBUFS;
-       }
+       if (sk == NULL)
+               goto out;
 
        sk->reuse = 1;
+       sock->ops = &packet_ops;
 #ifdef CONFIG_SOCK_PACKET
        if (sock->type == SOCK_PACKET)
                sock->ops = &packet_ops_spkt;
-       else
 #endif
-       sock->ops = &packet_ops;
        sock_init_data(sock,sk);
 
        sk->protinfo.af_packet = kmalloc(sizeof(struct packet_opt), GFP_KERNEL);
-       if (sk->protinfo.af_packet == NULL) {
-               sk_free(sk);
-               MOD_DEC_USE_COUNT;
-               return -ENOBUFS;
-       }
+       if (sk->protinfo.af_packet == NULL)
+               goto out_free;
        memset(sk->protinfo.af_packet, 0, sizeof(struct packet_opt));
        sk->zapped=0;
        sk->family = AF_PACKET;
@@ -741,13 +728,11 @@ static int packet_create(struct socket *sock, int protocol)
         *      Attach a protocol block
         */
 
+       sk->protinfo.af_packet->prot_hook.func = packet_rcv;
 #ifdef CONFIG_SOCK_PACKET
        if (sock->type == SOCK_PACKET)
                sk->protinfo.af_packet->prot_hook.func = packet_rcv_spkt;
-       else
 #endif
-       sk->protinfo.af_packet->prot_hook.func = packet_rcv;
-
        sk->protinfo.af_packet->prot_hook.data = (void *)sk;
 
        if (protocol) {
@@ -758,6 +743,12 @@ static int packet_create(struct socket *sock, int protocol)
 
        sklist_insert_socket(&packet_sklist, sk);
        return(0);
+
+out_free:
+       sk_free(sk);
+out:
+       MOD_DEC_USE_COUNT;
+       return err;
 }
 
 /*
@@ -832,10 +823,8 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, int len,
 
        /* We can't use skb_copy_datagram here */
        err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
-       if (err) {
-               err = -EFAULT;
+       if (err)
                goto out_free;
-       }
        sk->stamp=skb->stamp;
 
        if (msg->msg_name)
@@ -932,37 +921,39 @@ static void packet_dev_mclist(struct device *dev, struct packet_mclist *i, int w
 
 static int packet_mc_add(struct sock *sk, struct packet_mreq *mreq)
 {
-       int err;
        struct packet_mclist *ml, *i;
        struct device *dev;
+       int err;
 
        rtnl_shlock();
 
-       dev = dev_get_by_index(mreq->mr_ifindex);
-
-       i = NULL;
        err = -ENODEV;
+       dev = dev_get_by_index(mreq->mr_ifindex);
        if (!dev)
                goto done;
+
        err = -EINVAL;
        if (mreq->mr_alen > dev->addr_len)
                goto done;
 
+       err = -ENOBUFS;
        i = (struct packet_mclist *)kmalloc(sizeof(*i), GFP_KERNEL);
+       if (i == NULL)
+               goto done;
 
+       err = 0;
        for (ml=sk->protinfo.af_packet->mclist; ml; ml=ml->next) {
                if (ml->ifindex == mreq->mr_ifindex &&
                    ml->type == mreq->mr_type &&
                    ml->alen == mreq->mr_alen &&
                    memcmp(ml->addr, mreq->mr_address, ml->alen) == 0) {
                        ml->count++;
-                       err = 0;
+                       /* Free the new element ... */
+                       kfree(i);
                        goto done;
                }
        }
-       err = -ENOBUFS;
-       if (i == NULL)
-               goto done;
+
        i->type = mreq->mr_type;
        i->ifindex = mreq->mr_ifindex;
        i->alen = mreq->mr_alen;
@@ -971,13 +962,9 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq *mreq)
        i->next = sk->protinfo.af_packet->mclist;
        sk->protinfo.af_packet->mclist = i;
        packet_dev_mc(dev, i, +1);
-       i = NULL;
-       err = 0;
 
 done:
        rtnl_shunlock();
-       if (i)
-               kfree(i);
        return err;
 }
 
@@ -1109,13 +1096,12 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg
                case FIOGETOWN:
                case SIOCGPGRP:
                        return put_user(sk->proc, (int *)arg);
-                       return(0);                      
                case SIOCGSTAMP:
                        if(sk->stamp.tv_sec==0)
                                return -ENOENT;
-                       err = copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval));
-                       if (err)
-                               err = -EFAULT;
+                       err = -EFAULT;
+                       if (!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
+                               err = 0;
                        return err;
                case SIOCGIFFLAGS:
 #ifndef CONFIG_INET
index 97ce069d1825cbf11216be05ce004affbee872b6..6220cff4541b38d55a210e6c653b2ad8d4d88a9f 100644 (file)
@@ -1142,19 +1142,21 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
        char address[MAX_SOCK_ADDR];
        struct iovec iov[UIO_FASTIOV];
        unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */
-       struct msghdr msg_sys;
-       int err= -EINVAL;
-       int total_len;
        unsigned char *ctl_buf = ctl;
+       struct msghdr msg_sys;
+       int err, total_len;
        
        lock_kernel();
 
-       err=-EFAULT;
+       err = -EFAULT;
        if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
                goto out; 
+
        /* do not move before msg_sys is valid */
-       if (msg_sys.msg_iovlen>UIO_MAXIOV)
+       err = -EINVAL;
+       if (msg_sys.msg_iovlen > UIO_MAXIOV)
                goto out;
+
        /* This will also move the address data into kernel space */
        err = verify_iovec(&msg_sys, iov, address, VERIFY_READ);
        if (err < 0) 
@@ -1164,7 +1166,7 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
 
        sock = sockfd_lookup(fd, &err);
        if (!sock) 
-               goto out
+               goto out_freeiov;
 
        if (msg_sys.msg_controllen) 
        {
@@ -1198,9 +1200,10 @@ failed:
        if (ctl_buf != ctl)    
                sock_kfree_s(sock->sk, ctl_buf, msg_sys.msg_controllen);
 failed2:
+       sockfd_put(sock);
+out_freeiov:
        if (msg_sys.msg_iov != iov)
                kfree(msg_sys.msg_iov);
-       sockfd_put(sock);
 out:       
        unlock_kernel();
        return err;
@@ -1229,16 +1232,13 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
        int *uaddr_len;
        
        lock_kernel();
+       err=-EFAULT;
        if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
-       {
-               err=-EFAULT;
                goto out;
-       }
-       if (msg_sys.msg_iovlen>UIO_MAXIOV)
-       {
-               err=-EINVAL;
+
+       err=-EINVAL;
+       if (msg_sys.msg_iovlen > UIO_MAXIOV)
                goto out;
-       }
        
        /*
         *      Save the user-mode address (verify_iovec will change the
index e8c87fd56478fa9ce1ddf4b5033c5896bf50cf88..624cbb8d89ea63b81d7696f08c8cf346525dbefc 100644 (file)
@@ -687,17 +687,19 @@ static int unix_stream_connect1(struct socket *sock, struct msghdr *msg,
         
                skb=sock_alloc_send_skb(sk, len, 0, nonblock, &err); /* Marker object */
                if(skb==NULL)
-                       return err;
+                       goto out;
                memcpy(&UNIXCB(skb), cmsg, sizeof(*cmsg));
-               if (len)
-                       memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+               if (len) {
+                       err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov,
+                                               len);
+                       if (err)
+                               goto out_free;
+               }
+
                sk->state=TCP_CLOSE;
                other=unix_find_other(sunaddr, addr_len, sk->type, hash, &err);
                if(other==NULL)
-               {
-                       kfree_skb(skb);
-                       return err;
-               }
+                       goto out_free;
                other->ack_backlog++;
                unix_peer(sk)=other;
                skb_queue_tail(&other->receive_queue,skb);
@@ -738,6 +740,11 @@ static int unix_stream_connect1(struct socket *sock, struct msghdr *msg,
        if (!sk->protinfo.af_unix.addr)
                unix_autobind(sock);
        return 0;
+
+out_free:
+       kfree_skb(skb);
+out:
+       return err;
 }
 
 
@@ -908,8 +915,8 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int len,
                              struct scm_cookie *scm)
 {
        struct sock *sk = sock->sk;
-       unix_socket *other;
        struct sockaddr_un *sunaddr=msg->msg_name;
+       unix_socket *other;
        int namelen = 0; /* fake GCC */
        int err;
        unsigned hash;
@@ -935,9 +942,8 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int len,
                unix_autobind(sock);
 
        skb = sock_alloc_send_skb(sk, len, 0, msg->msg_flags&MSG_DONTWAIT, &err);
-
        if (skb==NULL)
-               return err;
+               goto out;
 
        memcpy(UNIXCREDS(skb), &scm->creds, sizeof(struct ucred));
        UNIXCB(skb).attr = msg->msg_flags;
@@ -945,7 +951,9 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int len,
                unix_attach_fds(scm, skb);
 
        skb->h.raw = skb->data;
-       memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+       err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+       if (err)
+               goto out_free;
 
        other = unix_peer(sk);
        if (other && other->dead)
@@ -957,26 +965,18 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int len,
                unix_unlock(other);
                unix_peer(sk)=NULL;
                other = NULL;
-               if (sunaddr == NULL) {
-                       kfree_skb(skb);
-                       return -ECONNRESET;
-               }
+               err = -ECONNRESET;
+               if (sunaddr == NULL)
+                       goto out_free;
        }
        if (!other)
        {
                other = unix_find_other(sunaddr, namelen, sk->type, hash, &err);
-               
                if (other==NULL)
-               {
-                       kfree_skb(skb);
-                       return err;
-               }
+                       goto out_free;
+               err = -EINVAL;
                if (!unix_may_send(sk, other))
-               {
-                       unix_unlock(other);
-                       kfree_skb(skb);
-                       return -EINVAL;
-               }
+                       goto out_unlock;
        }
 
        skb_queue_tail(&other->receive_queue, skb);
@@ -985,6 +985,13 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, int len,
        if (!unix_peer(sk))
                unix_unlock(other);
        return len;
+
+out_unlock:
+       unix_unlock(other);
+out_free:
+       kfree_skb(skb);
+out:
+       return err;
 }
 
                
@@ -1267,9 +1274,7 @@ static int unix_stream_recvmsg(struct socket *sock, struct msghdr *msg, int size
                }
 
                chunk = min(skb->len, size);
-               /* N.B. This could fail with a non-zero value (which means -EFAULT
-                *      and the non-zero value is the number of bytes not copied).
-                */
+               /* N.B. This could fail with -EFAULT */
                memcpy_toiovec(msg->msg_iov, skb->data, chunk);
                copied += chunk;
                size -= chunk;