From 5f32fc45b21733d42804d6d5fbd1fa1e5ab2b403 Mon Sep 17 00:00:00 2001 From: Mark Fasheh Date: Sun, 16 Sep 2007 20:10:16 -0700 Subject: [PATCH] --- yaml --- r: 65093 b: refs/heads/master c: 415cb800375cc4e89fb5a6a454e484bd4adbffb4 h: refs/heads/master i: 65091: 4225cbeb8418abe85d2aaefbe9537c92c405e42e v: v3 --- [refs] | 2 +- trunk/MAINTAINERS | 6 +- trunk/arch/x86_64/ia32/ia32entry.S | 18 +- trunk/arch/x86_64/kernel/ptrace.c | 4 + trunk/drivers/ata/ahci.c | 10 +- trunk/drivers/ata/libata-core.c | 4 - trunk/drivers/ata/libata-sff.c | 5 +- trunk/drivers/ieee1394/ieee1394_core.c | 2 +- trunk/drivers/ieee1394/ohci1394.c | 4 +- trunk/drivers/net/bnx2.c | 7 +- trunk/drivers/net/myri10ge/myri10ge.c | 3 - trunk/drivers/net/phy/phy.c | 1 - trunk/drivers/net/pppoe.c | 3 +- trunk/drivers/net/pppol2tp.c | 118 ++++---- trunk/drivers/net/sky2.c | 368 ++++++++----------------- trunk/drivers/net/sky2.h | 41 +-- trunk/fs/exec.c | 3 + trunk/fs/ocfs2/file.c | 4 +- trunk/fs/ocfs2/localalloc.c | 4 +- trunk/fs/ocfs2/localalloc.h | 2 +- trunk/fs/ocfs2/suballoc.c | 29 +- trunk/fs/ocfs2/suballoc.h | 11 + trunk/fs/signalfd.c | 190 +++++++++++-- trunk/include/linux/init_task.h | 2 +- trunk/include/linux/sched.h | 2 +- trunk/include/linux/signalfd.h | 40 ++- trunk/kernel/exit.c | 9 + trunk/kernel/fork.c | 2 +- trunk/kernel/signal.c | 8 +- trunk/net/netfilter/nfnetlink_log.c | 13 +- trunk/net/sched/sch_sfq.c | 10 +- trunk/net/sunrpc/svcsock.c | 3 +- 32 files changed, 476 insertions(+), 452 deletions(-) diff --git a/[refs] b/[refs] index 463e7b58037f..92a55b6b74d3 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 176df2457ef6207156ca1a40991c54ca01fef567 +refs/heads/master: 415cb800375cc4e89fb5a6a454e484bd4adbffb4 diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 9a91d9e3f1f2..9c54a5ef0ba7 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -2622,8 +2622,8 @@ P: Harald Welte P: Jozsef Kadlecsik P: Patrick McHardy M: kaber@trash.net -L: netfilter-devel@vger.kernel.org -L: netfilter@vger.kernel.org +L: netfilter-devel@lists.netfilter.org +L: netfilter@lists.netfilter.org (subscribers-only) L: coreteam@netfilter.org W: http://www.netfilter.org/ W: http://www.iptables.org/ @@ -2676,7 +2676,7 @@ M: jmorris@namei.org P: Hideaki YOSHIFUJI M: yoshfuji@linux-ipv6.org P: Patrick McHardy -M: kaber@trash.net +M: kaber@coreworks.de L: netdev@vger.kernel.org T: git kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6.git S: Maintained diff --git a/trunk/arch/x86_64/ia32/ia32entry.S b/trunk/arch/x86_64/ia32/ia32entry.S index 18b231810908..938278697e20 100644 --- a/trunk/arch/x86_64/ia32/ia32entry.S +++ b/trunk/arch/x86_64/ia32/ia32entry.S @@ -38,18 +38,6 @@ movq %rax,R8(%rsp) .endm - .macro LOAD_ARGS32 offset - movl \offset(%rsp),%r11d - movl \offset+8(%rsp),%r10d - movl \offset+16(%rsp),%r9d - movl \offset+24(%rsp),%r8d - movl \offset+40(%rsp),%ecx - movl \offset+48(%rsp),%edx - movl \offset+56(%rsp),%esi - movl \offset+64(%rsp),%edi - movl \offset+72(%rsp),%eax - .endm - .macro CFI_STARTPROC32 simple CFI_STARTPROC \simple CFI_UNDEFINED r8 @@ -164,7 +152,7 @@ sysenter_tracesys: movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ + LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST movl %ebp, %ebp /* no need to do an access_ok check here because rbp has been @@ -267,7 +255,7 @@ cstar_tracesys: movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ + LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST movl RSP-ARGOFFSET(%rsp), %r8d /* no need to do an access_ok check here because r8 has been @@ -346,7 +334,7 @@ ia32_tracesys: movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace_enter - LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */ + LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST jmp ia32_do_syscall END(ia32_syscall) diff --git a/trunk/arch/x86_64/kernel/ptrace.c b/trunk/arch/x86_64/kernel/ptrace.c index eea3702427b4..e83cc67155ac 100644 --- a/trunk/arch/x86_64/kernel/ptrace.c +++ b/trunk/arch/x86_64/kernel/ptrace.c @@ -232,6 +232,10 @@ static int putreg(struct task_struct *child, { unsigned long tmp; + /* Some code in the 64bit emulation may not be 64bit clean. + Don't take any chances. */ + if (test_tsk_thread_flag(child, TIF_IA32)) + value &= 0xffffffff; switch (regno) { case offsetof(struct user_regs_struct,fs): if (value && (value & 3) != 3) diff --git a/trunk/drivers/ata/ahci.c b/trunk/drivers/ata/ahci.c index c16820325d7b..06f212ff2b4f 100644 --- a/trunk/drivers/ata/ahci.c +++ b/trunk/drivers/ata/ahci.c @@ -418,12 +418,10 @@ static const struct pci_device_id ahci_pci_tbl[] = { /* ATI */ { PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */ - { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700/800 */ - { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700/800 */ - { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700/800 */ - { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700/800 */ - { PCI_VDEVICE(ATI, 0x4394), board_ahci_sb600 }, /* ATI SB700/800 */ - { PCI_VDEVICE(ATI, 0x4395), board_ahci_sb600 }, /* ATI SB700/800 */ + { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 IDE */ + { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700 AHCI */ + { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700 nraid5 */ + { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700 raid5 */ /* VIA */ { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */ diff --git a/trunk/drivers/ata/libata-core.c b/trunk/drivers/ata/libata-core.c index 772be09b4689..c43de9a710db 100644 --- a/trunk/drivers/ata/libata-core.c +++ b/trunk/drivers/ata/libata-core.c @@ -3778,9 +3778,6 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "Maxtor 6L250S0", "BANC1G10", ATA_HORKAGE_NONCQ }, { "Maxtor 6B200M0", "BANC1BM0", ATA_HORKAGE_NONCQ }, { "Maxtor 6B200M0", "BANC1B10", ATA_HORKAGE_NONCQ }, - { "Maxtor 7B250S0", "BANC1B70", ATA_HORKAGE_NONCQ, }, - { "Maxtor 7B300S0", "BANC1B70", ATA_HORKAGE_NONCQ }, - { "Maxtor 7V300F0", "VA111630", ATA_HORKAGE_NONCQ }, { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI", ATA_HORKAGE_NONCQ }, /* NCQ hard hangs device under heavier load, needs hard power cycle */ @@ -3797,7 +3794,6 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, }, { "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, }, { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, }, - { "ST3160812AS", "3.AD", ATA_HORKAGE_NONCQ, }, { "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, }, /* devices which puke on READ_NATIVE_MAX */ diff --git a/trunk/drivers/ata/libata-sff.c b/trunk/drivers/ata/libata-sff.c index 8023167bbbeb..1cce2198baaf 100644 --- a/trunk/drivers/ata/libata-sff.c +++ b/trunk/drivers/ata/libata-sff.c @@ -297,7 +297,7 @@ void ata_bmdma_start (struct ata_queued_cmd *qc) dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); - /* Strictly, one may wish to issue an ioread8() here, to + /* Strictly, one may wish to issue a readb() here, to * flush the mmio write. However, control also passes * to the hardware at this point, and it will interrupt * us when we are to resume control. So, in effect, @@ -307,9 +307,6 @@ void ata_bmdma_start (struct ata_queued_cmd *qc) * is expected, so I think it is best to not add a readb() * without first all the MMIO ATA cards/mobos. * Or maybe I'm just being paranoid. - * - * FIXME: The posting of this write means I/O starts are - * unneccessarily delayed for MMIO */ } diff --git a/trunk/drivers/ieee1394/ieee1394_core.c b/trunk/drivers/ieee1394/ieee1394_core.c index 98fd985a32ff..ee45259573c8 100644 --- a/trunk/drivers/ieee1394/ieee1394_core.c +++ b/trunk/drivers/ieee1394/ieee1394_core.c @@ -1273,7 +1273,7 @@ static void __exit ieee1394_cleanup(void) unregister_chrdev_region(IEEE1394_CORE_DEV, 256); } -module_init(ieee1394_init); +fs_initcall(ieee1394_init); /* same as ohci1394 */ module_exit(ieee1394_cleanup); /* Exported symbols */ diff --git a/trunk/drivers/ieee1394/ohci1394.c b/trunk/drivers/ieee1394/ohci1394.c index 372c5c16eb31..5667c8102efc 100644 --- a/trunk/drivers/ieee1394/ohci1394.c +++ b/trunk/drivers/ieee1394/ohci1394.c @@ -3537,5 +3537,7 @@ static int __init ohci1394_init(void) return pci_register_driver(&ohci1394_pci_driver); } -module_init(ohci1394_init); +/* Register before most other device drivers. + * Useful for remote debugging via physical DMA, e.g. using firescope. */ +fs_initcall(ohci1394_init); module_exit(ohci1394_cleanup); diff --git a/trunk/drivers/net/bnx2.c b/trunk/drivers/net/bnx2.c index 66eed22cbd21..854d80c330ec 100644 --- a/trunk/drivers/net/bnx2.c +++ b/trunk/drivers/net/bnx2.c @@ -54,8 +54,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.6.5" -#define DRV_MODULE_RELDATE "September 20, 2007" +#define DRV_MODULE_VERSION "1.6.4" +#define DRV_MODULE_RELDATE "August 3, 2007" #define RUN_AT(x) (jiffies + (x)) @@ -6727,8 +6727,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) } else if (CHIP_NUM(bp) == CHIP_NUM_5706 || CHIP_NUM(bp) == CHIP_NUM_5708) bp->phy_flags |= PHY_CRC_FIX_FLAG; - else if (CHIP_ID(bp) == CHIP_ID_5709_A0 || - CHIP_ID(bp) == CHIP_ID_5709_A1) + else if (CHIP_ID(bp) == CHIP_ID_5709_A0) bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG; if ((CHIP_ID(bp) == CHIP_ID_5708_A0) || diff --git a/trunk/drivers/net/myri10ge/myri10ge.c b/trunk/drivers/net/myri10ge/myri10ge.c index 556962f9612d..1c42266bf889 100644 --- a/trunk/drivers/net/myri10ge/myri10ge.c +++ b/trunk/drivers/net/myri10ge/myri10ge.c @@ -3094,12 +3094,9 @@ static void myri10ge_remove(struct pci_dev *pdev) } #define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E 0x0008 -#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9 0x0009 static struct pci_device_id myri10ge_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E)}, - {PCI_DEVICE - (PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9)}, {0}, }; diff --git a/trunk/drivers/net/phy/phy.c b/trunk/drivers/net/phy/phy.c index cb230f44d6fc..0cc4369cacba 100644 --- a/trunk/drivers/net/phy/phy.c +++ b/trunk/drivers/net/phy/phy.c @@ -409,7 +409,6 @@ int phy_mii_ioctl(struct phy_device *phydev, return 0; } -EXPORT_SYMBOL(phy_mii_ioctl); /** * phy_start_aneg - start auto-negotiation for this PHY device diff --git a/trunk/drivers/net/pppoe.c b/trunk/drivers/net/pppoe.c index 9b30cd600a64..0d7f570b9a54 100644 --- a/trunk/drivers/net/pppoe.c +++ b/trunk/drivers/net/pppoe.c @@ -879,7 +879,8 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb) dev->hard_header(skb, dev, ETH_P_PPP_SES, po->pppoe_pa.remote, NULL, data_len); - dev_queue_xmit(skb); + if (dev_queue_xmit(skb) < 0) + goto abort; return 1; diff --git a/trunk/drivers/net/pppol2tp.c b/trunk/drivers/net/pppol2tp.c index abe91cb595f4..266e8b38fe10 100644 --- a/trunk/drivers/net/pppol2tp.c +++ b/trunk/drivers/net/pppol2tp.c @@ -491,46 +491,44 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) u16 hdrflags; u16 tunnel_id, session_id; int length; - int offset; + struct udphdr *uh; tunnel = pppol2tp_sock_to_tunnel(sock); if (tunnel == NULL) goto error; - /* UDP always verifies the packet length. */ - __skb_pull(skb, sizeof(struct udphdr)); - /* Short packet? */ - if (!pskb_may_pull(skb, 12)) { + if (skb->len < sizeof(struct udphdr)) { PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO, "%s: recv short packet (len=%d)\n", tunnel->name, skb->len); goto error; } /* Point to L2TP header */ - ptr = skb->data; + ptr = skb->data + sizeof(struct udphdr); /* Get L2TP header flags */ hdrflags = ntohs(*(__be16*)ptr); /* Trace packet contents, if enabled */ if (tunnel->debug & PPPOL2TP_MSG_DATA) { - length = min(16u, skb->len); - if (!pskb_may_pull(skb, length)) - goto error; - printk(KERN_DEBUG "%s: recv: ", tunnel->name); - offset = 0; - do { - printk(" %02X", ptr[offset]); - } while (++offset < length); - + for (length = 0; length < 16; length++) + printk(" %02X", ptr[length]); printk("\n"); } /* Get length of L2TP packet */ - length = skb->len; + uh = (struct udphdr *) skb_transport_header(skb); + length = ntohs(uh->len) - sizeof(struct udphdr); + + /* Too short? */ + if (length < 12) { + PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO, + "%s: recv short L2TP packet (len=%d)\n", tunnel->name, length); + goto error; + } /* If type is control packet, it is handled by userspace. */ if (hdrflags & L2TP_HDRFLAG_T) { @@ -608,6 +606,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) "%s: recv data has no seq numbers when required. " "Discarding\n", session->name); session->stats.rx_seq_discards++; + session->stats.rx_errors++; goto discard; } @@ -626,6 +625,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) "%s: recv data has no seq numbers when required. " "Discarding\n", session->name); session->stats.rx_seq_discards++; + session->stats.rx_errors++; goto discard; } @@ -634,14 +634,10 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) } /* If offset bit set, skip it. */ - if (hdrflags & L2TP_HDRFLAG_O) { - offset = ntohs(*(__be16 *)ptr); - skb->transport_header += 2 + offset; - if (!pskb_may_pull(skb, skb_transport_offset(skb) + 2)) - goto discard; - } + if (hdrflags & L2TP_HDRFLAG_O) + ptr += 2 + ntohs(*(__be16 *) ptr); - __skb_pull(skb, skb_transport_offset(skb)); + skb_pull(skb, ptr - skb->data); /* Skip PPP header, if present. In testing, Microsoft L2TP clients * don't send the PPP header (PPP header compression enabled), but @@ -677,6 +673,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) */ if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) { session->stats.rx_seq_discards++; + session->stats.rx_errors++; PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, "%s: oos pkt %hu len %d discarded, " "waiting for %hu, reorder_q_len=%d\n", @@ -701,7 +698,6 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) return 0; discard: - session->stats.rx_errors++; kfree_skb(skb); sock_put(session->sock); @@ -962,6 +958,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) int data_len = skb->len; struct inet_sock *inet; __wsum csum = 0; + struct sk_buff *skb2 = NULL; struct udphdr *uh; unsigned int len; @@ -992,30 +989,41 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) */ headroom = NET_SKB_PAD + sizeof(struct iphdr) + sizeof(struct udphdr) + hdr_len + sizeof(ppph); - if (skb_cow_head(skb, headroom)) - goto abort; + if (skb_headroom(skb) < headroom) { + skb2 = skb_realloc_headroom(skb, headroom); + if (skb2 == NULL) + goto abort; + } else + skb2 = skb; + + /* Check that the socket has room */ + if (atomic_read(&sk_tun->sk_wmem_alloc) < sk_tun->sk_sndbuf) + skb_set_owner_w(skb2, sk_tun); + else + goto discard; /* Setup PPP header */ - __skb_push(skb, sizeof(ppph)); - skb->data[0] = ppph[0]; - skb->data[1] = ppph[1]; + skb_push(skb2, sizeof(ppph)); + skb2->data[0] = ppph[0]; + skb2->data[1] = ppph[1]; /* Setup L2TP header */ - pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len)); + skb_push(skb2, hdr_len); + pppol2tp_build_l2tp_header(session, skb2->data); /* Setup UDP header */ inet = inet_sk(sk_tun); - __skb_push(skb, sizeof(*uh)); - skb_reset_transport_header(skb); - uh = udp_hdr(skb); + skb_push(skb2, sizeof(struct udphdr)); + skb_reset_transport_header(skb2); + uh = (struct udphdr *) skb2->data; uh->source = inet->sport; uh->dest = inet->dport; uh->len = htons(sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len); uh->check = 0; - /* *BROKEN* Calculate UDP checksum if configured to do so */ + /* Calculate UDP checksum if configured to do so */ if (sk_tun->sk_no_check != UDP_CSUM_NOXMIT) - csum = udp_csum_outgoing(sk_tun, skb); + csum = udp_csum_outgoing(sk_tun, skb2); /* Debug */ if (session->send_seq) @@ -1028,7 +1036,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) if (session->debug & PPPOL2TP_MSG_DATA) { int i; - unsigned char *datap = skb->data; + unsigned char *datap = skb2->data; printk(KERN_DEBUG "%s: xmit:", session->name); for (i = 0; i < data_len; i++) { @@ -1041,18 +1049,18 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) printk("\n"); } - memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); - IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | - IPSKB_REROUTED); - nf_reset(skb); + memset(&(IPCB(skb2)->opt), 0, sizeof(IPCB(skb2)->opt)); + IPCB(skb2)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | + IPSKB_REROUTED); + nf_reset(skb2); /* Get routing info from the tunnel socket */ - dst_release(skb->dst); - skb->dst = sk_dst_get(sk_tun); + dst_release(skb2->dst); + skb2->dst = sk_dst_get(sk_tun); /* Queue the packet to IP for output */ - len = skb->len; - rc = ip_queue_xmit(skb, 1); + len = skb2->len; + rc = ip_queue_xmit(skb2, 1); /* Update stats */ if (rc >= 0) { @@ -1065,12 +1073,17 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) session->stats.tx_errors++; } - return 1; - -abort: /* Free the original skb */ kfree_skb(skb); + return 1; + +discard: + /* Free the new skb. Caller will free original skb. */ + if (skb2 != skb) + kfree_skb(skb2); +abort: + return 0; } /***************************************************************************** @@ -1313,14 +1326,12 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id, goto err; } - sk = sock->sk; - /* Quick sanity checks */ - err = -EPROTONOSUPPORT; - if (sk->sk_protocol != IPPROTO_UDP) { + err = -ESOCKTNOSUPPORT; + if (sock->type != SOCK_DGRAM) { PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR, - "tunl %hu: fd %d wrong protocol, got %d, expected %d\n", - tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP); + "tunl %hu: fd %d wrong type, got %d, expected %d\n", + tunnel_id, fd, sock->type, SOCK_DGRAM); goto err; } err = -EAFNOSUPPORT; @@ -1332,6 +1343,7 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id, } err = -ENOTCONN; + sk = sock->sk; /* Check if this socket has already been prepped */ tunnel = (struct pppol2tp_tunnel *)sk->sk_user_data; diff --git a/trunk/drivers/net/sky2.c b/trunk/drivers/net/sky2.c index eaffe551d1d8..5d812de65d90 100644 --- a/trunk/drivers/net/sky2.c +++ b/trunk/drivers/net/sky2.c @@ -51,7 +51,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.18" +#define DRV_VERSION "1.17" #define PFX DRV_NAME " " /* @@ -118,15 +118,12 @@ static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4351) }, /* 88E8036 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) }, /* 88E8038 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, /* 88E8039 */ - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4354) }, /* 88E8040 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4356) }, /* 88EC033 */ - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x435A) }, /* 88E8048 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) }, /* 88E8052 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, /* 88E8053 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, /* 88E8055 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, /* 88E8056 */ - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4365) }, /* 88E8070 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */ @@ -150,7 +147,6 @@ static const char *yukon2_name[] = { "Extreme", /* 0xb5 */ "EC", /* 0xb6 */ "FE", /* 0xb7 */ - "FE+", /* 0xb8 */ }; static void sky2_set_multicast(struct net_device *dev); @@ -221,7 +217,8 @@ static void sky2_power_on(struct sky2_hw *hw) else sky2_write8(hw, B2_Y2_CLK_GATE, 0); - if (hw->flags & SKY2_HW_ADV_POWER_CTL) { + if (hw->chip_id == CHIP_ID_YUKON_EC_U || + hw->chip_id == CHIP_ID_YUKON_EX) { u32 reg; sky2_pci_write32(hw, PCI_DEV_REG3, 0); @@ -314,8 +311,10 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) struct sky2_port *sky2 = netdev_priv(hw->dev[port]); u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg; - if (sky2->autoneg == AUTONEG_ENABLE && - !(hw->flags & SKY2_HW_NEWER_PHY)) { + if (sky2->autoneg == AUTONEG_ENABLE + && !(hw->chip_id == CHIP_ID_YUKON_XL + || hw->chip_id == CHIP_ID_YUKON_EC_U + || hw->chip_id == CHIP_ID_YUKON_EX)) { u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK | @@ -335,7 +334,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); if (sky2_is_copper(hw)) { - if (!(hw->flags & SKY2_HW_GIGABIT)) { + if (hw->chip_id == CHIP_ID_YUKON_FE) { /* enable automatic crossover */ ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO) >> 1; } else { @@ -347,7 +346,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* downshift on PHY 88E1112 and 88E1149 is changed */ if (sky2->autoneg == AUTONEG_ENABLE - && (hw->flags & SKY2_HW_NEWER_PHY)) { + && (hw->chip_id == CHIP_ID_YUKON_XL + || hw->chip_id == CHIP_ID_YUKON_EC_U + || hw->chip_id == CHIP_ID_YUKON_EX)) { /* set downshift counter to 3x and enable downshift */ ctrl &= ~PHY_M_PC_DSC_MSK; ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA; @@ -363,7 +364,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); /* special setup for PHY 88E1112 Fiber */ - if (hw->chip_id == CHIP_ID_YUKON_XL && (hw->flags & SKY2_HW_FIBRE_PHY)) { + if (hw->chip_id == CHIP_ID_YUKON_XL && !sky2_is_copper(hw)) { pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); /* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */ @@ -454,7 +455,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gma_write16(hw, port, GM_GP_CTRL, reg); - if (hw->flags & SKY2_HW_GIGABIT) + if (hw->chip_id != CHIP_ID_YUKON_FE) gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000); gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv); @@ -478,23 +479,6 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl); break; - case CHIP_ID_YUKON_FE_P: - /* Enable Link Partner Next Page */ - ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); - ctrl |= PHY_M_PC_ENA_LIP_NP; - - /* disable Energy Detect and enable scrambler */ - ctrl &= ~(PHY_M_PC_ENA_ENE_DT | PHY_M_PC_DIS_SCRAMB); - gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); - - /* set LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED */ - ctrl = PHY_M_FELP_LED2_CTRL(LED_PAR_CTRL_ACT_BL) | - PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_LINK) | - PHY_M_FELP_LED0_CTRL(LED_PAR_CTRL_SPEED); - - gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl); - break; - case CHIP_ID_YUKON_XL: pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); @@ -564,13 +548,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* set page register to 0 */ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0); - } else if (hw->chip_id == CHIP_ID_YUKON_FE_P && - hw->chip_rev == CHIP_REV_YU_FE2_A0) { - /* apply workaround for integrated resistors calibration */ - gm_phy_write(hw, port, PHY_MARV_PAGE_ADDR, 17); - gm_phy_write(hw, port, PHY_MARV_PAGE_DATA, 0x3f60); } else if (hw->chip_id != CHIP_ID_YUKON_EX) { - /* no effect on Yukon-XL */ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) { @@ -691,25 +669,25 @@ static void sky2_wol_init(struct sky2_port *sky2) static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port) { - struct net_device *dev = hw->dev[port]; - - if (dev->mtu <= ETH_DATA_LEN) + if (hw->chip_id == CHIP_ID_YUKON_EX && hw->chip_rev != CHIP_REV_YU_EX_A0) { sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_JUMBO_DIS | TX_STFW_ENA); - - else if (hw->chip_id != CHIP_ID_YUKON_EC_U) - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_STFW_ENA | TX_JUMBO_ENA); - else { - /* set Tx GMAC FIFO Almost Empty Threshold */ - sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), - (ECU_JUMBO_WM << 16) | ECU_AE_THR); + TX_STFW_ENA | + (hw->dev[port]->mtu > ETH_DATA_LEN) ? TX_JUMBO_ENA : TX_JUMBO_DIS); + } else { + if (hw->dev[port]->mtu > ETH_DATA_LEN) { + /* set Tx GMAC FIFO Almost Empty Threshold */ + sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR), + (ECU_JUMBO_WM << 16) | ECU_AE_THR); - sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), - TX_JUMBO_ENA | TX_STFW_DIS); + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), + TX_JUMBO_ENA | TX_STFW_DIS); - /* Can't do offload because of lack of store/forward */ - dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM); + /* Can't do offload because of lack of store/forward */ + hw->dev[port]->features &= ~(NETIF_F_TSO | NETIF_F_SG + | NETIF_F_ALL_CSUM); + } else + sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), + TX_JUMBO_DIS | TX_STFW_ENA); } } @@ -795,8 +773,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) /* Configure Rx MAC FIFO */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON; - if (hw->chip_id == CHIP_ID_YUKON_EX || - hw->chip_id == CHIP_ID_YUKON_FE_P) + if (hw->chip_id == CHIP_ID_YUKON_EX) rx_reg |= GMF_RX_OVER_ON; sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg); @@ -805,18 +782,13 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR); /* Set threshold to 0xa (64 bytes) + 1 to workaround pause bug */ - reg = RX_GMF_FL_THR_DEF + 1; - /* Another magic mystery workaround from sk98lin */ - if (hw->chip_id == CHIP_ID_YUKON_FE_P && - hw->chip_rev == CHIP_REV_YU_FE2_A0) - reg = 0x178; - sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), reg); + sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF+1); /* Configure Tx MAC FIFO */ sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); - if (!(hw->flags & SKY2_HW_RAMBUFFER)) { + if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) { sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8); sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8); @@ -995,15 +967,19 @@ static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re) */ static void rx_set_checksum(struct sky2_port *sky2) { - struct sky2_rx_le *le = sky2_next_rx(sky2); + struct sky2_rx_le *le; - le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN); - le->ctrl = 0; - le->opcode = OP_TCPSTART | HW_OWNER; + if (sky2->hw->chip_id != CHIP_ID_YUKON_EX) { + le = sky2_next_rx(sky2); + le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN); + le->ctrl = 0; + le->opcode = OP_TCPSTART | HW_OWNER; + + sky2_write32(sky2->hw, + Q_ADDR(rxqaddr[sky2->port], Q_CSR), + sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); + } - sky2_write32(sky2->hw, - Q_ADDR(rxqaddr[sky2->port], Q_CSR), - sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } /* @@ -1199,8 +1175,7 @@ static int sky2_rx_start(struct sky2_port *sky2) sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1); - if (!(hw->flags & SKY2_HW_NEW_LE)) - rx_set_checksum(sky2); + rx_set_checksum(sky2); /* Space needed for frame data + headers rounded up */ size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8); @@ -1271,7 +1246,7 @@ static int sky2_up(struct net_device *dev) struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; - u32 imask; + u32 ramsize, imask; int cap, err = -ENOMEM; struct net_device *otherdev = hw->dev[sky2->port^1]; @@ -1326,12 +1301,12 @@ static int sky2_up(struct net_device *dev) sky2_mac_init(hw, port); - if (hw->flags & SKY2_HW_RAMBUFFER) { - /* Register is number of 4K blocks on internal RAM buffer. */ - u32 ramsize = sky2_read8(hw, B2_E_0) * 4; - u32 rxspace; + /* Register is number of 4K blocks on internal RAM buffer. */ + ramsize = sky2_read8(hw, B2_E_0) * 4; + printk(KERN_INFO PFX "%s: ram buffer %dK\n", dev->name, ramsize); - printk(KERN_DEBUG PFX "%s: ram buffer %dK\n", dev->name, ramsize); + if (ramsize > 0) { + u32 rxspace; if (ramsize < 16) rxspace = ramsize / 2; @@ -1461,15 +1436,13 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* Check for TCP Segmentation Offload */ mss = skb_shinfo(skb)->gso_size; if (mss != 0) { - - if (!(hw->flags & SKY2_HW_NEW_LE)) + if (hw->chip_id != CHIP_ID_YUKON_EX) mss += ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb); if (mss != sky2->tx_last_mss) { le = get_tx_le(sky2); le->addr = cpu_to_le32(mss); - - if (hw->flags & SKY2_HW_NEW_LE) + if (hw->chip_id == CHIP_ID_YUKON_EX) le->opcode = OP_MSS | HW_OWNER; else le->opcode = OP_LRGLEN | HW_OWNER; @@ -1495,7 +1468,8 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* Handle TCP checksum offload */ if (skb->ip_summed == CHECKSUM_PARTIAL) { /* On Yukon EX (some versions) encoding change. */ - if (hw->flags & SKY2_HW_AUTO_TX_SUM) + if (hw->chip_id == CHIP_ID_YUKON_EX + && hw->chip_rev != CHIP_REV_YU_EX_B0) ctrl |= CALSUM; /* auto checksum */ else { const unsigned offset = skb_transport_offset(skb); @@ -1648,6 +1622,9 @@ static int sky2_down(struct net_device *dev) if (netif_msg_ifdown(sky2)) printk(KERN_INFO PFX "%s: disabling interface\n", dev->name); + if (netif_carrier_ok(dev) && --hw->active == 0) + del_timer(&hw->watchdog_timer); + /* Stop more packets from being queued */ netif_stop_queue(dev); @@ -1731,15 +1708,11 @@ static int sky2_down(struct net_device *dev) static u16 sky2_phy_speed(const struct sky2_hw *hw, u16 aux) { - if (hw->flags & SKY2_HW_FIBRE_PHY) + if (!sky2_is_copper(hw)) return SPEED_1000; - if (!(hw->flags & SKY2_HW_GIGABIT)) { - if (aux & PHY_M_PS_SPEED_100) - return SPEED_100; - else - return SPEED_10; - } + if (hw->chip_id == CHIP_ID_YUKON_FE) + return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10; switch (aux & PHY_M_PS_SPEED_MSK) { case PHY_M_PS_SPEED_1000: @@ -1772,13 +1745,17 @@ static void sky2_link_up(struct sky2_port *sky2) netif_carrier_on(sky2->netdev); - mod_timer(&hw->watchdog_timer, jiffies + 1); + if (hw->active++ == 0) + mod_timer(&hw->watchdog_timer, jiffies + 1); + /* Turn on link LED */ sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF); - if (hw->flags & SKY2_HW_NEWER_PHY) { + if (hw->chip_id == CHIP_ID_YUKON_XL + || hw->chip_id == CHIP_ID_YUKON_EC_U + || hw->chip_id == CHIP_ID_YUKON_EX) { u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); u16 led = PHY_M_LEDC_LOS_CTRL(1); /* link active */ @@ -1823,6 +1800,11 @@ static void sky2_link_down(struct sky2_port *sky2) netif_carrier_off(sky2->netdev); + /* Stop watchdog if both ports are not active */ + if (--hw->active == 0) + del_timer(&hw->watchdog_timer); + + /* Turn on link LED */ sky2_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF); @@ -1865,7 +1847,7 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) /* Since the pause result bits seem to in different positions on * different chips. look at registers. */ - if (hw->flags & SKY2_HW_FIBRE_PHY) { + if (!sky2_is_copper(hw)) { /* Shift for bits in fiber PHY */ advert &= ~(ADVERTISE_PAUSE_CAP|ADVERTISE_PAUSE_ASYM); lpa &= ~(LPA_PAUSE_CAP|LPA_PAUSE_ASYM); @@ -1976,9 +1958,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) return -EINVAL; - if (new_mtu > ETH_DATA_LEN && - (hw->chip_id == CHIP_ID_YUKON_FE || - hw->chip_id == CHIP_ID_YUKON_FE_P)) + if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_FE) return -EINVAL; if (!netif_running(dev)) { @@ -1995,7 +1975,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) synchronize_irq(hw->pdev->irq); - if (!(hw->flags & SKY2_HW_RAMBUFFER)) + if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) sky2_set_tx_stfwd(hw, port); ctl = gma_read16(hw, port, GM_GP_CTRL); @@ -2123,13 +2103,6 @@ static struct sk_buff *sky2_receive(struct net_device *dev, struct sky2_port *sky2 = netdev_priv(dev); struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next; struct sk_buff *skb = NULL; - u16 count = (status & GMR_FS_LEN) >> 16; - -#ifdef SKY2_VLAN_TAG_USED - /* Account for vlan tag */ - if (sky2->vlgrp && (status & GMR_FS_VLAN)) - count -= VLAN_HLEN; -#endif if (unlikely(netif_msg_rx_status(sky2))) printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n", @@ -2144,8 +2117,7 @@ static struct sk_buff *sky2_receive(struct net_device *dev, if (!(status & GMR_FS_RX_OK)) goto resubmit; - /* if length reported by DMA does not match PHY, packet was truncated */ - if (length != count) + if (status >> 16 != length) goto len_mismatch; if (length < copybreak) @@ -2161,10 +2133,6 @@ static struct sk_buff *sky2_receive(struct net_device *dev, /* Truncation of overlength packets causes PHY length to not match MAC length */ ++sky2->net_stats.rx_length_errors; - if (netif_msg_rx_err(sky2) && net_ratelimit()) - pr_info(PFX "%s: rx length mismatch: length %d status %#x\n", - dev->name, length, status); - goto resubmit; error: ++sky2->net_stats.rx_errors; @@ -2234,7 +2202,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) } /* This chip reports checksum status differently */ - if (hw->flags & SKY2_HW_NEW_LE) { + if (hw->chip_id == CHIP_ID_YUKON_EX) { if (sky2->rx_csum && (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) && (le->css & CSS_TCPUDPCSOK)) @@ -2275,14 +2243,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do) if (!sky2->rx_csum) break; - /* If this happens then driver assuming wrong format */ - if (unlikely(hw->flags & SKY2_HW_NEW_LE)) { - if (net_ratelimit()) - printk(KERN_NOTICE "%s: unexpected" - " checksum status\n", - dev->name); + if (hw->chip_id == CHIP_ID_YUKON_EX) break; - } /* Both checksum counters are programmed to start at * the same offset, so unless there is a problem they @@ -2474,72 +2436,20 @@ static void sky2_le_error(struct sky2_hw *hw, unsigned port, sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_IRQ_CHK); } -static int sky2_rx_hung(struct net_device *dev) -{ - struct sky2_port *sky2 = netdev_priv(dev); - struct sky2_hw *hw = sky2->hw; - unsigned port = sky2->port; - unsigned rxq = rxqaddr[port]; - u32 mac_rp = sky2_read32(hw, SK_REG(port, RX_GMF_RP)); - u8 mac_lev = sky2_read8(hw, SK_REG(port, RX_GMF_RLEV)); - u8 fifo_rp = sky2_read8(hw, Q_ADDR(rxq, Q_RP)); - u8 fifo_lev = sky2_read8(hw, Q_ADDR(rxq, Q_RL)); - - /* If idle and MAC or PCI is stuck */ - if (sky2->check.last == dev->last_rx && - ((mac_rp == sky2->check.mac_rp && - mac_lev != 0 && mac_lev >= sky2->check.mac_lev) || - /* Check if the PCI RX hang */ - (fifo_rp == sky2->check.fifo_rp && - fifo_lev != 0 && fifo_lev >= sky2->check.fifo_lev))) { - printk(KERN_DEBUG PFX "%s: hung mac %d:%d fifo %d (%d:%d)\n", - dev->name, mac_lev, mac_rp, fifo_lev, fifo_rp, - sky2_read8(hw, Q_ADDR(rxq, Q_WP))); - return 1; - } else { - sky2->check.last = dev->last_rx; - sky2->check.mac_rp = mac_rp; - sky2->check.mac_lev = mac_lev; - sky2->check.fifo_rp = fifo_rp; - sky2->check.fifo_lev = fifo_lev; - return 0; - } -} - +/* Check for lost IRQ once a second */ static void sky2_watchdog(unsigned long arg) { struct sky2_hw *hw = (struct sky2_hw *) arg; - struct net_device *dev; - /* Check for lost IRQ once a second */ if (sky2_read32(hw, B0_ISRC)) { - dev = hw->dev[0]; + struct net_device *dev = hw->dev[0]; + if (__netif_rx_schedule_prep(dev)) __netif_rx_schedule(dev); - } else { - int i, active = 0; - - for (i = 0; i < hw->ports; i++) { - dev = hw->dev[i]; - if (!netif_running(dev)) - continue; - ++active; - - /* For chips with Rx FIFO, check if stuck */ - if ((hw->flags & SKY2_HW_RAMBUFFER) && - sky2_rx_hung(dev)) { - pr_info(PFX "%s: receiver hang detected\n", - dev->name); - schedule_work(&hw->restart_work); - return; - } - } - - if (active == 0) - return; } - mod_timer(&hw->watchdog_timer, round_jiffies(jiffies + HZ)); + if (hw->active > 0) + mod_timer(&hw->watchdog_timer, round_jiffies(jiffies + HZ)); } /* Hardware/software error handling */ @@ -2636,25 +2546,17 @@ static void sky2_netpoll(struct net_device *dev) #endif /* Chip internal frequency for clock calculations */ -static u32 sky2_mhz(const struct sky2_hw *hw) +static inline u32 sky2_mhz(const struct sky2_hw *hw) { switch (hw->chip_id) { case CHIP_ID_YUKON_EC: case CHIP_ID_YUKON_EC_U: case CHIP_ID_YUKON_EX: - return 125; - + return 125; /* 125 Mhz */ case CHIP_ID_YUKON_FE: - return 100; - - case CHIP_ID_YUKON_FE_P: - return 50; - - case CHIP_ID_YUKON_XL: - return 156; - - default: - BUG(); + return 100; /* 100 Mhz */ + default: /* YUKON_XL */ + return 156; /* 156 Mhz */ } } @@ -2679,62 +2581,23 @@ static int __devinit sky2_init(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_RST_CLR); hw->chip_id = sky2_read8(hw, B2_CHIP_ID); - hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4; - - switch(hw->chip_id) { - case CHIP_ID_YUKON_XL: - hw->flags = SKY2_HW_GIGABIT - | SKY2_HW_NEWER_PHY - | SKY2_HW_RAMBUFFER; - break; - - case CHIP_ID_YUKON_EC_U: - hw->flags = SKY2_HW_GIGABIT - | SKY2_HW_NEWER_PHY - | SKY2_HW_ADV_POWER_CTL; - break; - - case CHIP_ID_YUKON_EX: - hw->flags = SKY2_HW_GIGABIT - | SKY2_HW_NEWER_PHY - | SKY2_HW_NEW_LE - | SKY2_HW_ADV_POWER_CTL; - - /* New transmit checksum */ - if (hw->chip_rev != CHIP_REV_YU_EX_B0) - hw->flags |= SKY2_HW_AUTO_TX_SUM; - break; - - case CHIP_ID_YUKON_EC: - /* This rev is really old, and requires untested workarounds */ - if (hw->chip_rev == CHIP_REV_YU_EC_A1) { - dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n"); - return -EOPNOTSUPP; - } - hw->flags = SKY2_HW_GIGABIT | SKY2_HW_RAMBUFFER; - break; - - case CHIP_ID_YUKON_FE: - hw->flags = SKY2_HW_RAMBUFFER; - break; - - case CHIP_ID_YUKON_FE_P: - hw->flags = SKY2_HW_NEWER_PHY - | SKY2_HW_NEW_LE - | SKY2_HW_AUTO_TX_SUM - | SKY2_HW_ADV_POWER_CTL; - break; - default: + if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) { dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n", hw->chip_id); return -EOPNOTSUPP; } - hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); - if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P') - hw->flags |= SKY2_HW_FIBRE_PHY; + hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4; + /* This rev is really old, and requires untested workarounds */ + if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) { + dev_err(&hw->pdev->dev, "unsupported revision Yukon-%s (0x%x) rev %d\n", + yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], + hw->chip_id, hw->chip_rev); + return -EOPNOTSUPP; + } + hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); hw->ports = 1; t8 = sky2_read8(hw, B2_Y2_HW_RES); if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) { @@ -2928,9 +2791,7 @@ static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) sky2->wol = wol->wolopts; - if (hw->chip_id == CHIP_ID_YUKON_EC_U || - hw->chip_id == CHIP_ID_YUKON_EX || - hw->chip_id == CHIP_ID_YUKON_FE_P) + if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) sky2_write32(hw, B0_CTST, sky2->wol ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF); @@ -2948,7 +2809,7 @@ static u32 sky2_supported_modes(const struct sky2_hw *hw) | SUPPORTED_100baseT_Full | SUPPORTED_Autoneg | SUPPORTED_TP; - if (hw->flags & SKY2_HW_GIGABIT) + if (hw->chip_id != CHIP_ID_YUKON_FE) modes |= SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; return modes; @@ -2968,6 +2829,13 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) ecmd->supported = sky2_supported_modes(hw); ecmd->phy_address = PHY_ADDR_MARV; if (sky2_is_copper(hw)) { + ecmd->supported = SUPPORTED_10baseT_Half + | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half + | SUPPORTED_100baseT_Full + | SUPPORTED_1000baseT_Half + | SUPPORTED_1000baseT_Full + | SUPPORTED_Autoneg | SUPPORTED_TP; ecmd->port = PORT_TP; ecmd->speed = sky2->speed; } else { @@ -3923,13 +3791,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->hw = hw; sky2->msg_enable = netif_msg_init(debug, default_msg); - /* This chip has hardware problems that generates - * bogus PHY receive status so by default shut up the message. - */ - if (hw->chip_id == CHIP_ID_YUKON_FE_P && - hw->chip_rev == CHIP_REV_YU_FE2_A0) - sky2->msg_enable &= ~NETIF_MSG_RX_ERR; - /* Auto speed and flow control */ sky2->autoneg = AUTONEG_ENABLE; sky2->flow_mode = FC_BOTH; @@ -3985,7 +3846,7 @@ static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id) return IRQ_NONE; if (status & Y2_IS_IRQ_SW) { - hw->flags |= SKY2_HW_USE_MSI; + hw->msi = 1; wake_up(&hw->msi_wait); sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ); } @@ -4013,9 +3874,9 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ); sky2_read8(hw, B0_CTST); - wait_event_timeout(hw->msi_wait, (hw->flags & SKY2_HW_USE_MSI), HZ/10); + wait_event_timeout(hw->msi_wait, hw->msi, HZ/10); - if (!(hw->flags & SKY2_HW_USE_MSI)) { + if (!hw->msi) { /* MSI test failed, go back to INTx mode */ dev_info(&pdev->dev, "No interrupt generated using MSI, " "switching to INTx mode.\n"); @@ -4148,8 +4009,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, goto err_out_free_netdev; } - err = request_irq(pdev->irq, sky2_intr, - (hw->flags & SKY2_HW_USE_MSI) ? 0 : IRQF_SHARED, + err = request_irq(pdev->irq, sky2_intr, hw->msi ? 0 : IRQF_SHARED, dev->name, hw); if (err) { dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq); @@ -4182,7 +4042,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, return 0; err_out_unregister: - if (hw->flags & SKY2_HW_USE_MSI) + if (hw->msi) pci_disable_msi(pdev); unregister_netdev(dev); err_out_free_netdev: @@ -4231,7 +4091,7 @@ static void __devexit sky2_remove(struct pci_dev *pdev) sky2_read8(hw, B0_CTST); free_irq(pdev->irq, hw); - if (hw->flags & SKY2_HW_USE_MSI) + if (hw->msi) pci_disable_msi(pdev); pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); pci_release_regions(pdev); @@ -4299,9 +4159,7 @@ static int sky2_resume(struct pci_dev *pdev) pci_enable_wake(pdev, PCI_D0, 0); /* Re-enable all clocks */ - if (hw->chip_id == CHIP_ID_YUKON_EX || - hw->chip_id == CHIP_ID_YUKON_EC_U || - hw->chip_id == CHIP_ID_YUKON_FE_P) + if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U) sky2_pci_write32(hw, PCI_DEV_REG3, 0); sky2_reset(hw); diff --git a/trunk/drivers/net/sky2.h b/trunk/drivers/net/sky2.h index 69cd98400fe6..72e12b7cfa40 100644 --- a/trunk/drivers/net/sky2.h +++ b/trunk/drivers/net/sky2.h @@ -470,24 +470,18 @@ enum { CHIP_ID_YUKON_EX = 0xb5, /* Chip ID for YUKON-2 Extreme */ CHIP_ID_YUKON_EC = 0xb6, /* Chip ID for YUKON-2 EC */ CHIP_ID_YUKON_FE = 0xb7, /* Chip ID for YUKON-2 FE */ - CHIP_ID_YUKON_FE_P = 0xb8, /* Chip ID for YUKON-2 FE+ */ -}; -enum yukon_ec_rev { + CHIP_REV_YU_EC_A1 = 0, /* Chip Rev. for Yukon-EC A1/A0 */ CHIP_REV_YU_EC_A2 = 1, /* Chip Rev. for Yukon-EC A2 */ CHIP_REV_YU_EC_A3 = 2, /* Chip Rev. for Yukon-EC A3 */ -}; -enum yukon_ec_u_rev { + CHIP_REV_YU_EC_U_A0 = 1, CHIP_REV_YU_EC_U_A1 = 2, CHIP_REV_YU_EC_U_B0 = 3, -}; -enum yukon_fe_rev { + CHIP_REV_YU_FE_A1 = 1, CHIP_REV_YU_FE_A2 = 2, -}; -enum yukon_fe_p_rev { - CHIP_REV_YU_FE2_A0 = 0, + }; enum yukon_ex_rev { CHIP_REV_YU_EX_A0 = 1, @@ -1674,7 +1668,7 @@ enum { /* Receive Frame Status Encoding */ enum { - GMR_FS_LEN = 0x7fff<<16, /* Bit 30..16: Rx Frame Length */ + GMR_FS_LEN = 0xffff<<16, /* Bit 31..16: Rx Frame Length */ GMR_FS_VLAN = 1<<13, /* VLAN Packet */ GMR_FS_JABBER = 1<<12, /* Jabber Packet */ GMR_FS_UN_SIZE = 1<<11, /* Undersize Packet */ @@ -1735,10 +1729,6 @@ enum { GMF_RX_CTRL_DEF = GMF_OPER_ON | GMF_RX_F_FL_ON, }; -/* TX_GMF_EA 32 bit Tx GMAC FIFO End Address */ -enum { - TX_DYN_WM_ENA = 3, /* Yukon-FE+ specific */ -}; /* TX_GMF_CTRL_T 32 bit Tx GMAC FIFO Control/Test */ enum { @@ -2027,14 +2017,6 @@ struct sky2_port { u16 rx_tag; struct vlan_group *vlgrp; #endif - struct { - unsigned long last; - u32 mac_rp; - u8 mac_lev; - u8 fifo_rp; - u8 fifo_lev; - } check; - dma_addr_t rx_le_map; dma_addr_t tx_le_map; @@ -2058,20 +2040,12 @@ struct sky2_hw { void __iomem *regs; struct pci_dev *pdev; struct net_device *dev[2]; - unsigned long flags; -#define SKY2_HW_USE_MSI 0x00000001 -#define SKY2_HW_FIBRE_PHY 0x00000002 -#define SKY2_HW_GIGABIT 0x00000004 -#define SKY2_HW_NEWER_PHY 0x00000008 -#define SKY2_HW_RAMBUFFER 0x00000010 /* chip has RAM FIFO */ -#define SKY2_HW_NEW_LE 0x00000020 /* new LSOv2 format */ -#define SKY2_HW_AUTO_TX_SUM 0x00000040 /* new IP decode for Tx */ -#define SKY2_HW_ADV_POWER_CTL 0x00000080 /* additional PHY power regs */ u8 chip_id; u8 chip_rev; u8 pmd_type; u8 ports; + u8 active; struct sky2_status_le *st_le; u32 st_idx; @@ -2079,12 +2053,13 @@ struct sky2_hw { struct timer_list watchdog_timer; struct work_struct restart_work; + int msi; wait_queue_head_t msi_wait; }; static inline int sky2_is_copper(const struct sky2_hw *hw) { - return !(hw->flags & SKY2_HW_FIBRE_PHY); + return !(hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P'); } /* Register accessor for memory mapped device */ diff --git a/trunk/fs/exec.c b/trunk/fs/exec.c index 073b0b8c6d05..c21a8cc06277 100644 --- a/trunk/fs/exec.c +++ b/trunk/fs/exec.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -783,6 +784,7 @@ static int de_thread(struct task_struct *tsk) * and we can just re-use it all. */ if (atomic_read(&oldsighand->count) <= 1) { + signalfd_detach(tsk); exit_itimers(sig); return 0; } @@ -921,6 +923,7 @@ static int de_thread(struct task_struct *tsk) sig->flags = 0; no_thread_group: + signalfd_detach(tsk); exit_itimers(sig); if (leader) release_task(leader); diff --git a/trunk/fs/ocfs2/file.c b/trunk/fs/ocfs2/file.c index 7e34e66159c6..f3bc3658e7a5 100644 --- a/trunk/fs/ocfs2/file.c +++ b/trunk/fs/ocfs2/file.c @@ -491,8 +491,8 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb, goto leave; } - status = ocfs2_claim_clusters(osb, handle, data_ac, 1, - &bit_off, &num_bits); + status = __ocfs2_claim_clusters(osb, handle, data_ac, 1, + clusters_to_add, &bit_off, &num_bits); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); diff --git a/trunk/fs/ocfs2/localalloc.c b/trunk/fs/ocfs2/localalloc.c index 545f7892cdf3..de984d272576 100644 --- a/trunk/fs/ocfs2/localalloc.c +++ b/trunk/fs/ocfs2/localalloc.c @@ -524,13 +524,12 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb, int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb, handle_t *handle, struct ocfs2_alloc_context *ac, - u32 min_bits, + u32 bits_wanted, u32 *bit_off, u32 *num_bits) { int status, start; struct inode *local_alloc_inode; - u32 bits_wanted; void *bitmap; struct ocfs2_dinode *alloc; struct ocfs2_local_alloc *la; @@ -538,7 +537,6 @@ int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb, mlog_entry_void(); BUG_ON(ac->ac_which != OCFS2_AC_USE_LOCAL); - bits_wanted = ac->ac_bits_wanted - ac->ac_bits_given; local_alloc_inode = ac->ac_inode; alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data; la = OCFS2_LOCAL_ALLOC(alloc); diff --git a/trunk/fs/ocfs2/localalloc.h b/trunk/fs/ocfs2/localalloc.h index 385a10152f9c..3f76631e110c 100644 --- a/trunk/fs/ocfs2/localalloc.h +++ b/trunk/fs/ocfs2/localalloc.h @@ -48,7 +48,7 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb, int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb, handle_t *handle, struct ocfs2_alloc_context *ac, - u32 min_bits, + u32 bits_wanted, u32 *bit_off, u32 *num_bits); diff --git a/trunk/fs/ocfs2/suballoc.c b/trunk/fs/ocfs2/suballoc.c index d9c5c9fcb30f..8f09f5235e3a 100644 --- a/trunk/fs/ocfs2/suballoc.c +++ b/trunk/fs/ocfs2/suballoc.c @@ -1486,21 +1486,21 @@ static inline void ocfs2_block_to_cluster_group(struct inode *inode, * contig. allocation, set to '1' to indicate we can deal with extents * of any size. */ -int ocfs2_claim_clusters(struct ocfs2_super *osb, - handle_t *handle, - struct ocfs2_alloc_context *ac, - u32 min_clusters, - u32 *cluster_start, - u32 *num_clusters) +int __ocfs2_claim_clusters(struct ocfs2_super *osb, + handle_t *handle, + struct ocfs2_alloc_context *ac, + u32 min_clusters, + u32 max_clusters, + u32 *cluster_start, + u32 *num_clusters) { int status; - unsigned int bits_wanted = ac->ac_bits_wanted - ac->ac_bits_given; + unsigned int bits_wanted = max_clusters; u64 bg_blkno = 0; u16 bg_bit_off; mlog_entry_void(); - BUG_ON(!ac); BUG_ON(ac->ac_bits_given >= ac->ac_bits_wanted); BUG_ON(ac->ac_which != OCFS2_AC_USE_LOCAL @@ -1557,6 +1557,19 @@ int ocfs2_claim_clusters(struct ocfs2_super *osb, return status; } +int ocfs2_claim_clusters(struct ocfs2_super *osb, + handle_t *handle, + struct ocfs2_alloc_context *ac, + u32 min_clusters, + u32 *cluster_start, + u32 *num_clusters) +{ + unsigned int bits_wanted = ac->ac_bits_wanted - ac->ac_bits_given; + + return __ocfs2_claim_clusters(osb, handle, ac, min_clusters, + bits_wanted, cluster_start, num_clusters); +} + static inline int ocfs2_block_group_clear_bits(handle_t *handle, struct inode *alloc_inode, struct ocfs2_group_desc *bg, diff --git a/trunk/fs/ocfs2/suballoc.h b/trunk/fs/ocfs2/suballoc.h index f212dc01a84b..cafe93703095 100644 --- a/trunk/fs/ocfs2/suballoc.h +++ b/trunk/fs/ocfs2/suballoc.h @@ -85,6 +85,17 @@ int ocfs2_claim_clusters(struct ocfs2_super *osb, u32 min_clusters, u32 *cluster_start, u32 *num_clusters); +/* + * Use this variant of ocfs2_claim_clusters to specify a maxiumum + * number of clusters smaller than the allocation reserved. + */ +int __ocfs2_claim_clusters(struct ocfs2_super *osb, + handle_t *handle, + struct ocfs2_alloc_context *ac, + u32 min_clusters, + u32 max_clusters, + u32 *cluster_start, + u32 *num_clusters); int ocfs2_free_suballoc_bits(handle_t *handle, struct inode *alloc_inode, diff --git a/trunk/fs/signalfd.c b/trunk/fs/signalfd.c index aefb0be07942..a8e293d30034 100644 --- a/trunk/fs/signalfd.c +++ b/trunk/fs/signalfd.c @@ -11,10 +11,8 @@ * Now using anonymous inode source. * Thanks to Oleg Nesterov for useful code review and suggestions. * More comments and suggestions from Arnd Bergmann. - * Sat May 19, 2007: Davi E. M. Arnaut + * Sat May 19, 2007: Davi E. M. Arnaut * Retrieve multiple signals with one read() call - * Sun Jul 15, 2007: Davide Libenzi - * Attach to the sighand only during read() and poll(). */ #include @@ -29,12 +27,102 @@ #include struct signalfd_ctx { + struct list_head lnk; + wait_queue_head_t wqh; sigset_t sigmask; + struct task_struct *tsk; }; +struct signalfd_lockctx { + struct task_struct *tsk; + unsigned long flags; +}; + +/* + * Tries to acquire the sighand lock. We do not increment the sighand + * use count, and we do not even pin the task struct, so we need to + * do it inside an RCU read lock, and we must be prepared for the + * ctx->tsk going to NULL (in signalfd_deliver()), and for the sighand + * being detached. We return 0 if the sighand has been detached, or + * 1 if we were able to pin the sighand lock. + */ +static int signalfd_lock(struct signalfd_ctx *ctx, struct signalfd_lockctx *lk) +{ + struct sighand_struct *sighand = NULL; + + rcu_read_lock(); + lk->tsk = rcu_dereference(ctx->tsk); + if (likely(lk->tsk != NULL)) + sighand = lock_task_sighand(lk->tsk, &lk->flags); + rcu_read_unlock(); + + if (!sighand) + return 0; + + if (!ctx->tsk) { + unlock_task_sighand(lk->tsk, &lk->flags); + return 0; + } + + if (lk->tsk->tgid == current->tgid) + lk->tsk = current; + + return 1; +} + +static void signalfd_unlock(struct signalfd_lockctx *lk) +{ + unlock_task_sighand(lk->tsk, &lk->flags); +} + +/* + * This must be called with the sighand lock held. + */ +void signalfd_deliver(struct task_struct *tsk, int sig) +{ + struct sighand_struct *sighand = tsk->sighand; + struct signalfd_ctx *ctx, *tmp; + + BUG_ON(!sig); + list_for_each_entry_safe(ctx, tmp, &sighand->signalfd_list, lnk) { + /* + * We use a negative signal value as a way to broadcast that the + * sighand has been orphaned, so that we can notify all the + * listeners about this. Remember the ctx->sigmask is inverted, + * so if the user is interested in a signal, that corresponding + * bit will be zero. + */ + if (sig < 0) { + if (ctx->tsk == tsk) { + ctx->tsk = NULL; + list_del_init(&ctx->lnk); + wake_up(&ctx->wqh); + } + } else { + if (!sigismember(&ctx->sigmask, sig)) + wake_up(&ctx->wqh); + } + } +} + +static void signalfd_cleanup(struct signalfd_ctx *ctx) +{ + struct signalfd_lockctx lk; + + /* + * This is tricky. If the sighand is gone, we do not need to remove + * context from the list, the list itself won't be there anymore. + */ + if (signalfd_lock(ctx, &lk)) { + list_del(&ctx->lnk); + signalfd_unlock(&lk); + } + kfree(ctx); +} + static int signalfd_release(struct inode *inode, struct file *file) { - kfree(file->private_data); + signalfd_cleanup(file->private_data); return 0; } @@ -42,15 +130,23 @@ static unsigned int signalfd_poll(struct file *file, poll_table *wait) { struct signalfd_ctx *ctx = file->private_data; unsigned int events = 0; + struct signalfd_lockctx lk; - poll_wait(file, ¤t->sighand->signalfd_wqh, wait); + poll_wait(file, &ctx->wqh, wait); - spin_lock_irq(¤t->sighand->siglock); - if (next_signal(¤t->pending, &ctx->sigmask) || - next_signal(¤t->signal->shared_pending, - &ctx->sigmask)) + /* + * Let the caller get a POLLIN in this case, ala socket recv() when + * the peer disconnects. + */ + if (signalfd_lock(ctx, &lk)) { + if ((lk.tsk == current && + next_signal(&lk.tsk->pending, &ctx->sigmask) > 0) || + next_signal(&lk.tsk->signal->shared_pending, + &ctx->sigmask) > 0) + events |= POLLIN; + signalfd_unlock(&lk); + } else events |= POLLIN; - spin_unlock_irq(¤t->sighand->siglock); return events; } @@ -123,46 +219,59 @@ static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info, int nonblock) { ssize_t ret; + struct signalfd_lockctx lk; DECLARE_WAITQUEUE(wait, current); - spin_lock_irq(¤t->sighand->siglock); - ret = dequeue_signal(current, &ctx->sigmask, info); + if (!signalfd_lock(ctx, &lk)) + return 0; + + ret = dequeue_signal(lk.tsk, &ctx->sigmask, info); switch (ret) { case 0: if (!nonblock) break; ret = -EAGAIN; default: - spin_unlock_irq(¤t->sighand->siglock); + signalfd_unlock(&lk); return ret; } - add_wait_queue(¤t->sighand->signalfd_wqh, &wait); + add_wait_queue(&ctx->wqh, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); - ret = dequeue_signal(current, &ctx->sigmask, info); + ret = dequeue_signal(lk.tsk, &ctx->sigmask, info); + signalfd_unlock(&lk); if (ret != 0) break; if (signal_pending(current)) { ret = -ERESTARTSYS; break; } - spin_unlock_irq(¤t->sighand->siglock); schedule(); - spin_lock_irq(¤t->sighand->siglock); + ret = signalfd_lock(ctx, &lk); + if (unlikely(!ret)) { + /* + * Let the caller read zero byte, ala socket + * recv() when the peer disconnect. This test + * must be done before doing a dequeue_signal(), + * because if the sighand has been orphaned, + * the dequeue_signal() call is going to crash + * because ->sighand will be long gone. + */ + break; + } } - spin_unlock_irq(¤t->sighand->siglock); - remove_wait_queue(¤t->sighand->signalfd_wqh, &wait); + remove_wait_queue(&ctx->wqh, &wait); __set_current_state(TASK_RUNNING); return ret; } /* - * Returns a multiple of the size of a "struct signalfd_siginfo", or a negative - * error code. The "count" parameter must be at least the size of a - * "struct signalfd_siginfo". + * Returns either the size of a "struct signalfd_siginfo", or zero if the + * sighand we are attached to, has been orphaned. The "count" parameter + * must be at least the size of a "struct signalfd_siginfo". */ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -178,6 +287,7 @@ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count, return -EINVAL; siginfo = (struct signalfd_siginfo __user *) buf; + do { ret = signalfd_dequeue(ctx, &info, nonblock); if (unlikely(ret <= 0)) @@ -190,7 +300,7 @@ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count, nonblock = 1; } while (--count); - return total ? total: ret; + return total ? total : ret; } static const struct file_operations signalfd_fops = { @@ -199,13 +309,20 @@ static const struct file_operations signalfd_fops = { .read = signalfd_read, }; +/* + * Create a file descriptor that is associated with our signal + * state. We can pass it around to others if we want to, but + * it will always be _our_ signal state. + */ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask) { int error; sigset_t sigmask; struct signalfd_ctx *ctx; + struct sighand_struct *sighand; struct file *file; struct inode *inode; + struct signalfd_lockctx lk; if (sizemask != sizeof(sigset_t) || copy_from_user(&sigmask, user_mask, sizeof(sigmask))) @@ -218,7 +335,17 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas if (!ctx) return -ENOMEM; + init_waitqueue_head(&ctx->wqh); ctx->sigmask = sigmask; + ctx->tsk = current->group_leader; + + sighand = current->sighand; + /* + * Add this fd to the list of signal listeners. + */ + spin_lock_irq(&sighand->siglock); + list_add_tail(&ctx->lnk, &sighand->signalfd_list); + spin_unlock_irq(&sighand->siglock); /* * When we call this, the initialization must be complete, since @@ -237,18 +364,23 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas fput(file); return -EINVAL; } - spin_lock_irq(¤t->sighand->siglock); - ctx->sigmask = sigmask; - spin_unlock_irq(¤t->sighand->siglock); - - wake_up(¤t->sighand->signalfd_wqh); + /* + * We need to be prepared of the fact that the sighand this fd + * is attached to, has been detched. In that case signalfd_lock() + * will return 0, and we'll just skip setting the new mask. + */ + if (signalfd_lock(ctx, &lk)) { + ctx->sigmask = sigmask; + signalfd_unlock(&lk); + } + wake_up(&ctx->wqh); fput(file); } return ufd; err_fdalloc: - kfree(ctx); + signalfd_cleanup(ctx); return error; } diff --git a/trunk/include/linux/init_task.h b/trunk/include/linux/init_task.h index f8abfa349ef9..cab741c2d603 100644 --- a/trunk/include/linux/init_task.h +++ b/trunk/include/linux/init_task.h @@ -86,7 +86,7 @@ extern struct nsproxy init_nsproxy; .count = ATOMIC_INIT(1), \ .action = { { { .sa_handler = NULL, } }, }, \ .siglock = __SPIN_LOCK_UNLOCKED(sighand.siglock), \ - .signalfd_wqh = __WAIT_QUEUE_HEAD_INITIALIZER(sighand.signalfd_wqh), \ + .signalfd_list = LIST_HEAD_INIT(sighand.signalfd_list), \ } extern struct group_info init_groups; diff --git a/trunk/include/linux/sched.h b/trunk/include/linux/sched.h index a01ac6dd5f5e..3de79016f2a6 100644 --- a/trunk/include/linux/sched.h +++ b/trunk/include/linux/sched.h @@ -438,7 +438,7 @@ struct sighand_struct { atomic_t count; struct k_sigaction action[_NSIG]; spinlock_t siglock; - wait_queue_head_t signalfd_wqh; + struct list_head signalfd_list; }; struct pacct_struct { diff --git a/trunk/include/linux/signalfd.h b/trunk/include/linux/signalfd.h index 4c9ff0910ae0..510429495690 100644 --- a/trunk/include/linux/signalfd.h +++ b/trunk/include/linux/signalfd.h @@ -45,17 +45,49 @@ struct signalfd_siginfo { #ifdef CONFIG_SIGNALFD /* - * Deliver the signal to listening signalfd. + * Deliver the signal to listening signalfd. This must be called + * with the sighand lock held. Same are the following that end up + * calling signalfd_deliver(). + */ +void signalfd_deliver(struct task_struct *tsk, int sig); + +/* + * No need to fall inside signalfd_deliver() if no signal listeners + * are available. */ static inline void signalfd_notify(struct task_struct *tsk, int sig) { - if (unlikely(waitqueue_active(&tsk->sighand->signalfd_wqh))) - wake_up(&tsk->sighand->signalfd_wqh); + if (unlikely(!list_empty(&tsk->sighand->signalfd_list))) + signalfd_deliver(tsk, sig); +} + +/* + * The signal -1 is used to notify the signalfd that the sighand + * is on its way to be detached. + */ +static inline void signalfd_detach_locked(struct task_struct *tsk) +{ + if (unlikely(!list_empty(&tsk->sighand->signalfd_list))) + signalfd_deliver(tsk, -1); +} + +static inline void signalfd_detach(struct task_struct *tsk) +{ + struct sighand_struct *sighand = tsk->sighand; + + if (unlikely(!list_empty(&sighand->signalfd_list))) { + spin_lock_irq(&sighand->siglock); + signalfd_deliver(tsk, -1); + spin_unlock_irq(&sighand->siglock); + } } #else /* CONFIG_SIGNALFD */ -static inline void signalfd_notify(struct task_struct *tsk, int sig) { } +#define signalfd_deliver(t, s) do { } while (0) +#define signalfd_notify(t, s) do { } while (0) +#define signalfd_detach_locked(t) do { } while (0) +#define signalfd_detach(t) do { } while (0) #endif /* CONFIG_SIGNALFD */ diff --git a/trunk/kernel/exit.c b/trunk/kernel/exit.c index 993369ee94d1..06b24b3aa370 100644 --- a/trunk/kernel/exit.c +++ b/trunk/kernel/exit.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -85,6 +86,14 @@ static void __exit_signal(struct task_struct *tsk) sighand = rcu_dereference(tsk->sighand); spin_lock(&sighand->siglock); + /* + * Notify that this sighand has been detached. This must + * be called with the tsk->sighand lock held. Also, this + * access tsk->sighand internally, so it must be called + * before tsk->sighand is reset. + */ + signalfd_detach_locked(tsk); + posix_cpu_timers_exit(tsk); if (atomic_dec_and_test(&sig->count)) posix_cpu_timers_exit_group(tsk); diff --git a/trunk/kernel/fork.c b/trunk/kernel/fork.c index 33f12f48684a..7332e236d367 100644 --- a/trunk/kernel/fork.c +++ b/trunk/kernel/fork.c @@ -1438,7 +1438,7 @@ static void sighand_ctor(void *data, struct kmem_cache *cachep, struct sighand_struct *sighand = data; spin_lock_init(&sighand->siglock); - init_waitqueue_head(&sighand->signalfd_wqh); + INIT_LIST_HEAD(&sighand->signalfd_list); } void __init proc_caches_init(void) diff --git a/trunk/kernel/signal.c b/trunk/kernel/signal.c index 9fb91a32edda..3169bed0b4d0 100644 --- a/trunk/kernel/signal.c +++ b/trunk/kernel/signal.c @@ -378,7 +378,8 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) /* We only dequeue private signals from ourselves, we don't let * signalfd steal them */ - signr = __dequeue_signal(&tsk->pending, mask, info); + if (likely(tsk == current)) + signr = __dequeue_signal(&tsk->pending, mask, info); if (!signr) { signr = __dequeue_signal(&tsk->signal->shared_pending, mask, info); @@ -406,7 +407,8 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) } } } - recalc_sigpending(); + if (likely(tsk == current)) + recalc_sigpending(); if (signr && unlikely(sig_kernel_stop(signr))) { /* * Set a marker that we have dequeued a stop signal. Our @@ -423,7 +425,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) tsk->signal->flags |= SIGNAL_STOP_DEQUEUED; } - if (signr && + if (signr && likely(tsk == current) && ((info->si_code & __SI_MASK) == __SI_TIMER) && info->si_sys_private){ /* diff --git a/trunk/net/netfilter/nfnetlink_log.c b/trunk/net/netfilter/nfnetlink_log.c index 2351533a8507..e185a5b55913 100644 --- a/trunk/net/netfilter/nfnetlink_log.c +++ b/trunk/net/netfilter/nfnetlink_log.c @@ -58,6 +58,7 @@ struct nfulnl_instance { unsigned int qlen; /* number of nlmsgs in skb */ struct sk_buff *skb; /* pre-allocatd skb */ + struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */ struct timer_list timer; int peer_pid; /* PID of the peer process */ @@ -344,12 +345,10 @@ static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size, static int __nfulnl_send(struct nfulnl_instance *inst) { - int status = -1; + int status; if (inst->qlen > 1) - NLMSG_PUT(inst->skb, 0, 0, - NLMSG_DONE, - sizeof(struct nfgenmsg)); + inst->lastnlh->nlmsg_type = NLMSG_DONE; status = nfnetlink_unicast(inst->skb, inst->peer_pid, MSG_DONTWAIT); if (status < 0) { @@ -359,8 +358,8 @@ __nfulnl_send(struct nfulnl_instance *inst) inst->qlen = 0; inst->skb = NULL; + inst->lastnlh = NULL; -nlmsg_failure: return status; } @@ -539,6 +538,7 @@ __build_packet_message(struct nfulnl_instance *inst, } nlh->nlmsg_len = inst->skb->tail - old_tail; + inst->lastnlh = nlh; return 0; nlmsg_failure: @@ -644,8 +644,7 @@ nfulnl_log_packet(unsigned int pf, } if (inst->qlen >= qthreshold || - (inst->skb && size > - skb_tailroom(inst->skb) - sizeof(struct nfgenmsg))) { + (inst->skb && size > skb_tailroom(inst->skb))) { /* either the queue len is too high or we don't have * enough room in the skb left. flush to userspace. */ UDEBUG("flushing old skb\n"); diff --git a/trunk/net/sched/sch_sfq.c b/trunk/net/sched/sch_sfq.c index 3a23e30bc79e..957957309859 100644 --- a/trunk/net/sched/sch_sfq.c +++ b/trunk/net/sched/sch_sfq.c @@ -270,7 +270,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc* sch) q->tail = x; } } - if (++sch->q.qlen <= q->limit) { + if (++sch->q.qlen < q->limit-1) { sch->bstats.bytes += skb->len; sch->bstats.packets++; return 0; @@ -306,7 +306,7 @@ sfq_requeue(struct sk_buff *skb, struct Qdisc* sch) q->tail = x; } } - if (++sch->q.qlen <= q->limit) { + if (++sch->q.qlen < q->limit - 1) { sch->qstats.requeues++; return 0; } @@ -391,10 +391,10 @@ static int sfq_change(struct Qdisc *sch, struct rtattr *opt) q->quantum = ctl->quantum ? : psched_mtu(sch->dev); q->perturb_period = ctl->perturb_period*HZ; if (ctl->limit) - q->limit = min_t(u32, ctl->limit, SFQ_DEPTH - 2); + q->limit = min_t(u32, ctl->limit, SFQ_DEPTH); qlen = sch->q.qlen; - while (sch->q.qlen > q->limit) + while (sch->q.qlen >= q->limit-1) sfq_drop(sch); qdisc_tree_decrease_qlen(sch, qlen - sch->q.qlen); @@ -423,7 +423,7 @@ static int sfq_init(struct Qdisc *sch, struct rtattr *opt) q->dep[i+SFQ_DEPTH].next = i+SFQ_DEPTH; q->dep[i+SFQ_DEPTH].prev = i+SFQ_DEPTH; } - q->limit = SFQ_DEPTH - 2; + q->limit = SFQ_DEPTH; q->max_depth = 0; q->tail = SFQ_DEPTH; if (opt == NULL) { diff --git a/trunk/net/sunrpc/svcsock.c b/trunk/net/sunrpc/svcsock.c index 036ab520df21..1a899924023f 100644 --- a/trunk/net/sunrpc/svcsock.c +++ b/trunk/net/sunrpc/svcsock.c @@ -1110,8 +1110,7 @@ svc_tcp_accept(struct svc_sock *svsk) serv->sv_name); printk(KERN_NOTICE "%s: last TCP connect from %s\n", - serv->sv_name, __svc_print_addr(sin, - buf, sizeof(buf))); + serv->sv_name, buf); } /* * Always select the oldest socket. It's not fair,