Какой процесс создал семафор

May 26, 2013 19:56


Иногда система или приложения могут внезапно выдавать ошибки вида «количество семафоров в системе исчерпано, не могу создать новый семафор». Это скорее всего значит, что какой-то процесс создал настолько много семафоров в системе, что нельзя создать новые. Необходимо узнать - кто.

Здесь следует отметить пару деталей. Семафоры не создаются по одному, создаётся сразу массив семафоров запрошенного размера, изменить число семафоров в массиве после создания нельзя. Суммарное число семафоров во всех массивах не должно превышать общесистемный предел, задаваемый параметром ядра kernel.sem. Строго говоря, узнать кто создал данный массив семафоров нельзя, информация об этом нигде не хранится. Хранится информация о том, какой процесс последним совершал операцию с этим семафором, скорее всего тот же процесс и создал семафор, но также возможно что этот процесс давно завершился.

Посмотреть, какие массивы семафоров созданы в системе и системные лимиты на семафоры можно командой ipcs -s. Системные пределы на массивы и семафоры задаются параметром ядра в следующем формате: kernel.sem = <максимум семафоров на массив> <максимум семафоров на всю систему> <максимум операций на вызов семафора> <максимальное количество массивов>. Текущее суммарное использование массивов и семафоров в системе показывает команда ipcs -s -u:

[root@serv ~]# ipcs -s ------ Массивы семафоров -------- ключ semid владелец права nsems 0x00000000 0 root 600 1 0x00000000 65537 root 600 1 0x00000000 98306 apache 600 1 0x00000000 131075 apache 600 1 [root@serv ~]# ipcs -s -l ------ Пределы семафоров -------- максимальное количество массивов = 128 максимум семафоров на массив = 250 максимум семафоров на всю систему = 32000 максимум операций на вызов семафора = 32 максимальное значение семафора = 32767 [root@serv ~]# sysctl kernel.sem kernel.sem = 250 32000 32 128 [root@serv ~]# ipcs -s -u ------ Состояние семафора -------- использовано массивов = 4 выделено семафоров = 4
Каждый массив семафоров идентифицируется его semid. Получить подробную информацию о семафорах из массива, включая процесс, который последним совершал операцию над семафором, можно командой ipcs -s -i . Вот простая команда, которая покажет эти детали для всех массивов семафоров в системе:

[root@serv ~]# ipcs -s | grep ^0x | awk '{print $2}' | while read semid; do ipcs -s -i $semid; done Semaphore Array semid=0 uid=0 gid=0 cuid=0 cgid=0 mode=0600, access_perms=0600 nsems = 1 otime = Wed May 1 08:44:34 2013 ctime = Wed May 1 08:44:32 2013 semnum value ncount zcount pid 0 1 0 0 100 Semaphore Array semid=65537 uid=0 gid=0 cuid=0 cgid=0 mode=0600, access_perms=0600 nsems = 1 otime = Wed May 1 04:44:41 2013 ctime = Wed May 1 08:44:37 2013 semnum value ncount zcount pid 0 1 0 0 459 Semaphore Array semid=98306 uid=48 gid=48 cuid=0 cgid=0 mode=0600, access_perms=0600 nsems = 1 otime = Not set ctime = Wed May 1 04:51:29 2013 semnum value ncount zcount pid 0 1 0 0 1211 Semaphore Array semid=131075 uid=48 gid=48 cuid=0 cgid=0 mode=0600, access_perms=0600 nsems = 1 otime = Not set ctime = Wed May 1 04:51:29 2013 semnum value ncount zcount pid 0 1 0 0 1211
В колонке pid находится номер процесса, который последним совершал операцию над семафором. Этого процесса может и не быть, если он уже завершился, не удалив массив семафоров:

[root@serv ~]# ps -flp 100 F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD [root@serv ~]# ps -flp 1211 F S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD 1 S root 1211 1 0 80 0 - 43371 poll_s 04:51 ? 00:00:00 /usr/sbin/httpd
Есть ещё один гораздо более сложный, но более забавный способ получить ту же информацию - полезть смотреть непосредственно структуры ядра с помощью утилиты crash. Для этого кроме самой утилиты crash из пакета crash нам понадобятся пакеты -debug с отладочной информацией для данного ядра:

[root@serv ~]# rpm -qa kernel\* kernel-2.6.32-358.2.1.el6.x86_64 kernel-firmware-2.6.32-358.2.1.el6.noarch kernel-debuginfo-common-x86_64-2.6.32-358.2.1.el6.x86_64 kernel-debuginfo-2.6.32-358.2.1.el6.x86_64
По-умолчанию репозитории с пакетами -debug не подключены, поэтому самым простым будет установить пакет yum-utils и использовать команду debuginfo-install из него:

[root@serv ~]# yum install crash yum-utils [root@serv ~]# debuginfo-install kernel
После установки пакетов kernel-debuginfo-common-x86_64 и kernel-debuginfo можно запустить crash для ковыряния в живом ядре:

[root@isp ~]# crash crash 6.1.0-1.el6 ...skip... crash> sym init_ipc_ns голова списка всего IPC в системе - init_ipc_ns ffffffff81adc8e0 (D) init_ipc_ns crash> whatis init_ipc_ns struct ipc_namespace init_ipc_ns; имеет тип struct ipc_namespace, посмотрим на её поля crash> struct ipc_namespace init_ipc_ns struct ipc_namespace { ...skip... sem_ctls = {250, 32000, 32, 128}, общесистемные лимиты на семафоры used_sems = 4, количество созданных семафоров ...skip... msg_ctlmax = 65536, лимиты на сообщения... msg_ctlmnb = 65536, msg_ctlmni = 1977, ...skip... shm_ctlmax = 68719476736, ...и на разделяемую память хранятся здесь же shm_ctlall = 4294967296, shm_ctlmni = 4096, ...skip... } crash> struct ipc_namespace.ids init_ipc_ns ids = {{ ipc_namespace.ids[0] - головная структура семафоров в системе in_use = 4, seq = 5, seq_max = 65535, ...skip... ipcs_idr = { top = 0xffff880037af5d50, указатель на struct idr_layer, которая содержит массив указателей id_free = 0xffff880037af5b30, на массивы семафоров ...skip... crash> struct idr_layer 0xffff880037af5d50 struct idr_layer { bitmap = 15, ary = {0xffff880037905150, 0xffff88003722de10, 0xffff88003e224750, 0xffff88003e224bd0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, count = 4, здесь в ary массив указателей на 4 массива семафоров struct sem_array ...skip... crash> struct sem_array посмотрим, что такое struct sem_array... struct sem_array { struct kern_ipc_perm sem_perm; time_t sem_otime; time_t sem_ctime; struct sem *sem_base; struct list_head sem_pending; struct list_head list_id; long unsigned int sem_nsems; } SIZE: 120 crash> struct sem ...и struct sem struct sem { int semval; int sempid; } SIZE: 8 crash> struct sem_array 0xffff88003e224bd0 struct sem_array { посмотрим на последний struct sem_array в ary sem_perm = { ...skip... id = 131075, видим тот же semid, что и в ipcs -s key = 0, тот же key uid = 48, те же uid, gid gid = 48, ...skip... }, sem_otime = 0, sem_ctime = 1367369489, sem_base = 0xffff88003e224c48, наконец, адрес самого семафора ...skip... sem_nsems = 1 количество семафоров в этом массиве } crash> struct sem 0xffff88003e224c48 struct sem { наконец, сам семафор semval = 1, sempid = 1211 pid последнего процесса, что мы и искали }
Вот примерно так можно копаться в структурах ядра. Следует учитывать, что никто не гарантирует стабильность внутренних структур ядра и поэтому они могут быть совершенно другие в другой версии ядра.

Пыщь! Оригинал поста размещен в блоге Ад, ненависть и локалхост. Комментить? Набигай. Подкат? ОИНЧ.
Previous post Next post
Up