implement RE UID matching; vatidation RE patterns at startup
This commit is contained in:
parent
4fcab87fc5
commit
68e0efc6a5
175
nohang
175
nohang
@ -194,7 +194,6 @@ def pid_to_name(pid):
|
||||
return ''
|
||||
|
||||
|
||||
|
||||
def pid_to_cmdline(pid):
|
||||
"""
|
||||
Get process cmdline by pid.
|
||||
@ -209,11 +208,11 @@ def pid_to_cmdline(pid):
|
||||
return ''
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def pid_to_uid(pid):
|
||||
with open('/proc/' + pid + '/status') as f:
|
||||
for n, line in enumerate(f):
|
||||
if n is uid_index:
|
||||
return line.split('\t')[1]
|
||||
|
||||
|
||||
def send_notify_warn():
|
||||
@ -324,13 +323,6 @@ def sleep_after_send_signal(signal):
|
||||
sleep(min_delay_after_sigterm)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def find_victim_and_send_signal(signal):
|
||||
"""
|
||||
Find victim with highest badness and send SIGTERM/SIGKILL
|
||||
@ -338,10 +330,11 @@ def find_victim_and_send_signal(signal):
|
||||
pid_badness_list = []
|
||||
|
||||
for pid in os.listdir('/proc'):
|
||||
# только директории, имена которых состоят только из цифр, за исключением /proc/1/
|
||||
# only directories whose names consist only of numbers, except /proc/1/
|
||||
if pid[0].isdecimal() is False or pid == '1':
|
||||
continue
|
||||
|
||||
# find and modify badness (if it needs)
|
||||
try:
|
||||
badness = int(rline1('/proc/' + pid + '/oom_score'))
|
||||
|
||||
@ -354,13 +347,13 @@ def find_victim_and_send_signal(signal):
|
||||
|
||||
name = pid_to_name(pid)
|
||||
cmdline = pid_to_cmdline(pid)
|
||||
#uid = pid_to_uid(pid)
|
||||
uid = pid_to_uid(pid)
|
||||
|
||||
# skip kthreads
|
||||
if cmdline == '':
|
||||
continue
|
||||
|
||||
#print([pid], [name], [cmdline])
|
||||
#print([uid], [name], [cmdline])
|
||||
|
||||
if search(avoid_regex, name) is not None:
|
||||
badness = int(badness / avoid_factor)
|
||||
@ -382,6 +375,16 @@ def find_victim_and_send_signal(signal):
|
||||
print(' Cmdline matches with prefer_re_cmdline \033[33m{}\033[0m: \033[33m{}\033[0m, Name: {}'.format(
|
||||
prefer_re_cmdline, cmdline, name))
|
||||
|
||||
if search(avoid_re_uid, uid) is not None:
|
||||
badness = int(badness / avoid_uid_factor)
|
||||
print(' UID matches with avoid_re_uid \033[33m{}\033[0m: \033[33m{}\033[0m, Name: {}'.format(
|
||||
avoid_re_uid, uid, name))
|
||||
|
||||
if search(prefer_re_uid, uid) is not None:
|
||||
badness = int((badness + 1) * prefer_cmd_factor)
|
||||
print(' UID matches with prefer_re_uid \033[33m{}\033[0m: \033[33m{}\033[0m, Name: {}'.format(
|
||||
prefer_re_uid, uid, name))
|
||||
|
||||
except FileNotFoundError:
|
||||
badness = 0
|
||||
except ProcessLookupError:
|
||||
@ -449,11 +452,9 @@ def find_victim_and_send_signal(signal):
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
if detailed_rss:
|
||||
print('anon file shmem, MiB:', anon_rss, file_rss, shmem_rss)
|
||||
|
||||
|
||||
if execute_the_command and signal is SIGTERM and name in etc_dict:
|
||||
command = etc_dict[name]
|
||||
exit_status = os.system(etc_dict[name])
|
||||
@ -523,7 +524,6 @@ def find_victim_and_send_signal(signal):
|
||||
|
||||
print(victim_badness_is_too_small)
|
||||
|
||||
|
||||
sleep_after_send_signal(signal)
|
||||
|
||||
|
||||
@ -664,18 +664,6 @@ def calculate_percent(arg_key):
|
||||
##########################################################################
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# find mem_total
|
||||
# find positions of SwapFree and SwapTotal in /proc/meminfo
|
||||
|
||||
@ -778,7 +766,6 @@ print('The path to the config:', config)
|
||||
|
||||
##########################################################################
|
||||
|
||||
|
||||
# parsing the config with obtaining the parameters dictionary
|
||||
|
||||
# conf_parameters_dict
|
||||
@ -846,18 +833,94 @@ mlockall = conf_parse_bool('mlockall')
|
||||
gui_low_memory_warnings = conf_parse_bool('gui_low_memory_warnings')
|
||||
gui_notifications = conf_parse_bool('gui_notifications')
|
||||
decrease_oom_score_adj = conf_parse_bool('decrease_oom_score_adj')
|
||||
|
||||
regex_matching = conf_parse_bool('regex_matching')
|
||||
if regex_matching:
|
||||
from re import search
|
||||
import sre_constants
|
||||
|
||||
execute_the_command = conf_parse_bool('execute_the_command')
|
||||
|
||||
prefer_regex = conf_parse_string('prefer_regex')
|
||||
if prefer_regex == '':
|
||||
print('Invalid prefer_regex value, ' \
|
||||
'regex pattern must not be empty')
|
||||
exit()
|
||||
# RE pattern validation
|
||||
try:
|
||||
search(prefer_regex, '')
|
||||
except sre_constants.error:
|
||||
print('Invalid prefer_regex value, ' \
|
||||
'invalid RE pattern: {}'.format(prefer_regex))
|
||||
exit()
|
||||
|
||||
avoid_regex = conf_parse_string('avoid_regex')
|
||||
if avoid_regex == '':
|
||||
print('Invalid avoid_regex value, ' \
|
||||
'regex pattern must not be empty')
|
||||
exit()
|
||||
# RE pattern validation
|
||||
try:
|
||||
search(avoid_regex, '')
|
||||
except sre_constants.error:
|
||||
print('Invalid avoid_regex value, ' \
|
||||
'invalid RE pattern: {}'.format(avoid_regex))
|
||||
exit()
|
||||
|
||||
prefer_re_cmdline = conf_parse_string('prefer_re_cmdline')
|
||||
if prefer_re_cmdline == '':
|
||||
print('Invalid prefer_re_cmdline value, ' \
|
||||
'regex pattern must not be empty')
|
||||
exit()
|
||||
# RE pattern validation
|
||||
try:
|
||||
search(prefer_re_cmdline, '')
|
||||
except sre_constants.error:
|
||||
print('Invalid prefer_re_cmdline value, ' \
|
||||
'invalid RE pattern: {}'.format(prefer_re_cmdline))
|
||||
exit()
|
||||
|
||||
|
||||
avoid_re_cmdline = conf_parse_string('avoid_re_cmdline')
|
||||
if avoid_re_cmdline == '':
|
||||
print('Invalid avoid_re_cmdline value, ' \
|
||||
'regex pattern must not be empty')
|
||||
exit()
|
||||
# RE pattern validation
|
||||
try:
|
||||
search(avoid_re_cmdline, '')
|
||||
except sre_constants.error:
|
||||
print('Invalid avoid_re_cmdline value, ' \
|
||||
'invalid RE pattern: {}'.format(avoid_re_cmdline))
|
||||
exit()
|
||||
|
||||
|
||||
prefer_re_uid = conf_parse_string('prefer_re_uid')
|
||||
if prefer_re_uid == '':
|
||||
print('Invalid prefer_re_uid value, ' \
|
||||
'regex pattern must not be empty')
|
||||
exit()
|
||||
# RE pattern validation
|
||||
try:
|
||||
search(prefer_re_uid, '')
|
||||
except sre_constants.error:
|
||||
print('Invalid prefer_re_uid value, ' \
|
||||
'invalid RE pattern: {}'.format(prefer_re_uid))
|
||||
exit()
|
||||
|
||||
|
||||
avoid_re_uid = conf_parse_string('avoid_re_uid')
|
||||
if avoid_re_uid == '':
|
||||
print('Invalid avoid_re_uid value, ' \
|
||||
'regex pattern must not be empty')
|
||||
exit()
|
||||
# RE pattern validation
|
||||
try:
|
||||
search(avoid_re_uid, '')
|
||||
except sre_constants.error:
|
||||
print('Invalid avoid_re_uid value, ' \
|
||||
'invalid RE pattern: {}'.format(avoid_re_uid))
|
||||
exit()
|
||||
|
||||
|
||||
mem_min_sigterm_kb, mem_min_sigterm_mb, mem_min_sigterm_percent = calculate_percent(
|
||||
@ -1059,15 +1122,6 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if 'prefer_cmd_factor' in config_dict:
|
||||
prefer_cmd_factor = string_to_float_convert_test(config_dict['prefer_cmd_factor'])
|
||||
if prefer_cmd_factor is None:
|
||||
@ -1094,20 +1148,30 @@ else:
|
||||
exit()
|
||||
|
||||
|
||||
if 'prefer_uid_factor' in config_dict:
|
||||
prefer_uid_factor = string_to_float_convert_test(config_dict['prefer_uid_factor'])
|
||||
if prefer_uid_factor is None:
|
||||
print('Invalid prefer_uid_factor value, not float\nExit')
|
||||
exit()
|
||||
if prefer_uid_factor < 1 and prefer_uid_factor > 1000:
|
||||
print('prefer_uid_factor value out of range [1; 1000]\nExit')
|
||||
exit()
|
||||
else:
|
||||
print('prefer_uid_factor not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if 'avoid_uid_factor' in config_dict:
|
||||
avoid_uid_factor = string_to_float_convert_test(config_dict['avoid_uid_factor'])
|
||||
if avoid_uid_factor is None:
|
||||
print('Invalid avoid_uid_factor value, not float\nExit')
|
||||
exit()
|
||||
if avoid_uid_factor < 1 and avoid_uid_factor > 1000:
|
||||
print('avoid_uid_factor value out of range [1; 1000]\nExit')
|
||||
exit()
|
||||
else:
|
||||
print('avoid_uid_factor not in config\nExit')
|
||||
exit()
|
||||
|
||||
|
||||
if 'min_time_between_warnings' in config_dict:
|
||||
@ -1329,16 +1393,11 @@ if print_config:
|
||||
# for calculating the column width when printing mem and zram
|
||||
mem_len = len(str(round(mem_total / 1024.0)))
|
||||
|
||||
|
||||
if gui_notifications or gui_low_memory_warnings:
|
||||
from subprocess import Popen, PIPE
|
||||
notify_sig_dict = {SIGKILL: 'Killing',
|
||||
SIGTERM: 'Terminating'}
|
||||
|
||||
if regex_matching:
|
||||
from re import search
|
||||
|
||||
|
||||
rate_mem = rate_mem * 1048576
|
||||
rate_swap = rate_swap * 1048576
|
||||
rate_zram = rate_zram * 1048576
|
||||
|
42
nohang.conf
42
nohang.conf
@ -108,10 +108,11 @@ min_delay_after_sigkill = 3
|
||||
oom_score_adj_max значение oom_score_adj будет опущено
|
||||
до oom_score_adj_max перед поиском жертвы.
|
||||
|
||||
Enabling the option requires root privileges.
|
||||
Valid values are True and False.
|
||||
Values are case sensitive.
|
||||
|
||||
decrease_oom_score_adj = False
|
||||
decrease_oom_score_adj = True
|
||||
|
||||
Valid values are integers from the range [0; 1000].
|
||||
|
||||
@ -141,13 +142,15 @@ regex_matching = False
|
||||
|
||||
RE pattern must not be empty!
|
||||
|
||||
Matching with process names
|
||||
Matching process names with RE patterns
|
||||
|
||||
Прблема в том, что если включил регекс, то нельзя выключить ненужный мэтчинг. Можно только установить фактор в единицу.
|
||||
|
||||
prefer_regex = foo
|
||||
|
||||
Valid values are floating-point numbers from the range [1; 1000].
|
||||
|
||||
prefer_factor = 3
|
||||
prefer_factor = 2
|
||||
|
||||
Badness of processes whose names correspond to avoid_regex will
|
||||
be calculated by the following formula:
|
||||
@ -155,22 +158,41 @@ prefer_factor = 3
|
||||
|
||||
# Need more examples
|
||||
|
||||
avoid_regex = ^(sshd|Xorg)$
|
||||
avoid_regex = foo
|
||||
|
||||
Valid values are floating-point numbers from the range [1; 1000].
|
||||
|
||||
avoid_factor = 3
|
||||
avoid_factor = 2
|
||||
|
||||
|
||||
Matching with cmdlines
|
||||
Matching cmlines with RE patterns
|
||||
|
||||
prefer_re_cmdline = ^/usr/lib/firefox
|
||||
# re_match_cmdline = True
|
||||
|
||||
avoid_re_cmdline = ^/usr/lib/virtualbox
|
||||
prefer_re_cmdline = voo
|
||||
|
||||
avoid_re_cmdline = foo
|
||||
|
||||
prefer_cmd_factor = 20
|
||||
|
||||
avoid_cmd_factor = 2
|
||||
|
||||
|
||||
Matching UIDs with RE patterns
|
||||
|
||||
Note that UID=0 итак избегается для убийства.
|
||||
|
||||
# re_match_uid = True
|
||||
|
||||
prefer_re_uid = ^(0)$
|
||||
|
||||
avoid_re_uid=foo
|
||||
|
||||
prefer_uid_factor = 200
|
||||
|
||||
avoid_uid_factor = 2
|
||||
|
||||
prefer_cmd_factor = 3
|
||||
|
||||
avoid_cmd_factor = 3
|
||||
|
||||
|
||||
#####################################################################
|
||||
|
Loading…
Reference in New Issue
Block a user