Index: linux-2.4.24/drivers/net/netconsole.c =================================================================== Index: bglio/drivers/net/netconsole.c =================================================================== --- bglio.orig/drivers/net/netconsole.c 2004-05-07 15:50:22.000000000 -0700 +++ bglio/drivers/net/netconsole.c 2004-05-07 17:15:28.000000000 -0700 @@ -12,6 +12,8 @@ * * 2001-09-17 started by Ingo Molnar. * 2002-03-14 simultaneous syslog packet option by Michael K. Johnson + * 2003-10-30 Add sysrq command processing by Wangdi + * */ /**************************************************************** @@ -51,6 +53,7 @@ #include #include #include +#include "netconsole.h" static struct net_device *netconsole_dev; static u16 source_port, netdump_target_port, netlog_target_port, syslog_target_port; @@ -62,12 +65,11 @@ static unsigned int mhz = 500, idle_timeout; static unsigned long long mhz_cycles, jiffy_cycles; -#include "netconsole.h" #define MAX_UDP_CHUNK 1460 #define MAX_PRINT_CHUNK (MAX_UDP_CHUNK-HEADER_LEN) -#define DEBUG 0 +#define DEBUG 0 #if DEBUG # define Dprintk(x...) printk(KERN_INFO x) #else @@ -187,6 +189,22 @@ } } } +void (*irqfunc)(int, void *, struct pt_regs *); + +static void netdump_poll(struct net_device *dev) +{ + int budget = 1; + + disable_irq(dev->irq); + + irqfunc(dev->irq, dev, 0); + + if(dev->poll && test_bit(__LINK_STATE_RX_SCHED, &dev->state)) + dev->poll(dev, &budget); + + enable_irq(dev->irq); + +} static struct sk_buff * alloc_netconsole_skb(struct net_device *dev, int len, int reserve) { @@ -209,7 +227,7 @@ once = 0; } Dprintk("alloc skb: polling controller ...\n"); - dev->poll_controller(dev); + netdump_poll(dev); goto repeat; } } @@ -231,7 +249,7 @@ spin_unlock(&dev->xmit_lock); Dprintk("xmit skb: polling controller ...\n"); - dev->poll_controller(dev); + netdump_poll(dev); zap_completion_queue(); goto repeat_poll; } @@ -426,18 +444,79 @@ static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED; static unsigned int log_offset; +static int thread_stopped = 0; +/*Interrupt function for netdump */ +static int sysrq_mode = 0; +static int stop_sysrq_thread = 0; +#define Set_Sysrq_mode() (sysrq_mode = 1) +#define Clear_Sysrq_mode() (sysrq_mode = 0) +static char send_cache[MAX_PRINT_CHUNK]; +static unsigned int send_cache_pos = 0; +wait_queue_head_t sysrq_thread_queue; +wait_queue_head_t sysrq_thread_waiter_queue; + +#define SEND_MSG_BUFFER(buf, len) \ +do \ +{ \ + reply_t reply; \ + unsigned int flags; \ + __save_flags(flags); \ + __cli(); \ + reply.code = REPLY_LOG; \ + reply.nr = 0; \ + reply.info = 0; \ + spin_lock(&sequence_lock); \ + send_netlog_skb(dev, buf, len, &reply); \ + spin_unlock(&sequence_lock); \ + __restore_flags(flags); \ +}while(0); + +void netconsole_do_sysrq(req_t *req) +{ + struct pt_regs regs; + struct net_device *dev = netconsole_dev; + + if (!dev) + return; + Set_Sysrq_mode(); + get_current_regs(®s); + handle_sysrq((int)req->from, ®s, NULL); + + if (send_cache_pos != 0){ + SEND_MSG_BUFFER(send_cache, send_cache_pos); + memset(send_cache, 0, MAX_PRINT_CHUNK); + send_cache_pos = 0; + } + + Clear_Sysrq_mode(); +} static void write_netconsole_msg(struct console *con, const char *msg0, unsigned int msg_len) { int len, left, i; struct net_device *dev; const char *msg = msg0; reply_t reply; - + dev = netconsole_dev; if (!dev || netdump_mode) return; - - if (dev->poll_controller && netif_running(dev)) { + if (sysrq_mode){ + unsigned long total_len = send_cache_pos + msg_len; + unsigned long left_len = msg_len; + while (total_len >= MAX_PRINT_CHUNK){ + unsigned long send_len = MAX_PRINT_CHUNK - send_cache_pos; + memcpy(send_cache + send_cache_pos, msg, send_len); + SEND_MSG_BUFFER(send_cache, MAX_PRINT_CHUNK); + send_cache_pos = 0; + total_len -= MAX_PRINT_CHUNK; + left_len -= send_len; + } + if (left_len > 0){ + memcpy(send_cache + send_cache_pos, msg + (msg_len -left_len), left_len); + send_cache_pos += left_len; + } + return; + }else if (netif_running(dev)) { unsigned long flags; __save_flags(flags); @@ -567,8 +646,6 @@ req_t *req; struct net_device *dev; - if (!netdump_mode) - return NET_RX_SUCCESS; #if DEBUG { static int packet_count; @@ -722,8 +799,16 @@ Dprintk("... netdump from: %08x.\n", req->from); Dprintk("... netdump to: %08x.\n", req->to); - add_new_req(req); + if (netdump_mode) + add_new_req(req); + else if (req->command == COMM_SYSRQ){ + add_new_req(req); + wake_up(&sysrq_thread_queue); + return NET_RX_DROP; + } out: + if (!netdump_mode) + return NET_RX_SUCCESS; return NET_RX_DROP; } @@ -763,6 +848,7 @@ kunmap_atomic(kaddr, KM_NETDUMP); } + /* * This function waits for the client to acknowledge the receipt * of the netdump startup reply, with the possibility of packets @@ -792,7 +878,7 @@ // wait 1 sec. udelay(100); Dprintk("handshake: polling controller ...\n"); - dev->poll_controller(dev); + netdump_poll(dev); zap_completion_queue(); req = get_new_req(); if (req) @@ -884,6 +970,7 @@ */ spin_lock_init(&dev->xmit_lock); +#ifdef __i386__ esp = (unsigned long) ((char *)regs + sizeof (struct pt_regs)); ss = __KERNEL_DS; if (regs->xcs & 3) { @@ -893,6 +980,7 @@ myregs = *regs; myregs.esp = esp; myregs.xss = (myregs.xss & 0xffff0000) | ss; +#endif rdtscll(t0); @@ -904,7 +992,7 @@ while (netdump_mode) { __cli(); Dprintk("main netdump loop: polling controller ...\n"); - dev->poll_controller(dev); + netdump_poll(dev); zap_completion_queue(); #if !CLI __sti(); @@ -1009,6 +1097,32 @@ printk("NETDUMP END!\n"); __restore_flags(flags); } +static int netconsole_sysrq_schedule(void *arg) +{ + struct task_struct *tsk = current; + + sprintf(tsk->comm, "sysrq_schedule"); + sigfillset(&tsk->blocked); + + /* main loop */ + thread_stopped = 0; + for (;;) { + wait_event_interruptible(sysrq_thread_queue, + !list_empty(&request_list) || stop_sysrq_thread); + while (!list_empty(&request_list)) { + req_t *req = get_new_req(); + if (req->command == COMM_SYSRQ) + netconsole_do_sysrq(req); + } + if (stop_sysrq_thread) + break; + wake_up(&sysrq_thread_waiter_queue); + } + thread_stopped = 1; + wake_up(&sysrq_thread_waiter_queue); + return 0; +} + static char *dev; static int netdump_target_eth_byte0 = 255; @@ -1087,11 +1201,12 @@ static struct console netconsole = { flags: CON_ENABLED, write: write_netconsole_msg }; - static int init_netconsole(void) { struct net_device *ndev = NULL; struct in_device *in_dev; + struct irqaction *action; + int rc = 0; printk(KERN_INFO "netlog: using network device <%s>\n", dev); // this will be valid once the device goes up. @@ -1101,10 +1216,6 @@ printk(KERN_ERR "netlog: network device %s does not exist, aborting.\n", dev); return -1; } - if (!ndev->poll_controller) { - printk(KERN_ERR "netlog: %s's network driver does not implement netlogging yet, aborting.\n", dev); - return -1; - } in_dev = in_dev_get(ndev); if (!in_dev) { printk(KERN_ERR "netlog: network device %s is not an IP protocol device, aborting.\n", dev); @@ -1137,8 +1248,6 @@ if (!netdump_target_ip && !netlog_target_ip && !syslog_target_ip) { printk(KERN_ERR "netlog: target_ip parameter not specified, aborting.\n"); return -1; - } - if (netdump_target_ip) { #define IP(x) ((unsigned char *)&netdump_target_ip)[x] printk(KERN_INFO "netlog: using netdump target IP %u.%u.%u.%u\n", IP(3), IP(2), IP(1), IP(0)); @@ -1214,12 +1323,27 @@ mhz_cycles = (unsigned long long)mhz * 1000000ULL; jiffy_cycles = (unsigned long long)mhz * (1000000/HZ); - - INIT_LIST_HEAD(&request_list); - + ndev->rx_hook = netconsole_rx_hook; netdump_func = netconsole_netdump; netconsole_dev = ndev; + /* find irq function of the ndev*/ + action=find_irq_action(ndev->irq, ndev); + if (!action) { + printk(KERN_ERR "couldn't find irq handler for <%s>", dev); + return -1; + } + irqfunc = action->handler; + + stop_sysrq_thread = 0; + INIT_LIST_HEAD(&request_list); + init_waitqueue_head(&sysrq_thread_queue); + init_waitqueue_head(&sysrq_thread_waiter_queue); + if ((rc = kernel_thread(netconsole_sysrq_schedule, NULL, 0)) < 0 ){ + printk(KERN_ERR "Can not start netconsole sysrq thread: rc %d\n", rc); + return -1; + } + #define STARTUP_MSG "[...network console startup...]\n" write_netconsole_msg(NULL, STARTUP_MSG, strlen(STARTUP_MSG)); @@ -1230,7 +1354,11 @@ static void cleanup_netconsole(void) { - printk(KERN_INFO "netlog: network logging shut down.\n"); + stop_sysrq_thread = 1; + + wake_up(&sysrq_thread_queue); + wait_event(sysrq_thread_waiter_queue, thread_stopped); + printk(KERN_INFO"netlog: network logging shut down.\n"); unregister_console(&netconsole); #define SHUTDOWN_MSG "[...network console shutdown...]\n" Index: bglio/drivers/net/netconsole.h =================================================================== --- bglio.orig/drivers/net/netconsole.h 2004-05-07 15:50:22.000000000 -0700 +++ bglio/drivers/net/netconsole.h 2004-05-07 17:11:01.000000000 -0700 @@ -29,7 +29,7 @@ * ****************************************************************/ -#define NETCONSOLE_VERSION 0x04 +#define NETCONSOLE_VERSION 0x03 enum netdump_commands { COMM_NONE = 0, @@ -42,6 +42,8 @@ COMM_START_NETDUMP_ACK = 7, COMM_GET_REGS = 8, COMM_SHOW_STATE = 9, + COMM_START_WRITE_NETDUMP_ACK = 10, + COMM_SYSRQ = 11, }; #define NETDUMP_REQ_SIZE (8+4*4) @@ -69,6 +71,7 @@ REPLY_REGS = 10, REPLY_MAGIC = 11, REPLY_SHOW_STATE = 12, + REPLY_SYSRQ = 13, }; typedef struct netdump_reply_s { @@ -78,4 +81,24 @@ } reply_t; #define HEADER_LEN (1 + sizeof(reply_t)) - +/* for netconsole */ +static inline void get_current_regs(struct pt_regs *regs) +{ +#ifdef __i386__ + __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx)); + __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx)); + __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx)); + __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi)); + __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi)); + __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp)); + __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax)); + __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp)); + __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss)); + __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs)); + __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds)); + __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes)); + __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags)); + regs->eip = (unsigned long)current_text_addr(); +#endif +} + Index: bglio/arch/i386/kernel/irq.c =================================================================== --- bglio.orig/arch/i386/kernel/irq.c 2004-05-07 15:50:17.000000000 -0700 +++ bglio/arch/i386/kernel/irq.c 2004-05-07 17:11:01.000000000 -0700 @@ -182,7 +182,20 @@ return 0; } +struct irqaction *find_irq_action(unsigned int irq, void *dev_id) +{ + struct irqaction *a, *r=0; + spin_lock_irq(&irq_desc[irq].lock); + for(a=irq_desc[irq].action; a; a=a->next) { + if(a->dev_id == dev_id) { + r=a; + break; + } + } + spin_unlock_irq(&irq_desc[irq].lock); + return r; +} /* * Global interrupt locks for SMP. Allow interrupts to come in on any Index: bglio/arch/i386/kernel/i386_ksyms.c =================================================================== --- bglio.orig/arch/i386/kernel/i386_ksyms.c 2004-05-07 15:50:22.000000000 -0700 +++ bglio/arch/i386/kernel/i386_ksyms.c 2004-05-07 17:11:01.000000000 -0700 @@ -66,6 +66,7 @@ EXPORT_SYMBOL(iounmap); EXPORT_SYMBOL(enable_irq); EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(find_irq_action); EXPORT_SYMBOL(disable_irq_nosync); EXPORT_SYMBOL(probe_irq_mask); EXPORT_SYMBOL(kernel_thread); @@ -186,7 +187,6 @@ EXPORT_SYMBOL(edd); EXPORT_SYMBOL(eddnr); #endif - EXPORT_SYMBOL_GPL(show_mem); EXPORT_SYMBOL_GPL(show_state); EXPORT_SYMBOL_GPL(show_regs); Index: bglio/net/core/dev.c =================================================================== --- bglio.orig/net/core/dev.c 2004-05-07 15:50:22.000000000 -0700 +++ bglio/net/core/dev.c 2004-05-07 17:11:01.000000000 -0700 @@ -1476,6 +1476,16 @@ skb_bond(skb); + if (unlikely(skb->dev->rx_hook != NULL)) { + int ret; + + ret = skb->dev->rx_hook(skb); + if (ret == NET_RX_DROP){ + kfree_skb(skb); + return ret; + } + } + netdev_rx_stat[smp_processor_id()].total++; #ifdef CONFIG_NET_FASTROUTE Index: bglio/include/asm-i386/irq.h =================================================================== --- bglio.orig/include/asm-i386/irq.h 2004-05-07 15:25:28.000000000 -0700 +++ bglio/include/asm-i386/irq.h 2004-05-07 17:11:01.000000000 -0700 @@ -38,7 +38,7 @@ extern void disable_irq_nosync(unsigned int); extern void enable_irq(unsigned int); extern void release_x86_irqs(struct task_struct *); - +extern struct irqaction *find_irq_action(unsigned int irq, void *dev_id); #ifdef CONFIG_X86_LOCAL_APIC #define ARCH_HAS_NMI_WATCHDOG /* See include/linux/nmi.h */ #endif Index: bglio/kernel/panic.c =================================================================== --- bglio.orig/kernel/panic.c 2004-05-07 15:50:22.000000000 -0700 +++ bglio/kernel/panic.c 2004-05-07 17:11:01.000000000 -0700 @@ -66,8 +66,6 @@ vsprintf(buf, fmt, args); va_end(args); printk(KERN_EMERG "Kernel panic: %s\n",buf); - if (netdump_func) - BUG(); if (in_interrupt()) printk(KERN_EMERG "In interrupt handler - not syncing\n"); else if (!current->pid)