トップ «前の日記(2003年07月16日) 最新 次の日記(2003年07月20日)» 編集
2003|01|02|03|04|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|10|12|
2009|02|03|06|07|10|11|12|
2010|01|02|03|04|07|09|10|11|12|
2011|01|03|04|05|06|07|08|10|
2012|01|06|08|09|10|12|
2013|01|02|03|04|07|09|11|12|
2014|01|03|04|05|06|09|
2015|04|
2016|01|08|
ここは旧えびめもです。えびめも2に移行します(2016/12/1)

2003年07月18日

カーネル八苦

sh-linuxの話。ARCNET上でTCP/IPを動かすことをやっているが上手くいかない。arcnet上でIPを張り、pingが通るところまではできたのだが、tcpセッションを張ろうとするとサーバー側が下のように落ちる。
Unable to handle kernel NULL pointer dereference at virtual address 00000028
pc = 8c0f240c
*pde = 00000000
Oops: 0001
PC  : 8c0f240c SP  : 8d9f9b38 SR  : 40000101 TEA : c0181034    Not tainted
R0  : 000000f0 R1  : 8df4d800 R2  : 8dee6ba8 R3  : 8dbaad0c
R4  : 8dbaac50 R5  : 8dbaae0f R6  : 8dbaac90 R7  : 8dee6b90
R8  : 8dbaad0c R9  : 00000020 R10 : 8dbaac50 R11 : 8dee6b50
R12 : 8df5ca79 R13 : 00000000 R14 : 8dee6b7c
MACH: 00000000 MACL: 00000180 GBR : 00000000 PR  : 8c0f8da8
Kernel panic: Aiee, killing interrupt handler!
In interrupt handler - not syncing
gdbでアドレスから探していって20時間目にして原因を突き止めた。 gdbで落ちているアドレス付近を逆アセンブルしてみると @(8,r9) のアドレス(00000028)をmov.lしているて落ちているのだが、なんとこのダンプ画面に来る前に原因があった。いくつかの複合的な問題だった。
カーネルソースの net/ipv4/tcp_input.c:3346付近
int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                        struct tcphdr *th, unsigned len)
{
        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
        struct tcp_skb_cb *tmp1;
        unsigned long seq;
        unsigned long rcv_nxt;
 
        printk("<1>sk=0x%p, skb=0x%p, th=0x%p, len=d\n",sk,skb,th,len);
        // sk=0x8da15c50, skb=0x8df52c60, th=0x8df5c979, len=56
        // ここで th が奇数アドレスなのがおかしい
 
[略]
 
        if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags && seq == rcv_nxt) {  ←ここのth参照で死ぬらしい
ここで
union tcp_word_hdr {
        struct tcphdr hdr;
        __u32             words[5];
};
#define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3])
となっているので、結果、th+0xc番地からlongアクセスしてアライメントエラーになっているらしい。

thを追いかければよさそうというところまでで封じ手。

カーネル八苦続き

辛かったが分かった。完全に理解した!!!!!すべての原因はRFC1051だ。こいつが完全に悪い。

ARCNET上にIPを通すためのプロトコルとしてrfc1051(古)とrfc1201(新)の2種類があって選択できる。ARCNETのlongパケット512バイトはそれぞれ以下のような構造になる。

include/linux/if_arcnet.h で宣言されているヘッダー
struct arc_hardware
{
    uint8_t  source,    // source ARCnet - filled in automagically
             dest,      // destination ARCnet - 0 for broadcast
             offset[2]; // offset bytes (some weird semantics)
};
#define ARC_HDR_SIZE 4
 
struct archdr                       // 20byteってことになる
{
    struct arc_hardware hard;            //   4 byte
    union {
        struct arc_rfc1201   rfc1201;    //   4 byte
        struct arc_rfc1051   rfc1051;    //   1 byte
        struct arc_eth_encap eth_encap;  //  20 byte
        uint8_t raw[0];                  // 508 byte
    } soft;
};
rfc1201を使用するときは受信バッファ+8番地からIPヘッダーがあるのだが、rfc1051を選択してしまうとバッファ+5番地からIPヘッダーが始まる。driver/net/arcnet/rcf1051.c から net/core/dev.c にskbが放り込まれたときに、まさか奇数番地からIPヘッダーが始まっているなど想像もしないので奇数アドレスからIPヘッダーを構造体にぶち込んでしまう。で、アライメント例外大発生だ。

i386 CPUでは奇数アドレスからのlongアクセスは(効率が落ちるが)特に問題は無い。そのためi386機ではrfc1051.cは問題なく動作する。しかしPC以外のRISC型アーキテクチャではrfc1051.cは動作しないだろう。まとめるとRISC型アーキテクチャでARCNETを使用するときは現状のrfc1051.cは組み込んではならないのだ。(え?コードを直せって?)

include/linux/skbuff.h の自分用備忘録
skb_push(struct sk_buff *skb, unsigned int len) データ領域の下位側を拡張する
skb_pull(struct sk_buff *skb, unsigned int len) データ領域の下位側を縮める
skb_put(struct sk_buff *skb, unsigned int len) データ領域の上位側を拡張する

椅子を買った

結局アーロンチェアは買わなかった。海老原はコンテッサを選んだ(オレンジのメッシュ地。フレームはポリッシュでボディーは黒)。岩崎と新谷はエルシオを選んでいた。3脚でかなりの金額になった(*_*)が、賞与が出ないかわりに必要だと思う備品は整備することにした(賞与を出せという話も(A^^;;)

プリンター


頼んでおいたレーザープリンター用の両面印刷ユニットが届いた。早速取り付ける。これでA3を折って製本ができるようになる。まんなかホチキスを買わねば。