作者clanguage (C语言)
看板LinuxDev
标题Re: [问题] kernel socket 产生 bug:scheduling wh …
时间Mon Jun 13 23:53:24 2011
没看过 network driver 的 code. trace 一下看会不会蒙到
就你那行 BUG 的意思解释在这:
112 /*
113 * Check whether we were atomic before we did preempt_disable():
114 * (used by the scheduler, *after* releasing the kernel lock)
115 */
116 #define in_atomic_preempt_off() \
117 ((preempt_count() & ~PREEMPT_ACTIVE) != PREEMPT_CHECK_OFFSET)
=> 必须确保你是在 atomic context
1576 static struct packet_type ip_packet_type __read_mostly = {
1577 .type = cpu_to_be16(ETH_P_IP),
1578 .func = ip_rcv,
1579 .gso_send_check = inet_gso_send_check,
1580 .gso_segment = inet_gso_segment,
1581 .gro_receive = inet_gro_receive,
1582 .gro_complete = inet_gro_complete,
1583 };
inet_init()
...
1686 ipv4_proc_init();
1687
1688 ipfrag_init();
1689
1690 dev_add_pack(&ip_packet_type);
1691
1692 rc = 0;
看起来 func 就是收到 data 时要执行的内容.
1203 struct packet_type {
1204 __be16 type; /* This is really htons(ether_type). */
1205 struct net_device *dev; /* NULL is wildcarded here */
1206 int (*func) (struct sk_buff *,
1207 struct net_device *,
1208 struct packet_type *,
1209 struct net_device *);
1210 struct sk_buff *(*gso_segment)(struct sk_buff *skb,
1211 int features);
1212 int (*gso_send_check)(struct sk_buff *skb);
1213 struct sk_buff **(*gro_receive)(struct sk_buff **head,
1214 struct sk_buff *skb);
1215 int (*gro_complete)(struct sk_buff *skb);
1216 void *af_packet_priv;
1217 struct list_head list;
1218 };
所以 ip_rcv 就是收到 packet 的动作对吧
377 * dev_add_pack - add packet handler
378 * @pt: packet type declaration
379 *
380 * Add a protocol handler to the networking stack. The passed &packet_type
381 * is linked into kernel lists and may not be freed until it has been
382 * removed from the kernel lists.
383 *
384 * This call does not sleep therefore it can not
385 * guarantee all CPU's that are in middle of receiving packets
386 * will see the new packet type (until the next received packet).
387 */
388
389 void dev_add_pack(struct packet_type *pt)
看了一下 网路教的 trace 是 netif_rx()--->netif_receive_skb()->deliver_skb()->packet_type.func 呼叫的
所以可能从 softirq context 或 interrupt 呼叫上来.
所以可能要注意你的 function 里面要注意 softirq 的性质
1. 不能睡
2. softirqs on the current processor are disabled
3. 需对资料做好 locking
这就是问题了,你去呼叫 schedule 就是有 code 去睡了吧?
所以你要检查一下你写的 code 那边会把 cpu 让给别人的,
违背kernel/driver的设计, 感觉是这样,一点浅见。
2950 /**
2951 * netif_receive_skb - process receive buffer from network
2952 * @skb: buffer to process
2953 *
2954 * netif_receive_skb() is the main receive data processing function.
2955 * It always succeeds. The buffer may be dropped during processing
2956 * for congestion control or by the protocol layers.
2957 *
2958 * This function may only be called from softirq context and interrupts
2959 * should be enabled.
2960 *
2961 * Return values (usually ignored):
2962 * NET_RX_SUCCESS: no congestion
2963 * NET_RX_DROP: packet was dropped
2964 */
2965 int netif_receive_skb(struct sk_buff *skb)
※ 引述《squallbbking (阿爽BB)》之铭言:
: 不好意思 小弟在Kernel 接收封包得地方(net/ipv4/ip_input.c)中的ip_rcv中
: 加入发送kernel socket 的函式 sock_sendmsg,目前程式可以顺利发送封包至我
: 设定的目的端,但是我发现kernel中会印出"BUG : scheduling while atomic..."
: 等等一大串讯息,重点是发送一阵子後我的module就会当掉,小弟觉得是这个BUG所影响
: ,上网爬了一下文有某些外国网站有提到此问题,不过没有明确的解决办法,不知道
: 有没有高手大大能替小弟解惑一下,这是满重要的问题,拜托好心人帮忙一下了><
: 万分感谢!!!!
: 不好意思,补上程式码,有点长我撷取重点部分,如果还有需要请在跟我说
: ,真的非常感谢!!
: 这是kernel中修改的部分,路径如我上文中
: int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
: *pt, struct net_device *orig_dev)
: {
: struct iphdr *iph;
: u32 len;
: //这里开始是我增加连结MODULE的地方
: int check11;
: if(pkt_input)
: {
: pkt_input(skb);
: }
: if(multicast)
: {
: check11 = multicast(skb);
: if(check11==1)
: {
: //printk("now drop\n");
: goto drop;
: }
: }
: //以上是我增加的部分,pkt_input回传 check11为0就送出封包,为1就goto drop
: .
: .
: .
: inhdr_error:
: IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
: drop:
: kfree_skb(skb);
: out:
: return NET_RX_DROP;
: 接下来是module code
: init_module(void)部分先创此socket
: //========merge kernel socket========//
: socket_sendmeg = kmalloc(sizeof(struct socketpair) , GFP_KERNEL);
: memset(socket_sendmeg , 0 , sizeof(struct socketpair));
: if((err=sock_create(PF_PACKET , SOCK_PACKET , htons(ETH_P_IP) ,
: &socket_sendmeg->sock)))
: {
: printk("create socket err!\n");
: return 0;
: }
: createsocketmeg(pktinfm);
: 再来连结地址和类型
: void createsocketmeg(struct pktinf *pktinfm)
: {
: char DEV[]="eth1"; //140.117.157.50
: memset(&socket_sendmeg->addr,0,sizeof(struct sockaddr));
: strcpy(socket_sendmeg->addr.sa_data , DEV);
: socket_sendmeg->addr.sa_family = PF_PACKET;
: msgmeg.msg_flags=0;
: msgmeg.msg_name=&socket_sendmeg->addr;
: msgmeg.msg_namelen=sizeof(struct sockaddr);
: msgmeg.msg_control=NULL;
: msgmeg.msg_controllen=0;
: msgmeg.msg_iovlen=1;
: msgmeg.msg_control=NULL;
: };
: 最後要送出封包时,module会呼叫此函式,制作ethernet、IP、TCP的header然後
: 加入payload送出
: void C2_sendto_c1( mm_segment_t oldfs , unsigned char *megbuf , int *mbuf
: ,int pkt)
: {
: src_port_csc = 0x5000;
: dest_port_csc = pktinfm->IPC1_destport;
: ACK_NO_csc = htonl(pktinfm-> C1img_end_ack);
: //------------Ether header build---------------//
: memset(&Ethmeg , 0 , sizeof(Ethmeg));
: Get_Hw_Addr(mac_sadr_csc, mac_sor_csc);
: memcpy(Ethmeg.eth.h_source , mac_sadr_csc , ETH_ALEN);
: Get_Hw_Addr(mac_dadr_csc , mac_des_csc);
: memcpy(Ethmeg.eth.h_dest, mac_dadr_csc , ETH_ALEN);
: Ethmeg.eth.h_proto = htons(ETH_P_IP);
: memcpy(C1pkt , &Ethmeg.eth , 14);
: //------------IP header build---------------//
: memset(&Ipmeg , 0 , sizeof(Ipmeg));
: set_ip_ihl( &Ipmeg.iph );
: set_ip_version( &Ipmeg.iph ,IPVERSION);
: set_ip_tos( &Ipmeg.iph ,tos);
: tot_len_csc = 0x0028 +mbuf[pkt] ;
: set_ip_tot_len( &Ipmeg.iph ,tot_len_csc);
: pktinfm->C1img_end_ID = set_ip_id( &Ipmeg.iph ,pktinfm->C1img_end_ID);
: set_ip_frag_off( &Ipmeg.iph ,frag_off);
: set_ip_ttl( &Ipmeg.iph ,ttl_csc);
: set_ip_protocol( &Ipmeg.iph ,IPPROTO_TCP);
: set_ip_saddr( &Ipmeg.iph ,source_ip_csc);
: set_ip_daddr( &Ipmeg.iph ,dest_ip_csc);
: set_ip_check( &Ipmeg.iph);
: memcpy( C1pkt+sizeof(Ethmeg) , &Ipmeg.iph , 20);
: //------------TCP header build---------------//
: memset(&Tcpmeg , 0 , sizeof(Tcpmeg));
: set_tcp_source( &Tcpmeg.tcph ,src_port_csc);
: set_tcp_dest( &Tcpmeg.tcph ,dest_port_csc);
: seq_csc = htonl(pktinfm-> C1img_end_seq) + pktinfm-> C1img_end_len;
: set_tcp_seq( &Tcpmeg.tcph ,seq_csc);
: pktinfm-> C1img_end_seq = Tcpmeg.tcph.seq;
: pktinfm-> C1img_end_len = mbuf[pkt];
: set_tcp_ack_seq( &Tcpmeg.tcph ,ACK_NO_csc);
: set_tcp_res1( &Tcpmeg.tcph ,res1);
: set_tcp_doff( &Tcpmeg.tcph ,doff);
: set_tcp_cwr(&Tcpmeg.tcph , cwr);
: set_tcp_ece(&Tcpmeg.tcph , ece);
: set_tcp_urg(&Tcpmeg.tcph , urg);
: set_tcp_ack(&Tcpmeg.tcph , ack);
: set_tcp_psh(&Tcpmeg.tcph , psh);
: set_tcp_rst(&Tcpmeg.tcph , rst);
: set_tcp_syn(&Tcpmeg.tcph , syn);
: set_tcp_fin(&Tcpmeg.tcph , fin);
: set_tcp_window( &Tcpmeg.tcph , winmeg);
: set_tcp_urg_ptr( &Tcpmeg.tcph , Urp);
: memcpy(C1pkt+sizeof(Ethmeg)+sizeof(Ipmeg), &Tcpmeg.tcph , 20);
: //------------payload build---------------//
: memcpy( C1pkt+sizeof(Ethmeg)+sizeof(Ipmeg)+sizeof(Tcpmeg) , megbuf ,
: mbuf[pkt]);
: set_tcp_check_meg( &Tcpmeg.tcph , &Ipmeg.iph ,
: C1pkt+sizeof(Ethmeg)+sizeof(Ipmeg)+sizeof(Tcpmeg));
: memcpy(C1pkt+sizeof(Ethmeg)+sizeof(Ipmeg)+16, &Tcpmeg.tcph.check , 2);
: //-------end header build----------------//
: iovmeg.iov_base= C1pkt;
: iovmeg.iov_len = sizeof(C1pkt);
: msgmeg.msg_iov = &iovmeg;
: oldfs = get_fs();
: set_fs(KERNEL_DS);
: //这里送出封包
: sock_sendmsg(socket_sendmeg->sock , &msgmeg, sizeof(C1pkt));
: //printk("merg for C1C2\n") ;
: set_fs(oldfs);
: };
: 大致上是这样,如有需要提供的请在跟我说,我查到说呼叫sock_sendmsg会产生此BUG
: ,不好意思文章有点长,但这问题非常重要,拜托了!!!再次万分感谢
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 61.57.131.154