Bölüm 16: Linux

İşletim Sistemleri
UNIX ve Linux tarihçesiTasarım hedefleri ve arayüzlerKabuk ve boru hatlarıÇekirdek yapısı ve modüllerSüreçler, sinyaller, iş parçacıklarıÇizelgeleme: EEVDF, gerçek zamanlıÖnyükleme ve systemdBellek: sayfalama, buddy, SLUBG/Ç: aygıtlar, blk-mq, ağDosya sistemleri: VFS, ext4Güvenlik: izinler, konteynerlerAndroid
Sercan KÜLCÜ · Giresun Üniversitesi · Bilgisayar Mühendisliği

Giriş

Öğrenme Çıktıları

Tarih ve aile

UNIX’ten BSD, MINIX, GNU ve Linux’a uzanan çizgiyi; dağıtımları ve Android’i konumlandırmak.

Arayüzler ve kabuk

Kütüphane / sistem çağrısı / çekirdek katmanlarını ayırmak; boru hatlarının fork, pipe, dup2 ile kurulduğunu göstermek.

Süreçler ve çizelgeleme

fork/exec/wait, sinyaller, task_struct, clone() ve NPTL; EEVDF ve gerçek zamanlı sınıfları açıklamak.

Bellek

Adres alanı düzenini, 4/5 düzeyli sayfa tablolarını, buddy + SLUB ayırıcılarını, sayfa önbelleğini ve OOM’u yorumlamak.

G/Ç ve dosyalar

Aygıt dosyaları, blk-mq, ağ yığını; VFS, i-node, ext4 extent ve günlükleme, bağlar ve /proc.

Güvenlik

rwx/setuid/umask hesaplamak; yetenekler, namespaces + cgroups, SELinux/AppArmor, seccomp ve Android kum havuzunu tanımak.

Giriş ve Tarihçe · Adım adım

UNIX’ten Linux’a Zaman Çizelgesi

1969–1983UNIX doğuyor1969UNIX, PDP-7 (Bell Labs)1971PDP-11’e taşındı1973C ile yeniden yazıldı1977BSD (Berkeley)1983System V, 4.2BSD1983GNU projesi1984–1993?1994–2010?2011–2026?

Ken Thompson ve Dennis Ritchie UNIX’i 1969’da PDP-7 üzerinde assembly ile yazdı; 1973’te C ile yeniden yazılması taşınabilirliği getirdi. AT&T kaynak kodunu üniversitelere verdi: Berkeley’den BSD doğdu.

1969–1983UNIX doğuyor1969UNIX, PDP-7 (Bell Labs)1971PDP-11’e taşındı1973C ile yeniden yazıldı1977BSD (Berkeley)1983System V, 4.2BSD1983GNU projesi1984–1993Özgür UNIX arayışı1987MINIX (Tanenbaum)1988POSIX standardı1989GPL lisansı1991Linux 0.01 (Torvalds)19920.12: GPL’ye geçiş1993Slackware, Debian1994–2010?2011–2026?

Ticari UNIX’ler (System V, SunOS, AIX…) birbirinden ayrışınca POSIX ortak arayüzü tanımladı. Tanenbaum öğretim için MINIX’i yazdı; Linus Torvalds 1991’de MINIX üzerinde kendi çekirdeğini geliştirdi ve GNU araçlarıyla birleştirdi.

1969–1983UNIX doğuyor1969UNIX, PDP-7 (Bell Labs)1971PDP-11’e taşındı1973C ile yeniden yazıldı1977BSD (Berkeley)1983System V, 4.2BSD1983GNU projesi1984–1993Özgür UNIX arayışı1987MINIX (Tanenbaum)1988POSIX standardı1989GPL lisansı1991Linux 0.01 (Torvalds)19920.12: GPL’ye geçiş1993Slackware, Debian1994–2010Linux olgunlaşıyor1994Linux 1.019962.0: SMP desteği1999Red Hat halka arz20032.6 serisi2005git2008Android: HTC Dream2011–2026?

Linux 1.0 (1994), 2.0 ile çok işlemci (Bkz. Bölüm 12), 2.6 ile kesilebilir çekirdek ve O(1)/CFS çizelgeleyicileri. 2005’te BitKeeper sorunu üzerine Torvalds git’i yazdı. İlk Android telefonu 2008’de çıktı.

1969–1983UNIX doğuyor1969UNIX, PDP-7 (Bell Labs)1971PDP-11’e taşındı1973C ile yeniden yazıldı1977BSD (Berkeley)1983System V, 4.2BSD1983GNU projesi1984–1993Özgür UNIX arayışı1987MINIX (Tanenbaum)1988POSIX standardı1989GPL lisansı1991Linux 0.01 (Torvalds)19920.12: GPL’ye geçiş1993Slackware, Debian1994–2010Linux olgunlaşıyor1994Linux 1.019962.0: SMP desteği1999Red Hat halka arz20032.6 serisi2005git2008Android: HTC Dream2011–2026Her yerde Linux20113.0 numarası2017Top500: %100 Linux20226.0; 6.1’de Rust20236.6: EEVDF20246.12: sched_ext, RT20266.x → 7.0 serisi

2017’den beri dünyanın en hızlı 500 süper bilgisayarının tamamı Linux çalıştırıyor. 6.x serisinde Rust desteği, EEVDF ve sched_ext geldi; numaralar yalnızca büyüdüğü için artar (6.19’un ardından 7.0).

Giriş ve Tarihçe

GNU, Linux ve Dağıtımlar

Uygulamalar: masaüstü, sunucu yazılımlarıPaket yöneticisi + depolar (apt, dnf, pacman)init sistemi: systemdGNU araçları + C kütüphanesi (glibc, musl)Linux çekirdeğidağıtım(distro)Android: Linux çekirdeği + Bionic libc,GNU araçları yok
AileÖrneklerPaket
DebianDebian, Ubuntu, Mint, Pardus.deb / apt
Red HatFedora, RHEL, Rocky, Alma.rpm / dnf
ArchArch, Manjaropacman
SUSEopenSUSE, SLESzypper
HafifAlpine (musl + BusyBox)apk

Sürüm modeli: ~9–10 haftada bir ana sürüm (2 haftalık birleştirme penceresi + rc1…rc7). Her yılın son sürümü LTS olur: 6.6, 6.12, 6.18…

“Linux” tam olarak yalnızca çekirdeğin adıdır; kullanıcıların kurduğu sistem bir dağıtımdır (GNU/Linux).

Giriş ve Tarihçe

Tasarım Hedefleri ve UNIX Felsefesi

Basit (simple)

Az sayıda, iyi tanımlı kavram: süreç, dosya, boru.

Şık (elegant)

Küçük, tek iş yapan araçlar birleştirilerek büyük iş yapılır.

Tutarlı (consistent)

“Her şey dosyadır”: disk, terminal, boru aynı read/write ile.

Güçlü (powerful)

Kabuk betikleri, boru hatları, düzenli ifadeler.

Esnek (flexible)

Metin akışları evrensel arayüz; araçlar birbirini bilmeden çalışır.

Programcı için

Sistemi programcılar programcılar için tasarladı: az “sihir”, sessiz başarı.

UNIX felsefesi (McIlroy): Tek bir işi iyi yapan programlar yazın; birlikte çalışacak programlar yazın; metin akışlarını işleyen programlar yazın, çünkü metin evrensel arayüzdür.

POSIX bu arayüzü standartlaştırır: aynı kaynak kod Linux, BSD ve macOS’ta derlenebilir.

Kabuk ve Arayüzler · Adım adım

Katmanlar ve Arayüzler: Bir printf’in Yolculuğu

KullanıcılarStandart yardımcı programlarkabuk, editör, derleyiciStandart kütüphane (glibc)printf, open, fork sarmalayıcılarıLinux çekirdeğisüreç, bellek, dosya, G/ÇDonanımCPU, bellek, diskler, terminalkullanıcı arayüzükütüphane arayüzüsistem çağrısı arayüzükullanıcı kipiçekirdek kipi1 · Uygulamaprintf("merhaba\n");glibc tamponuna yazar

Program printf çağırır. Bu henüz bir sistem çağrısı değildir: glibc metni kullanıcı alanındaki bir tampona yazar.

KullanıcılarStandart yardımcı programlarkabuk, editör, derleyiciStandart kütüphane (glibc)printf, open, fork sarmalayıcılarıLinux çekirdeğisüreç, bellek, dosya, G/ÇDonanımCPU, bellek, diskler, terminalkullanıcı arayüzükütüphane arayüzüsistem çağrısı arayüzükullanıcı kipiçekirdek kipi1 · Uygulamaprintf("merhaba\n");glibc tamponuna yazar2 · glibcwrite(1, buf, 8)rax ← 1 (write), syscall

Tampon boşaltılırken glibc’nin write() sarmalayıcısı çalışır: sistem çağrısı numarasını (x86-64’te write = 1) rax’a, argümanları yazmaçlara koyar ve syscall komutunu yürütür.

KullanıcılarStandart yardımcı programlarkabuk, editör, derleyiciStandart kütüphane (glibc)printf, open, fork sarmalayıcılarıLinux çekirdeğisüreç, bellek, dosya, G/ÇDonanımCPU, bellek, diskler, terminalkullanıcı arayüzükütüphane arayüzüsistem çağrısı arayüzükullanıcı kipiçekirdek kipi1 · Uygulamaprintf("merhaba\n");glibc tamponuna yazar2 · glibcwrite(1, buf, 8)rax ← 1 (write), syscall3 · Çekirdek girişientry_SYSCALL_64sys_call_table[1] → vfs_write

CPU çekirdek kipine geçer (Bkz. Bölüm 2). Giriş kodu numarayla sys_call_table’dan işleyiciyi seçer; VFS dosya tanımlayıcısı 1’in arkasındaki nesneyi bulur.

KullanıcılarStandart yardımcı programlarkabuk, editör, derleyiciStandart kütüphane (glibc)printf, open, fork sarmalayıcılarıLinux çekirdeğisüreç, bellek, dosya, G/ÇDonanımCPU, bellek, diskler, terminalkullanıcı arayüzükütüphane arayüzüsistem çağrısı arayüzükullanıcı kipiçekirdek kipi1 · Uygulamaprintf("merhaba\n");glibc tamponuna yazar2 · glibcwrite(1, buf, 8)rax ← 1 (write), syscall3 · Çekirdek girişientry_SYSCALL_64sys_call_table[1] → vfs_write4 · Sürücüpty/tty sürücüsüterminal ekrana basar

fd 1 bir sözde terminale (pty) bağlıdır; tty katmanı veriyi terminal öykünücüsüne iletir. Disk olsaydı yol sayfa önbelleğine ve blok katmanına giderdi.

KullanıcılarStandart yardımcı programlarkabuk, editör, derleyiciStandart kütüphane (glibc)printf, open, fork sarmalayıcılarıLinux çekirdeğisüreç, bellek, dosya, G/ÇDonanımCPU, bellek, diskler, terminalkullanıcı arayüzükütüphane arayüzüsistem çağrısı arayüzükullanıcı kipiçekirdek kipi1 · Uygulamaprintf("merhaba\n");glibc tamponuna yazar2 · glibcwrite(1, buf, 8)rax ← 1 (write), syscall3 · Çekirdek girişientry_SYSCALL_64sys_call_table[1] → vfs_write4 · Sürücüpty/tty sürücüsüterminal ekrana basar5 · Dönüşrax ← 8 (yazılan bayt)sysret → kullanıcı kipi

Dönüş değeri rax’ta (8 bayt) döner, sysret ile kullanıcı kipine dönülür. Hata olursa negatif değer glibc’de errno’ya çevrilir ve −1 döner.

Kabuk ve Arayüzler

Temel Komutlar ve Yönlendirme

KategoriKomutlarNot
Dosya / dizinls cd pwd mkdir rm -r cp mv touch find tartouch zaman damgasını günceller; dosya yoksa boş dosya oluşturur
Metin (filtre)cat less head tail grep sort uniq wc echostdin’den okur, stdout’a yazar: boru hattında birleşir
Süreç / sistemps top kill chmod chown df du syncsync kirli tamponları diske yazar (makineler arası eşitleme: rsync)
Ağssh scp ping curl wget tracerouteip addr, ip route, ss, nft eski ifconfig, route, netstat, iptables’ın yerini aldı
Bilgiman uname free lsblk/proc komut değil, sözde dosya sistemidir: cat /proc/meminfo
# yönlendirme: 0 = stdin, 1 = stdout, 2 = stderr
sort < girdi.txt > cikti.txt 2> hatalar.log   # < okur, > yazar (üzerine)
echo "satır" >> gunluk.txt                  # >> sona ekler
make 2>&1 | tee derleme.log &              # stderr→stdout, boru, arka plan

Kabuk ve Arayüzler · Adım adım

Boru Hattı: Veri Aşamalardan Akar

cat log.txtPID 2101|çıktı (stdout)grep hataPID 2102|çıktı (stdout)sortPID 2103|çıktı (stdout)uniq -cPID 2104çıktı (stdout)kabuk: 3 boru + 4 çocuk süreç (fork + exec), hepsi eşzamanlı

Kabuk satırı ayrıştırır, 3 boru ve 4 süreç oluşturur. Süreçler aynı anda çalışır; her biri yalnızca kendi stdin/stdout’unu bilir.

cat log.txtPID 2101|çıktı (stdout)hata: diskbilgi: açılışhata: ağhata: diskuyarı: ısıhata: ağhata: diskgrep hataPID 2102|çıktı (stdout)sortPID 2103|çıktı (stdout)uniq -cPID 2104çıktı (stdout)

cat dosyanın 7 satırını boruya yazar. Boru tamponu (varsayılan 64 KiB) dolarsa yazan süreç bloke olur: üretici–tüketici (Bkz. Bölüm 6).

cat log.txtPID 2101|çıktı (stdout)hata: diskbilgi: açılışhata: ağhata: diskuyarı: ısıhata: ağhata: diskgrep hataPID 2102|çıktı (stdout)hata: diskhata: ağhata: diskhata: ağhata: disksortPID 2103|çıktı (stdout)uniq -cPID 2104çıktı (stdout)

grep satır satır okur, eşleşen 5 satırı hemen iletir. Filtre durumsuzdur, akışı bekletmez.

cat log.txtPID 2101|çıktı (stdout)hata: diskbilgi: açılışhata: ağhata: diskuyarı: ısıhata: ağhata: diskgrep hataPID 2102|çıktı (stdout)hata: diskhata: ağhata: diskhata: ağhata: disksortPID 2103|çıktı (stdout)hata: ağhata: ağhata: diskhata: diskhata: diskuniq -cPID 2104çıktı (stdout)

sort ise tüm girdiyi (EOF’a kadar) okumadan çıktı veremez: son satır ilk sırayı değiştirebilir.

cat log.txtPID 2101|çıktı (stdout)hata: diskbilgi: açılışhata: ağhata: diskuyarı: ısıhata: ağhata: diskgrep hataPID 2102|çıktı (stdout)hata: diskhata: ağhata: diskhata: ağhata: disksortPID 2103|çıktı (stdout)hata: ağhata: ağhata: diskhata: diskhata: diskuniq -cPID 2104çıktı (stdout) 2 hata: ağ 3 hata: diskterminal

uniq -c yalnızca ardışık tekrarları sayar; bu yüzden önce sort gerekir. Sonuç: 2 × “hata: ağ”, 3 × “hata: disk”.

Kabuk ve Arayüzler · Kodu adım adım çalıştır

Kabuk Bir Boru Hattını Nasıl Kurar?

int fd[2];
pipe(fd);              /* 3: okuma, 4: yazma */
if (fork() == 0) {    /* çocuk 1 */
    dup2(fd[1], 1);
    close(fd[0]); close(fd[1]);
    execlp("ls", "ls", NULL);
}
if (fork() == 0) {    /* çocuk 2 */
    dup2(fd[0], 0);
    close(fd[0]); close(fd[1]);
    execlp("wc", "wc", "-l", NULL);
}
/* kabuk: iki ucu da kapat */
close(fd[0]); close(fd[1]);
wait(NULL); wait(NULL);
kabuk0tty1tty2tty3boru-o4boru-yçocuk 101234çocuk 201234boru tamponuy →→ o

pipe() çekirdekte bir tampon ve iki uç oluşturur: en küçük boş numaralar 3 (okuma) ve 4 (yazma).

kabuk0tty1tty2tty3boru-o4boru-yçocuk 10tty1tty2tty3boru-o4boru-yçocuk 201234boru tamponuy →→ o

fork(): çocuk, tanımlayıcı tablosunun kopyasını alır; iki süreç aynı boruyu işaret eder.

kabuk0tty1tty2tty3boru-o4boru-yçocuk 10tty1boru-y2tty34çocuk 201234boru tamponuy →→ o

dup2(4, 1): stdout artık borunun yazma ucu. Fazla uçlar kapatılır.

kabuk0tty1tty2tty3boru-o4boru-yls0tty1boru-y2tty34çocuk 201234boru tamponuy →→ o

execlp görüntüyü ls ile değiştirir; tanımlayıcı tablosu korunur. ls hiçbir şey bilmeden boruya yazar.

kabuk0tty1tty2tty3boru-o4boru-yls0tty1boru-y2tty34wc0boru-o1tty2tty34boru tamponuy →→ o

İkinci çocuk stdin’ini borunun okuma ucuna bağlar ve wc -l olur.

kabuk0tty1tty2tty34ls0tty1boru-y2tty34wc0boru-o1tty2tty34boru tamponuy →→ o

Kabuk iki ucu da kapatır. Kapatmasaydı yazma ucu açık kalır, wc hiç EOF görmez ve sonsuza dek beklerdi. Sonra iki çocuğu bekler.

Çekirdek Yapısı

Linux Çekirdeğinin Yapısı

Sistem çağrılarıG/Ç bileşeniSanal dosya sistemi (VFS)TerminallerSatır disipliniKarakter aygıt sürücüleriSoketlerAğ protokolleriAğ aygıt sürücüleriDosya sistemleriGenel blok katmanıG/Ç zamanlayıcıBlok aygıt sürücüleriBellek yönetimiSanal bellekSayfalama,sayfa değiştirmeSayfa önbelleğiSüreç yönetimiSinyal işlemeSüreç/iş parçacığıoluşturma, sonlanmaCPU çizelgelemeKesmelerDağıtıcı (dispatcher)

Üstte sistem çağrısı arayüzü, altta kesmeler ve dağıtıcı (bağlam değiştirme). Tüm bileşenler tek adres alanında çalışır: Linux monolitik bir çekirdektir (Bkz. Bölüm 2). Klasik 4.4BSD çekirdeği de aynı üç bileşene ayrılıyordu.

Çekirdek Yapısı · Adım adım

Yüklenebilir Çekirdek Modülleri (LKM)

kullanıcı alanı# modprobe e1000emodules.dep: bağımlılıklarçekirdekfinit_module()imza denetimiyer değiştirmesembol bağlamamodule_init()sürücü kaydıPCI aygıtı eşleşir → probe()çekirdek sembol tablosuEXPORT_SYMBOL ile dışa açılanlareth0 arayüzü hazır

Monolitik ama modüler: sürücülerin çoğu yüklenebilir çekirdek modülüdür (.ko). Yönetici modprobe ile ister ya da udev aygıt görününce otomatik yükler.

kullanıcı alanı# modprobe e1000emodules.dep: bağımlılıklarçekirdekfinit_module()imza denetimiyer değiştirmesembol bağlamamodule_init()sürücü kaydıPCI aygıtı eşleşir → probe()çekirdek sembol tablosuEXPORT_SYMBOL ile dışa açılanlareth0 arayüzü hazır

modprobe, /lib/modules/$(uname -r)/modules.dep dosyasından bağımlılıkları bulur ve önce onları yükler (insmod bunu yapmaz).

kullanıcı alanı# modprobe e1000emodules.dep: bağımlılıklarçekirdekfinit_module()imza denetimiyer değiştirmesembol bağlamamodule_init()sürücü kaydıPCI aygıtı eşleşir → probe()çekirdek sembol tablosuEXPORT_SYMBOL ile dışa açılanlareth0 arayüzü hazır

finit_module() sistem çağrısı modülü çekirdeğe kopyalar; Secure Boot açıkken imzası doğrulanır. CAP_SYS_MODULE yeteneği gerekir.

kullanıcı alanı# modprobe e1000emodules.dep: bağımlılıklarçekirdekfinit_module()imza denetimiyer değiştirmesembol bağlamamodule_init()sürücü kaydıPCI aygıtı eşleşir → probe()çekirdek sembol tablosuEXPORT_SYMBOL ile dışa açılanlareth0 arayüzü hazır

Çekirdek modülün yer değiştirmelerini yapar ve kullandığı sembolleri EXPORT_SYMBOL ile dışa açılmış çekirdek fonksiyonlarına bağlar.

kullanıcı alanı# modprobe e1000emodules.dep: bağımlılıklarçekirdekfinit_module()imza denetimiyer değiştirmesembol bağlamamodule_init()sürücü kaydıPCI aygıtı eşleşir → probe()çekirdek sembol tablosuEXPORT_SYMBOL ile dışa açılanlareth0 arayüzü hazır

module_init fonksiyonu çalışır: sürücü kendini PCI alt sistemine kaydeder (pci_register_driver).

kullanıcı alanı# modprobe e1000emodules.dep: bağımlılıklarçekirdekfinit_module()imza denetimiyer değiştirmesembol bağlamamodule_init()sürücü kaydıPCI aygıtı eşleşir → probe()çekirdek sembol tablosuEXPORT_SYMBOL ile dışa açılanlareth0 arayüzü hazır

Eşleşen aygıt için probe() çağrılır, ağ arayüzü oluşur. lsmod listeler, rmmod kaldırır. Modül çekirdek ayrıcalığıyla çalışır: hatası tüm sistemi çökertebilir.

Kaynak ağacı ~40 milyon satır; büyük kısmı sürücüler. 6.1’den beri bazı sürücüler Rust ile yazılabiliyor; eBPF güvenli, doğrulanmış küçük programları çekirdekte çalıştırır.

Süreçler

Süreç Ağacı

swapper / idlePID 0systemdPID 1kthreaddPID 2journaldPID 312agetty tty1PID 901sshdPID 820sshd-sessionPID 4100bashPID 4105cp f1 f2PID 4190[kswapd0]PID 98[kworker/0:1]PID 45[ksoftirqd/0]PID 14çekirdek iş parçacıkları:yalnızca çekirdek alanında,ps çıktısında [köşeli parantez]öksüz kalan süreçlerPID 1’e bağlanır

Her sürecin bir PID’i ve bir ebeveyni (PPID) vardır; ağaç pstree -p veya ps -ef --forest ile görülür. Eski UNIX’te 1 numara init, 2 numara “sayfa cini” idi; Linux’ta PID 1 systemd, sayfa geri kazanımı ise kthreadd altındaki kswapd çekirdek iş parçacığıdır (Bkz. Bölüm 3).

Süreçler · Kodu adım adım çalıştır

fork, exec ve wait

int main(void) {
    pid_t pid = fork();
    if (pid == 0) {          /* çocuk */
        execlp("ls", "ls", "-l", NULL);
        _exit(127);         /* exec hatası */
    }
    int st;                   /* ebeveyn */
    waitpid(pid, &st, 0);
    printf("çocuk bitti: %d\n",
           WEXITSTATUS(st));
    return 0;
}
ebeveyn: a.outPID 501 · durum R

Kabuk programı başlatmış; tek süreç var (PID 501).

ebeveyn: a.outPID 501 · durum Rçocuk: a.outPID 748 · durum Rsayfalar paylaşılır: yazınca kopyala (COW)

fork() bir kez çağrılır, iki kez döner: ebeveynde çocuğun PID’i (748), çocukta 0. Bellek kopyalanmaz; sayfalar paylaşılır ve yazınca kopyalanır.

ebeveyn: a.outPID 501 · durum Rçocuk: ls -lPID 748 · durum Raynı PID, yeni program görüntüsü

Çocuk execlp ile kendini ls ile değiştirir. Başarılı exec geri dönmez; 5. satır yalnızca hata durumunda çalışır.

ebeveyn: a.outPID 501 · durum Sçocuk: ls -lPID 748 · durum Raynı PID, yeni program görüntüsüwaitpid() içinde uyuyor

Ebeveyn waitpid’de bloke olur (durum S). Hangi sürecin önce CPU alacağı belirsizdir, ama bekleme sayesinde çıktı sırası deterministiktir.

ebeveyn: a.outPID 501 · durum Sçocuk: zombiPID 748 · durum Zexit(0) → SIGCHLD

ls çıktısını yazar ve exit(0) ile biter. Çıkış durumu okunana kadar süreç zombi (Z) kalır; ebeveyne SIGCHLD gider.

ebeveyn: a.outPID 501 · durum R(toplandı)PID 748 · durum —çıkış durumu okundu, task_struct serbest

waitpid döner, zombi toplanır. WEXITSTATUS(st) = 0. Ebeveyn hiç beklemeseydi zombiler birikir, ebeveyn ölünce PID 1 toplardı.

Süreçler

fork ve exec Çekirdekte Ne Yapar?

shPID 501shPID 748lsPID 7481. fork() → yeni süreç2. execve() → aynı süreçkopya: aynı programgörüntü ls ile değişir

fork() çekirdekte

  • Yeni task_struct ayır, ebeveynden doldur, yeni PID ata
  • Çekirdek yığını ayır; yazmaçları kopyala (çocukta dönüş değeri 0)
  • Sayfa tablolarını kopyala, yazılabilir sayfaları salt okunur işaretle (COW)
  • Açık dosyaları paylaş: struct file referans sayısı artar
  • Sinyal işleyicileri, cwd, kimlik bilgileri kopyalanır

execve() çekirdekte

  • Yürütülebilir dosyayı bul, x iznini denetle, ELF başlığını oku
  • argv ve ortam değişkenlerini çekirdeğe kopyala
  • Eski adres alanını bırak; yeni mm_struct, segmentleri mmap et
  • argv/ortamı yeni yığına yerleştir; setuid bitine göre kimliği ayarla
  • Yakalanan sinyalleri varsayılana döndür, close-on-exec fd’leri kapat; PC ← ld.so veya giriş noktası

Eski UNIX fork’ta veri ve yığını gerçekten kopyalardı; Linux yalnızca sayfa tablolarını kopyalar (COW). Çoğu fork’u hemen exec izlediği için kopyalanan sayfa sayısı çok azdır.

Süreçler

POSIX Sinyalleri

Sinyal, bir sürece olay bildiren yazılım kesmesidir. Senkron (SIGSEGV, SIGFPE: sürecin kendi komutu) ya da asenkron (SIGINT, SIGTERM: dışarıdan) olabilir. Süreç her sinyal için varsayılan eylemi, yok saymayı ya da bir işleyici (kaynak temizleme, günlük yazma) seçebilir.

SinyalNoNe zaman üretilir?Varsayılan
SIGHUP1Terminal bağlantısı koptu; cinlerde “yapılandırmayı yeniden oku”sonlandır
SIGINT2Ctrl-C (ön plan süreç grubuna)sonlandır
SIGQUIT3Ctrl-\çekirdek dökümü
SIGILL4Geçersiz makine komutuçekirdek dökümü
SIGABRT6abort(): süreç kendini anormal sonlandırırçekirdek dökümü
SIGFPE8Tamsayı sıfıra bölme gibi aritmetik hataçekirdek dökümü
SIGKILL9kill -9; yakalanamaz, yok sayılamazsonlandır
SIGSEGV11Geçersiz bellek erişimiçekirdek dökümü
SIGPIPE13Okuyanı kalmamış boruya yazmasonlandır
SIGALRM14alarm() süresi doldusonlandır
SIGTERM15kill komutunun varsayılanı; nazik sonlandırma isteğisonlandır
SIGUSR1/210/12Kullanıcı tanımlısonlandır
SIGCHLD17Çocuk süreç bitti/durduyok say
SIGSTOP / SIGCONT19/18Durdur (yakalanamaz) / devam ettir; Ctrl-Z → SIGTSTPdurdur / sürdür

Numaralar x86/ARM Linux içindir. SIGKILL ve SIGTERM’ü ikisi de kill komutuyla gönderilebilir; fark yakalanabilirlikte.

Süreçler · Adım adım

Sinyal Teslimi

kullanıcı kipiçekirdek kipimain() döngüsükesildiği yer: PC = 0x401a2chandler(SIGINT)bayrak = 1; return;rt_sigreturntrampolin: sistem çağrısıtty sürücüsüCtrl-C → SIGINTtask_structbekleyen: 2 · maske: boşsinyal çerçevesiyazmaçlar kullanıcı yığınına

Kullanıcı Ctrl-C’ye basar: tty satır disiplini ön plan süreç grubuna SIGINT üretir. Çekirdek yalnızca hedef görevin bekleyen sinyal kümesinde 2. biti açar.

kullanıcı kipiçekirdek kipimain() döngüsükesildiği yer: PC = 0x401a2chandler(SIGINT)bayrak = 1; return;rt_sigreturntrampolin: sistem çağrısıtty sürücüsüCtrl-C → SIGINTtask_structbekleyen: 2 · maske: boşsinyal çerçevesiyazmaçlar kullanıcı yığınınaçekirdekten dönüşte denetim

Sinyal hemen işlenmez. Süreç bir sistem çağrısından ya da kesmeden kullanıcı kipine dönerken çekirdek “bekleyen ve maskelenmemiş” sinyal var mı diye bakar.

kullanıcı kipiçekirdek kipimain() döngüsükesildiği yer: PC = 0x401a2chandler(SIGINT)bayrak = 1; return;rt_sigreturntrampolin: sistem çağrısıtty sürücüsüCtrl-C → SIGINTtask_structbekleyen: 2 · maske: boşsinyal çerçevesiyazmaçlar kullanıcı yığınına

sigaction ile işleyici kurulmuşsa çekirdek kullanıcı yığınına bir sinyal çerçevesi (kaydedilmiş yazmaçlar + dönüş trampolini) yazar ve PC’yi işleyiciye ayarlar.

kullanıcı kipiçekirdek kipimain() döngüsükesildiği yer: PC = 0x401a2chandler(SIGINT)bayrak = 1; return;rt_sigreturntrampolin: sistem çağrısıtty sürücüsüCtrl-C → SIGINTtask_structbekleyen: 2 · maske: boşsinyal çerçevesiyazmaçlar kullanıcı yığınınayalnızca async-signal-safe çağrılar

İşleyici kullanıcı kipinde çalışır. İçinde yalnızca async-signal-safe fonksiyonlar (ör. write, bir volatile sig_atomic_t bayrağı) güvenlidir; printf, malloc değil.

kullanıcı kipiçekirdek kipimain() döngüsükesildiği yer: PC = 0x401a2chandler(SIGINT)bayrak = 1; return;rt_sigreturntrampolin: sistem çağrısıtty sürücüsüCtrl-C → SIGINTtask_structbekleyen: 2 · maske: boşsinyal çerçevesiyazmaçlar kullanıcı yığınına

İşleyici dönünce trampolin rt_sigreturn sistem çağrısını yapar: çekirdek çerçevedeki yazmaçları geri yükler. (sigreturn işleyiciye girmez, işleyiciden döner.)

kullanıcı kipiçekirdek kipimain() döngüsükesildiği yer: PC = 0x401a2chandler(SIGINT)bayrak = 1; return;rt_sigreturntrampolin: sistem çağrısıtty sürücüsüCtrl-C → SIGINTtask_structbekleyen: 2 · maske: boşsinyal çerçevesiyazmaçlar kullanıcı yığınınabağlam geri yüklendi, kaldığı yerden devam

Süreç kesildiği komuttan devam eder. İşleyici yoksa varsayılan eylem uygulanırdı: SIGINT için sonlandırma.

Süreçler

Süreç Yönetimi Sistem Çağrıları

Sistem çağrısıAçıklama
fork()Süreci kopyalayarak yeni süreç oluşturur (COW)
clone(), clone3()Neyin paylaşılacağı bayraklarla seçilen yeni görev (iş parçacığı, konteyner)
execve()Mevcut süreç görüntüsünü yeni programla değiştirir
waitpid()Çocuğun bitmesini bekler, çıkış durumunu alır (zombiyi toplar)
exit() / _exit()Çağıran süreci sonlandırır (exit stdio tamponlarını boşaltır)
kill()Sürece sinyal gönderir; sinyal sonlandırma olmak zorunda değil
sigaction()Bir sinyal için işleyici ya da eylem atar
sigprocmask()Sinyal maskesini (bloke edilen sinyaller) okur/değiştirir
sigpending()Bloke olduğu için bekleyen sinyalleri döndürür
sigsuspend()Maskeyi geçici değiştirir ve bir sinyal gelene kadar uyur
rt_sigreturn()İşleyiciden dönüşte kaydedilmiş bağlamı geri yükler
alarm() / pause()n saniye sonra SIGALRM / bir sinyal gelene kadar uyu

Sistem çağrısı, kullanıcı programının çekirdekten hizmet istemesinin tek yoludur; Linux x86-64’te ~460 tane vardır. Dosya, G/Ç ve IPC çağrıları ileride.

Süreçler

Süreç Tanımlayıcısı: task_struct

struct task_struct__state (R, S, D…)pid, tgidprio, policyse: vruntime, deadlinemmfilesfssighand, signalcrednsproxycgroupsparent, childrenmm_structVMA’lar, pgd (sayfa tablosu)files_structfd dizisi → struct filefs_structkök dizin, cwd, umasksighand_structsinyal işleyicilericreduid, gid, yeteneklernsproxypid, net, mnt… ad alanlarıcss_setcgroup sınırlarısched_entityEEVDF ağacındaki düğümiş parçacıkları bunları paylaşabilirher görev: ayrı çekirdek yığını

Linux’ta süreç ile iş parçacığı arasında yapısal fark yoktur: ikisi de bir görev (task_struct). Fark, hangi alt yapıları paylaştıklarıdır. Kullanıcının gördüğü PID aslında tgid’dir (iş parçacığı grubu kimliği).

Süreçler · Adım adım

clone() ve İş Parçacıkları

fork() = clone(SIGCHLD)ebeveynPID 900, TGID 900çocukPID 901, TGID 901mm (adres alanı)mm (adres alanı)files (açık dosyalar)files (açık dosyalar)fs (kök, cwd)fs (kök, cwd)sighand (işleyiciler)sighand (işleyiciler)nsproxy (ad alanları)nsproxy (ad alanları)kopya (COW): ayrı ama başta aynı

fork() glibc’de bayraksız bir clone()’dur: çocuk her yapının kopyasını alır (bellek COW ile). Ayrı PID, ayrı TGID: yeni bir süreç.

pthread_create()ebeveynPID 900, TGID 900iş parçacığıTID 902, TGID 900mm (adres alanı)files (açık dosyalar)fs (kök, cwd)sighand (işleyiciler)nsproxy (ad alanları)tümü paylaşılır: aynı adres alanı

pthread_create() → clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | …). Hepsi paylaşılır; yeni görev aynı TGID’e girer. NPTL: her iş parçacığı bir çekirdek görevi (1:1 model, Bkz. Bölüm 4).

konteyner: clone(CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET …)ebeveynPID 900, TGID 900çocukPID 1 (içeride)mm (adres alanı)mm (adres alanı)files (açık dosyalar)files (açık dosyalar)fs (kök, cwd)fs (kök, cwd)sighand (işleyiciler)sighand (işleyiciler)nsproxy (ad alanları)yeni ad alanlarıkopya + yeni ad alanları

Ad alanı bayrakları (CLONE_NEWPID, CLONE_NEWNS, CLONE_NEWNET…) çocuğa yeni bir görünüm verir: içeride kendini PID 1 sanır. Konteynerlerin temeli budur.

Süreçler

POSIX İş Parçacıkları (pthread) ve futex

Fonksiyonİşlev
pthread_createYeni iş parçacığı oluşturur
pthread_exitÇağıran iş parçacığını sonlandırır
pthread_joinBir iş parçacığının bitmesini bekler
pthread_mutex_init / destroyMuteksi başlatır / yok eder
pthread_mutex_lock / unlockMuteksi alır (gerekirse bekler) / bırakır
pthread_cond_init / destroyKoşul değişkenini başlatır / yok eder
pthread_cond_waitMuteksi atomik olarak bırakıp bekler; uyanınca yeniden alır
pthread_cond_signalBekleyenlerden en az birini uyandırır (broadcast: hepsini)
/* tüketici */
pthread_mutex_lock(&m);
while (sayac == 0)        /* if değil! */
    pthread_cond_wait(&c, &m);
sayac--;
pthread_mutex_unlock(&m);
futex: çekişme yoksa kilit tamamen kullanıcı alanında tek bir atomik komutla alınır. Yalnız çekişmede futex(FUTEX_WAIT) sistem çağrısıyla uyunur (Bkz. Bölüm 6).

Koşul değişkeninde sahte uyanmalar olabilir ve başka bir iş parçacığı koşulu önce tüketebilir; bu yüzden bekleme her zaman while döngüsündedir.

Süreçler

Süreç Durumları

fork()R: çalışabilirR: çalışıyorS: kesilebilir uykuD: kesilemez uykuT: durdurulmuşZ: zombiX: yokseçildiönceliği alındı / dilim bittiread(), sleep()olay / sinyaldisk G/ÇG/Ç bittiSIGSTOP, Ctrl-ZSIGCONTexit()ebeveyn wait()

ps/top STAT sütunu bu harfleri gösterir. D durumundaki süreç SIGKILL ile bile hemen ölmez (çoğu yerde artık TASK_KILLABLE kullanılır). Çalışabilir ve çalışıyor Linux’ta aynı harfle (R) gösterilir (Bkz. Bölüm 3).

Çizelgeleme ve Önyükleme

Çizelgeleme Sınıfları

stopCPU durdurma, görev göçü (yalnız çekirdek)deadlineSCHED_DEADLINE: EDF + bant sınırı (runtime/period)rtSCHED_FIFO, SCHED_RR: statik öncelik 1–99fairSCHED_NORMAL, BATCH, IDLE: EEVDF, nice −20…19extSCHED_EXT: BPF ile yüklenen çizelgeleyici (6.12+)idleyapacak iş yoksa: CPU boştasıra0RT (99 − rt_priority)100 nice −20120 nice 0139 nice 19çekirdek prio

Çizelgeleyici sınıfları sırayla sorar: üst sınıfta çalışabilir görev varsa alttakiler bekler. FIFO görev bırakana kadar çalışır; RR 100 ms dilim kullanır. RT görevler saniyede en fazla 0,95 s alabilir ki sistem kilitlenmesin. 6.12 ile PREEMPT_RT ana çekirdeğe girdi (Bkz. Bölüm 5, 12).

Çizelgeleme ve Önyükleme · Adım adım

CFS’ten EEVDF’ye: Adil Paylaşım

02468101214sanal zaman (ms)A (nice 0)v=4,0 d=7,0B (nice 0)v=6,0 d=9,0C (nice 5)v=2,0 d=11,2D (nice -5)v=7,0 d=8,0V = 6,0EEVDF seçer: ACFS seçerdi: C

Her görev için v (vruntime) ve d = v + dilim × 1024 / ağırlık. Ağırlık nice’a bağlı: nice 0 → 1024, nice 5 → 335, nice −5 → 3121. V = ağırlıklı ortalama sanal zaman = 6,0. Uygun (v ≤ V, gecikmesi ≥ 0): A, C. Bunlardan en erken sanal son tarih d: A. CFS en küçük v’yi (C) seçerdi.

02468101214sanal zaman (ms)A (nice 0)v=7,0 d=10,0B (nice 0)v=6,0 d=9,0C (nice 5)v=2,0 d=11,2D (nice -5)v=7,0 d=8,0V = 6,5EEVDF seçer: BCFS seçerdi: C

A 3 ms çalıştı: v’si 3 × 1024 / ağırlık kadar ilerledi. V = ağırlıklı ortalama sanal zaman = 6,5. Uygun (v ≤ V, gecikmesi ≥ 0): B, C. Bunlardan en erken sanal son tarih d: B.

02468101214sanal zaman (ms)A (nice 0)v=7,0 d=10,0B (nice 0)v=9,0 d=12,0C (nice 5)v=2,0 d=11,2D (nice -5)v=7,0 d=8,0V = 7,1EEVDF seçer: DCFS seçerdi: C

B 3 ms çalıştı: v’si 3 × 1024 / ağırlık kadar ilerledi. V = ağırlıklı ortalama sanal zaman = 7,1. Uygun (v ≤ V, gecikmesi ≥ 0): A, C, D. Bunlardan en erken sanal son tarih d: D.

02468101214sanal zaman (ms)A (nice 0)v=7,0 d=10,0B (nice 0)v=9,0 d=12,0C (nice 5)v=2,0 d=11,2D (nice -5)v=8,0 d=9,0V = 7,6EEVDF seçer: ACFS seçerdi: C

D 3 ms çalıştı: v’si 3 × 1024 / ağırlık kadar ilerledi. V = ağırlıklı ortalama sanal zaman = 7,6. Uygun (v ≤ V, gecikmesi ≥ 0): A, C. Bunlardan en erken sanal son tarih d: A.

02468101214sanal zaman (ms)A (nice 0)v=10,0 d=13,0B (nice 0)v=9,0 d=12,0C (nice 5)v=2,0 d=11,2D (nice -5)v=8,0 d=9,0V = 8,2EEVDF seçer: DCFS seçerdi: C

A 3 ms çalıştı: v’si 3 × 1024 / ağırlık kadar ilerledi. V = ağırlıklı ortalama sanal zaman = 8,2. Uygun (v ≤ V, gecikmesi ≥ 0): C, D. Bunlardan en erken sanal son tarih d: D.

02468101214sanal zaman (ms)A (nice 0)v=10,0 d=13,0B (nice 0)v=9,0 d=12,0C (nice 5)v=2,0 d=11,2D (nice -5)v=9,0 d=10,0V = 8,7EEVDF seçer: CCFS seçerdi: C

D 3 ms çalıştı: v’si 3 × 1024 / ağırlık kadar ilerledi. V = ağırlıklı ortalama sanal zaman = 8,7. Uygun (v ≤ V, gecikmesi ≥ 0): C. Bunlardan en erken sanal son tarih d: C. Sonunda düşük ağırlıklı C’nin sırası gelir; çalışınca v’si 3 × 1024 / 335 ≈ 9,2 ilerler. Uzun vadede herkes ağırlığı oranında CPU alır.

CFS (2.6.23, 2007) kırmızı-siyah ağaçta en küçük vruntime’ı seçiyordu; 6.6 (2023) ile yerini alan EEVDF aynı ağacı kullanır ama gecikmeye duyarlı (kısa dilimli) görevlere daha erken son tarih verir. Öncesinde O(1) çizelgeleyici (2.6.0–2.6.22) etkin/süresi dolmuş dizileri kullanıyordu.

Çizelgeleme ve Önyükleme · Adım adım

Önyükleme: UEFI’den systemd’ye

UEFIürün yazılımıGRUB2 /systemd-bootÇekirdekvmlinuzinitramfsgeçici köksystemdPID 1Oturumgetty, gdm, sshd• POST, donanımı başlat• NVRAM’deki önyükleme girdisi• ESP (FAT32) bölümünden• EFI uygulamasını yükle• Secure Boot: imza denetimi (shim)

Güç verilince UEFI ürün yazılımı donanımı sınar ve ESP bölümündeki EFI uygulamasını yükler. Secure Boot açıksa her aşama bir sonrakinin imzasını doğrular (Bkz. Bölüm 13).

UEFIürün yazılımıGRUB2 /systemd-bootÇekirdekvmlinuzinitramfsgeçici köksystemdPID 1Oturumgetty, gdm, sshd• menü, çekirdek seçimi• komut satırı: root=… quiet• vmlinuz + initramfs• dosyalarını belleğe yükle• çekirdeğe atla

Önyükleyici çekirdek görüntüsünü (vmlinuz) ve initramfs’i belleğe yükler, komut satırı parametrelerini verir. Çekirdek EFI uygulaması olarak doğrudan da başlatılabilir (UKI).

UEFIürün yazılımıGRUB2 /systemd-bootÇekirdekvmlinuzinitramfsgeçici köksystemdPID 1Oturumgetty, gdm, sshd• kendini aç, start_kernel()• bellek, kesmeler, zamanlayıcı• PID 0 → boşta görevi• kernel_init (PID 1)• kthreadd (PID 2)Linux başladı

Çekirdek kendini açar, start_kernel() bellek yönetimini, kesmeleri, çizelgeleyiciyi kurar. İlk görev PID 0 boşta görevi olur; kernel_init (PID 1) ve kthreadd (PID 2) oluşturulur.

UEFIürün yazılımıGRUB2 /systemd-bootÇekirdekvmlinuzinitramfsgeçici köksystemdPID 1Oturumgetty, gdm, sshd• RAM’de cpio arşivi• gerekli modüller: NVMe, LVM• LUKS şifre çözme• gerçek kökü bağla• switch_root → /sbin/initLinux başladı

Kök dosya sistemini bağlamak için gereken sürücüler çekirdekte olmayabilir (NVMe, RAID, şifreli disk). initramfs RAM’de geçici bir kök sağlar, gerçek kökü bağlar ve switch_root yapar.

UEFIürün yazılımıGRUB2 /systemd-bootÇekirdekvmlinuzinitramfsgeçici köksystemdPID 1Oturumgetty, gdm, sshd• birim (unit) dosyaları• bağımlılık grafiği• paralel başlatma• journald, udevd, ağ• default.targetLinux başladı

PID 1 artık systemd: birim dosyalarındaki bağımlılıklara göre servisleri paralel başlatır, hedefe (multi-user.target veya graphical.target) ulaşır.

UEFIürün yazılımıGRUB2 /systemd-bootÇekirdekvmlinuzinitramfsgeçici köksystemdPID 1Oturumgetty, gdm, sshd• agetty → login → bash• veya gdm grafik oturum• sshd uzaktan giriş• systemd --user• systemd-analyze: süreLinux başladı

Konsolda agetty → login → kabuk; masaüstünde gdm; uzaktan sshd. Klasik UNIX’teki init → getty → login → sh zinciri hâlâ tanınabilir.

Bellek Yönetimi

Sürecin Sanal Adres Alanı

Çekirdek alanıtüm süreçlerde aynı; kullanıcı kipinde erişilemezkanonik olmayan delikbu adresler kullanılamazYığın (stack) ↓main, yerel değişkenler; ASLR ile rastgele başlangıçmmap bölgesi ↓libc.so, ld.so, eşlenmiş dosyalar, iş parçacığı yığınlarıÖbek (heap) ↑ brkmalloc’un küçük istekleri; brk ile büyürbsssıfırla başlatılan küresellerdatailk değerli küresellertext (kod)salt okunur + çalıştırılabilir; süreçler arasında paylaşılırNULL sayfası eşlenmez → SIGSEGVx86-64, 4 düzey (48 bit):kullanıcı 2⁴⁷ B = 128 TiBçekirdek 128 TiB5 düzey, LA57 (57 bit):kullanıcı 2⁵⁶ B = 64 PiBcat /proc/PID/maps

Her bölge bir VMA (vm_area_struct) ile tanımlanır; VMA’lar mm_struct içinde bir “maple tree”de tutulur. Yığın ve mmap aşağı, öbek yukarı büyür; aradaki boşluk yalnızca sanaldır, fiziksel bellek harcamaz (Bkz. Bölüm 9).

Bellek Yönetimi

Paylaşım, Eşlenmiş Dosyalar ve Bellek Çağrıları

Süreç ASüreç BFiziksel bellektextsayfa önbelleğiveri Ayığın Averi Byığın Byığın Averi.db (eşl.)veri Atextyığın Bveri.db (eşl.)veri Btextyeşil oklar: paylaşılan çerçeveler
Çağrıİşlev
brk / sbrkÖbeğin (veri kesiminin) sonunu taşıyarak büyütür/küçültür
mmapDosyayı, aygıtı ya da anonim belleği adres alanına eşler
munmapEşlemeyi kaldırır, belleği sisteme geri verir
mprotectBölgenin izinlerini (r/w/x) değiştirir
madviseÇekirdeğe kullanım ipucu verir (ör. MADV_DONTNEED)
msyncPaylaşımlı eşlemenin kirli sayfalarını dosyaya yazar

MAP_SHARED: yazılanlar dosyaya ve diğer süreçlere görünür. MAP_PRIVATE: yazınca kopyala, dosya değişmez. glibc malloc küçük istekleri öbekten, ≥ 128 KiB istekleri doğrudan mmap ile karşılar.

Bellek Yönetimi · Adım adım

Sayfa Tablosu Yürüyüşü: 4 ve 5 Düzey

sanal adres 0x00007f3a1c2b5e88işaret = 0bit 63–48PGD = 254bit 47–39PUD = 232bit 38–30PMD = 225bit 29–21PTE = 181bit 20–12ofset = 0xe88bit 11–0CR3PGD tablosu512 girdi × 8 BPUD tablosu512 girdi × 8 BPMD tablosu512 girdi × 8 BPTE tablosu512 girdi × 8 B48 bitlik adres: 4 × 9 bit dizin + 12 bit ofset

x86-64’te 4 KiB sayfa → 12 bit ofset. Kalan 36 bit, her biri 512 girdilik (9 bit) dört tabloya bölünür. 63–48. bitler 47. bitin kopyasıdır (kanonik adres).

sanal adres 0x00007f3a1c2b5e88işaret = 0bit 63–48PGD = 254bit 47–39PUD = 232bit 38–30PMD = 225bit 29–21PTE = 181bit 20–12ofset = 0xe88bit 11–0CR3PGD tablosu512 girdi × 8 B[254]PUD tablosu512 girdi × 8 BPMD tablosu512 girdi × 8 BPTE tablosu512 girdi × 8 B

CR3 yazmacı sürecin en üst tablosunu (PGD) gösterir; bağlam değiştirmede CR3 değişir. Dizin 254 → PUD tablosunun adresi.

sanal adres 0x00007f3a1c2b5e88işaret = 0bit 63–48PGD = 254bit 47–39PUD = 232bit 38–30PMD = 225bit 29–21PTE = 181bit 20–12ofset = 0xe88bit 11–0CR3PGD tablosu512 girdi × 8 B[254]PUD tablosu512 girdi × 8 B[232]PMD tablosu512 girdi × 8 BPTE tablosu512 girdi × 8 B

PUD[232] bir PMD tablosunu gösterir. (Burada 1 GiB’lık dev sayfa da bitebilir.)

sanal adres 0x00007f3a1c2b5e88işaret = 0bit 63–48PGD = 254bit 47–39PUD = 232bit 38–30PMD = 225bit 29–21PTE = 181bit 20–12ofset = 0xe88bit 11–0CR3PGD tablosu512 girdi × 8 B[254]PUD tablosu512 girdi × 8 B[232]PMD tablosu512 girdi × 8 B[225]PTE tablosu512 girdi × 8 B

PMD[225] bir PTE tablosunu gösterir. (2 MiB’lık dev sayfa / THP burada biter.)

sanal adres 0x00007f3a1c2b5e88işaret = 0bit 63–48PGD = 254bit 47–39PUD = 232bit 38–30PMD = 225bit 29–21PTE = 181bit 20–12ofset = 0xe88bit 11–0CR3PGD tablosu512 girdi × 8 B[254]PUD tablosu512 girdi × 8 B[232]PMD tablosu512 girdi × 8 B[225]PTE tablosu512 girdi × 8 B[181]

PTE[181]: geçerli (present) biti, çerçeve numarası, R/W, U/S, NX, kirli (D) ve erişildi (A) bitleri. Present = 0 ise sayfa hatası (Bkz. Bölüm 9).

sanal adres 0x00007f3a1c2b5e88işaret = 0bit 63–48PGD = 254bit 47–39PUD = 232bit 38–30PMD = 225bit 29–21PTE = 181bit 20–12ofset = 0xe88bit 11–0CR3PGD tablosu512 girdi × 8 B[254]PUD tablosu512 girdi × 8 B[232]PMD tablosu512 girdi × 8 B[225]PTE tablosu512 girdi × 8 B[181]4 KiB çerçeveçerçeve0x3c5a1+ 0xe88fiziksel adres = 0x3c5a1e88

Çerçeve numarası ofsetle birleşir: fiziksel adres = çerçeve × 4096 + ofset.

sanal adres 0x00007f3a1c2b5e88işaret = 0bit 63–48PGD = 254bit 47–39PUD = 232bit 38–30PMD = 225bit 29–21PTE = 181bit 20–12ofset = 0xe88bit 11–0CR3PGD tablosu512 girdi × 8 B[254]PUD tablosu512 girdi × 8 B[232]PMD tablosu512 girdi × 8 B[225]PTE tablosu512 girdi × 8 B[181]4 KiB çerçeveçerçeve0x3c5a1+ 0xe88fiziksel adres = 0x3c5a1e88TLB: sonraki erişimde 4 bellek okuması atlanır

Her erişimde 4 ek okuma pahalıdır: TLB çeviriyi önbelleğe alır. 5 düzeyli sayfalama (LA57, Linux 4.14+) araya P4D ekleyerek 57 bit adres sağlar. Linux’un genel modeli 5 düzeydir; donanım daha azını kullanıyorsa düzeyler katlanır.

Bellek Yönetimi

Fiziksel Belleğin Gösterimi

NUMA düğümü 0 (pglist_data)ZONE_DMA0–16 MiB (eski ISA)ZONE_DMA320–4 GiB (32 bit DMA)ZONE_NORMALgeri kalan RAMZONE_MOVABLEtaşınabilir sayfalarher bölgede:free_area[0…10] (buddy listeleri)LRU listeleri, su seviyelerimem_map: struct page dizisi70: boş80: boş150: eşlenmiş200: boşher 4 KiB sayfa için 64 B→ RAM’in %1,56’sıaddress_space (dosya)folio: ardışık sayfalarıtek birim olarak yönetir (5.16+)boş liste

Linux fiziksel belleği düğüm → bölge → sayfa hiyerarşisiyle tanımlar. Çok soketli makinede her CPU kendi düğümünden ayırmayı tercih eder (NUMA, Bkz. Bölüm 12). 64 bit sistemlerde ZONE_HIGHMEM yoktur; yalnızca 32 bit çekirdeklerde kalmıştır.

Bellek Yönetimi · Adım adım

Buddy (Eş) Ayırıcı

64081624324864sayfa çerçeveleri 0–63 (bir order-6 blok)free_area (boş listeler):order 6 (64 sayfa): 0–63order 5 (32 sayfa): —order 4 (16 sayfa): —order 3 ( 8 sayfa): —order 2 ( 4 sayfa): —

Buddy ayırıcı belleği 2’nin kuvveti büyüklüğünde bloklarla yönetir: order 0 = 1 sayfa … order 10 = 1024 sayfa (4 MiB). Her order için ayrı bir boş liste vardır.

A: 8 sayfa81632081624324864sayfa çerçeveleri 0–63 (bir order-6 blok)free_area (boş listeler):order 6 (64 sayfa): —order 5 (32 sayfa): 32–63order 4 (16 sayfa): 16–31order 3 ( 8 sayfa): 8–15order 2 ( 4 sayfa): —

A 8 sayfa (order 3) ister. 64’lük blok ikiye bölünür: 32+32 → 16+16 → 8+8. İlk 8 A’ya verilir; artanlar listelere eklenir.

A: 8 sayfaB: 8 sayfa1632081624324864sayfa çerçeveleri 0–63 (bir order-6 blok)free_area (boş listeler):order 6 (64 sayfa): —order 5 (32 sayfa): 32–63order 4 (16 sayfa): 16–31order 3 ( 8 sayfa): —order 2 ( 4 sayfa): —

B 8 sayfa ister: order-3 listesinde hazır blok (8–15) var, bölme gerekmez.

A: 8 sayfaB: 8 sayfaC:44832081624324864sayfa çerçeveleri 0–63 (bir order-6 blok)free_area (boş listeler):order 6 (64 sayfa): —order 5 (32 sayfa): 32–63order 4 (16 sayfa): —order 3 ( 8 sayfa): 24–31order 2 ( 4 sayfa): 20–23

C 4 sayfa ister: order 2 boş; 16–31 bloğu 8+8’e, 16–23 de 4+4’e bölünür; C 16–19’u alır.

A: 8 sayfa8C:44832081624324864sayfa çerçeveleri 0–63 (bir order-6 blok)free_area (boş listeler):order 6 (64 sayfa): —order 5 (32 sayfa): 32–63order 4 (16 sayfa): —order 3 ( 8 sayfa): 8–15, 24–31order 2 ( 4 sayfa): 20–23

B serbest kalır. Kardeşi (buddy) A — adresi XOR ile bulunur: 8 ⊕ 8 = 0 — dolu olduğu için birleşme yok.

16C:44832081624324864sayfa çerçeveleri 0–63 (bir order-6 blok)free_area (boş listeler):order 6 (64 sayfa): —order 5 (32 sayfa): 32–63order 4 (16 sayfa): 0–15order 3 ( 8 sayfa): 24–31order 2 ( 4 sayfa): 20–23

A serbest kalır: kardeşi 8–15 boş → birleşip 0–15 (order 4). Onun kardeşi 16–31 kısmen dolu (C) → dur.

64081624324864sayfa çerçeveleri 0–63 (bir order-6 blok)free_area (boş listeler):order 6 (64 sayfa): 0–63order 5 (32 sayfa): —order 4 (16 sayfa): —order 3 ( 8 sayfa): —order 2 ( 4 sayfa): —

C serbest kalır: 16–19 + 20–23 → 16–23, + 24–31 → 16–31, + 0–15 → 0–31, + 32–63 → 0–63. Tüm bellek yeniden tek blok: dış parçalanma azalır.

Kardeş blok bir ağaçta aranmaz: blok başlangıcının order bitini çevirmek (s ⊕ 2^order) yeterlidir. Bedeli iç parçalanmadır: 65 sayfa isteyen 128 sayfa alır.

Bellek Yönetimi

SLUB Nesne Ayırıcısı

Buddy ayırıcı: sayfa çerçeveleri (alloc_pages)kmem_cache: task_structkmem_cache: dentry (192 B)kmem_cache: kmalloc-64kmem_cache: inode_cachedentry önbelleğinin içi:CPU 0 etkin slabkilitsiz hızlı yolkısmi (partial) slabboş nesnesi olanlardolu slabtamamen kullanılıyorslab = 1 veya birkaç ardışık sayfa

Çekirdek çok sayıda küçük, aynı boyda nesne (task_struct, dentry, inode) ayırır; her biri için sayfa ayırmak israftır. SLUB nesne önbellekleri tutar; kmalloc 8 B–8 KiB boy sınıflarını kullanır. SLOB (6.4) ve SLAB (6.8) kaldırıldı: tek ayırıcı SLUB. Büyük, fiziksel bitişik olması gerekmeyen alan için vmalloc.

Bellek Yönetimi · Adım adım

Sayfa Önbelleği, Geri Kazanım ve OOM

5 GiBanonim (uygulama)8 GiBsayfa önbelleğiboş 2 GiBRAM 16 GiBboş bellek2 GiByüksekdüşükmin(büyütülmüş)kswapd0arka planda geri kazanımMGLRU nesillerigen 0 (soğuk) … gen 3 (sıcak)zswap → takassoğuk anonim sayfalardoğrudan geri kazanımayıran süreç beklerOOM killeren yüksek oom_score → SIGKILLtakas: 0 GiBzswap + swap alanı

Boş bellek israftır: Linux kullanılmayan RAM’i sayfa önbelleği olarak dosya verisi için kullanır. free -h’deki “available” bu önbelleğin geri alınabilir kısmını da sayar.

8,3 GiBanonim (uygulama)6 GiBsayfa önbelleğiRAM 16 GiBboş bellek0,7 GiByüksekdüşükmin(büyütülmüş)kswapd0arka planda geri kazanımMGLRU nesillerigen 0 (soğuk) … gen 3 (sıcak)zswap → takassoğuk anonim sayfalardoğrudan geri kazanımayıran süreç beklerOOM killeren yüksek oom_score → SIGKILLtakas: 0 GiBzswap + swap alanı

Uygulama büyüdü, boş bellek düşük su seviyesinin altına indi: kswapd uyanır ve arka planda temiz önbellek sayfalarını bırakır (kirli olanlar önce diske yazılır).

9 GiBanonim (uygulama)4,7 GiBsayfa önbelleği1,3 GiBRAM 16 GiBboş bellek1,3 GiByüksekdüşükmin(büyütülmüş)kswapd0arka planda geri kazanımMGLRU nesillerigen 0 (soğuk) … gen 3 (sıcak)zswap → takassoğuk anonim sayfalardoğrudan geri kazanımayıran süreç beklerOOM killeren yüksek oom_score → SIGKILLtakas: 1 GiBzswap + swap alanı

MGLRU (6.1) sayfaları erişim nesillerine ayırır; en soğuk nesil önce gider. Soğuk anonim sayfaların dosyası yoktur: zswap ile RAM’de sıkıştırılır, gerekirse takas alanına yazılır.

11,5 GiBanonim (uygulama)3,2 GiBsayfa önbelleğiRAM 16 GiBboş bellek0,3 GiByüksekdüşükmin(büyütülmüş)kswapd0arka planda geri kazanımMGLRU nesillerigen 0 (soğuk) … gen 3 (sıcak)zswap → takassoğuk anonim sayfalardoğrudan geri kazanımayıran süreç beklerOOM killeren yüksek oom_score → SIGKILLtakas: 2 GiBzswap + swap alanı

Ayırma hızı geri kazanımı geçti, boş bellek min seviyesinin altında: ayıran süreç kendisi doğrudan geri kazanım yapar ve takılır (gecikme artar).

4,6 GiBanonim (uygulama)2 GiBboş 8,4 GiBRAM 16 GiBboş bellek8,4 GiByüksekdüşükmin(büyütülmüş)kswapd0arka planda geri kazanımMGLRU nesillerigen 0 (soğuk) … gen 3 (sıcak)zswap → takassoğuk anonim sayfalardoğrudan geri kazanımayıran süreç beklerOOM killeren yüksek oom_score → SIGKILLtakas: 2 GiBzswap + swap alanıbellek_yiyen (PID 7311)öldürüldü

Hiçbir şey yetmezse OOM killer en yüksek oom_score’lu (çoğunlukla en büyük) süreci SIGKILL ile öldürür; oom_score_adj ile etkilenebilir. cgroup sınırı aşılırsa yalnız o gruptan seçilir.

Giriş/Çıkış

Aygıtlar Dosyadır: Major ve Minor Numaralar

$ ls -l /dev     # seçilmiş satırlar
brw-rw---- 1 root disk   8, 0 sda
brw-rw---- 1 root disk   8, 1 sda1
brw-rw---- 1 root disk 259, 0 nvme0n1
crw-rw-rw- 1 root root   1, 3 null
crw-rw-rw- 1 root tty    5, 0 tty
  • c karakter aygıtı: bayt akışı, genelde önbelleksiz (terminal, /dev/null, fare)
  • b blok aygıtı: sabit boy bloklar, rastgele erişim; sayfa önbelleği ve G/Ç zamanlayıcı kullanır
  • Ağ arayüzleri (eth0) /dev’de yoktur; soketlerle kullanılır
  • Düğümleri devtmpfs + udev aygıt görününce dinamik oluşturur
open("/dev/sda1")i-node: tür bmajor 8, minor 1blok aygıt tablosu7 → loop8 → sd (SCSI disk)259 → blkext (NVMe)minor: 0 = tüm disk, 1 = bölüm 1disk başına 16 minor: sdb = 16

Boyut sütunu yerine “major, minor” görünür. Major sürücüyü, minor o sürücünün yönettiği birimi seçer. Uygulama diske de terminale de aynı open/read/write ile erişir (Bkz. Bölüm 11).

Giriş/Çıkış

Linux G/Ç Sisteminin Yapısı

Sistem çağrıları: open, read, write, ioctl, mmap, send, recvVFS (sanal dosya sistemi)Soket katmanıKarakter aygıtlarıtty + satır disiplinikarakter sürücüsüBlok aygıtlarıext4 / XFS / Btrfssayfa önbelleğiblok katmanı: blk-mqG/Ç zamanlayıcıblok sürücüsü (NVMe)Ağ aygıtlarıTCP / UDPIP + netfilterkuyruk disiplini (qdisc)ağ sürücüsü (NAPI)Donanım: terminal, NVMe SSD, ağ kartı

Üç aygıt türü üç ayrı yoldan iner. Klasik BSD’de de benzer ayrım vardı; System V’in STREAMS modül yığını ise Linux ana çekirdeğine hiç girmedi. Ağ yolunda veri sk_buff yapılarında taşınır; XDP/eBPF paketleri sürücü düzeyinde işleyebilir.

Giriş/Çıkış

Sürücü Arayüzü: file_operations ve Terminal

static const struct file_operations my_fops = {
    .owner          = THIS_MODULE,
    .open           = my_open,
    .release        = my_release,     /* close */
    .read           = my_read,
    .write          = my_write,
    .unlocked_ioctl = my_ioctl,
    .poll           = my_poll,
    .mmap           = my_mmap,
};
cdev_init(&cdev, &my_fops);  /* major:minor → fops */
Eski UNIX girişleriLinux karşılığı
k_open, tty_open, pr_open, ip_open.open
k_close, tty_close, pr_close….release
mem_read, k_read, tty_read.read
mem_write, tty_write, pr_write….write
k_ioctl, tty_ioctl, pr_ioctl….unlocked_ioctl
Terminal G/Ç (termios): tcgetattr/tcsetattr terminal parametrelerini okur/yazar: kanonik kip (satır düzenleme, ICANON) ya da ham kip, ECHO. cfset/cfget[io]speed giriş/çıkış baud hızı; bugün çoğunlukla seri portlar için, terminaller ise sözde terminaldir (pty).

Klasik ders kitabı tablosu her sürücü için ayrı giriş noktaları (k_*, tty_*, pr_*, ip_*) listeler; Linux bunları tek bir işlev işaretçisi yapısında toplar. VFS her read()’i ilgili sürücünün .read’ine yönlendirir.

Giriş/Çıkış

Blok Katmanı: blk-mq ve G/Ç Zamanlayıcılar

CPU 0yazılım kuyruğuCPU 1yazılım kuyruğuCPU 2yazılım kuyruğuCPU 3yazılım kuyruğuG/Ç zamanlayıcı (isteğe bağlı): none · mq-deadline · bfq · kyberdonanım kuyruğu 0donanım kuyruğu 1donanım kuyruğu 2donanım kuyruğu 3NVMe SSD: çekirdek başına gönderim + tamamlama kuyruğu çifti

Tek kuyruklu eski blok katmanı (CFQ, deadline, noop) 5.0’da kaldırıldı. Milyonlarca IOPS yapan NVMe’de kilit çekişmesini önlemek için her CPU kendi kuyruğuna yazar. Varsayılanlar: NVMe none, SATA mq-deadline, etkileşimli masaüstü/HDD bfq. cat /sys/block/nvme0n1/queue/scheduler → [none] mq-deadline kyber bfq. io_uring (5.1) paylaşımlı halkalarla sistem çağrısı yükünü azaltan asenkron G/Ç arayüzüdür (Bkz. Bölüm 11).

Giriş/Çıkış · Adım adım

Ağ: Soketler ve Bağlantı Kurulumu

Sunucuİstemcisocket() → fd 3bind(:80)listen(3, 128)accept() → fd 4read(4) / write(4)socket() → fd 3connect(sunucu:80)write(3) / read(3)close(3) → FIN

Sunucu bir soket oluşturur (fd 3), 80. porta bağlar (bind) ve listen ile dinleme kuyruğu açar. Soket de bir dosya tanımlayıcısıdır.

Sunucuİstemcisocket() → fd 3bind(:80)listen(3, 128)accept() → fd 4read(4) / write(4)socket() → fd 3connect(sunucu:80)write(3) / read(3)close(3) → FINaccept bloke: bağlantı bekliyor

Sunucu accept’te bloke olur. İstemci kendi soketini oluşturur.

Sunucuİstemcisocket() → fd 3bind(:80)listen(3, 128)accept() → fd 4read(4) / write(4)socket() → fd 3connect(sunucu:80)write(3) / read(3)close(3) → FINSYNSYN-ACKACK

connect çağrısıyla istemci çekirdeği üçlü el sıkışmayı (SYN, SYN-ACK, ACK) yapar; uygulama bu paketleri hiç görmez.

Sunucuİstemcisocket() → fd 3bind(:80)listen(3, 128)accept() → fd 4read(4) / write(4)socket() → fd 3connect(sunucu:80)write(3) / read(3)close(3) → FINSYNSYN-ACKACKçekirdek el sıkışmayı tamamladı,accept yeni bir soket döndürür

Bağlantı kurulunca accept yeni bir soket (fd 4) döndürür; fd 3 dinlemeye devam eder. Çok istemcili sunucular epoll veya iş parçacıklarıyla binlerce soketi yönetir.

Sunucuİstemcisocket() → fd 3bind(:80)listen(3, 128)accept() → fd 4read(4) / write(4)socket() → fd 3connect(sunucu:80)write(3) / read(3)close(3) → FINSYNSYN-ACKACKçekirdek el sıkışmayı tamamladı,accept yeni bir soket döndürürGET / HTTP/1.1200 OK …

Veri write/read ile akar: çekirdek sk_buff’lara koyar, TCP/IP başlıklarını ekler, sürücü kartın halkasına yazar. close FIN gönderir.

Dosya Sistemleri

Dizin Ağacı ve Bağlama

/binbootdevetchomelibprocsystmpusrvarmnt→ usr/bin→ usr/libsanalsanaldevtmpfsalibinlibshareusbvfat (USB)foto/ belge/mount /dev/sdb1 /mnt/usb
  • /usr/bin: komutlar (/bin artık ona bağlantı)
  • /etc: metin yapılandırma dosyaları
  • /dev: aygıt dosyaları
  • /usr/lib: paylaşılan kütüphaneler, /usr/lib/modules: çekirdek modülleri
  • /usr: salt okunur, paylaşılabilir yazılım (bin, lib, share)
  • /home: kullanıcı dizinleri; /root: yöneticinin
  • /var: değişken veri (günlükler, kuyruklar, önbellek)
  • /proc, /sys: çekirdeğin sözde dosya sistemleri
  • /boot: çekirdek ve initramfs
  • /tmp: geçici (çoğu dağıtımda tmpfs)

Windows’taki sürücü harfleri yerine tek bir ağaç vardır: başka bir dosya sistemi herhangi bir dizine bağlanır (mount). Düzen FHS standardına uyar; çoğu dağıtım “usrmerge” ile /bin, /lib’i /usr altına taşıdı.

Dosya Sistemleri · Adım adım

VFS: Tanımlayıcılar, Açık Dosyalar ve i-node’lar

Süreç A (fd)0tty1tty2tty3→ dosya#14struct file #1f_pos = 0 O_RDONLYreferans = 1dentry"x.txt"inode 1234boyut, izin, extentext4 → disk

fd = open("x.txt", O_RDONLY): VFS yolu çözer, bir struct file (açık dosya: konum, kip) oluşturur ve sürecin tablosundaki ilk boş numarayı (3) ona bağlar.

Süreç A (fd)0tty1tty2tty3→ dosya#14struct file #1f_pos = 100 O_RDONLYreferans = 1dentry"x.txt"inode 1234boyut, izin, extentext4 → disk

read(3, buf, 100) konumu 100’e ilerletir. Konum (f_pos) fd tablosunda değil, açık dosya nesnesinde tutulur.

Süreç A (fd)0tty1tty2tty3→ dosya#14çocuk A′ (fork)0tty1tty2tty3→ dosya#14struct file #1f_pos = 150 O_RDONLYreferans = 2dentry"x.txt"inode 1234boyut, izin, extentext4 → disk

fork() sonrası çocuk aynı struct file’ı paylaşır (referans 2). Çocuk 50 bayt okuyunca ebeveynin konumu da 150 olur: kabukta (cmd1; cmd2) > log bu yüzden çalışır.

Süreç A (fd)0tty1tty2tty3→ dosya#14çocuk A′ (fork)0tty1tty2tty3→ dosya#14Süreç C0tty1tty2tty3→ dosya#24struct file #1f_pos = 150 O_RDONLYreferans = 2struct file #2f_pos = 0referans = 1dentry"x.txt"inode 1234boyut, izin, extentext4 → disk

İlgisiz bir süreç aynı dosyayı açarsa yeni bir struct file alır: konumlar bağımsızdır, ama dentry ve inode ortaktır.

Süreç A (fd)0tty1tty2tty3→ dosya#14çocuk A′ (fork)0tty1tty2tty3→ dosya#14Süreç C0tty1tty2tty3→ dosya#24struct file #1f_pos = 150 O_RDONLYreferans = 2struct file #2f_pos = 0referans = 1dentry"x.txt"inode 1234boyut, izin, extentext4 → diskVFS nesneleri:superblock: bağlı dosya sistemiinode: dosyanın kendisidentry: ad → inode (önbellek)file: açık dosya oturumu

VFS, ext4, XFS, Btrfs, NFS, procfs… hepsine aynı nesnelerle bakar; her nesnenin işlem tablosu (inode_operations, file_operations) çağrıyı gerçek dosya sistemine yönlendirir.

Dosya Sistemleri

Dosya ve Dizin Sistem Çağrıları, stat

Dosya çağrısıİşlev
open, creatAç / oluştur, fd döndür
closeTanımlayıcıyı kapat
read, writeKonumdan oku / yaz
lseekKonumu taşı
stat, fstat, lstatBilgi al (lstat: bağın kendisi)
pipe, dup2Boru oluştur / fd kopyala
fcntlKilit, bayraklar vb.
mkdir, rmdirDizin oluştur / sil (boşsa)
link, unlinkAd ekle / sil
rename, chdirTaşı (atomik) / cwd değiştir
getdents64Dizin girdilerini oku
stat alanıAnlamı
st_devDosyanın bulunduğu aygıt
st_inoi-node numarası
st_modeTür + izin bitleri
st_nlinkSert bağ sayısı
st_uid, st_gidSahip ve grup
st_sizeBayt cinsinden boyut
st_atimeSon erişim zamanı
st_mtimeSon içerik değişikliği
st_ctimeSon i-node değişikliği (oluşturma değil!)
st_blocksAyrılan 512 B blok sayısı

opendir/readdir/closedir sistem çağrısı değil, getdents64 üzerine kurulu kütüphane fonksiyonlarıdır. Oluşturma zamanı yalnız yeni statx() ile (stx_btime) alınabilir.

Dosya Sistemleri · Adım adım

Dosya Kilitleme

0123456789101112131415A: paylaşımlı kilit 4–7baytpaylaşımlı (okuma) kilitler çakışabilir; özel (yazma) kilidi hiçbir kilitle çakışamaz

A süreci 4–7. baytlara paylaşımlı (okuma) kilit koyar: fcntl(fd, F_SETLK, &fl) ile l_type = F_RDLCK, l_start = 4, l_len = 4.

0123456789101112131415A: paylaşımlı kilit 4–7B: paylaşımlı kilit 6–9baytpaylaşımlı (okuma) kilitler çakışabilir; özel (yazma) kilidi hiçbir kilitle çakışamaz

B 6–9’a paylaşımlı kilit ister: çakışma paylaşımlı kilitler arasında serbesttir, istek kabul edilir.

0123456789101112131415A: paylaşımlı kilit 4–7B: paylaşımlı kilit 6–9C: paylaşımlı kilit 2–11baytpaylaşımlı (okuma) kilitler çakışabilir; özel (yazma) kilidi hiçbir kilitle çakışamaz

C 2–11’e paylaşımlı kilit koyar; 6–7 baytları artık üç kilitle kaplı.

0123456789101112131415A: paylaşımlı kilit 4–7B: paylaşımlı kilit 6–9C: paylaşımlı kilit 2–11baytD: özel (yazma) kilidi bayt 9 → F_SETLKW ile blokepaylaşımlı (okuma) kilitler çakışabilir; özel (yazma) kilidi hiçbir kilitle çakışamaz

D bayt 9’a özel (F_WRLCK) kilit ister: B ve C’nin kilitleriyle çakışır. F_SETLK hemen hata döndürür, F_SETLKW ise kilitler kalkana dek bekler. Çekirdek bekleme döngüsünü fark ederse EDEADLK döndürür (Bkz. Bölüm 7).

Bu kilitler tavsiye niteliğindedir (advisory): kilidi sormayan bir süreç yine yazabilir. Bütün dosya için flock(); iş parçacıklarıyla güvenli kullanım için açık dosyaya bağlı OFD kilitleri vardır.

Dosya Sistemleri

ext2/ext4 Disk Düzeni ve i-node

Disk bölümü:önyüklemeblok grubu 0blok grubu 1blok grubu 2…blok grubu nsüper blokgrup tanımlayıcılarıblok bit eşlemii-node bit eşlemii-node tablosuveri bloklarıi-node (256 B)mod (tür + izin)uid, gid, boyutatime, mtime, ctimebağ sayısı12 doğrudan bloktekli dolaylıikili dolaylıüçlü dolaylı12 × 4 KiB = 48 KiB+ 1024 × 4 KiB = 4 MiB+ 1024² × 4 KiB = 4 GiB+ 1024³ × 4 KiB = 4 TiBext4: extent ağacıi-node’da 4 extent sığar:(mantıksal blok, uzunluk, fiziksel blok)0, 2048, 34816 → 8 MiB tek girditek extent en çok 32768 blok= 128 MiB; dosya ≤ 16 TiBdolaylı blok yerine az sayıdabüyük ardışık parça

Klasik UNIX düzeni (önyükleme bloğu, süper blok, i-node’lar, veri) ext2’de blok gruplarına bölündü: i-node ile verisi aynı gruba yakın konur, süper blok yedeklenir. Dolaylı bloklarla teorik sınır ~4 TiB’tır (ext2’de i_blocks alanı nedeniyle 2 TiB). Kök dizinin i-node numarası her zaman 2’dir.

Dosya Sistemleri · Adım adım

ext4 Günlükleme (Journaling)

Bellek (sayfa önbelleği)Günlük (journal)Diskteki asıl yerlerveri Di-node M1bitmap M2extent M3kirli sayfalar

Bir write() + fsync() birkaç bloğu değiştirir: veri (D) ile birlikte i-node, blok bit eşlemi ve extent gibi üst veriler. Bunlardan biri yazılıp diğeri yazılmadan çökme olursa dosya sistemi tutarsız kalır (Bkz. Bölüm 10).

Bellek (sayfa önbelleği)Günlük (journal)Diskteki asıl yerlerveri Di-node M1bitmap M2extent M3kirli sayfalarveri D

Varsayılan data=ordered kipinde önce veri blokları asıl yerine yazılır; böylece üst veri hiçbir zaman çöp içeren bloğu göstermez.

Bellek (sayfa önbelleği)Günlük (journal)Diskteki asıl yerlerveri Di-node M1bitmap M2extent M3kirli sayfalarveri DT42 tanımM1M2M3T42 commit

Üst veri blokları günlüğe bir işlem (T42) olarak yazılır; en sonda commit kaydı. Commit diske ulaştığı an işlem kalıcıdır.

Bellek (sayfa önbelleği)Günlük (journal)Diskteki asıl yerlerveri Di-node M1bitmap M2extent M3kirli sayfalarveri DT42 tanımM1M2M3T42 commitM1M2M3checkpoint: günlük alanı serbest

Checkpoint: üst veri asıl yerlerine yazılır, günlükteki alan yeniden kullanılır (dairesel tampon).

Bellek (sayfa önbelleği)Günlük (journal)Diskteki asıl yerlerveri Di-node M1bitmap M2extent M3kirli sayfalarveri DT42 tanımM1M2M3T42 commitM1M2M3commit’ten sonra çökme → bağlarken T42 yeniden oynatılırcommit’ten önce çökme → T42 yok sayılır; eski tutarlı hâl

Çökmeden sonra tam fsck taraması yerine günlük okunur: commit’li işlemler yeniden oynatılır, yarım kalanlar atılır. Saniyeler içinde tutarlılık.

Diğer kipler: data=journal (veri de günlüğe; en güvenli, en yavaş) ve data=writeback (sıra garantisi yok). XFS de üst veri günlüğü kullanır; Btrfs ise günlük yerine yazınca kopyala ile tutarlıdır.

Dosya Sistemleri · Adım adım

Dizinler ve Yol Çözümleme

open("/home/ali/notlar.txt")/ (i-node 2).2..2etc524289home131073usr786433home (131073)ali (131074)

Mutlak yol kökten başlar: kök dizinin i-node’u (2) okunur, veri bloklarındaki girdilerde “home” aranır → 131073. Her dizin için x (arama) izni denetlenir.

open("/home/ali/notlar.txt")/ (i-node 2).2..2etc524289home131073usr786433home (131073).131073..2ali131074ayse131090ali (131074)

“home” dizininin verisinde “ali” aranır → 131074.

open("/home/ali/notlar.txt")/ (i-node 2).2..2etc524289home131073usr786433home (131073).131073..2ali131074ayse131090ali (131074).131074..131073foto132011notlar.txt132010

“ali” dizininde “notlar.txt” → 132010. (Göreli yol olsaydı süreç cwd’sinden başlanırdı.)

open("/home/ali/notlar.txt")/ (i-node 2).2..2etc524289home131073usr786433home (131073).131073..2ali131074ayse131090ali (131074).131074..131073foto132011notlar.txt132010i-node 132010-rw-r--r-- aliboyut 2 KiBextent: 1 blok→ struct file, fd 3

Son bileşenin i-node’u okunur, izinler denetlenir, struct file oluşturulup fd döndürülür.

open("/home/ali/notlar.txt")/ (i-node 2).2..2etc524289home131073usr786433home (131073).131073..2ali131074ayse131090ali (131074).131074..131073foto132011notlar.txt132010i-node 132010-rw-r--r-- aliboyut 2 KiBextent: 1 blok→ struct file, fd 3dizin girdisi (ext2/4): i-node no · kayıt uzunluğu · ad uzunluğu · tür · adsilinen girdi bir öncekinin kayıt uzunluğuna eklenir; büyük dizinlerde htree (karma ağaç) kullanılır

Her adım disk okuması gerektirseydi yavaş olurdu: dentry önbelleği (dcache) ad → i-node eşlemelerini bellekte tutar; sıcak yollar diske hiç gitmeden çözülür.

Dosya Sistemleri

Sert ve Sembolik Bağlar

/home/alia.txt500k777/home/ali/yedekb.txt500i-node 500bağ sayısı = 2sert baği-node 777 (bağ)hedef: "a.txt"yol ileveri blokları
$ ln a.txt yedek/b.txt     # sert
$ ln -s a.txt k            # sembolik
$ ls -li
500 -rw-r--r-- 2 ali ali 9 a.txt
777 lrwxrwxrwx 1 ali ali 5 k -> a.txt
  • Sert bağ: aynı i-node, bağ sayısı artar. rm a.txt yalnız adı siler; veri sayaç 0 olunca (ve açık fd kalmayınca) serbest kalır.
  • Sert bağ dosya sistemi sınırını aşamaz, dizinlere konamaz.
  • Sembolik bağ: hedefin yolunu tutar; başka dosya sistemine, dizine işaret edebilir. Hedef silinirse bağ sarkar.

Dosya Sistemleri

ext4’ün Ötesi: XFS, Btrfs ve Diğerleri

Dosya sistemiÖne çıkan özellikTipik kullanım
ext4Günlükleme, extent, olgun ve hızlı fsckÇoğu dağıtımda varsayılan
XFSParalel G/Ç, büyük dosyalar, gecikmeli ayırmaRHEL varsayılanı, büyük sunucular
BtrfsYazınca kopyala, anlık görüntü, sağlama toplamı, sıkıştırma, alt birimlerFedora, openSUSE varsayılanı
F2FSFlash’a uygun günlük yapılı (log-structured)Android telefonlar
tmpfsTamamen RAM’de (sayfa önbelleği + takas)/tmp, /run, /dev/shm
NFS, SMBAğ dosya sistemleriPaylaşılan ev dizinleri
kök v1kök v2düğümdüğümdüğüm′B1B2B3B4B4′B4 değişince yalnız yol kopyalanır;kök v1 = anlık görüntü (snapshot)

VFS sayesinde hepsi aynı sistem çağrılarıyla kullanılır; findmnt veya df -T hangi dizinde hangi dosya sisteminin bağlı olduğunu gösterir.

Dosya Sistemleri

/proc ve /sys: Çekirdeğe Açılan Pencereler

$ cat /proc/loadavg
0.42 0.37 0.30 2/1234 98765
$ grep -E "MemTotal|MemAvailable" /proc/meminfo
MemTotal:       16303452 kB
MemAvailable:    9876544 kB
$ ls /proc/self
cmdline  cwd  environ  exe  fd  maps  status  …
$ cat /sys/block/nvme0n1/queue/scheduler
[none] mq-deadline kyber bfq
$ sysctl vm.swappiness        # = /proc/sys/vm/swappiness
vm.swappiness = 60
/proc

Süreç başına dizinler (/proc/PID/status, maps, fd/) ve çekirdek istatistikleri. ps, top, free verisini buradan okur. /proc/sys: ayarlanabilir çekirdek parametreleri.

/sys (sysfs)

Aygıt modeli: her aygıt, sürücü ve veri yolu bir dizin; dosya başına tek değer. /sys/fs/cgroup cgroup v2 arayüzüdür.

Etkileşimli deneme: Linux Süreç Gezgini sayfasında ps, top, /proc, PID/PPID ilişkileri, süreç ağacı, dosya tanımlayıcıları ve bellek haritalarını keşfedebilirsiniz.

Dosya Sistemleri

Ağ Dosya Sistemi (NFS)

İstemciSunucuuygulama: read()VFSNFS istemcisiRPC (XDR)TCP / IPyerel diskte /home yoknfsd (çekirdek)VFSext4 / XFSblok katmanıdiskağ: TCP port 2049# mount sunucu:/export/home /home

İstemci uzak dizini kendi ağacına bağlar; uygulama farkı görmez, çünkü NFS de VFS altında bir dosya sistemidir. NFSv3 durumsuzdu (her istek kendi başına anlamlı); NFSv4 durumlu, tek port (2049), TCP, ACL, Kerberos ve istemciye yetki devri (delegation) sunar.

Güvenlik

Dosya Koruma: İzin Bitleri

türs1g1t1r1w0x1r0w0x0rwx-setuid / setgid / yapışkansahip (u)grup (g)diğer (o)-rwxr-x--- = 111 101 000₂ = 0750
İkiliSekizliSembolikİzin verilen erişim
1110000000700rwx------Sahip okur, yazar, çalıştırır
1111110000770rwxrwx---Sahip ve grup okur, yazar, çalıştırır
1101000000640rw-r-----Sahip okur ve yazar; grup okur
1101001000644rw-r--r--Sahip okur ve yazar; herkes okur
1111011010755rwxr-xr-xSahip her şeyi yapar; diğerleri okur ve çalıştırır
0000000000000---------Kimsenin erişimi yok
0000001110007------rwxYalnız “diğerleri” erişir (garip ama geçerli)

Dizinlerde r = girdileri listele, w = girdi ekle/sil, x = içine gir / ad ara. Bir dosyayı silmek için dosyaya değil dizine yazma izni gerekir.

Güvenlik · Adım adım

chmod ve umask Hesapları

$ chmod 754 betik.shsgtrwxrwxrwxistenen0754000111101100rwxr-xr--sonuç0754000111101100rwxr-xr--

Her sekizli rakam üç bittir: 7 = 111 = rwx, 5 = 101 = r-x, 4 = 100 = r--.

$ chmod g+w,o-r betik.shsgtrwxrwxrwxönceki0754000111101100rwxr-xr--g+w: OR 0200020000000010000o-r: AND ~0040004000000000100sonuç0770000111111000rwxrwx---

Sembolik kip mevcut bitleri değiştirir: grup yazma biti eklenir, diğerlerinin okuma biti silinir → 0770.

$ umask 022 ; touch a ; mkdir dsgtrwxrwxrwxdosya isteği0666000110110110umask0022000000010010sonuç0644000110100100rw-r--r--

Yeni dosya 666, dizin 777 ister; umask’taki bitler silinir: 666 & ~022 = 0644, dizin 777 & ~022 = 0755. (Çıkarma değil, bit temizleme!)

$ umask 027 ; touch a ; mkdir dsgtrwxrwxrwxdosya isteği0666000110110110umask0027000000010111sonuç0640000110100000rw-r-----

Daha sıkı umask: dosya 666 & ~027 = 0640 (rw-r-----), dizin 777 & ~027 = 0750 (rwxr-x---). Diğerleri hiçbir şey göremez.

$ chmod 4755 passwd ; chmod 1777 /tmpsgtrwxrwxrwxsetuid + 7554755100111101101rwsr-xr-xyapışkan + 7771777001111111111rwxrwxrwt

4xxx setuid: çalışan süreç dosya sahibinin kimliğini alır → rwsr-xr-x. 2xxx setgid (dizinde: yeni dosyalar grubu miras alır). 1xxx yapışkan bit: /tmp’de herkes yazar ama yalnız kendi dosyasını silebilir → rwxrwxrwt.

Kontrol: stat -c "%a %A" dosya sekizli ve sembolik izni birlikte gösterir; umask -S maskeyi sembolik yazar.

Güvenlik

Erişim Denetimi, root ve Yetenekler

  1. euid = 0 (root) → izin ver (çalıştırma için en az bir x biti gerekir)
  2. euid = dosya sahibi → yalnız sahip bitlerine bak
  3. egid ya da ek gruplardan biri = dosya grubu → grup bitleri
  4. aksi halde diğer bitleri

İlk eşleşen sınıf kazanır: ----rw-rw- dosyasını sahibi ali okuyamaz, başkaları okur.

Yetenekler (capabilities): root’un gücü ~41 parçaya bölünmüştür: CAP_NET_BIND_SERVICE (1024 altı port), CAP_NET_RAW, CAP_KILL, CAP_DAC_OVERRIDE, CAP_SYS_ADMIN… setcap cap_net_raw+ep /usr/bin/ping ile setuid root gerekmez (Bkz. Bölüm 13).
Çağrıİşlev
chmodDosyanın izin kipini değiştirir
chownSahip ve grubu değiştirir
accessErişimi gerçek uid/gid ile sınar
getuid, geteuidGerçek / etkin uid
getgid, getegidGerçek / etkin gid
setuid, setresuiduid değiştirir (ayrıcalık bırakma)
setgidgid değiştirir
umaskYeni dosyalar için izin maskesi

Kullanıcı ve grup kimlikleri /etc/passwd ve /etc/group’ta; parola özetleri yalnız root’un okuyabildiği /etc/shadow’da tutulur. sudo yetkilendirilmiş kullanıcıya komut başına root yetkisi verir.

Güvenlik · Adım adım

Konteynerler: Ad Alanları + cgroups

Tek Linux çekirdeği (konak)Konak süreçlerisystemd (PID 1)sshd (PID 820)containerdapp → PID 48213Konteynerpid nsmnt nsnet nsuts nsipc nsuser nscgroup nstime ns

Çalışma zamanı (runc, crun) clone()/unshare() ile yeni ad alanları oluşturur: kendi PID numaraları, bağlama ağacı, ağ yığını, ana makine adı, IPC, kullanıcı eşlemesi (içerideki root dışarıda sıradan uid), cgroup ve saat görünümü.

Tek Linux çekirdeği (konak)Konak süreçlerisystemd (PID 1)sshd (PID 820)containerdapp → PID 48213Konteynerpid nsmnt nsnet nsuts nsipc nsuser nscgroup nstime nskök: overlayfsimaj katmanları (ro) + üst (rw)

Bağlama ad alanında pivot_root ile imajın kök dosya sistemine geçilir. Kök genelde overlayfs’tir: salt okunur imaj katmanları + konteynere özel yazılabilir üst katman.

Tek Linux çekirdeği (konak)Konak süreçlerisystemd (PID 1)sshd (PID 820)containerdapp → PID 48213Konteynerpid nsmnt nsnet nsuts nsipc nsuser nscgroup nstime nskök: overlayfsimaj katmanları (ro) + üst (rw)cgroup v2cpu.max · memory.max · pids.max

cgroup v2 kaynakları sınırlar: cpu.max = "50000 100000" (yarım CPU), memory.max = 512M, pids.max = 100. Ad alanı ne görüleceğini, cgroup ne kadar kullanılacağını belirler.

Tek Linux çekirdeği (konak)Konak süreçlerisystemd (PID 1)sshd (PID 820)containerdapp → PID 48213Konteynerpid nsmnt nsnet nsuts nsipc nsuser nscgroup nstime nskök: overlayfsimaj katmanları (ro) + üst (rw)cgroup v2cpu.max · memory.max · pids.maxgüvenlikyetenek düşür, seccomp, LSM

Saldırı yüzeyi daraltılır: gereksiz yetenekler düşürülür, no_new_privs, seccomp filtresi (onlarca riskli sistem çağrısı engellenir) ve AppArmor/SELinux profili uygulanır.

Tek Linux çekirdeği (konak)Konak süreçlerisystemd (PID 1)sshd (PID 820)containerdapp → PID 48213Konteynerpid nsmnt nsnet nsuts nsipc nsuser nscgroup nstime nskök: overlayfsimaj katmanları (ro) + üst (rw)cgroup v2cpu.max · memory.max · pids.maxgüvenlikyetenek düşür, seccomp, LSMexecve(app)içeride PID 1

Son olarak execve: uygulama içeride PID 1, konakta PID 48213. Hepsi aynı çekirdeği paylaşır: VM’den çok hafiftir ama çekirdek açığı tüm konteynerleri etkiler (Bkz. Bölüm 13).

Güvenlik

seccomp ve Linux Güvenlik Modülleri (LSM)

uygulamaseccompDACyeteneklerLSM kancalarınesneopen("/etc/shadow")izin / errno / öldürrwx, uid, gidCAP_DAC_OVERRIDE?SELinux, AppArmorerişim verildiherhangi bir aşama “hayır” derse: EPERM / EACCES (seccomp: süreç öldürülebilir)
SELinux

Etiket tabanlı zorunlu erişim denetimi (MAC): her süreç ve dosyanın bir tipi var; politika hangi tipin hangisine ne yapabileceğini söyler. RHEL, Fedora, Android.

AppArmor

Yol tabanlı profiller: “bu program yalnız şu dosyalara erişebilir”. Yazması kolay. Ubuntu, SUSE, Debian.

Landlock (5.13+)

Ayrıcalıksız süreç kendini kum havuzuna alır: “bundan sonra yalnız ./veri altına yazabilirim”.

seccomp-BPF

Sürecin yapabileceği sistem çağrılarını filtreler; Chrome, systemd servisleri, Docker, Android uygulamaları kullanır.

Android ve Özet · Adım adım

Android: Binder, Zygote ve Kum Havuzu

Uygulamalar (APK)Android çatısı (Java/Kotlin API)ART çalışma zamanı + yerel kütüphaneler (Bionic)HAL (donanım soyutlama)Linux çekirdeği + Binder, SELinuxzygoteçatı önceden yüklüsystem_serveruid 1000 (system)

Android Linux çekirdeği üzerinde çalışır ama GNU kullanıcı alanı yoktur: C kütüphanesi Bionic, uygulamalar ART’ta çalışır. Çekirdeğe eklenenler: Binder IPC, enerji yönetimi (wakelock), zorunlu SELinux.

Uygulamalar (APK)Android çatısı (Java/Kotlin API)ART çalışma zamanı + yerel kütüphaneler (Bionic)HAL (donanım soyutlama)Linux çekirdeği + Binder, SELinuxzygoteçatı önceden yüklüsystem_serveruid 1000 (system)

Önyüklemede init zygote sürecini başlatır; zygote çatı sınıflarını ve kaynakları bir kez yükleyip bekler.

Uygulamalar (APK)Android çatısı (Java/Kotlin API)ART çalışma zamanı + yerel kütüphaneler (Bionic)HAL (donanım soyutlama)Linux çekirdeği + Binder, SELinuxzygoteçatı önceden yüklüsystem_serveruid 1000 (system)com.ornek.appuid 10123 · untrusted_appfork() + kimlik

Uygulama açılırken zygote fork() eder: yüklü sayfalar COW ile paylaşılır, başlatma hızlanır. Çocuk uygulamanın benzersiz uid’ine, SELinux bağlamına ve seccomp filtresine geçer.

Uygulamalar (APK)Android çatısı (Java/Kotlin API)ART çalışma zamanı + yerel kütüphaneler (Bionic)HAL (donanım soyutlama)Linux çekirdeği + Binder, SELinuxzygoteçatı önceden yüklüsystem_serveruid 1000 (system)com.ornek.appuid 10123 · untrusted_appfork() + kimlik/dev/bindertek kopya +arayan uid

Uygulama bir servisi (konum, kamera) Binder ile çağırır: çekirdek veriyi alıcının eşlenmiş tamponuna tek kopyayla taşır ve arayanın uid’ini iletir; servis izni buna göre denetler.

Uygulamalar (APK)Android çatısı (Java/Kotlin API)ART çalışma zamanı + yerel kütüphaneler (Bionic)HAL (donanım soyutlama)Linux çekirdeği + Binder, SELinuxzygoteçatı önceden yüklüsystem_serveruid 1000 (system)com.ornek.appuid 10123 · untrusted_appfork() + kimlik/dev/bindertek kopya +arayan uid/data/data/com.ornek.appyalnız uid 10123lmkd: arka planı öldür

Kum havuzu: her uygulama ayrı bir Linux kullanıcısıdır, verisi yalnız kendisine açıktır. Bellek azalınca kullanıcı alanındaki lmkd, PSI sinyalleriyle önemsiz arka plan uygulamalarını öldürür.

Özet

Özet: Dersin Kavramları Linux’ta

BölümKavramLinux’taki karşılığı
2 · YapılarSistem çağrısı, monolitik çekirdeksyscall, LKM, eBPF
3 · SüreçlerPCB, oluşturma, IPCtask_struct, fork/exec/wait, sinyal, boru
4 · İş parçacıklarıÇekirdek iş parçacığı modeliclone(), NPTL 1:1
5 · ÇizelgelemeAdil paylaşım, gerçek zamanEEVDF, FIFO/RR/DEADLINE, sched_ext
6 · SenkronizasyonKilit, koşul değişkenifutex, spinlock, RCU
7 · KilitlenmeTespit ve önlemelockdep, fcntl EDEADLK
8 · BellekAyırma, parçalanmabuddy, SLUB, NUMA bölgeleri
9 · Sanal bellekSayfalama, değiştirme4/5 düzey tablo, COW, MGLRU, zswap, OOM
10 · Dosya sistemlerii-node, dizin, günlükVFS, ext4, XFS, Btrfs
11 · G/ÇSürücü, zamanlamaaygıt dosyaları, blk-mq, io_uring
12 · Çok işlemciliYük dengeleme, NUMACPU başına kuyruklar, zamanlama alanları
13 · GüvenlikErişim denetimi, yalıtımrwx, yetenekler, namespaces, SELinux, seccomp
14 · Çoklu ortamZamanında işlemePipeWire, ALSA, V4L2
15 · TasarımMekanizma ve politika ayrımıcgroup, sched_ext: politika kullanıcıda

Özet

Kontrol Soruları

  1. fork() neden “bir kez çağrılıp iki kez döner”? Dönüş değerleri nedir, COW neyi kazandırır?
  2. Kabuk ls | wc -l’yi nasıl kurar? Ebeveyn boru uçlarını kapatmazsa ne olur?
  3. Linux’ta süreç ile iş parçacığı arasındaki fark nedir? clone bayraklarıyla açıklayın.
  4. EEVDF’de bir görev hangi koşulda seçilebilir? nice 5 görevin vruntime’ı neden daha hızlı ilerler?
  5. 0x00007f3a1c2b5e88 adresinin 4 düzeyli tablodaki dört dizini ve ofseti nedir?
  6. Buddy ayırıcıdan 5 sayfa istenirse hangi order verilir, iç parçalanma kaç sayfadır?
  7. umask 027 iken oluşturulan dosya ve dizinin izinleri nedir?
  8. Sert bağ ile sembolik bağ arasındaki fark nedir? Hedef silinince ne olur?
  9. ext4 sıralı günlüklemede çökmeden sonra tutarlılık nasıl sağlanır?
  10. Konteyner = ad alanları + cgroups: her biri neyi sağlar? VM’den farkı nedir?
Cevaplar
  1. fork süreci kopyalar; ikisi de çağrının içinden döner. Ebeveyne çocuğun PID’i, çocuğa 0 döner. COW ile sayfalar ancak yazılınca kopyalanır; fork’u exec izlediğinde neredeyse hiç kopya yapılmaz.
  2. pipe() → fork; çocuk 1 dup2(yazma, 1) + exec ls; çocuk 2 dup2(okuma, 0) + exec wc. Ebeveyn yazma ucunu açık tutarsa wc EOF görmez, sonsuza dek bekler.
  3. Yapısal fark yok: ikisi de task_struct. İş parçacığı CLONE_VM, CLONE_FILES, CLONE_SIGHAND, CLONE_THREAD ile adres alanını, dosyaları ve işleyicileri paylaşır, aynı TGID’dedir.
  4. Uygun olmalı (v ≤ V, gecikme ≥ 0); uygunlar arasında en erken sanal son tarihli seçilir. vruntime artışı gerçek süre × 1024 / ağırlık; nice 5’in ağırlığı 335 olduğu için ~3 kat hızlı ilerler.
  5. PGD = 254, PUD = 232, PMD = 225, PTE = 181, ofset = 0xe88.
  6. 5 sayfa 2’nin kuvvetine yuvarlanır: order 3 = 8 sayfa; 3 sayfa iç parçalanma.
  7. Dosya 666 & ~027 = 0640 (rw-r-----), dizin 777 & ~027 = 0750 (rwxr-x---).
  8. Sert bağ aynı i-node’a ikinci addır; hedef adı silinse de veri kalır. Sembolik bağ yolu tutan ayrı dosyadır; hedef silinince sarkar. Sert bağ dosya sistemi sınırını aşamaz.
  9. Veri önce asıl yerine, üst veri günlüğe yazılır, sonra commit. Bağlarken commit’li işlemler yeniden oynatılır, commit’siz olanlar atılır; tam fsck gerekmez.
  10. Ad alanları görünümü yalıtır (PID, ağ, bağlama…), cgroups kaynak kullanımını sınırlar. Konteynerler konak çekirdeğini paylaşır: hafif ama yalıtım VM’den zayıftır.

Özet

Kaynaklar

  • A. S. Tanenbaum, H. Bos, Modern Operating Systems, 4. baskı (2014) / 5. baskı (2022), Pearson — Bölüm 10: Case Study 1: Unix, Linux and Android.
  • A. Silberschatz, P. B. Galvin, G. Gagne, Operating System Concepts, 10. baskı, Wiley, 2018 — Bölüm 20: The Linux System.
  • R. Love, Linux Kernel Development, 3. baskı, Addison-Wesley, 2010.
  • M. Kerrisk, The Linux Programming Interface, No Starch Press, 2010; man7.org kılavuz sayfaları.
  • The Linux Kernel Documentation, docs.kernel.org — scheduler (EEVDF, sched-ext), admin-guide/mm (MGLRU, zswap), block (blk-mq), filesystems (vfs, ext4), userspace-api (seccomp, landlock).
  • Android Open Source Project, source.android.com — mimari, Binder, uygulama kum havuzu.
  • D. M. Ritchie, K. Thompson, “The UNIX Time-Sharing System”, Communications of the ACM, 1974.

Son

Bölüm 16: Linux
Dersin son bölümü — İşletim Sistemleri dersi burada tamamlanıyor.
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.