https://dvdhrm.wordpress.com/2014/06/10/memfd_create2/
Théoriquement, vous pourriez obtenir [
memfd_create()
] comportement sans introduire de nouveaux appels système, comme ceci :
int fd = open("/tmp", O_RDWR | O_TMPFILE | O_EXCL, S_IRWXU);
(Remarque, pour garantir de manière plus portable un tmpfs ici, nous pouvons utiliser "/dev/shm
” au lieu de “/tmp
").
Par conséquent, la question la plus importante est pourquoi diable avons-nous besoin d'une troisième voie ?
[…]
- La mémoire de sauvegarde est comptabilisée pour le processus propriétaire du fichier et n'est pas soumise aux quotas de montage.
^ Ai-je raison de penser que la première partie de cette phrase n'est pas fiable ?
Le code memfd_create() est littéralement implémenté comme un "fichier non lié vivant dans [a] tmpfs qui doit être interne au noyau". En traçant le code, je comprends qu'il diffère de ne pas implémenter les vérifications LSM, et les memfds sont également créés pour prendre en charge les "sceaux", comme l'explique le billet de blog. Cependant, je suis extrêmement sceptique quant au fait que les memfds sont comptabilisés différemment d'un fichier tmp en principe.
Plus précisément, lorsque le tueur d'OOM frappera, je ne pense pas qu'il tiendra compte de la mémoire détenue par memfds. Cela pourrait totaliser jusqu'à 50% de RAM - la valeur de l'option size=pour tmpfs. Le noyau ne définit pas de valeur différente pour le tmpfs interne, il utilisera donc la taille par défaut de 50 %.
Je pense donc que nous pouvons généralement nous attendre à ce que les processus qui contiennent un grand memfd, mais aucune autre allocation de mémoire significative, ne soient pas tués par OOM. Est-ce exact ?
Réponse acceptée :
S'appuyant sur la réponse de @danblack :
La décision est basée sur oom_kill_process()
(nettoyé un peu):
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)
Qui dépend de oom_badness()
pour trouver le meilleur candidat :
child_points = oom_badness(child,
oc->memcg, oc->nodemask, oc->totalpages);
oom_badness()
fait :
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)
Où :
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)
Il semble donc qu'il compte les pages anonymes, c'est ce que memfd_create()
utilise.