https://dvdhrm.wordpress.com/2014/06/10/memfd_create2/
Teóricamente, podría lograr [memfd_create()
] comportamiento sin introducir nuevas llamadas al sistema, como esta:
int fd = open("/tmp", O_RDWR | O_TMPFILE | O_EXCL, S_IRWXU);
(Nota:para garantizar de forma más portátil un tmpfs aquí, podemos usar “/dev/shm
” en lugar de “/tmp
“).
Por lo tanto, la pregunta más importante es ¿por qué diablos necesitamos una tercera vía?
[…]
- La memoria de respaldo se contabiliza para el proceso propietario del archivo y no está sujeta a cuotas de montaje.
^ ¿Tengo razón al pensar que no se puede confiar en la primera parte de esta oración?
El código memfd_create() se implementa literalmente como un "archivo no vinculado que vive en [a] tmpfs que debe ser interno del kernel". Al rastrear el código, entiendo que difiere en no implementar controles LSM, también se crean memfds para admitir "sellos", como explica la publicación del blog. Sin embargo, soy extremadamente escéptico de que los memfds se contabilicen de manera diferente a un tmpfile en principio.
Específicamente, cuando el asesino de OOM llama a la puerta, no creo que tenga en cuenta la memoria en poder de memfds. Esto podría totalizar hasta el 50 % de la RAM:el valor de la opción size=para tmpfs. El kernel no establece un valor diferente para el tmpfs interno, por lo que usaría el tamaño predeterminado del 50 %.
Por lo tanto, creo que, en general, podemos esperar que los procesos que contienen un gran memfd, pero ninguna otra asignación de memoria significativa, no sean eliminados por OOM. ¿Es eso correcto?
Respuesta aceptada:
Sobre la base de la respuesta de @danblack:
La decisión se basa en oom_kill_process()
(limpiado un poco):
for_each_thread(p, t) {
list_for_each_entry(child, &t->children, sibling) {
unsigned int child_points;
child_points = oom_badness(child,
oc->memcg, oc->nodemask, oc->totalpages);
if (child_points > victim_points) {
put_task_struct(victim);
victim = child;
victim_points = child_points;
get_task_struct(victim);
}
}
}
(https://github.com/torvalds/linux/blob/master/mm/oom_kill.c#L974)
Que depende de oom_badness()
para encontrar al mejor candidato:
child_points = oom_badness(child,
oc->memcg, oc->nodemask, oc->totalpages);
oom_badness()
hace:
points = get_mm_rss(p->mm) + get_mm_counter(p->mm, MM_SWAPENTS) +
mm_pgtables_bytes(p->mm) / PAGE_SIZE;
(https://github.com/torvalds/linux/blob/master/mm/oom_kill.c#L233)
donde:
static inline unsigned long get_mm_rss(struct mm_struct *mm)
{
return get_mm_counter(mm, MM_FILEPAGES) +
get_mm_counter(mm, MM_ANONPAGES) +
get_mm_counter(mm, MM_SHMEMPAGES);
}
(https://github.com/torvalds/linux/blob/master/mm/oom_kill.c#L966)
Entonces parece que cuenta páginas anónimas, que es lo que memfd_create()
usos.