From: Chris Wright Date: Tue, 2 Jan 2007 20:40:43 +0000 (-0800) Subject: update 2.6.19 queue X-Git-Tag: v2.6.19.2~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=282e0a079e1846a76009dcbe254187fa76d1ef4e;p=thirdparty%2Fkernel%2Fstable-queue.git update 2.6.19 queue --- diff --git a/queue-2.6.19/bluetooth-add-packet-size-checks-for-capi-messages.patch b/queue-2.6.19/bluetooth-add-packet-size-checks-for-capi-messages.patch new file mode 100644 index 00000000000..bef4f679544 --- /dev/null +++ b/queue-2.6.19/bluetooth-add-packet-size-checks-for-capi-messages.patch @@ -0,0 +1,121 @@ +From vendor-sec-admin@lst.de Mon Dec 11 06:28:38 2006 +Message-ID: <457D68B0.6060503@redhat.com> +From: Marcel Holtmann +CC: Al Viro +Subject: Bluetooth: Add packet size checks for CAPI messages (CVE-2006-6106) +Date: Mon, 11 Dec 2006 15:18:24 +0100 + +With malformed packets it might be possible to overwrite internal +CMTP and CAPI data structures. This patch adds additional length +checks to prevent these kinds of remote attacks. + +Signed-off-by: Marcel Holtmann +Signed-off-by: Chris Wright +--- + + net/bluetooth/cmtp/capi.c | 39 +++++++++++++++++++++++++++++++++------ + 1 file changed, 33 insertions(+), 6 deletions(-) + +--- linux-2.6.19.1.orig/net/bluetooth/cmtp/capi.c ++++ linux-2.6.19.1/net/bluetooth/cmtp/capi.c +@@ -196,6 +196,9 @@ static void cmtp_recv_interopmsg(struct + + switch (CAPIMSG_SUBCOMMAND(skb->data)) { + case CAPI_CONF: ++ if (skb->len < CAPI_MSG_BASELEN + 10) ++ break; ++ + func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5); + info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8); + +@@ -226,6 +229,9 @@ static void cmtp_recv_interopmsg(struct + break; + + case CAPI_FUNCTION_GET_PROFILE: ++ if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile)) ++ break; ++ + controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11); + msgnum = CAPIMSG_MSGID(skb->data); + +@@ -246,17 +252,26 @@ static void cmtp_recv_interopmsg(struct + break; + + case CAPI_FUNCTION_GET_MANUFACTURER: ++ if (skb->len < CAPI_MSG_BASELEN + 15) ++ break; ++ + controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10); + + if (!info && ctrl) { ++ int len = min_t(uint, CAPI_MANUFACTURER_LEN, ++ skb->data[CAPI_MSG_BASELEN + 14]); ++ ++ memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN); + strncpy(ctrl->manu, +- skb->data + CAPI_MSG_BASELEN + 15, +- skb->data[CAPI_MSG_BASELEN + 14]); ++ skb->data + CAPI_MSG_BASELEN + 15, len); + } + + break; + + case CAPI_FUNCTION_GET_VERSION: ++ if (skb->len < CAPI_MSG_BASELEN + 32) ++ break; ++ + controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12); + + if (!info && ctrl) { +@@ -269,13 +284,18 @@ static void cmtp_recv_interopmsg(struct + break; + + case CAPI_FUNCTION_GET_SERIAL_NUMBER: ++ if (skb->len < CAPI_MSG_BASELEN + 17) ++ break; ++ + controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12); + + if (!info && ctrl) { ++ int len = min_t(uint, CAPI_SERIAL_LEN, ++ skb->data[CAPI_MSG_BASELEN + 16]); ++ + memset(ctrl->serial, 0, CAPI_SERIAL_LEN); + strncpy(ctrl->serial, +- skb->data + CAPI_MSG_BASELEN + 17, +- skb->data[CAPI_MSG_BASELEN + 16]); ++ skb->data + CAPI_MSG_BASELEN + 17, len); + } + + break; +@@ -284,14 +304,18 @@ static void cmtp_recv_interopmsg(struct + break; + + case CAPI_IND: ++ if (skb->len < CAPI_MSG_BASELEN + 6) ++ break; ++ + func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3); + + if (func == CAPI_FUNCTION_LOOPBACK) { ++ int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6, ++ skb->data[CAPI_MSG_BASELEN + 5]); + appl = CAPIMSG_APPID(skb->data); + msgnum = CAPIMSG_MSGID(skb->data); + cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func, +- skb->data + CAPI_MSG_BASELEN + 6, +- skb->data[CAPI_MSG_BASELEN + 5]); ++ skb->data + CAPI_MSG_BASELEN + 6, len); + } + + break; +@@ -309,6 +333,9 @@ void cmtp_recv_capimsg(struct cmtp_sessi + + BT_DBG("session %p skb %p len %d", session, skb, skb->len); + ++ if (skb->len < CAPI_MSG_BASELEN) ++ return; ++ + if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) { + cmtp_recv_interopmsg(session, skb); + return; diff --git a/queue-2.6.19/buglet-in-vmscan.c.patch b/queue-2.6.19/buglet-in-vmscan.c.patch new file mode 100644 index 00000000000..66555405263 --- /dev/null +++ b/queue-2.6.19/buglet-in-vmscan.c.patch @@ -0,0 +1,32 @@ +From stable-bounces@linux.kernel.org Fri Dec 29 16:57:04 2006 +Message-Id: <200612300049.kBU0nJHN008167@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Fri, 29 Dec 2006 16:48:59 -0800 +Cc: akpm@osdl.org, clameter@engr.sgi.com, stable@kernel.org, sgoel01@yahoo.com +Subject: Buglet in vmscan.c + +From: Shantanu Goel + +Fix a rather obvious buglet. Noticed while instrumenting the VM using +/proc/vmstat. + +Cc: Christoph Lameter +Cc: +Signed-off-by: Andrew Morton +--- + + mm/vmscan.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.19.1.orig/mm/vmscan.c ++++ linux-2.6.19.1/mm/vmscan.c +@@ -691,7 +691,7 @@ static unsigned long shrink_inactive_lis + __count_vm_events(KSWAPD_STEAL, nr_freed); + } else + __count_zone_vm_events(PGSCAN_DIRECT, zone, nr_scan); +- __count_vm_events(PGACTIVATE, nr_freed); ++ __count_zone_vm_events(PGSTEAL, zone, nr_freed); + + if (nr_taken == 0) + goto done; diff --git a/queue-2.6.19/cciss-fix-xfer_read-xfer_write-in-do_cciss_request.patch b/queue-2.6.19/cciss-fix-xfer_read-xfer_write-in-do_cciss_request.patch new file mode 100644 index 00000000000..f4d44b0af4f --- /dev/null +++ b/queue-2.6.19/cciss-fix-xfer_read-xfer_write-in-do_cciss_request.patch @@ -0,0 +1,35 @@ +From stable-bounces@linux.kernel.org Sat Dec 23 12:21:40 2006 +Date: Sat, 23 Dec 2006 15:11:58 -0500 +From: Chuck Ebbert <76306.1226@compuserve.com> +To: linux-stable +Message-ID: <200612231514_MC3-1-D628-9FB6@compuserve.com> +Content-Disposition: inline +Cc: Mike Miller +Subject: cciss: fix XFER_READ/XFER_WRITE in do_cciss_request + +From: Mike Miller + +This patch fixes a stupid bug. Sometime during the 2tb enhancement I ended up +replacing the macros XFER_READ and XFER_WRITE with h->cciss_read and +h->cciss_write respectively. It seemed to work somehow at least on x86_64 and +ia64. I don't know how. But people started complaining about command timeouts +on older controllers like the 64xx series and only on ia32. This resolves the +issue reproduced in our lab. Please consider this for inclusion. + +Signed-off-by: Mike Miller +Signed-off-by: Chris Wright +--- + drivers/block/cciss.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.19.1.orig/drivers/block/cciss.c ++++ linux-2.6.19.1/drivers/block/cciss.c +@@ -2530,7 +2530,7 @@ static void do_cciss_request(request_que + c->Request.Type.Type = TYPE_CMD; // It is a command. + c->Request.Type.Attribute = ATTR_SIMPLE; + c->Request.Type.Direction = +- (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; ++ (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE; + c->Request.Timeout = 0; // Don't time out + c->Request.CDB[0] = + (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write; diff --git a/queue-2.6.19/corrupted-cramfs-filesystems-cause-kernel-oops.patch b/queue-2.6.19/corrupted-cramfs-filesystems-cause-kernel-oops.patch new file mode 100644 index 00000000000..5fa5308191e --- /dev/null +++ b/queue-2.6.19/corrupted-cramfs-filesystems-cause-kernel-oops.patch @@ -0,0 +1,47 @@ +From stable-bounces@linux.kernel.org Sat Dec 30 15:33:45 2006 +Message-ID: <4596F606.2090504@gentoo.org> +Date: Sat, 30 Dec 2006 18:28:06 -0500 +From: Daniel Drake +To: stable@kernel.org +Cc: phillip@lougher.org.uk +Subject: corrupted cramfs filesystems cause kernel oops (CVE-2006-5823) + +From: Phillip Lougher + +Steve Grubb's fzfuzzer tool (http://people.redhat.com/sgrubb/files/ +fsfuzzer-0.6.tar.gz) generates corrupt Cramfs filesystems which cause +Cramfs to kernel oops in cramfs_uncompress_block(). The cause of the oops +is an unchecked corrupted block length field read by cramfs_readpage(). + +This patch adds a sanity check to cramfs_readpage() which checks that the +block length field is sensible. The (PAGE_CACHE_SIZE << 1) size check is +intentional, even though the uncompressed data is not going to be larger +than PAGE_CACHE_SIZE, gzip sometimes generates compressed data larger than +the original source data. Mkcramfs checks that the compressed size is +always less than or equal to PAGE_CACHE_SIZE << 1. Of course Cramfs could +use the original uncompressed data in this case, but it doesn't. + +Signed-off-by: Phillip Lougher +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Chris Wright +--- +Date: Thu, 7 Dec 2006 04:37:20 +0000 (-0800) +Subject: [PATCH] corrupted cramfs filesystems cause kernel oops +X-Git-Tag: v2.6.20-rc1 +X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=8bb0269160df2a60764013994d0bc5165406cf4a + + fs/cramfs/inode.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- linux-2.6.19.1.orig/fs/cramfs/inode.c ++++ linux-2.6.19.1/fs/cramfs/inode.c +@@ -481,6 +481,8 @@ static int cramfs_readpage(struct file * + pgdata = kmap(page); + if (compr_len == 0) + ; /* hole */ ++ else if (compr_len > (PAGE_CACHE_SIZE << 1)) ++ printk(KERN_ERR "cramfs: bad compressed blocksize %u\n", compr_len); + else { + mutex_lock(&read_mutex); + bytes_filled = cramfs_uncompress_block(pgdata, diff --git a/queue-2.6.19/ext2-skip-pages-past-number-of-blocks-in-ext2_find_entry.patch b/queue-2.6.19/ext2-skip-pages-past-number-of-blocks-in-ext2_find_entry.patch new file mode 100644 index 00000000000..8a1256a15f9 --- /dev/null +++ b/queue-2.6.19/ext2-skip-pages-past-number-of-blocks-in-ext2_find_entry.patch @@ -0,0 +1,47 @@ +From stable-bounces@linux.kernel.org Sat Dec 30 15:36:19 2006 +Message-ID: <4596F698.5070505@gentoo.org> +Date: Sat, 30 Dec 2006 18:30:32 -0500 +From: Daniel Drake +To: stable@kernel.org +Cc: sandeen@redhat.com +Subject: ext2: skip pages past number of blocks in ext2_find_entry (CVE-2006-6054) + +From: Eric Sandeen + +This one was pointed out on the MOKB site: +http://kernelfun.blogspot.com/2006/11/mokb-09-11-2006-linux-26x-ext2checkpage.html + +If a directory's i_size is corrupted, ext2_find_entry() will keep processing +pages until the i_size is reached, even if there are no more blocks associated +with the directory inode. This patch puts in some minimal sanity-checking +so that we don't keep checking pages (and issuing errors) if we know there +can be no more data to read, based on the block count of the directory inode. + +This is somewhat similar in approach to the ext3 patch I sent earlier this +year. + +Signed-off-by: Eric Sandeen +Signed-off-by: Chris Wright +--- +Not upstream yet + + fs/ext2/dir.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- linux-2.6.19.1.orig/fs/ext2/dir.c ++++ linux-2.6.19.1/fs/ext2/dir.c +@@ -368,6 +368,14 @@ struct ext2_dir_entry_2 * ext2_find_entr + } + if (++n >= npages) + n = 0; ++ /* next page is past the blocks we've got */ ++ if (unlikely(n > (dir->i_blocks >> (PAGE_CACHE_SHIFT - 9)))) { ++ ext2_error(dir->i_sb, __FUNCTION__, ++ "dir %lu size %lld exceeds block count %llu", ++ dir->i_ino, dir->i_size, ++ (unsigned long long)dir->i_blocks); ++ goto out; ++ } + } while (n != start); + out: + return NULL; diff --git a/queue-2.6.19/fix-aoe-without-scatter-gather.patch b/queue-2.6.19/fix-aoe-without-scatter-gather.patch new file mode 100644 index 00000000000..dac2f669a99 --- /dev/null +++ b/queue-2.6.19/fix-aoe-without-scatter-gather.patch @@ -0,0 +1,89 @@ +From stable-bounces@linux.kernel.org Fri Dec 22 01:16:04 2006 +Message-Id: <200612220909.kBM99N3M018750@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Fri, 22 Dec 2006 01:09:21 -0800 +Cc: akpm@osdl.org, greg@kroah.com, boddingt@optusnet.com.au, ecashin@coraid.com, stable@kernel.org +Subject: fix aoe without scatter-gather [Bug 7662] + +From: "Ed L. Cashin" + +Fix a bug that only appears when AoE goes over a network card that does not +support scatter-gather. The headers in the linear part of the skb appeared +to be larger than they really were, resulting in data that was offset by 24 +bytes. + +This patch eliminates the offset data on cards that don't support +scatter-gather or have had scatter-gather turned off. There remains an +unrelated issue that I'll address in a separate email. + +Fixes bugzilla #7662 + +Signed-off-by: "Ed L. Cashin" +Cc: +Cc: Greg KH +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Chris Wright +--- + + drivers/block/aoe/aoecmd.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +--- linux-2.6.19.1.orig/drivers/block/aoe/aoecmd.c ++++ linux-2.6.19.1/drivers/block/aoe/aoecmd.c +@@ -30,8 +30,6 @@ new_skb(ulong len) + skb->nh.raw = skb->mac.raw = skb->data; + skb->protocol = __constant_htons(ETH_P_AOE); + skb->priority = 0; +- skb_put(skb, len); +- memset(skb->head, 0, len); + skb->next = skb->prev = NULL; + + /* tell the network layer not to perform IP checksums +@@ -122,8 +120,8 @@ aoecmd_ata_rw(struct aoedev *d, struct f + skb = f->skb; + h = (struct aoe_hdr *) skb->mac.raw; + ah = (struct aoe_atahdr *) (h+1); +- skb->len = sizeof *h + sizeof *ah; +- memset(h, 0, ETH_ZLEN); ++ skb_put(skb, sizeof *h + sizeof *ah); ++ memset(h, 0, skb->len); + f->tag = aoehdr_atainit(d, h); + f->waited = 0; + f->buf = buf; +@@ -149,7 +147,6 @@ aoecmd_ata_rw(struct aoedev *d, struct f + skb->len += bcnt; + skb->data_len = bcnt; + } else { +- skb->len = ETH_ZLEN; + writebit = 0; + } + +@@ -206,6 +203,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigne + printk(KERN_INFO "aoe: skb alloc failure\n"); + continue; + } ++ skb_put(skb, sizeof *h + sizeof *ch); + skb->dev = ifp; + if (sl_tail == NULL) + sl_tail = skb; +@@ -243,6 +241,7 @@ freeframe(struct aoedev *d) + continue; + if (atomic_read(&skb_shinfo(f->skb)->dataref) == 1) { + skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0; ++ skb_trim(f->skb, 0); + return f; + } + n++; +@@ -698,8 +697,8 @@ aoecmd_ata_id(struct aoedev *d) + skb = f->skb; + h = (struct aoe_hdr *) skb->mac.raw; + ah = (struct aoe_atahdr *) (h+1); +- skb->len = ETH_ZLEN; +- memset(h, 0, ETH_ZLEN); ++ skb_put(skb, sizeof *h + sizeof *ah); ++ memset(h, 0, skb->len); + f->tag = aoehdr_atainit(d, h); + f->waited = 0; + diff --git a/queue-2.6.19/fix-for-shmem_truncate_range-bug_on.patch b/queue-2.6.19/fix-for-shmem_truncate_range-bug_on.patch new file mode 100644 index 00000000000..752305031c5 --- /dev/null +++ b/queue-2.6.19/fix-for-shmem_truncate_range-bug_on.patch @@ -0,0 +1,42 @@ +From stable-bounces@linux.kernel.org Fri Dec 22 01:13:06 2006 +Message-Id: <200612220906.kBM96PM4018647@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Fri, 22 Dec 2006 01:06:23 -0800 +Cc: akpm@osdl.org, hugh@veritas.com, pbadari@us.ibm.com, stable@kernel.org +Subject: Fix for shmem_truncate_range() BUG_ON() + +From: Badari Pulavarty + +Ran into BUG() while doing madvise(REMOVE) testing. If we are punching a +hole into shared memory segment using madvise(REMOVE) and the entire hole +is below the indirect blocks, we hit following assert. + + BUG_ON(limit <= SHMEM_NR_DIRECT); + +Signed-off-by: Badari Pulavarty +Cc: Hugh Dickins +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Chris Wright +--- + + mm/shmem.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- linux-2.6.19.1.orig/mm/shmem.c ++++ linux-2.6.19.1/mm/shmem.c +@@ -515,7 +515,12 @@ static void shmem_truncate_range(struct + size = SHMEM_NR_DIRECT; + nr_swaps_freed = shmem_free_swp(ptr+idx, ptr+size); + } +- if (!topdir) ++ ++ /* ++ * If there are no indirect blocks or we are punching a hole ++ * below indirect blocks, nothing to be done. ++ */ ++ if (!topdir || (punch_hole && (limit <= SHMEM_NR_DIRECT))) + goto done2; + + BUG_ON(limit <= SHMEM_NR_DIRECT); diff --git a/queue-2.6.19/fix-reversed-logic-in-udp_get_port.patch b/queue-2.6.19/fix-reversed-logic-in-udp_get_port.patch new file mode 100644 index 00000000000..413cdd317d2 --- /dev/null +++ b/queue-2.6.19/fix-reversed-logic-in-udp_get_port.patch @@ -0,0 +1,60 @@ +From stable-bounces@linux.kernel.org Fri Dec 22 12:02:42 2006 +Date: Fri, 22 Dec 2006 11:56:21 -0800 (PST) +Message-Id: <20061222.115621.104034701.davem@davemloft.net> +To: stable@kernel.org +From: David Miller +Subject: [UDP]: Fix reversed logic in udp_get_port() + +When this code was converted to use sk_for_each() the +logic for the "best hash chain length" code was reversed, +breaking everything. + +The original code was of the form: + + size = 0; + do { + if (++size >= best_size_so_far) + goto next; + } while ((sk = sk->next) != NULL); + best_size_so_far = size; + best = result; + next:; + +and this got converted into: + + sk_for_each(sk2, node, head) + if (++size < best_size_so_far) { + best_size_so_far = size; + best = result; + } + +Which does something very very different from the original. + +Signed-off-by: David S. Miller +Signed-off-by: Chris Wright +--- + net/ipv4/udp.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +--- linux-2.6.19.1.orig/net/ipv4/udp.c ++++ linux-2.6.19.1/net/ipv4/udp.c +@@ -167,11 +167,14 @@ int udp_get_port(struct sock *sk, unsign + goto gotit; + } + size = 0; +- sk_for_each(sk2, node, head) +- if (++size < best_size_so_far) { +- best_size_so_far = size; +- best = result; +- } ++ sk_for_each(sk2, node, head) { ++ if (++size >= best_size_so_far) ++ goto next; ++ } ++ best_size_so_far = size; ++ best = result; ++ next: ++ ; + } + result = best; + for(i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) { diff --git a/queue-2.6.19/handle-ext3-directory-corruption-better.patch b/queue-2.6.19/handle-ext3-directory-corruption-better.patch new file mode 100644 index 00000000000..aaacd744bdb --- /dev/null +++ b/queue-2.6.19/handle-ext3-directory-corruption-better.patch @@ -0,0 +1,89 @@ +From stable-bounces@linux.kernel.org Sat Dec 30 15:27:45 2006 +Message-ID: <4596F49F.4080406@gentoo.org> +Date: Sat, 30 Dec 2006 18:22:07 -0500 +From: Daniel Drake +To: stable@kernel.org +Cc: sandeen@redhat.com +Subject: handle ext3 directory corruption better (CVE-2006-6053) + +From: Eric Sandeen + +I've been using Steve Grubb's purely evil "fsfuzzer" tool, at +http://people.redhat.com/sgrubb/files/fsfuzzer-0.4.tar.gz + +Basically it makes a filesystem, splats some random bits over it, then +tries to mount it and do some simple filesystem actions. + +At best, the filesystem catches the corruption gracefully. At worst, +things spin out of control. + +As you might guess, we found a couple places in ext3 where things spin out +of control :) + +First, we had a corrupted directory that was never checked for +consistency... it was corrupt, and pointed to another bad "entry" of +length 0. The for() loop looped forever, since the length of +ext3_next_entry(de) was 0, and we kept looking at the same pointer over and +over and over and over... I modeled this check and subsequent action on +what is done for other directory types in ext3_readdir... + +(adding this check adds some computational expense; I am testing a followup +patch to reduce the number of times we check and re-check these directory +entries, in all cases. Thanks for the idea, Andreas). + +Next we had a root directory inode which had a corrupted size, claimed to +be > 200M on a 4M filesystem. There was only really 1 block in the +directory, but because the size was so large, readdir kept coming back for +more, spewing thousands of printk's along the way. + +Per Andreas' suggestion, if we're in this read error condition and we're +trying to read an offset which is greater than i_blocks worth of bytes, +stop trying, and break out of the loop. + +With these two changes fsfuzz test survives quite well on ext3. + +Signed-off-by: Eric Sandeen +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Chris Wright +--- +Date: Thu, 7 Dec 2006 04:36:26 +0000 (-0800) +Subject: [PATCH] handle ext3 directory corruption better +X-Git-Tag: v2.6.20-rc1 +X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=40b851348fe9bf49c26025b34261d25142269b60 + + fs/ext3/dir.c | 3 +++ + fs/ext3/namei.c | 9 +++++++++ + 2 files changed, 12 insertions(+) + +--- linux-2.6.19.1.orig/fs/ext3/dir.c ++++ linux-2.6.19.1/fs/ext3/dir.c +@@ -154,6 +154,9 @@ static int ext3_readdir(struct file * fi + ext3_error (sb, "ext3_readdir", + "directory #%lu contains a hole at offset %lu", + inode->i_ino, (unsigned long)filp->f_pos); ++ /* corrupt size? Maybe no more blocks to read */ ++ if (filp->f_pos > inode->i_blocks << 9) ++ break; + filp->f_pos += sb->s_blocksize - offset; + continue; + } +--- linux-2.6.19.1.orig/fs/ext3/namei.c ++++ linux-2.6.19.1/fs/ext3/namei.c +@@ -552,6 +552,15 @@ static int htree_dirblock_to_tree(struct + dir->i_sb->s_blocksize - + EXT3_DIR_REC_LEN(0)); + for (; de < top; de = ext3_next_entry(de)) { ++ if (!ext3_check_dir_entry("htree_dirblock_to_tree", dir, de, bh, ++ (block<i_sb)) ++ +((char *)de - bh->b_data))) { ++ /* On error, skip the f_pos to the next block. */ ++ dir_file->f_pos = (dir_file->f_pos | ++ (dir->i_sb->s_blocksize - 1)) + 1; ++ brelse (bh); ++ return count; ++ } + ext3fs_dirhash(de->name, de->name_len, hinfo); + if ((hinfo->hash < start_hash) || + ((hinfo->hash == start_hash) && diff --git a/queue-2.6.19/i2c-fix-broken-ds1337-initialization.patch b/queue-2.6.19/i2c-fix-broken-ds1337-initialization.patch new file mode 100644 index 00000000000..60f6a2246cf --- /dev/null +++ b/queue-2.6.19/i2c-fix-broken-ds1337-initialization.patch @@ -0,0 +1,60 @@ +From stable-bounces@linux.kernel.org Tue Dec 19 23:40:57 2006 +Date: Wed, 20 Dec 2006 08:34:43 +0100 +From: Jean Delvare +To: stable@kernel.org +Message-Id: <20061220083443.45e488cb.khali@linux-fr.org> +Cc: Dirk Eibach , Adrian Bunk +Subject: i2c: fix broken ds1337 initialization + +From: Dirk Eibach + +On a custom board with ds1337 RTC I found that upgrade from 2.6.15 to +2.6.18 broke RTC support. + +The main problem are changes to ds1337_init_client(). +When a ds1337 recognizes a problem (e.g. power or clock failure) bit 7 +in status register is set. This has to be reset by writing 0 to status +register. But since there are only 16 byte written to the chip and the +first byte is interpreted as an address, the status register (which is +the 16th) is never written. +The other problem is, that initializing all registers to zero is not +valid for day, date and month register. Funny enough this is checked by +ds1337_detect(), which depends on this values not being zero. So then +treated by ds1337_init_client() the ds1337 is not detected anymore, +whereas the failure bit in the status register is still set. + +Broken by commit f9e8957937ebf60d22732a5ca9130f48a7603f60 (2.6.16-rc1, +2006-01-06). This fix is in Linus' tree since 2.6.20-rc1 (commit +763d9c046a2e511ec090a8986d3f85edf7448e7e). + +Signed-off-by: Dirk Stieler +Signed-off-by: Dirk Eibach +Signed-off-by: Jean Delvare +Signed-off-by: Chris Wright +--- + drivers/i2c/chips/ds1337.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- linux-2.6.19.1.orig/drivers/i2c/chips/ds1337.c ++++ linux-2.6.19.1/drivers/i2c/chips/ds1337.c +@@ -347,13 +347,19 @@ static void ds1337_init_client(struct i2 + + if ((status & 0x80) || (control & 0x80)) { + /* RTC not running */ +- u8 buf[16]; ++ u8 buf[1+16]; /* First byte is interpreted as address */ + struct i2c_msg msg[1]; + + dev_dbg(&client->dev, "%s: RTC not running!\n", __FUNCTION__); + + /* Initialize all, including STATUS and CONTROL to zero */ + memset(buf, 0, sizeof(buf)); ++ ++ /* Write valid values in the date/time registers */ ++ buf[1+DS1337_REG_DAY] = 1; ++ buf[1+DS1337_REG_DATE] = 1; ++ buf[1+DS1337_REG_MONTH] = 1; ++ + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = sizeof(buf); diff --git a/queue-2.6.19/i386-cpu-hotplug-broken-with-2gb-vmsplit.patch b/queue-2.6.19/i386-cpu-hotplug-broken-with-2gb-vmsplit.patch new file mode 100644 index 00000000000..6f247fb2141 --- /dev/null +++ b/queue-2.6.19/i386-cpu-hotplug-broken-with-2gb-vmsplit.patch @@ -0,0 +1,30 @@ +From stable-bounces@linux.kernel.org Sat Dec 23 18:48:39 2006 +Date: Sat, 23 Dec 2006 21:39:08 -0500 +From: Chuck Ebbert <76306.1226@compuserve.com> +To: linux-stable +Message-ID: <200612232141_MC3-1-D628-F7DD@compuserve.com> +Content-Disposition: inline +Cc: Shaohua Li +Subject: [stable] [stable patch] i386: CPU hotplug broken with 2GB VMSPLIT + +From: Shaohua Li + +In VMSPLIT mode, kernel PGD might have more entries than user space + +Signed-off-by: Shaohua Li +Signed-off-by: Chris Wright +--- + arch/i386/kernel/smpboot.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.19.1.orig/arch/i386/kernel/smpboot.c ++++ linux-2.6.19.1/arch/i386/kernel/smpboot.c +@@ -1095,7 +1095,7 @@ static int __cpuinit __smp_prepare_cpu(i + + /* init low mem mapping */ + clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, +- KERNEL_PGD_PTRS); ++ min_t(unsigned long, KERNEL_PGD_PTRS, USER_PGD_PTRS)); + flush_tlb_all(); + schedule_work(&task); + wait_for_completion(&done); diff --git a/queue-2.6.19/net-don-t-export-linux-random.h-outside-__kernel__.patch b/queue-2.6.19/net-don-t-export-linux-random.h-outside-__kernel__.patch new file mode 100644 index 00000000000..4265b864617 --- /dev/null +++ b/queue-2.6.19/net-don-t-export-linux-random.h-outside-__kernel__.patch @@ -0,0 +1,39 @@ +From stable-bounces@linux.kernel.org Tue Jan 2 00:14:53 2007 +Date: Tue, 02 Jan 2007 00:07:50 -0800 (PST) +Message-Id: <20070102.000750.115910105.davem@davemloft.net> +To: stable@kernel.org +From: David Miller +Subject: NET: Don't export linux/random.h outside __KERNEL__ + +From: David Woodhouse + +Don't add it there please; add it lower down inside the existing #ifdef +__KERNEL__. You just made the _userspace_ net.h include random.h, which +then fails to compile unless was already included. + +Signed-off-by: David Woodhouse +Signed-off-by: David S. Miller +Signed-off-by: Chris Wright + +--- + include/linux/net.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.19.1.orig/include/linux/net.h ++++ linux-2.6.19.1/include/linux/net.h +@@ -19,7 +19,6 @@ + #define _LINUX_NET_H + + #include +-#include + #include + + struct poll_table_struct; +@@ -57,6 +56,7 @@ typedef enum { + + #ifdef __KERNEL__ + #include ++#include + + #define SOCK_ASYNC_NOSPACE 0 + #define SOCK_ASYNC_WAITDATA 1 diff --git a/queue-2.6.19/pktgen-fix-module-load-unload-races.patch b/queue-2.6.19/pktgen-fix-module-load-unload-races.patch new file mode 100644 index 00000000000..87003c8ca6a --- /dev/null +++ b/queue-2.6.19/pktgen-fix-module-load-unload-races.patch @@ -0,0 +1,91 @@ +From stable-bounces@linux.kernel.org Mon Jan 1 21:11:24 2007 +Date: Mon, 01 Jan 2007 21:04:19 -0800 (PST) +Message-Id: <20070101.210419.104643422.davem@davemloft.net> +To: stable@kernel.org +From: David Miller +Cc: bunk@stusta.de +Subject: PKTGEN: Fix module load/unload races. + +From: Robert Olsson + +Signed-off-by: David S. Miller +Signed-off-by: Chris Wright + +--- + net/core/pktgen.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +--- linux-2.6.19.1.orig/net/core/pktgen.c ++++ linux-2.6.19.1/net/core/pktgen.c +@@ -147,6 +147,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -206,6 +207,11 @@ static struct proc_dir_entry *pg_proc_di + #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4) + #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4) + ++struct pktgen_thread_info { ++ struct pktgen_thread *t; ++ struct completion *c; ++}; ++ + struct flow_state { + __u32 cur_daddr; + int count; +@@ -3264,10 +3270,11 @@ out:; + * Main loop of the thread goes here + */ + +-static void pktgen_thread_worker(struct pktgen_thread *t) ++static void pktgen_thread_worker(struct pktgen_thread_info *info) + { + DEFINE_WAIT(wait); + struct pktgen_dev *pkt_dev = NULL; ++ struct pktgen_thread *t = info->t; + int cpu = t->cpu; + sigset_t tmpsig; + u32 max_before_softirq; +@@ -3307,6 +3314,8 @@ static void pktgen_thread_worker(struct + __set_current_state(TASK_INTERRUPTIBLE); + mb(); + ++ complete(info->c); ++ + while (1) { + + __set_current_state(TASK_RUNNING); +@@ -3518,6 +3527,8 @@ static struct pktgen_thread *__init pktg + static int __init pktgen_create_thread(const char *name, int cpu) + { + int err; ++ struct pktgen_thread_info info; ++ struct completion started; + struct pktgen_thread *t = NULL; + struct proc_dir_entry *pe; + +@@ -3558,7 +3569,11 @@ static int __init pktgen_create_thread(c + + t->removed = 0; + +- err = kernel_thread((void *)pktgen_thread_worker, (void *)t, ++ init_completion(&started); ++ info.t = t; ++ info.c = &started; ++ ++ err = kernel_thread((void *)pktgen_thread_worker, (void *)&info, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (err < 0) { + printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu); +@@ -3568,6 +3583,7 @@ static int __init pktgen_create_thread(c + return err; + } + ++ wait_for_completion(&started); + return 0; + } + diff --git a/queue-2.6.19/ramfs-breaks-without-config_block.patch b/queue-2.6.19/ramfs-breaks-without-config_block.patch new file mode 100644 index 00000000000..712f98cb04b --- /dev/null +++ b/queue-2.6.19/ramfs-breaks-without-config_block.patch @@ -0,0 +1,60 @@ +From stable-bounces@linux.kernel.org Fri Dec 29 16:55:45 2006 +Message-Id: <200612300048.kBU0mhs0008126@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Fri, 29 Dec 2006 16:48:24 -0800 +Cc: akpm@osdl.org, dimitri.gorokhovik@free.fr, stable@kernel.org +Subject: ramfs breaks without CONFIG_BLOCK + +From: Dimitri Gorokhovik + +ramfs doesn't provide the .set_dirty_page a_op, and when the BLOCK layer is +not configured in, 'set_page_dirty' makes a call via a NULL pointer. + +Signed-off-by: Dimitri Gorokhovik +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Chris Wright +--- + + fs/ramfs/file-mmu.c | 4 +++- + fs/ramfs/file-nommu.c | 4 +++- + 2 files changed, 6 insertions(+), 2 deletions(-) + +--- linux-2.6.19.1.orig/fs/ramfs/file-mmu.c ++++ linux-2.6.19.1/fs/ramfs/file-mmu.c +@@ -25,11 +25,13 @@ + */ + + #include ++#include + + const struct address_space_operations ramfs_aops = { + .readpage = simple_readpage, + .prepare_write = simple_prepare_write, +- .commit_write = simple_commit_write ++ .commit_write = simple_commit_write, ++ .set_page_dirty = __set_page_dirty_nobuffers, + }; + + const struct file_operations ramfs_file_operations = { +--- linux-2.6.19.1.orig/fs/ramfs/file-nommu.c ++++ linux-2.6.19.1/fs/ramfs/file-nommu.c +@@ -11,6 +11,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -30,7 +31,8 @@ static int ramfs_nommu_setattr(struct de + const struct address_space_operations ramfs_aops = { + .readpage = simple_readpage, + .prepare_write = simple_prepare_write, +- .commit_write = simple_commit_write ++ .commit_write = simple_commit_write, ++ .set_page_dirty = __set_page_dirty_nobuffers, + }; + + const struct file_operations ramfs_file_operations = { diff --git a/queue-2.6.19/sched-fix-bad-missed-wakeups-in-the-i386-x86_64-ia64-acpi-and-apm-idle-code.patch b/queue-2.6.19/sched-fix-bad-missed-wakeups-in-the-i386-x86_64-ia64-acpi-and-apm-idle-code.patch new file mode 100644 index 00000000000..8198511f2e4 --- /dev/null +++ b/queue-2.6.19/sched-fix-bad-missed-wakeups-in-the-i386-x86_64-ia64-acpi-and-apm-idle-code.patch @@ -0,0 +1,224 @@ +From mingo@elte.hu Thu Dec 21 04:29:43 2006 +Date: Thu, 21 Dec 2006 13:20:30 +0100 +From: Ingo Molnar +To: Greg KH , Chris Wright , Adrian Bunk , stable@kernel.org +Subject: sched: fix bad missed wakeups in the i386, x86_64, ia64, ACPI and APM idle code +Message-ID: <20061221122030.GA10727@elte.hu> + +From: Ingo Molnar + +Fernando Lopez-Lezcano reported frequent scheduling latencies and audio +xruns starting at the 2.6.18-rt kernel, and those problems persisted all +until current -rt kernels. The latencies were serious and unjustified by +system load, often in the milliseconds range. + +After a patient and heroic multi-month effort of Fernando, where he +tested dozens of kernels, tried various configs, boot options, +test-patches of mine and provided latency traces of those incidents, the +following 'smoking gun' trace was captured by him: + + _------=> CPU# + / _-----=> irqs-off + | / _----=> need-resched + || / _---=> hardirq/softirq + ||| / _--=> preempt-depth + |||| / + ||||| delay + cmd pid ||||| time | caller + \ / ||||| \ | / + IRQ_19-1479 1D..1 0us : __trace_start_sched_wakeup (try_to_wake_up) + IRQ_19-1479 1D..1 0us : __trace_start_sched_wakeup <<...>-5856> (37 0) + IRQ_19-1479 1D..1 0us : __trace_start_sched_wakeup (c01262ba 0 0) + IRQ_19-1479 1D..1 0us : resched_task (try_to_wake_up) + IRQ_19-1479 1D..1 0us : __spin_unlock_irqrestore (try_to_wake_up) + ... + -0 1...1 11us!: default_idle (cpu_idle) + ... + -0 0Dn.1 602us : smp_apic_timer_interrupt (c0103baf 1 0) + ... + <...>-5856 0D..2 618us : __switch_to (__schedule) + <...>-5856 0D..2 618us : __schedule <-0> (20 162) + <...>-5856 0D..2 619us : __spin_unlock_irq (__schedule) + <...>-5856 0...1 619us : trace_stop_sched_switched (__schedule) + <...>-5856 0D..1 619us : trace_stop_sched_switched <<...>-5856> (37 0) + +what is visible in this trace is that CPU#1 ran try_to_wake_up() for +PID:5856, it placed PID:5856 on CPU#0's runqueue and ran resched_task() +for CPU#0. But it decided to not send an IPI that no CPU - due to +TS_POLLING. But CPU#0 never woke up after its NEED_RESCHED bit was set, +and only rescheduled to PID:5856 upon the next lapic timer IRQ. The +result was a 600+ usecs latency and a missed wakeup! + +the bug turned out to be an idle-wakeup bug introduced into the mainline +kernel this summer via an optimization in the x86_64 tree: + + commit 495ab9c045e1b0e5c82951b762257fe1c9d81564 + Author: Andi Kleen + Date: Mon Jun 26 13:59:11 2006 +0200 + + [PATCH] i386/x86-64/ia64: Move polling flag into thread_info_status + + During some profiling I noticed that default_idle causes a lot of + memory traffic. I think that is caused by the atomic operations + to clear/set the polling flag in thread_info. There is actually + no reason to make this atomic - only the idle thread does it + to itself, other CPUs only read it. So I moved it into ti->status. + +the problem is this type of change: + + if (!hlt_counter && boot_cpu_data.hlt_works_ok) { +- clear_thread_flag(TIF_POLLING_NRFLAG); ++ current_thread_info()->status &= ~TS_POLLING; + smp_mb__after_clear_bit(); + while (!need_resched()) { + local_irq_disable(); + +this changes clear_thread_flag() to an explicit clearing of TS_POLLING. +clear_thread_flag() is defined as: + + clear_bit(flag, &ti->flags); + +and clear_bit() is a LOCK-ed atomic instruction on all x86 platforms: + + static inline void clear_bit(int nr, volatile unsigned long * addr) + { + __asm__ __volatile__( LOCK_PREFIX + "btrl %1,%0" + +hence smp_mb__after_clear_bit() is defined as a simple compile barrier: + + #define smp_mb__after_clear_bit() barrier() + +but the explicit TS_POLLING clearing introduced by the patch: + ++ current_thread_info()->status &= ~TS_POLLING; + +is not an atomic op! So the clearing of the TS_POLLING bit is freely +reorderable with the reading of the NEED_RESCHED bit - and both now +reside in different memory addresses. + +CPU idle wakeup very much depends on ordered memory ops, the clearing of +the TS_POLLING flag must always be done before we test need_resched() +and hit the idle instruction(s). [Symmetrically, the wakeup code needs +to set NEED_RESCHED before it tests the TS_POLLING flag, so memory +ordering is paramount.] + +Fernando's dual-core Athlon64 system has a sufficiently advanced memory +ordering model so that it triggered this scenario very often. + +( And it also turned out that the reason why these latencies never + triggered on my testsystems is that i routinely use idle=poll, which + was the only idle variant not affected by this bug. ) + +The fix is to change the smp_mb__after_clear_bit() to an smp_mb(), to +act as an absolute barrier between the TS_POLLING write and the +NEED_RESCHED read. This affects almost all idling methods (default, +ACPI, APM), on all 3 x86 architectures: i386, x86_64, ia64. + +Signed-off-by: Ingo Molnar +Tested-by: Fernando Lopez-Lezcano +[chrisw: backport to 2.6.19.1] +Signed-off-by: Chris Wright +--- + arch/i386/kernel/apm.c | 6 +++++- + arch/i386/kernel/process.c | 7 ++++++- + arch/ia64/kernel/process.c | 10 ++++++++-- + arch/x86_64/kernel/process.c | 6 +++++- + drivers/acpi/processor_idle.c | 12 ++++++++++-- + 5 files changed, 34 insertions(+), 7 deletions(-) + +--- linux-2.6.19.1.orig/arch/i386/kernel/apm.c ++++ linux-2.6.19.1/arch/i386/kernel/apm.c +@@ -784,7 +784,11 @@ static int apm_do_idle(void) + polling = !!(current_thread_info()->status & TS_POLLING); + if (polling) { + current_thread_info()->status &= ~TS_POLLING; +- smp_mb__after_clear_bit(); ++ /* ++ * TS_POLLING-cleared state must be visible before we ++ * test NEED_RESCHED: ++ */ ++ smp_mb(); + } + if (!need_resched()) { + idled = 1; +--- linux-2.6.19.1.orig/arch/i386/kernel/process.c ++++ linux-2.6.19.1/arch/i386/kernel/process.c +@@ -103,7 +103,12 @@ void default_idle(void) + + if (!hlt_counter && boot_cpu_data.hlt_works_ok) { + current_thread_info()->status &= ~TS_POLLING; +- smp_mb__after_clear_bit(); ++ /* ++ * TS_POLLING-cleared state must be visible before we ++ * test NEED_RESCHED: ++ */ ++ smp_mb(); ++ + while (!need_resched()) { + local_irq_disable(); + if (!need_resched()) +--- linux-2.6.19.1.orig/arch/ia64/kernel/process.c ++++ linux-2.6.19.1/arch/ia64/kernel/process.c +@@ -268,10 +268,16 @@ cpu_idle (void) + + /* endless idle loop with no priority at all */ + while (1) { +- if (can_do_pal_halt) ++ if (can_do_pal_halt) { + current_thread_info()->status &= ~TS_POLLING; +- else ++ /* ++ * TS_POLLING-cleared state must be visible before we ++ * test NEED_RESCHED: ++ */ ++ smp_mb(); ++ } else { + current_thread_info()->status |= TS_POLLING; ++ } + + if (!need_resched()) { + void (*idle)(void); +--- linux-2.6.19.1.orig/arch/x86_64/kernel/process.c ++++ linux-2.6.19.1/arch/x86_64/kernel/process.c +@@ -111,7 +111,11 @@ static void default_idle(void) + local_irq_enable(); + + current_thread_info()->status &= ~TS_POLLING; +- smp_mb__after_clear_bit(); ++ /* ++ * TS_POLLING-cleared state must be visible before we ++ * test NEED_RESCHED: ++ */ ++ smp_mb(); + while (!need_resched()) { + local_irq_disable(); + if (!need_resched()) +--- linux-2.6.19.1.orig/drivers/acpi/processor_idle.c ++++ linux-2.6.19.1/drivers/acpi/processor_idle.c +@@ -211,7 +211,11 @@ acpi_processor_power_activate(struct acp + static void acpi_safe_halt(void) + { + current_thread_info()->status &= ~TS_POLLING; +- smp_mb__after_clear_bit(); ++ /* ++ * TS_POLLING-cleared state must be visible before we ++ * test NEED_RESCHED: ++ */ ++ smp_mb(); + if (!need_resched()) + safe_halt(); + current_thread_info()->status |= TS_POLLING; +@@ -345,7 +349,11 @@ static void acpi_processor_idle(void) + */ + if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { + current_thread_info()->status &= ~TS_POLLING; +- smp_mb__after_clear_bit(); ++ /* ++ * TS_POLLING-cleared state must be visible before we ++ * test NEED_RESCHED: ++ */ ++ smp_mb(); + if (need_resched()) { + current_thread_info()->status |= TS_POLLING; + local_irq_enable(); diff --git a/queue-2.6.19/series b/queue-2.6.19/series index cf6a8b16ca3..10f96858979 100644 --- a/queue-2.6.19/series +++ b/queue-2.6.19/series @@ -14,3 +14,24 @@ arm-add-sys_-at-syscalls.patch sched-remove-__cpuinitdata-anotation-to-cpu_isolated_map.patch ib-srp-fix-fmr-mapping-for-32-bit-kernels-and-addresses-above-4g.patch scsi-add-missing-cdb-clearing-in-scsi_execute.patch +bluetooth-add-packet-size-checks-for-capi-messages.patch +i2c-fix-broken-ds1337-initialization.patch +sched-fix-bad-missed-wakeups-in-the-i386-x86_64-ia64-acpi-and-apm-idle-code.patch +fix-for-shmem_truncate_range-bug_on.patch +smc911x-fix-netpoll-compilation-faliure.patch +fix-aoe-without-scatter-gather.patch +fix-reversed-logic-in-udp_get_port.patch +cciss-fix-xfer_read-xfer_write-in-do_cciss_request.patch +i386-cpu-hotplug-broken-with-2gb-vmsplit.patch +ramfs-breaks-without-config_block.patch +buglet-in-vmscan.c.patch +softmac-fixed-handling-of-deassociation-from-ap.patch +zd1211rw-call-ieee80211_rx-in-tasklet.patch +handle-ext3-directory-corruption-better.patch +corrupted-cramfs-filesystems-cause-kernel-oops.patch +ext2-skip-pages-past-number-of-blocks-in-ext2_find_entry.patch +pktgen-fix-module-load-unload-races.patch +sparc64-fix-mem-xxx-handling.patch +sparc64-handle-isa-devices-with-no-regs-property.patch +net-don-t-export-linux-random.h-outside-__kernel__.patch +sparc32-add-offset-in-pci_map_sg.patch diff --git a/queue-2.6.19/smc911x-fix-netpoll-compilation-faliure.patch b/queue-2.6.19/smc911x-fix-netpoll-compilation-faliure.patch new file mode 100644 index 00000000000..38beab86507 --- /dev/null +++ b/queue-2.6.19/smc911x-fix-netpoll-compilation-faliure.patch @@ -0,0 +1,33 @@ +From stable-bounces@linux.kernel.org Fri Dec 22 01:15:30 2006 +Message-Id: <200612220908.kBM98PCx018719@shell0.pdx.osdl.net> +To: torvalds@osdl.org +From: akpm@osdl.org +Date: Fri, 22 Dec 2006 01:08:24 -0800 +Cc: akpm@osdl.org, stable@kernel.org, jeff@garzik.org, vitalywool@gmail.com +Subject: smc911x: fix netpoll compilation faliure + +From: Vitaly Wool + +Fix the compilation failure for smc911x.c when NET_POLL_CONTROLLER is set. + +Signed-off-by: Vitaly Wool +Cc: Jeff Garzik +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Chris Wright +--- + + drivers/net/smc911x.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- linux-2.6.19.1.orig/drivers/net/smc911x.c ++++ linux-2.6.19.1/drivers/net/smc911x.c +@@ -1331,7 +1331,7 @@ smc911x_rx_dma_irq(int dma, void *data) + static void smc911x_poll_controller(struct net_device *dev) + { + disable_irq(dev->irq); +- smc911x_interrupt(dev->irq, dev, NULL); ++ smc911x_interrupt(dev->irq, dev); + enable_irq(dev->irq); + } + #endif diff --git a/queue-2.6.19/softmac-fixed-handling-of-deassociation-from-ap.patch b/queue-2.6.19/softmac-fixed-handling-of-deassociation-from-ap.patch new file mode 100644 index 00000000000..410f4da67b9 --- /dev/null +++ b/queue-2.6.19/softmac-fixed-handling-of-deassociation-from-ap.patch @@ -0,0 +1,80 @@ +From stable-bounces@linux.kernel.org Sat Dec 30 13:24:14 2006 +Message-ID: <4596D796.6030202@gentoo.org> +Date: Sat, 30 Dec 2006 16:18:14 -0500 +From: Daniel Drake +To: stable@kernel.org +Cc: Ulrich Kunitz +Subject: softmac: Fixed handling of deassociation from AP + +From: Ulrich Kunitz + +In 2.6.19 a deauthentication from the AP doesn't start a +reassociation by the softmac code. It appears that +mac->associnfo.associating must be set and the +ieee80211softmac_assoc_work function must be scheduled. This patch +fixes that. + +Signed-off-by: Ulrich Kunitz +Signed-off-by: John W. Linville +Signed-off-by: Chris Wright +--- +Date: Sun, 3 Dec 2006 15:32:00 +0000 (+0100) +Subject: [PATCH] softmac: Fixed handling of deassociation from AP +X-Git-Tag: v2.6.20-rc1 +X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=2b50c24554d31c2db2f93b1151b5991e62f96594 + + net/ieee80211/softmac/ieee80211softmac_assoc.c | 14 ++++++++++++-- + net/ieee80211/softmac/ieee80211softmac_auth.c | 2 ++ + net/ieee80211/softmac/ieee80211softmac_priv.h | 2 ++ + 3 files changed, 16 insertions(+), 2 deletions(-) + +--- linux-2.6.19.1.orig/net/ieee80211/softmac/ieee80211softmac_assoc.c ++++ linux-2.6.19.1/net/ieee80211/softmac/ieee80211softmac_assoc.c +@@ -427,6 +427,17 @@ ieee80211softmac_handle_assoc_response(s + return 0; + } + ++void ++ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&mac->lock, flags); ++ mac->associnfo.associating = 1; ++ schedule_work(&mac->associnfo.work); ++ spin_unlock_irqrestore(&mac->lock, flags); ++} ++ + int + ieee80211softmac_handle_disassoc(struct net_device * dev, + struct ieee80211_disassoc *disassoc) +@@ -445,8 +456,7 @@ ieee80211softmac_handle_disassoc(struct + dprintk(KERN_INFO PFX "got disassoc frame\n"); + ieee80211softmac_disassoc(mac); + +- /* try to reassociate */ +- schedule_work(&mac->associnfo.work); ++ ieee80211softmac_try_reassoc(mac); + + return 0; + } +--- linux-2.6.19.1.orig/net/ieee80211/softmac/ieee80211softmac_auth.c ++++ linux-2.6.19.1/net/ieee80211/softmac/ieee80211softmac_auth.c +@@ -328,6 +328,8 @@ ieee80211softmac_deauth_from_net(struct + /* can't transmit data right now... */ + netif_carrier_off(mac->dev); + spin_unlock_irqrestore(&mac->lock, flags); ++ ++ ieee80211softmac_try_reassoc(mac); + } + + /* +--- linux-2.6.19.1.orig/net/ieee80211/softmac/ieee80211softmac_priv.h ++++ linux-2.6.19.1/net/ieee80211/softmac/ieee80211softmac_priv.h +@@ -238,4 +238,6 @@ void ieee80211softmac_call_events_locked + int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac, + int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask); + ++void ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac); ++ + #endif /* IEEE80211SOFTMAC_PRIV_H_ */ diff --git a/queue-2.6.19/sparc32-add-offset-in-pci_map_sg.patch b/queue-2.6.19/sparc32-add-offset-in-pci_map_sg.patch new file mode 100644 index 00000000000..cd0b771aeaf --- /dev/null +++ b/queue-2.6.19/sparc32-add-offset-in-pci_map_sg.patch @@ -0,0 +1,36 @@ +From stable-bounces@linux.kernel.org Tue Jan 2 00:16:30 2007 +Date: Tue, 02 Jan 2007 00:09:25 -0800 (PST) +Message-Id: <20070102.000925.85688510.davem@davemloft.net> +To: stable@kernel.org +From: David Miller +Subject: sparc32: add offset in pci_map_sg() + +From: Jan Andersson + +Add sg->offset to sg->dvma_address in pci_map_sg() on sparc32. Without the +offset, transfers to buffers that do not begin on a page boundary will not +work as expected. + +Signed-off-by: Jan Andersson +Cc: "David S. Miller" +Cc: William Lee Irwin III +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Chris Wright + +--- + arch/sparc/kernel/ioport.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- linux-2.6.19.1.orig/arch/sparc/kernel/ioport.c ++++ linux-2.6.19.1/arch/sparc/kernel/ioport.c +@@ -728,7 +728,8 @@ int pci_map_sg(struct pci_dev *hwdev, st + /* IIep is write-through, not flushing. */ + for (n = 0; n < nents; n++) { + BUG_ON(page_address(sg->page) == NULL); +- sg->dvma_address = virt_to_phys(page_address(sg->page)); ++ sg->dvma_address = ++ virt_to_phys(page_address(sg->page)) + sg->offset; + sg->dvma_length = sg->length; + sg++; + } diff --git a/queue-2.6.19/sparc64-fix-mem-xxx-handling.patch b/queue-2.6.19/sparc64-fix-mem-xxx-handling.patch new file mode 100644 index 00000000000..6b6104f2597 --- /dev/null +++ b/queue-2.6.19/sparc64-fix-mem-xxx-handling.patch @@ -0,0 +1,190 @@ +From stable-bounces@linux.kernel.org Tue Jan 2 00:10:39 2007 +Date: Tue, 02 Jan 2007 00:03:37 -0800 (PST) +Message-Id: <20070102.000337.95059128.davem@davemloft.net> +To: stable@kernel.org +From: David Miller +Subject: SPARC64: Fix "mem=xxx" handling. + +We were not being careful enough. When we trim the physical +memory areas, we have to make sure we don't remove the kernel +image or initial ramdisk image ranges. + +Signed-off-by: David S. Miller +Signed-off-by: Chris Wright + +--- + arch/sparc64/mm/init.c | 147 +++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 124 insertions(+), 23 deletions(-) + +--- linux-2.6.19.1.orig/arch/sparc64/mm/init.c ++++ linux-2.6.19.1/arch/sparc64/mm/init.c +@@ -872,6 +872,115 @@ static unsigned long __init choose_bootm + prom_halt(); + } + ++static void __init trim_pavail(unsigned long *cur_size_p, ++ unsigned long *end_of_phys_p) ++{ ++ unsigned long to_trim = *cur_size_p - cmdline_memory_size; ++ unsigned long avoid_start, avoid_end; ++ int i; ++ ++ to_trim = PAGE_ALIGN(to_trim); ++ ++ avoid_start = avoid_end = 0; ++#ifdef CONFIG_BLK_DEV_INITRD ++ avoid_start = initrd_start; ++ avoid_end = PAGE_ALIGN(initrd_end); ++#endif ++ ++ /* Trim some pavail[] entries in order to satisfy the ++ * requested "mem=xxx" kernel command line specification. ++ * ++ * We must not trim off the kernel image area nor the ++ * initial ramdisk range (if any). Also, we must not trim ++ * any pavail[] entry down to zero in order to preserve ++ * the invariant that all pavail[] entries have a non-zero ++ * size which is assumed by all of the code in here. ++ */ ++ for (i = 0; i < pavail_ents; i++) { ++ unsigned long start, end, kern_end; ++ unsigned long trim_low, trim_high, n; ++ ++ kern_end = PAGE_ALIGN(kern_base + kern_size); ++ ++ trim_low = start = pavail[i].phys_addr; ++ trim_high = end = start + pavail[i].reg_size; ++ ++ if (kern_base >= start && ++ kern_base < end) { ++ trim_low = kern_base; ++ if (kern_end >= end) ++ continue; ++ } ++ if (kern_end >= start && ++ kern_end < end) { ++ trim_high = kern_end; ++ } ++ if (avoid_start && ++ avoid_start >= start && ++ avoid_start < end) { ++ if (trim_low > avoid_start) ++ trim_low = avoid_start; ++ if (avoid_end >= end) ++ continue; ++ } ++ if (avoid_end && ++ avoid_end >= start && ++ avoid_end < end) { ++ if (trim_high < avoid_end) ++ trim_high = avoid_end; ++ } ++ ++ if (trim_high <= trim_low) ++ continue; ++ ++ if (trim_low == start && trim_high == end) { ++ /* Whole chunk is available for trimming. ++ * Trim all except one page, in order to keep ++ * entry non-empty. ++ */ ++ n = (end - start) - PAGE_SIZE; ++ if (n > to_trim) ++ n = to_trim; ++ ++ if (n) { ++ pavail[i].phys_addr += n; ++ pavail[i].reg_size -= n; ++ to_trim -= n; ++ } ++ } else { ++ n = (trim_low - start); ++ if (n > to_trim) ++ n = to_trim; ++ ++ if (n) { ++ pavail[i].phys_addr += n; ++ pavail[i].reg_size -= n; ++ to_trim -= n; ++ } ++ if (to_trim) { ++ n = end - trim_high; ++ if (n > to_trim) ++ n = to_trim; ++ if (n) { ++ pavail[i].reg_size -= n; ++ to_trim -= n; ++ } ++ } ++ } ++ ++ if (!to_trim) ++ break; ++ } ++ ++ /* Recalculate. */ ++ *cur_size_p = 0UL; ++ for (i = 0; i < pavail_ents; i++) { ++ *end_of_phys_p = pavail[i].phys_addr + ++ pavail[i].reg_size; ++ *cur_size_p += pavail[i].reg_size; ++ } ++} ++ + static unsigned long __init bootmem_init(unsigned long *pages_avail, + unsigned long phys_base) + { +@@ -889,31 +998,13 @@ static unsigned long __init bootmem_init + end_of_phys_memory = pavail[i].phys_addr + + pavail[i].reg_size; + bytes_avail += pavail[i].reg_size; +- if (cmdline_memory_size) { +- if (bytes_avail > cmdline_memory_size) { +- unsigned long slack = bytes_avail - cmdline_memory_size; +- +- bytes_avail -= slack; +- end_of_phys_memory -= slack; +- +- pavail[i].reg_size -= slack; +- if ((long)pavail[i].reg_size <= 0L) { +- pavail[i].phys_addr = 0xdeadbeefUL; +- pavail[i].reg_size = 0UL; +- pavail_ents = i; +- } else { +- pavail[i+1].reg_size = 0Ul; +- pavail[i+1].phys_addr = 0xdeadbeefUL; +- pavail_ents = i + 1; +- } +- break; +- } +- } + } + +- *pages_avail = bytes_avail >> PAGE_SHIFT; +- +- end_pfn = end_of_phys_memory >> PAGE_SHIFT; ++ /* Determine the location of the initial ramdisk before trying ++ * to honor the "mem=xxx" command line argument. We must know ++ * where the kernel image and the ramdisk image are so that we ++ * do not trim those two areas from the physical memory map. ++ */ + + #ifdef CONFIG_BLK_DEV_INITRD + /* Now have to check initial ramdisk, so that bootmap does not overwrite it */ +@@ -932,6 +1023,16 @@ static unsigned long __init bootmem_init + } + } + #endif ++ ++ if (cmdline_memory_size && ++ bytes_avail > cmdline_memory_size) ++ trim_pavail(&bytes_avail, ++ &end_of_phys_memory); ++ ++ *pages_avail = bytes_avail >> PAGE_SHIFT; ++ ++ end_pfn = end_of_phys_memory >> PAGE_SHIFT; ++ + /* Initialize the boot-time allocator. */ + max_pfn = max_low_pfn = end_pfn; + min_low_pfn = (phys_base >> PAGE_SHIFT); diff --git a/queue-2.6.19/sparc64-handle-isa-devices-with-no-regs-property.patch b/queue-2.6.19/sparc64-handle-isa-devices-with-no-regs-property.patch new file mode 100644 index 00000000000..f13e546711b --- /dev/null +++ b/queue-2.6.19/sparc64-handle-isa-devices-with-no-regs-property.patch @@ -0,0 +1,92 @@ +From stable-bounces@linux.kernel.org Tue Jan 2 00:13:01 2007 +Date: Tue, 02 Jan 2007 00:06:00 -0800 (PST) +Message-Id: <20070102.000600.59655621.davem@davemloft.net> +To: stable@kernel.org +From: David Miller +Subject: SPARC64: Handle ISA devices with no 'regs' property. + +And this points out that the return value from +isa_dev_get_resource() and the 'pregs' arg to +isa_dev_get_irq() are totally unused. + +Based upon a patch from Richard Mortimer + +Signed-off-by: David S. Miller +Signed-off-by: Chris Wright + +--- + arch/sparc64/kernel/isa.c | 20 ++++++++------------ + 1 file changed, 8 insertions(+), 12 deletions(-) + +--- linux-2.6.19.1.orig/arch/sparc64/kernel/isa.c ++++ linux-2.6.19.1/arch/sparc64/kernel/isa.c +@@ -22,14 +22,15 @@ static void __init report_dev(struct spa + printk(" [%s", isa_dev->prom_node->name); + } + +-static struct linux_prom_registers * __init +-isa_dev_get_resource(struct sparc_isa_device *isa_dev) ++static void __init isa_dev_get_resource(struct sparc_isa_device *isa_dev) + { + struct linux_prom_registers *pregs; + unsigned long base, len; + int prop_len; + + pregs = of_get_property(isa_dev->prom_node, "reg", &prop_len); ++ if (!pregs) ++ return; + + /* Only the first one is interesting. */ + len = pregs[0].reg_size; +@@ -44,12 +45,9 @@ isa_dev_get_resource(struct sparc_isa_de + + request_resource(&isa_dev->bus->parent->io_space, + &isa_dev->resource); +- +- return pregs; + } + +-static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev, +- struct linux_prom_registers *pregs) ++static void __init isa_dev_get_irq(struct sparc_isa_device *isa_dev) + { + struct of_device *op = of_find_device_by_node(isa_dev->prom_node); + +@@ -69,7 +67,6 @@ static void __init isa_fill_children(str + + printk(" ->"); + while (dp) { +- struct linux_prom_registers *regs; + struct sparc_isa_device *isa_dev; + + isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL); +@@ -87,8 +84,8 @@ static void __init isa_fill_children(str + isa_dev->bus = parent_isa_dev->bus; + isa_dev->prom_node = dp; + +- regs = isa_dev_get_resource(isa_dev); +- isa_dev_get_irq(isa_dev, regs); ++ isa_dev_get_resource(isa_dev); ++ isa_dev_get_irq(isa_dev); + + report_dev(isa_dev, 1); + +@@ -101,7 +98,6 @@ static void __init isa_fill_devices(stru + struct device_node *dp = isa_br->prom_node->child; + + while (dp) { +- struct linux_prom_registers *regs; + struct sparc_isa_device *isa_dev; + + isa_dev = kmalloc(sizeof(*isa_dev), GFP_KERNEL); +@@ -141,8 +137,8 @@ static void __init isa_fill_devices(stru + isa_dev->bus = isa_br; + isa_dev->prom_node = dp; + +- regs = isa_dev_get_resource(isa_dev); +- isa_dev_get_irq(isa_dev, regs); ++ isa_dev_get_resource(isa_dev); ++ isa_dev_get_irq(isa_dev); + + report_dev(isa_dev, 0); + diff --git a/queue-2.6.19/zd1211rw-call-ieee80211_rx-in-tasklet.patch b/queue-2.6.19/zd1211rw-call-ieee80211_rx-in-tasklet.patch new file mode 100644 index 00000000000..cca2ab68a6b --- /dev/null +++ b/queue-2.6.19/zd1211rw-call-ieee80211_rx-in-tasklet.patch @@ -0,0 +1,223 @@ +From stable-bounces@linux.kernel.org Sat Dec 30 13:41:14 2006 +Message-ID: <4596DB95.8060004@gentoo.org> +Date: Sat, 30 Dec 2006 16:35:17 -0500 +From: Daniel Drake +To: stable@kernel.org +Cc: Ulrich Kunitz +Subject: zd1211rw: Call ieee80211_rx in tasklet + +From: Ulrich Kunitz + +[PATCH] zd1211rw: Call ieee80211_rx in tasklet + +The driver called ieee80211_rx in hardware interrupt context. This has +been against the intention of the ieee80211_rx function. It caused a bug +in the crypto routines used by WPA. This patch calls ieee80211_rx in a +tasklet. + +Signed-off-by: Ulrich Kunitz +Signed-off-by: Andrew Morton +Signed-off-by: John W. Linville +Signed-off-by: Chris Wright +--- +Date: Sun, 10 Dec 2006 19:13:12 +0000 (-0800) +Subject: [PATCH] zd1211rw: Call ieee80211_rx in tasklet +X-Git-Tag: v2.6.20-rc2 +X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=4d1feabcbf41f875447a392015acd0796f57baf6 + + drivers/net/wireless/zd1211rw/zd_mac.c | 91 ++++++++++++++++++++++++--------- + drivers/net/wireless/zd1211rw/zd_mac.h | 6 +- + drivers/net/wireless/zd1211rw/zd_usb.c | 4 - + 3 files changed, 75 insertions(+), 26 deletions(-) + +--- linux-2.6.19.1.orig/drivers/net/wireless/zd1211rw/zd_mac.c ++++ linux-2.6.19.1/drivers/net/wireless/zd1211rw/zd_mac.c +@@ -37,6 +37,8 @@ static void housekeeping_init(struct zd_ + static void housekeeping_enable(struct zd_mac *mac); + static void housekeeping_disable(struct zd_mac *mac); + ++static void do_rx(unsigned long mac_ptr); ++ + int zd_mac_init(struct zd_mac *mac, + struct net_device *netdev, + struct usb_interface *intf) +@@ -47,6 +49,10 @@ int zd_mac_init(struct zd_mac *mac, + spin_lock_init(&mac->lock); + mac->netdev = netdev; + ++ skb_queue_head_init(&mac->rx_queue); ++ tasklet_init(&mac->rx_tasklet, do_rx, (unsigned long)mac); ++ tasklet_disable(&mac->rx_tasklet); ++ + ieee_init(ieee); + softmac_init(ieee80211_priv(netdev)); + zd_chip_init(&mac->chip, netdev, intf); +@@ -132,6 +138,8 @@ out: + + void zd_mac_clear(struct zd_mac *mac) + { ++ skb_queue_purge(&mac->rx_queue); ++ tasklet_kill(&mac->rx_tasklet); + zd_chip_clear(&mac->chip); + ZD_ASSERT(!spin_is_locked(&mac->lock)); + ZD_MEMCLEAR(mac, sizeof(struct zd_mac)); +@@ -160,6 +168,8 @@ int zd_mac_open(struct net_device *netde + struct zd_chip *chip = &mac->chip; + int r; + ++ tasklet_enable(&mac->rx_tasklet); ++ + r = zd_chip_enable_int(chip); + if (r < 0) + goto out; +@@ -210,6 +220,8 @@ int zd_mac_stop(struct net_device *netde + */ + + zd_chip_disable_rx(chip); ++ skb_queue_purge(&mac->rx_queue); ++ tasklet_disable(&mac->rx_tasklet); + housekeeping_disable(mac); + ieee80211softmac_stop(netdev); + +@@ -873,45 +885,78 @@ static int fill_rx_stats(struct ieee8021 + return 0; + } + +-int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length) ++static void zd_mac_rx(struct zd_mac *mac, struct sk_buff *skb) + { + int r; + struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); + struct ieee80211_rx_stats stats; + const struct rx_status *status; +- struct sk_buff *skb; + +- if (length < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN + +- IEEE80211_FCS_LEN + sizeof(struct rx_status)) +- return -EINVAL; ++ if (skb->len < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN + ++ IEEE80211_FCS_LEN + sizeof(struct rx_status)) ++ { ++ dev_dbg_f(zd_mac_dev(mac), "Packet with length %u to small.\n", ++ skb->len); ++ goto free_skb; ++ } + +- r = fill_rx_stats(&stats, &status, mac, buffer, length); +- if (r) +- return r; ++ r = fill_rx_stats(&stats, &status, mac, skb->data, skb->len); ++ if (r) { ++ /* Only packets with rx errors are included here. */ ++ goto free_skb; ++ } + +- length -= ZD_PLCP_HEADER_SIZE+IEEE80211_FCS_LEN+ +- sizeof(struct rx_status); +- buffer += ZD_PLCP_HEADER_SIZE; ++ __skb_pull(skb, ZD_PLCP_HEADER_SIZE); ++ __skb_trim(skb, skb->len - ++ (IEEE80211_FCS_LEN + sizeof(struct rx_status))); + +- update_qual_rssi(mac, buffer, length, stats.signal, stats.rssi); ++ update_qual_rssi(mac, skb->data, skb->len, stats.signal, ++ status->signal_strength); + +- r = filter_rx(ieee, buffer, length, &stats); +- if (r <= 0) +- return r; + +- skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length); +- if (!skb) +- return -ENOMEM; ++ r = filter_rx(ieee, skb->data, skb->len, &stats); ++ if (r <= 0) { ++ if (r < 0) ++ dev_dbg_f(zd_mac_dev(mac), "Error in packet.\n"); ++ goto free_skb; ++ } ++ + if (ieee->iw_mode == IW_MODE_MONITOR) +- fill_rt_header(skb_put(skb, sizeof(struct zd_rt_hdr)), mac, ++ fill_rt_header(skb_push(skb, sizeof(struct zd_rt_hdr)), mac, + &stats, status); +- memcpy(skb_put(skb, length), buffer, length); + + r = ieee80211_rx(ieee, skb, &stats); +- if (!r) { +- ZD_ASSERT(in_irq()); +- dev_kfree_skb_irq(skb); ++ if (r) ++ return; ++ ++free_skb: ++ /* We are always in a soft irq. */ ++ dev_kfree_skb(skb); ++} ++ ++static void do_rx(unsigned long mac_ptr) ++{ ++ struct zd_mac *mac = (struct zd_mac *)mac_ptr; ++ struct sk_buff *skb; ++ ++ while ((skb = skb_dequeue(&mac->rx_queue)) != NULL) ++ zd_mac_rx(mac, skb); ++} ++ ++int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length) ++{ ++ struct sk_buff *skb; ++ ++ skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length); ++ if (!skb) { ++ dev_warn(zd_mac_dev(mac), "Could not allocate skb.\n"); ++ return -ENOMEM; + } ++ skb_reserve(skb, sizeof(struct zd_rt_hdr)); ++ memcpy(__skb_put(skb, length), buffer, length); ++ skb_queue_tail(&mac->rx_queue, skb); ++ tasklet_schedule(&mac->rx_tasklet); ++ + return 0; + } + +--- linux-2.6.19.1.orig/drivers/net/wireless/zd1211rw/zd_mac.h ++++ linux-2.6.19.1/drivers/net/wireless/zd1211rw/zd_mac.h +@@ -133,6 +133,10 @@ struct zd_mac { + /* Unlocked reading possible */ + struct iw_statistics iw_stats; + struct housekeeping housekeeping; ++ ++ struct tasklet_struct rx_tasklet; ++ struct sk_buff_head rx_queue; ++ + unsigned int stats_count; + u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE]; + u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE]; +@@ -174,7 +178,7 @@ int zd_mac_open(struct net_device *netde + int zd_mac_stop(struct net_device *netdev); + int zd_mac_set_mac_address(struct net_device *dev, void *p); + +-int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length); ++int zd_mac_rx_irq(struct zd_mac *mac, const u8 *buffer, unsigned int length); + + int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain); + u8 zd_mac_get_regdomain(struct zd_mac *zd_mac); +--- linux-2.6.19.1.orig/drivers/net/wireless/zd1211rw/zd_usb.c ++++ linux-2.6.19.1/drivers/net/wireless/zd1211rw/zd_usb.c +@@ -599,13 +599,13 @@ static void handle_rx_packet(struct zd_u + n = l+k; + if (n > length) + return; +- zd_mac_rx(mac, buffer+l, k); ++ zd_mac_rx_irq(mac, buffer+l, k); + if (i >= 2) + return; + l = (n+3) & ~3; + } + } else { +- zd_mac_rx(mac, buffer, length); ++ zd_mac_rx_irq(mac, buffer, length); + } + } +