4

維持するモジュールがあり、カーネルに保持されている参照カウンターに問題があるようです。その結果、モジュールへの 3 つの raw ソケットを開くデーモンを強制終了した後、モジュールを rmmod できなくなります。興味深いことに、デーモン 'lsmod' をロードした後、モジュールへの参照が 6 つ表示されますが、3 つしかないはずです。

これは、Linux-2.6.31 を搭載した ARM ベースの組み込みシステムで発生しており、rmmod には、モジュールを強制的にアンロードしようとする「強制」モードがありません (とにかく、良い考えではありません)。

私はコードを分析しましたが、ここに私が持っているものがあります: 1) モジュールは新しいソケットアドレスファミリー AF_HSL を作成し、カーネルに登録します:

static struct proto_ops SOCKOPS_WRAPPED (hsl_ops) = {
  family:       AF_HSL,

  owner:        THIS_MODULE,
  release:      hsl_sock_release,
  bind:         _hsl_sock_bind,
  connect:      sock_no_connect,
  socketpair:   sock_no_socketpair,
  accept:       sock_no_accept,
  getname:      _hsl_sock_getname,
  poll:         datagram_poll,
  ioctl:        sock_no_ioctl,
  listen:       sock_no_listen,
  shutdown:     sock_no_shutdown,
  setsockopt:   sock_no_setsockopt,
  getsockopt:   sock_no_getsockopt,
  sendmsg:      _hsl_sock_sendmsg,
  recvmsg:      _hsl_sock_recvmsg,
  mmap:         sock_no_mmap,
  sendpage:     sock_no_sendpage,
};

static struct net_proto_family hsl_family_ops = {
  family:               AF_HSL,
  create:               _hsl_sock_create,
  owner:                THIS_MODULE
};
...

static int
_hsl_sock_create (struct net *net, struct socket *sock, int protocol)
{
  struct sock *sk = NULL;

  sock->state = SS_UNCONNECTED;
  sk = sk_alloc (current->nsproxy->net_ns, AF_HSL, GFP_KERNEL, &_prot);
  if (sk == NULL)
    goto ERR;

  sock->ops = &SOCKOPS_WRAPPED(hsl_ops);
  sock_init_data (sock,sk);

  sock_hold (sk);  /* XXX */
  ...

}

static void
_hsl_sock_destruct (struct sock *sk)
{
  struct hsl_sock *hsk, *phsk;

  if (!sk)
    return;

  ...
  sock_orphan (sk);
  skb_queue_purge (&sk->sk_receive_queue);

  sock_put (sk);
}

int
hsl_sock_release (struct socket *sock)
{
  struct sock *sk = sock->sk;

  /* Here goes logic to destroy net_devices */
  ...

  _hsl_sock_destruct (sk);

  sock->sk = NULL;

  return 0;
}

2) デーモンはそのような方法でソケットを作成します

fd = socket(AF_HSL, SOCK_RAW, 0);;
bind();
getsockname();

ただし、_hsl_sock_create() が sock_hold() を呼び出す必要はないと思います。これにより、ソケットの参照カウントが増加しますが、sock_init_data() によって既に 1 に設定されており、ソケット削除フェーズで sock_put() が 1 減少しますが、これはソケットを解放せず、システムから完全に削除します。

だから私は実験して sock_hold(); を削除しました。現在、削除されたすべての参照でデーモンを強制終了すると、「rmmod」が成功しますが、デーモンを開始した後の参照の数はまだ 3 です。

また、内部関数 __socket_create() を呼び出す socket_create() のコードもチェックしました。内部関数 __socket_create() は、try_module_get() を呼び出し、モジュールの参照カウントを保持します。これは、モジュールのrefcntを明示的にインクリメントする唯一の場所のようです。

私はまだ混乱しています。何が起こっているのかを理解するのを手伝ってくれる人はいますか?

あなたからの返信を楽しみにしています。

マーク

4

0 に答える 0