Czy błędem jest myśleć o „memfd” jako o „procesie będącym właścicielem pliku”?

15

https://dvdhrm.wordpress.com/2014/06/10/memfd_create2/

Teoretycznie można osiągnąć memfd_create()zachowanie [ ] bez wprowadzania nowych wywołań systemowych, takich jak:

int fd = open("/tmp", O_RDWR | O_TMPFILE | O_EXCL, S_IRWXU);

(Uwaga: aby bardziej przenośnie zagwarantować tmpfs tutaj, możemy użyć „ /dev/shm” zamiast „ /tmp”).

Dlatego najważniejsze pytanie brzmi: dlaczego do diabła potrzebujemy trzeciej drogi?

[...]

  • Pamięć kopii zapasowej jest uwzględniana w procesie, który jest właścicielem pliku i nie podlega limitom montowania.

^ Czy mam rację, sądząc, że nie można polegać na pierwszej części tego zdania?

Kod memfd_create () jest dosłownie zaimplementowany jako „ niepowiązany plik żyjący w [a] tmpfs, który musi być wewnętrznym jądrem ”. Śledząc kod, rozumiem, że różni się tym, że nie wdraża kontroli LSM, a także memfds są tworzone w celu obsługi „pieczęci”, jak wyjaśnia blog. Jednak jestem bardzo sceptyczny że memfds są ujmowane odmiennie do tmpfile w zasadzie.

W szczególności, kiedy zabijający OOM puka, nie sądzę, że będzie to wyjaśniać pamięć przechowywaną przez memfds. Może to wynieść do 50% pamięci RAM - wartość opcji size = dla tmpfs . Jądro nie ustawia innej wartości dla wewnętrznych tmpfs, więc użyłby domyślnego rozmiaru 50%.

Myślę więc, że ogólnie możemy oczekiwać procesów, które przechowują dużą pamięć memfd, ale żadne inne znaczące przydziały pamięci nie zostaną zabite przez OOM. Czy to jest poprawne?

sourcejedi
źródło
2
Jeśli chodzi o wyniki OOM, wydaje się, że sprowadza się to do funkcji jądra oom_badness . Podejrzewam więc, że jeśli memfd_create nie pojawia się na mapie / proc / {pid} / map, to nie jest liczone. Ogólna odpowiedź brzmi: mogą zostać zabici, ale nie będą mieli dużej liczby punktów z powodu użycia memfd_create. Pamięć dla fd może być współużytkowana przez procesy, ponieważ wiele procesów może dziedziczyć / być wysyłanych, tak samo jak fd.
danblack

Odpowiedzi:

1

Opierając się na odpowiedzi @ danblack:

Decyzja opiera się na oom_kill_process()(nieco oczyszczonym):

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 )

Co zależy od oom_badness()znalezienia najlepszego kandydata:

child_points = oom_badness(child,
        oc->memcg, oc->nodemask, oc->totalpages);

oom_badness() robi:

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 )

Gdzie:

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 )

Wygląda więc na to, że liczy anonimowe strony, z których memfd_create()korzysta.

V13
źródło