Linux'ta süreç belleğini anlaşılır biçimde keşfetmek
(0xkato.xyz)- Linux'un süreç bellek yapısını gerçek çalışma düzeyinde açıklıyor; sanal adres alanı ile fiziksel bellek arasındaki ilişkiyi adım adım ele alıyor
- Page table, VMA, mmap, page fault, CoW gibi temel mekanizmalara odaklanarak süreçlerin belleği nasıl sahiplendiğini ve ona nasıl eriştiğini somut biçimde anlatıyor
/procdosya sistemi üzerinden süreç bazlı bellek durumunun nasıl gözlemleneceğini vepagemap,kpageflagsgibi gelişmiş tanılama araçlarının rolünü tanıtıyor- Transparent Huge Pages (THP), userfaultfd, PAGEMAP_SCAN gibi modern çekirdek özellikleriyle performans optimizasyonu ve kullanıcı alanı dirty tracking tekniklerini ele alıyor
- Meltdown için PTI, TLB flush, W^X politikası gibi güvenlik ve performans odaklı çekirdek tasarım ilkelerini de açıklayarak Linux bellek yönetimine bütüncül bir anlayış sunuyor
Süreç belleğinin temel yapısı
- Bir program çalıştığında devasa ve kesintisiz bir bellek varmış gibi görünür; ancak gerçekte bunu Linux çekirdeği sayfa düzeyinde dinamik olarak oluşturur
- CPU, sanal adresi fiziksel çerçeveye çevirmek için page table'ı sorgular
- Eşleme yoksa page fault oluşur; çekirdek yeni bir sayfa ayırır ya da hata döndürür
- Fiziksel RAM yetersiz kaldığında çekirdek kullanılmayan sayfaları diske taşır veya dosya sayfalarını çıkararak alan açar
/proc, çekirdeğin bellekte oluşturduğu sanal dosya sistemidir ve süreç ile çekirdek durumunu dosya biçiminde dışarı sunar
Adres alanı ve VMA
- Her süreç tek bir adres alanı nesnesine sahiptir; bunun içi birden fazla VMA (Virtual Memory Area) ile oluşturulur
- VMA, aynı izinlere (R/W/X) ve aynı arka uca (anonim bellek veya dosya) sahip kesintisiz adres aralığıdır
- Page table, donanımın başvurduğu yapıdır ve sanal sayfalar ile fiziksel sayfalar arasındaki eşleme bilgisini (PTE) saklar
- Adres alanı değişiklikleri üç sistem çağrısıyla yapılır
mmap: yeni alan oluşturmamprotect: izin değiştirmemunmap: eşlemeyi kaldırma
- Sayfalar varsayılan olarak 4KiB boyutundadır; bazı sistemler 2MiB ve 1GiB büyük sayfaları da destekler
/proc/self/maps ile bellek yapısını görmek
cat /proc/self/mapskomutuyla sürecin bellek eşlemesi görülebilir- Çalıştırılabilir dosyanın kodu, verisi, bss bölümü, heap, anonim eşlemeler, paylaşımlı kütüphaneler ve stack gösterilir
[vdso]ve[vvar]alanları, çekirdeğin eşlediği hızlı sistem çağrıları için kod ve veri bölgeleridir
mmap nasıl çalışır
mmap, gerçek bir bellek ayırma işlemi değil; adres alanı üzerinde bir taahhüt kaydı oluşturur- Sayfalar ilk erişim anında ayrılır
- Dosya eşlemelerinde
offsetsayfa hizalı olmalıdır; dosya sonunun ötesine erişimSIGBUSüretir MAP_SHAREDdeğişiklikleri doğrudan dosyaya yansıtır,MAP_PRIVATEise write sırasında copy-on-write (CoW) ile bağımsız sayfa oluştururMAP_FIXED_NOREPLACE, belirtilen adreste zaten bir eşleme varsa işlemi başarısız kılarak güvenliği artırır
İlk erişim ve page fault
- Yeni bir eşlemeye ilk erişimde CPU page table'da karşılık bulamazsa page fault oluşur
- Çekirdek adresin geçerliliğini, erişim iznini ve varlığını denetler
- Anonim eşlemeyse sıfırlarla doldurulmuş yeni sayfa ayırır; dosya eşlemeyse page cache'den okur
- minor fault, veri zaten RAM'deyse; major fault ise disk I/O gerektiğinde oluşur
- Stack, guard page ile korunur; fazla aşağıya erişimde
SIGSEGVoluşur
fork() ve MAP_PRIVATE için Copy-on-Write
forksırasında ebeveyn ve çocuk süreç aynı fiziksel sayfaları paylaşır ve bunların tümü salt okunur işaretlenir- Yalnızca yazma anında yeni sayfa kopyalanır ve bağımsızlık korunur
MAP_PRIVATEdosya eşlemeleri de aynı ilkeyle çalışır- İlgili seçenekler
vfork: ebeveynin adres alanını paylaşırclone(CLONE_VM): thread oluştururMADV_DONTFORK,MADV_WIPEONFORK: eşlemeyi çocuk süreçten hariç tutar veya sıfırlayarak başlatır
İzin değiştirme ve TLB geçersiz kılma
mprotectile sayfa izinleri değiştirildiğinde çekirdek VMA bölme ve page table güncelleme yapar, ardından TLB geçersiz kılma uygular- W^X politikası gereği bir sayfa aynı anda hem yazılabilir hem çalıştırılabilir olamaz
- TLB (Translation Lookaside Buffer), son adres çevirilerinin önbelleğidir; geçersiz kılma kısa gecikme yaratabilir
/proc üzerinden ayrıntılı gözlem
/proc/<pid>/maps,smaps,smaps_rollupile alan bazında izinler, RSS ve HugePage kullanımı görülebilir/proc/<pid>/pagemap, sayfa düzeyinde durum bilgisi sunar (mevcut, swap'te, PFN vb.); ancak PFN normal kullanıcılara kapalıdır/proc/kpagecount,/proc/kpageflags, PFN başına eşleme sayısını ve sayfa özelliklerini (anonim, dosya, dirty vb.) gösterirmincore,SEEK_DATA/SEEK_HOLEile seyrek dosyalardaki veri ve boşluk bölgeleri saptanabilirPAGEMAP_SCANileuserfaultfdbirlikte kullanılarak kullanıcı alanı dirty tracking uygulanabilir
Transparent Huge Pages (THP) ve mTHP
- THP, sık erişilen belleği otomatik olarak büyük sayfalarda (2MiB vb.) toplayarak TLB verimliliğini artırır
khugepagedthread'i bitişik sayfaları birleştirir
- mTHP, 16KiB ve 64KiB gibi farklı boyutlarda değişken büyük sayfaları (folio) destekler
/proc/self/smapsiçindekiAnonHugePages,FilePmdMappedalanlarından kullanım durumu görülebilir- Sistem genelindeki ayarlar
/sys/kernel/mm/transparent_hugepage/altında yönetilir MADV_HUGEPAGE,MADV_NOHUGEPAGEile alan bazında kontrol sağlanabilir
Kullanıcı alanı dirty tracking
userfaultfdvePAGEMAP_SCANkullanılarak yalnızca değişen sayfalar kopyalanabilir- Çekirdek tek bir atomik işlemle hem tarama hem write-protect uygular
- Snapshot, live migration gibi senaryolarda verimlidir
TLB flush mekanizması
- x86'da TLB geçersiz kılma iki şekilde yapılır
INVLPG: tek sayfayı geçersiz kılar- Page table kökünü yeniden yükleyerek tam flush
PCIDveINVPCID, süreç bazlı TLB etiket yönetimi ile gereksiz flush işlemlerini azaltırtlb_single_page_flush_ceiling, çekirdeğin sayfa bazlı mı yoksa tam flush mı seçeceğini belirleyen eşik değerdir
Meltdown önlemi: Page Table Isolation (PTI)
- Meltdown, spekülatif yürütme sırasında çekirdek verisinin önbellek üzerinden sızabilmesine yol açan bir zafiyettir
- Linux, PTI (Page Table Isolation) ile kullanıcı ve çekirdek adres alanlarını ayırır
- Girişte
CR3değiştirilerek yalnızca çekirdeğe ait page table kullanılır PCIDkullanılarak TLB flush etkisi en aza indirilir
- Girişte
- Varsayılan olarak etkindir;
noptiile devre dışı bırakılabilir
Çekirdeğin güvenli eşleme değiştirme süreci
- Eşleme değiştirirken sıra şöyledir
- Önbellek kurallarını işleme
- Page table'ı güncelleme
- TLB'yi geçersiz kılma
- Çekirdek içi eşlemelerde (
vmap,vmalloc) de I/O öncesi ve sonrasında cache ve TLB eşzamanlaması yapılır - Bazı mimarilerde kod kopyalandıktan sonra instruction cache flush gerekir
x86'da stack ve çağrı yapısı
- 64 bit modda RIP, RSP, RBP yazmaçları kullanılır; stack aşağı doğru büyür
- System V AMD64 ABI'ye göre argümanlar RDI, RSI, RDX, RCX, R8, R9, dönüş değeri ise RAX ile taşınır
- Kullanıcı modu ring 3, çekirdek ring 0 düzeyindedir; sistem çağrıları ve kesmeler kapılar üzerinden geçiş yapar
Hata durumları ve tanılama
mmap→EINVAL: dosya offset hizalama hatasımmap→ENOMEM: sanal alan yetersizliği veya overcommit sınırı- Dosya eşlemesine erişimde
SIGBUS: EOF ötesine erişim mprotect(PROT_EXEC)→EACCES:noexecmount veya W^X politikasıfork()sonrası RSS artışı: CoW nedeniyle sayfa kopyalamaMAP_FIXEDile mevcut eşlemenin üzerine yazma →MAP_FIXED_NOREPLACEönerilir
Uygulama için kontrol listesi
- Hemen bellek edinmek için:
mmap+PROT_READ|PROT_WRITE+MAP_PRIVATE|MAP_ANONYMOUS - Kod üretirken: W^X'i koru,
mprotect(PROT_READ|PROT_EXEC)kullan - Dosya eşlerken:
offsetsayfa hizalı olsun, EOF ötesine erişme - Çok sayıda page fault varsa:
MADV_WILLNEEDveya ön erişim kullan - Bellek kullanımını analiz ederken:
/proc/<pid>/smaps_rollup→/proc/<pid>/maps - Büyük süreçlerde fork: CoW'yi hesaba kat, çocuk süreçte
execkullan - Gecikmeye duyarlı ortamlarda: THP/mTHP,
mlock, TLB davranışını gözlemle
1 yorum
Hacker News görüşleri
Bu tür kısa açıklama yazılarını gerçekten seviyorum
Zaten bildiğim şeyler olsa bile, okurken bir kez daha teyit etme fırsatı verdiği için faydalı oluyor
“mmap, without the fog” gibi ifadeleri görünce, sanki LLM ile ortak yazılmış bir metin gibi geliyor; bu da beni gereksiz yere huzursuz edip sinirlendiriyor
Bir de içine “without the fog” gibi garip bir ifade girince, ChatGPT de katkı vermiş gibi bir izlenim oluşuyor
Instruction pipelining konusunu görünce, eski 6502 gibi basit mimarilerin dönemine geri dönmek istiyorum
O zamanlar karmaşık eşlemeler ya da proxy’ler olmadan, her şey “olduğu gibi” çalışıyordu
Yeterince hızlı ara bağlantılar olsa, o sadeliği yeniden hayal etmek mümkün olabilir gibi geliyor
Ama Meltdown ve Spectre gibi sorunlara bakınca, artan karmaşıklığın da açık bir bedeli olduğu ortada
Moore Yasası’nın sınıra dayandığı bugünkü noktada, bu karmaşıklık ödünleşiminin gerçekten en iyi seçenek olup olmadığını sorguluyorum
Sadelik her zaman daha iyi demek değil
Web sitesinin tehlikeli veya güvenli olmayan bir alan adı olarak engellendiği görünüyor
VirusTotal tarama sonucuna bakınca bir sorun görünmüyor
Hata raporlarının sadece “gürültü (noise)” olduğu sözüyle ne kastedildiğini merak ediyorum