LINUX.ORG.RU

rmmod возвращает EAGAIN (референсы на модуль)

 , ,


0

1

Приветствую,

достался в «наследство» сравнительно большое embedded проект (ARM процесор, linux 2.6.31, busybox), который нужно поддерживать. Столкнулся со следующей проблемой: ядерный модуль (часть этого проекта) всегда загружается первым, потом демон устанавливающий соединение по netlink сокету. Проблема в том, что после выгружения демона из памяти по SIGINT или SIGKILL, число референсов на этот модуль в ядре не 0 (cat /proc/net/modules | grep my_module, 3й параметр) и соответственно rmmod возвращает ошибку:

% rmmod my_module.ko
% rmmod: my_module.ko: Resource temporarily unavailable

Т.е. получаем -11 EAGAIN. Из кода демона известно, что открываются 3 netlink сокета в модуль и по таймеру один из сокетов регулярно читается, но после запуска демона число references в модуле (/proc/net/modules) поднимается с 0 до 6, после убийства демона опускается до 3, т.е. либо остаются открытые дескрипторы, либо что-то еще.

Подскажите, какие есть методы обнаружить и отловить такого рода баг?

Буду пременого благодарен! :)


Ответ на: комментарий от Dennis7

Интересно, как я узнаю этой команды, используют ли другие модули мой модуль? На самом деле загружены еще два драйвера из комплекта Marvell SDK которые ничего не знают про my_module.ko, но они используются напрямую тем самым демоном.

cruz7
() автор топика
Ответ на: комментарий от cruz7

Вы про марвеловский драйвер?

Про твой.

ничего не нашел. Аналогично в своем драйвере.

Т.е. ты до сих пор не знаешь, кто именно создает ссылки?

tailgunner
()

Пункт 0: отрезать яйца предыдущему драйверописателю

ttnl
()
Ответ на: комментарий от tailgunner

Т.е. ты до сих пор не знаешь, кто именно создает ссылки?

Таки если бы знал, то исходный вопрос звучал бы иначе :)

cruz7
() автор топика
Ответ на: комментарий от cruz7

Т.е. ты до сих пор не знаешь, кто именно создает ссылки?

Таки если бы знал

Ты по стеку вызовов не можешь определить вызывающий модуль или что?

tailgunner
()
Ответ на: комментарий от tailgunner

Ты по стеку вызовов не можешь определить вызывающий модуль или что?

Как я уже сказал выше, в «моем» драйвере нет ни единого try_module_get(), или вы имеете в виду поставить dump_stack перед вызовом try_module_get в kernel/module.c

PS. сорри что торможу.

cruz7
() автор топика
Ответ на: комментарий от tailgunner

У тебя нет try_module_get? O_o Тогда непонятно, кем увеличивается счетчик. Может, есть MOD_INC_USE_COUNT?

Здесь http://stackoverflow.com/questions/1741415/linux-kernel-modules-when-to-use-t... не рекомендуется вызывать try_module_get() для своего модуля.

MOD_INC_USE_COUNT в драйвере тоже отсутствует.

cruz7
() автор топика
Ответ на: комментарий от cruz7

не рекомендуется вызывать try_module_get() для своего модуля.

Надо же. Век живи - век учись.

У меня такое впечатление, что у тебя где-то стоит замаскированное увеличение счетчика ссылок _вдобавок_ к автоматическому - заметь, что при открытии 3 сокетов счетчик растет до 6, а потом падает до 3, как будто автоматическое уменьшение счетчика срабатывает, а ручное - нет (или наоборот).

tailgunner
()
Ответ на: комментарий от cruz7

выглядит как баг в модуле. проверяй, всё ли, что инициализируется имеет деинициализацию в каком-то другом месте. я с подобным советом похож на капитана наверное, но к сожалению с netlink ничего не делал, так что подробностей его работы не знаю.

про try_module_get спасибо, я тоже не знал.

nanoolinux
()
Ответ на: комментарий от nanoolinux

Всем привет, провел дополнительные исследования кода и вот что выяснил. Во-первых я был не прав, и создается не netlink сокет, а raw сокет нового семейства, которое регистрируется в этом ядерном модуле:

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;
}

Вот как создается сокет в демоне:

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

Во-вторых, меня смутило, что в _hsl_sock_create() вызывается sock_hold(), тем самым увеличивая reference counter сокета, хотя он уже выставляется в 1 в ф-ции sock_init_data(), а при уничтожении сокета sock_put уменьшает счетчик только на 1, и сокет полностью не удаляется из системы.

Убрал sock_hold, теперь при убийстве демона число ссылок опускается до 0 и rmmod работает, НО старте демона все равно число ссылок на модуль 6, это при том что создается только 3 raw сокета !

Посмотрел в код socket_create(): там вызывается внутрення ф-ция __socket_create() в которой собственно вызывается try_module_get, т.е. это единственное место увеличить счетчик.

PS. Ничего не понимаю(C) «Следствие ведут колобки»

cruz7
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.