Иногда система или приложения могут внезапно выдавать ошибки вида «количество семафоров в системе исчерпано, не могу создать новый семафор». Это скорее всего значит, что какой-то процесс создал настолько много семафоров в системе, что нельзя создать новые. Необходимо узнать - кто.
Здесь следует отметить пару деталей. Семафоры не создаются по одному, создаётся сразу массив семафоров запрошенного размера, изменить число семафоров в массиве после создания нельзя. Суммарное число семафоров во всех массивах не должно превышать общесистемный предел, задаваемый параметром ядра 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 последнего процесса, что мы и искали
}
Вот примерно так можно копаться в структурах ядра. Следует учитывать, что никто не гарантирует стабильность внутренних структур ядра и поэтому они могут быть совершенно другие в другой версии ядра.
Пыщь!
Оригинал поста размещен в блоге
Ад, ненависть и локалхост. Комментить?
Набигай. Подкат?
ОИНЧ.