伊藤です。

Hajimu UMEMOTO wrote:
>   梅本です。
> 
 >   9日に出されたばかりですよね。気軽にもう少し待たれてみては如何がでしょ
> うか。:)
>   反応がなさげなら、current@, net@ あたりに、PR 投げてあるのでよろしく
> みたいなメールを投げてみると良いかも。
> 
ありがとうございます。
英語があまり得意ではないので、もしかしたら意味が通じていないんじゃないか
と不安になっていました。

> kouji> 要は、 case SIOCGIFMEDIAの処理を、BGE_LOCKと、BGE_UNLOCKで
> kouji> 囲んだだけです。
> 
>   他のドライバを見ても、ifmedia_ioctl() の呼び出しまわりにはロックを掛
> けてないですね。他のドライバでも起こりそうな気がするのですが、どなたか
> 検証できないでしょうか?
>   ifmedia_ioctl() 側で面倒を見るようにするのが正しいような気がします。
> 
少なくとも、emに関してはOKでした。
確かに、他のドライバを見ても、ロックを掛けてはいないですね。

私の所のbgeは、miibusの下にぶら下がっている?様子で、
dev/bge/if_bge.c から、net/if_media.cを経由して、mii/brgphy.cに行って、
brgphy_status()で、NICから、PHY_READを使ってステータスを取ってきています。

miibusかそうでないかによって、この辺りの動きが変わって来るんじゃないかと
ふと思ったりもしています。

私の所では、HPのDL380というマシン(Xeon  * 2)と、自作マシン(P4 + HTT)にて
現象の確認をおこなっています。

ifconfig コマンドからNICのリンク状態を取り出す部分を抜粋したプログラムをつけ
ておきます。興味を持たれたかた、いらっしゃいましたらお使い下さい。

ifconfig コマンドよりも速いペースでNICからステータスを取り出す事が
可能ですが、そのぶんドライバへの負荷も高くなります。
最悪、パケットの取りこぼしなどが発生する恐れもあるかと思いますので、注意して
下さい。

このコマンドを使うと、bgeが他のNICに比べて、リンク状態の取り出しにやけに時間が
掛かっているのも判ると思います。

#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <net/if_media.h>
int link_status(char *adev);
int main(int argc, char *argv[])
{
   int status;
   int n, count;

   if (3 != argc) {
      fprintf(stderr, "Usage:%s device count\n");
      exit(-1);
   }
   count = atoi(argv[2]);

   for (n = 0; n < count; ++n) {
      status = link_status(argv[1]);
      if (0 == status) {
         printf("n=%d %s Link OK\n", n, argv[1]);
      }else{
         printf("n=%d %s Link NG\n", n, argv[1]);
         exit(-2);
      }
   }
}
int link_status(char *adev)
{
   struct ifreq ifr;
   struct ifmediareq ifmr;
   int s, nrc;

   ifr.ifr_addr.sa_family = AF_INET;
   s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
   if (0 > s) {
      printf("socket error errno=%d\n", errno);
      return -1;
   }

   memset(&ifmr, 0, sizeof(ifmr));
   strncpy(ifmr.ifm_name, adev, sizeof(ifmr.ifm_name));
   nrc = ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr);
   if (0 > nrc) {
      close(s);
      printf("ioctl error errno=%d\n", errno);
      return -2;
   }
   close(s);

   if (ifmr.ifm_status & IFM_ACTIVE) {
      return 0; /* active     */
   }else{
      printf("no carrier\n");
      printf("ifmr.ifm_status = 0x%08x\n", ifmr.ifm_status);
      return 1; /* no carrier */
   }
}

メールによる返信