diff --git a/debian/changelog b/debian/changelog index 76116768f..0f139df9d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -71,6 +71,15 @@ linux-2.6 (2.6.13-1) UNRELEASED; urgency=low - forcedeth: Initialize link settings in every nv_open() - Lost sockfd_put() in routing_ioctl() - lost fput in 32bit ioctl on x86-64 + * Added patch-2.6.13.3: + - Fix fs/exec.c:788 (de_thread()) BUG_ON + - Don't over-clamp window in tcp_clamp_window() + - fix IPv6 per-socket multicast filtering in exact-match case + - yenta oops fix + - ipvs: ip_vs_ftp breaks connections using persistence + - uml - Fix x86_64 page leak + - skge: set mac address oops with bonding + - tcp: set default congestion control correctly for incoming connections [ Sven Luther ] * [powerpc] Added hotplug support to the mv643xx_eth driver : diff --git a/debian/patches-debian/patch-2.6.13.3 b/debian/patches-debian/patch-2.6.13.3 new file mode 100644 index 000000000..bb2597279 --- /dev/null +++ b/debian/patches-debian/patch-2.6.13.3 @@ -0,0 +1,420 @@ +diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h +--- a/arch/um/kernel/skas/include/mmu-skas.h ++++ b/arch/um/kernel/skas/include/mmu-skas.h +@@ -6,11 +6,15 @@ + #ifndef __SKAS_MMU_H + #define __SKAS_MMU_H + ++#include "linux/config.h" + #include "mm_id.h" + + struct mmu_context_skas { + struct mm_id id; + unsigned long last_page_table; ++#ifdef CONFIG_3_LEVEL_PGTABLES ++ unsigned long last_pmd; ++#endif + }; + + extern void switch_mm_skas(struct mm_id * mm_idp); +diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c +--- a/arch/um/kernel/skas/mmu.c ++++ b/arch/um/kernel/skas/mmu.c +@@ -56,6 +56,9 @@ static int init_stub_pte(struct mm_struc + */ + + mm->context.skas.last_page_table = pmd_page_kernel(*pmd); ++#ifdef CONFIG_3_LEVEL_PGTABLES ++ mm->context.skas.last_pmd = (unsigned long) __va(pud_val(*pud)); ++#endif + + *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT)); + *pte = pte_mkexec(*pte); +@@ -140,6 +143,10 @@ void destroy_context_skas(struct mm_stru + else { + os_kill_ptraced_process(mmu->id.u.pid, 1); + free_page(mmu->id.stack); +- free_page(mmu->last_page_table); ++ pte_free_kernel((pte_t *) mmu->last_page_table); ++ dec_page_state(nr_page_table_pages); ++#ifdef CONFIG_3_LEVEL_PGTABLES ++ pmd_free((pmd_t *) mmu->last_pmd); ++#endif + } + } +diff --git a/drivers/net/skge.c b/drivers/net/skge.c +--- a/drivers/net/skge.c ++++ b/drivers/net/skge.c +@@ -2828,21 +2828,29 @@ static void skge_netpoll(struct net_devi + static int skge_set_mac_address(struct net_device *dev, void *p) + { + struct skge_port *skge = netdev_priv(dev); +- struct sockaddr *addr = p; +- int err = 0; ++ struct skge_hw *hw = skge->hw; ++ unsigned port = skge->port; ++ const struct sockaddr *addr = p; + + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + +- skge_down(dev); ++ spin_lock_bh(&hw->phy_lock); + memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); +- memcpy_toio(skge->hw->regs + B2_MAC_1 + skge->port*8, ++ memcpy_toio(hw->regs + B2_MAC_1 + port*8, + dev->dev_addr, ETH_ALEN); +- memcpy_toio(skge->hw->regs + B2_MAC_2 + skge->port*8, ++ memcpy_toio(hw->regs + B2_MAC_2 + port*8, + dev->dev_addr, ETH_ALEN); +- if (dev->flags & IFF_UP) +- err = skge_up(dev); +- return err; ++ ++ if (hw->chip_id == CHIP_ID_GENESIS) ++ xm_outaddr(hw, port, XM_SA, dev->dev_addr); ++ else { ++ gma_set_addr(hw, port, GM_SRC_ADDR_1L, dev->dev_addr); ++ gma_set_addr(hw, port, GM_SRC_ADDR_2L, dev->dev_addr); ++ } ++ spin_unlock_bh(&hw->phy_lock); ++ ++ return 0; + } + + static const struct { +diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c +--- a/drivers/pcmcia/yenta_socket.c ++++ b/drivers/pcmcia/yenta_socket.c +@@ -976,7 +976,18 @@ static int __devinit yenta_probe (struct + { + struct yenta_socket *socket; + int ret; +- ++ ++ /* ++ * If we failed to assign proper bus numbers for this cardbus ++ * controller during PCI probe, its subordinate pci_bus is NULL. ++ * Bail out if so. ++ */ ++ if (!dev->subordinate) { ++ printk(KERN_ERR "Yenta: no bus associated with %s! " ++ "(try 'pci=assign-busses')\n", pci_name(dev)); ++ return -ENODEV; ++ } ++ + socket = kmalloc(sizeof(struct yenta_socket), GFP_KERNEL); + if (!socket) + return -ENOMEM; +diff --git a/fs/exec.c b/fs/exec.c +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -745,8 +745,8 @@ static inline int de_thread(struct task_ + } + + /* +- * Now there are really no other threads at all, +- * so it's safe to stop telling them to kill themselves. ++ * There may be one thread left which is just exiting, ++ * but it's safe to stop telling the group to kill themselves. + */ + sig->flags = 0; + +@@ -785,7 +785,6 @@ no_thread_group: + kmem_cache_free(sighand_cachep, oldsighand); + } + +- BUG_ON(!thread_group_empty(current)); + BUG_ON(!thread_group_leader(current)); + return 0; + } +diff --git a/include/asm-um/pgalloc.h b/include/asm-um/pgalloc.h +--- a/include/asm-um/pgalloc.h ++++ b/include/asm-um/pgalloc.h +@@ -42,11 +42,13 @@ static inline void pte_free(struct page + #define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) + + #ifdef CONFIG_3_LEVEL_PGTABLES +-/* +- * In the 3-level case we free the pmds as part of the pgd. +- */ +-#define pmd_free(x) do { } while (0) +-#define __pmd_free_tlb(tlb,x) do { } while (0) ++ ++extern __inline__ void pmd_free(pmd_t *pmd) ++{ ++ free_page((unsigned long)pmd); ++} ++ ++#define __pmd_free_tlb(tlb,x) tlb_remove_page((tlb),virt_to_page(x)) + #endif + + #define check_pgt_cache() do { } while (0) +diff --git a/include/asm-um/pgtable-3level.h b/include/asm-um/pgtable-3level.h +--- a/include/asm-um/pgtable-3level.h ++++ b/include/asm-um/pgtable-3level.h +@@ -98,14 +98,11 @@ static inline pmd_t *pmd_alloc_one(struc + return pmd; + } + +-static inline void pmd_free(pmd_t *pmd){ +- free_page((unsigned long) pmd); ++extern inline void pud_clear (pud_t *pud) ++{ ++ set_pud(pud, __pud(0)); + } + +-#define __pmd_free_tlb(tlb,x) do { } while (0) +- +-static inline void pud_clear (pud_t * pud) { } +- + #define pud_page(pud) \ + ((struct page *) __va(pud_val(pud) & PAGE_MASK)) + +diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h +--- a/include/net/ip_vs.h ++++ b/include/net/ip_vs.h +@@ -84,6 +84,7 @@ + #define IP_VS_CONN_F_IN_SEQ 0x0400 /* must do input seq adjust */ + #define IP_VS_CONN_F_SEQ_MASK 0x0600 /* in/out sequence mask */ + #define IP_VS_CONN_F_NO_CPORT 0x0800 /* no client port set yet */ ++#define IP_VS_CONN_F_TEMPLATE 0x1000 /* template, not connection */ + + /* Move it to better place one day, for now keep it unique */ + #define NFC_IPVS_PROPERTY 0x10000 +@@ -740,6 +741,8 @@ enum { + + extern struct ip_vs_conn *ip_vs_conn_in_get + (int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port); ++extern struct ip_vs_conn *ip_vs_ct_in_get ++(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port); + extern struct ip_vs_conn *ip_vs_conn_out_get + (int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port); + +diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c +--- a/net/ipv4/ipvs/ip_vs_conn.c ++++ b/net/ipv4/ipvs/ip_vs_conn.c +@@ -196,6 +196,7 @@ static inline struct ip_vs_conn *__ip_vs + list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) { + if (s_addr==cp->caddr && s_port==cp->cport && + d_port==cp->vport && d_addr==cp->vaddr && ++ ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) && + protocol==cp->protocol) { + /* HIT */ + atomic_inc(&cp->refcnt); +@@ -227,6 +228,40 @@ struct ip_vs_conn *ip_vs_conn_in_get + return cp; + } + ++/* Get reference to connection template */ ++struct ip_vs_conn *ip_vs_ct_in_get ++(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port) ++{ ++ unsigned hash; ++ struct ip_vs_conn *cp; ++ ++ hash = ip_vs_conn_hashkey(protocol, s_addr, s_port); ++ ++ ct_read_lock(hash); ++ ++ list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) { ++ if (s_addr==cp->caddr && s_port==cp->cport && ++ d_port==cp->vport && d_addr==cp->vaddr && ++ cp->flags & IP_VS_CONN_F_TEMPLATE && ++ protocol==cp->protocol) { ++ /* HIT */ ++ atomic_inc(&cp->refcnt); ++ goto out; ++ } ++ } ++ cp = NULL; ++ ++ out: ++ ct_read_unlock(hash); ++ ++ IP_VS_DBG(7, "template lookup/in %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n", ++ ip_vs_proto_name(protocol), ++ NIPQUAD(s_addr), ntohs(s_port), ++ NIPQUAD(d_addr), ntohs(d_port), ++ cp?"hit":"not hit"); ++ ++ return cp; ++} + + /* + * Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab. +@@ -367,7 +402,7 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, s + atomic_read(&dest->refcnt)); + + /* Update the connection counters */ +- if (cp->cport || (cp->flags & IP_VS_CONN_F_NO_CPORT)) { ++ if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) { + /* It is a normal connection, so increase the inactive + connection counter because it is in TCP SYNRECV + state (inactive) or other protocol inacive state */ +@@ -406,7 +441,7 @@ static inline void ip_vs_unbind_dest(str + atomic_read(&dest->refcnt)); + + /* Update the connection counters */ +- if (cp->cport || (cp->flags & IP_VS_CONN_F_NO_CPORT)) { ++ if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) { + /* It is a normal connection, so decrease the inactconns + or activeconns counter */ + if (cp->flags & IP_VS_CONN_F_INACTIVE) { +@@ -776,7 +811,7 @@ void ip_vs_random_dropentry(void) + ct_write_lock_bh(hash); + + list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) { +- if (!cp->cport && !(cp->flags & IP_VS_CONN_F_NO_CPORT)) ++ if (cp->flags & IP_VS_CONN_F_TEMPLATE) + /* connection template */ + continue; + +diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c +--- a/net/ipv4/ipvs/ip_vs_core.c ++++ b/net/ipv4/ipvs/ip_vs_core.c +@@ -242,10 +242,10 @@ ip_vs_sched_persist(struct ip_vs_service + if (ports[1] == svc->port) { + /* Check if a template already exists */ + if (svc->port != FTPPORT) +- ct = ip_vs_conn_in_get(iph->protocol, snet, 0, ++ ct = ip_vs_ct_in_get(iph->protocol, snet, 0, + iph->daddr, ports[1]); + else +- ct = ip_vs_conn_in_get(iph->protocol, snet, 0, ++ ct = ip_vs_ct_in_get(iph->protocol, snet, 0, + iph->daddr, 0); + + if (!ct || !ip_vs_check_template(ct)) { +@@ -271,14 +271,14 @@ ip_vs_sched_persist(struct ip_vs_service + iph->daddr, + ports[1], + dest->addr, dest->port, +- 0, ++ IP_VS_CONN_F_TEMPLATE, + dest); + else + ct = ip_vs_conn_new(iph->protocol, + snet, 0, + iph->daddr, 0, + dest->addr, 0, +- 0, ++ IP_VS_CONN_F_TEMPLATE, + dest); + if (ct == NULL) + return NULL; +@@ -297,10 +297,10 @@ ip_vs_sched_persist(struct ip_vs_service + * port zero template: + */ + if (svc->fwmark) +- ct = ip_vs_conn_in_get(IPPROTO_IP, snet, 0, ++ ct = ip_vs_ct_in_get(IPPROTO_IP, snet, 0, + htonl(svc->fwmark), 0); + else +- ct = ip_vs_conn_in_get(iph->protocol, snet, 0, ++ ct = ip_vs_ct_in_get(iph->protocol, snet, 0, + iph->daddr, 0); + + if (!ct || !ip_vs_check_template(ct)) { +@@ -325,14 +325,14 @@ ip_vs_sched_persist(struct ip_vs_service + snet, 0, + htonl(svc->fwmark), 0, + dest->addr, 0, +- 0, ++ IP_VS_CONN_F_TEMPLATE, + dest); + else + ct = ip_vs_conn_new(iph->protocol, + snet, 0, + iph->daddr, 0, + dest->addr, 0, +- 0, ++ IP_VS_CONN_F_TEMPLATE, + dest); + if (ct == NULL) + return NULL; +diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c +--- a/net/ipv4/ipvs/ip_vs_sync.c ++++ b/net/ipv4/ipvs/ip_vs_sync.c +@@ -297,16 +297,24 @@ static void ip_vs_process_message(const + + p = (char *)buffer + sizeof(struct ip_vs_sync_mesg); + for (i=0; inr_conns; i++) { ++ unsigned flags; ++ + s = (struct ip_vs_sync_conn *)p; +- cp = ip_vs_conn_in_get(s->protocol, +- s->caddr, s->cport, +- s->vaddr, s->vport); ++ flags = ntohs(s->flags); ++ if (!(flags & IP_VS_CONN_F_TEMPLATE)) ++ cp = ip_vs_conn_in_get(s->protocol, ++ s->caddr, s->cport, ++ s->vaddr, s->vport); ++ else ++ cp = ip_vs_ct_in_get(s->protocol, ++ s->caddr, s->cport, ++ s->vaddr, s->vport); + if (!cp) { + cp = ip_vs_conn_new(s->protocol, + s->caddr, s->cport, + s->vaddr, s->vport, + s->daddr, s->dport, +- ntohs(s->flags), NULL); ++ flags, NULL); + if (!cp) { + IP_VS_ERR("ip_vs_conn_new failed\n"); + return; +@@ -315,11 +323,11 @@ static void ip_vs_process_message(const + } else if (!cp->dest) { + /* it is an entry created by the synchronization */ + cp->state = ntohs(s->state); +- cp->flags = ntohs(s->flags) | IP_VS_CONN_F_HASHED; ++ cp->flags = flags | IP_VS_CONN_F_HASHED; + } /* Note that we don't touch its state and flags + if it is a normal entry. */ + +- if (ntohs(s->flags) & IP_VS_CONN_F_SEQ_MASK) { ++ if (flags & IP_VS_CONN_F_SEQ_MASK) { + opt = (struct ip_vs_sync_conn_options *)&s[1]; + memcpy(&cp->in_seq, opt, sizeof(*opt)); + p += FULL_CONN_SIZE; +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -350,8 +350,6 @@ static void tcp_clamp_window(struct sock + app_win -= tp->ack.rcv_mss; + app_win = max(app_win, 2U*tp->advmss); + +- if (!ofo_win) +- tp->window_clamp = min(tp->window_clamp, app_win); + tp->rcv_ssthresh = min(tp->window_clamp, 2U*tp->advmss); + } + } +diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c +--- a/net/ipv4/tcp_minisocks.c ++++ b/net/ipv4/tcp_minisocks.c +@@ -774,7 +774,7 @@ struct sock *tcp_create_openreq_child(st + newtp->frto_counter = 0; + newtp->frto_highmark = 0; + +- newtp->ca_ops = &tcp_reno; ++ newtp->ca_ops = &tcp_init_congestion_ops; + + tcp_set_ca_state(newtp, TCP_CA_Open); + tcp_init_xmit_timers(newsk); +diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c +--- a/net/ipv6/udp.c ++++ b/net/ipv6/udp.c +@@ -404,9 +404,8 @@ static struct sock *udp_v6_mcast_next(st + continue; + + if (!ipv6_addr_any(&np->rcv_saddr)) { +- if (ipv6_addr_equal(&np->rcv_saddr, loc_addr)) +- return s; +- continue; ++ if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr)) ++ continue; + } + if(!inet6_mc_check(s, loc_addr, rmt_addr)) + continue; diff --git a/debian/patches-debian/series/2.6.13-1 b/debian/patches-debian/series/2.6.13-1 index 4fd401a32..5c23f2eef 100644 --- a/debian/patches-debian/series/2.6.13-1 +++ b/debian/patches-debian/series/2.6.13-1 @@ -24,4 +24,5 @@ + patch-2.6.13.2 + amd64-tlb-flush-sigsegv-fix.patch + powerpc-apus.patch ++ patch-2.6.13.3