<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://program.sonsuz.us/feed.xml" rel="self" type="application/atom+xml" /><link href="https://program.sonsuz.us/" rel="alternate" type="text/html" /><updated>2026-09-27T18:05:44+00:00</updated><id>https://program.sonsuz.us/feed.xml</id><title type="html">SonsuzUs</title><subtitle>Programlama ve Yazılım</subtitle><author><name>Sonsuz Us</name></author><entry><title type="html">Çekirdek Modülü Geliştirmeye Giriş: Kendi Linux Cihaz Sürücünü Yaz</title><link href="https://program.sonsuz.us/posts/cekirdek-modulu-gelistirmeye-giris-kendi-linux-cihaz-surucunu-yaz/" rel="alternate" type="text/html" title="Çekirdek Modülü Geliştirmeye Giriş: Kendi Linux Cihaz Sürücünü Yaz" /><published>2026-09-27T00:00:00+00:00</published><updated>2026-09-27T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/cekirdek-modulu-gelistirmeye-giris-kendi-linux-cihaz-surucunu-yaz</id><content type="html" xml:base="https://program.sonsuz.us/posts/cekirdek-modulu-gelistirmeye-giris-kendi-linux-cihaz-surucunu-yaz/"><![CDATA[<p>Linux çekirdeği devasa bir monolitik yapı olsa da her özelliği kalıcı olarak çekirdeğe gömmek zorunda değildir. Yüklenebilir Çekirdek Modülleri (Loadable Kernel Modules veya LKM), çalışan sistemi yeniden başlatmadan sürücü, dosya sistemi ya da ağ özelliği eklememizi sağlar. Bu yazıda küçük bir karakter cihazı geliştirerek modül mimarisini güvenli biçimde keşfedeceğiz.</p>

<p>``</p>

<h2 id="modül-mimarisi-nasıl-çalışır">Modül mimarisi nasıl çalışır?</h2>

<p>Bir çekirdek modülü, kullanıcı alanındaki sıradan uygulamalardan farklı olarak <strong>kernel space</strong> içinde çalışır. İşletim sisteminin belleğine ve donanım kaynaklarına doğrudan erişebildiği için küçük bir hata bile tüm sistemi durdurabilir. Bu nedenle geliştirmeyi sanal makinede yapmak akıllıcadır.</p>

<p>Modül çekirdeğe yüklendiğinde sembolleri bağlanır, başlangıç fonksiyonu çalıştırılır ve gerekli kaynaklar kaydedilir. Kaldırılırken kaynakların ters sırada serbest bırakılması gerekir. Basitleştirilmiş yaşam döngüsü şöyledir:</p>

\[Kaynak\ Durumu = Tahsis\ Edilenler - Serbest\ Bırakılanlar\]

<p>Sağlıklı bir kaldırma işleminde sonucun $0$ olması beklenir. Aksi durumda bellek sızıntıları, kullanımda kalan cihazlar veya çökmeler ortaya çıkabilir.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Kullanıcı alanı programı</th>
      <th>Çekirdek modülü</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Çalışma alanı</td>
      <td>User space</td>
      <td>Kernel space</td>
    </tr>
    <tr>
      <td>Standart kütüphane</td>
      <td>Genellikle kullanılabilir</td>
      <td>Kullanılamaz</td>
    </tr>
    <tr>
      <td>Hata sonucu</td>
      <td>Süreç kapanabilir</td>
      <td>Sistem çökebilir</td>
    </tr>
    <tr>
      <td>Çıktı yöntemi</td>
      <td><code class="language-plaintext highlighter-rouge">printf()</code></td>
      <td><code class="language-plaintext highlighter-rouge">pr_info()</code> / <code class="language-plaintext highlighter-rouge">printk()</code></td>
    </tr>
    <tr>
      <td>Yükleme</td>
      <td>Programı çalıştırma</td>
      <td><code class="language-plaintext highlighter-rouge">insmod</code> veya <code class="language-plaintext highlighter-rouge">modprobe</code></td>
    </tr>
  </tbody>
</table>

<p><img src="/img/cekirdek-modulu-gelistirmeye-69.svg" alt="cekirdek-modulu-gelistirmeye-69" /></p>

<h2 id="basit-bir-karakter-cihazı">Basit bir karakter cihazı</h2>

<p>Aşağıdaki modül, <code class="language-plaintext highlighter-rouge">/dev/minidriver</code> adında bir karakter cihazı oluşturur. Kullanıcı cihazı okuduğunda çekirdekten kısa bir mesaj alır. <code class="language-plaintext highlighter-rouge">miscdevice</code> arabirimi, ana cihaz numarasını otomatik seçerek örneği sade tutar.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;linux/module.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;linux/miscdevice.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;linux/fs.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;linux/uaccess.h&gt;</span><span class="cp">
</span>
<span class="k">static</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">message</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"Merhaba, çekirdek!</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>

<span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">mini_read</span><span class="p">(</span><span class="k">struct</span> <span class="n">file</span> <span class="o">*</span><span class="n">file</span><span class="p">,</span> <span class="kt">char</span> <span class="n">__user</span> <span class="o">*</span><span class="n">buffer</span><span class="p">,</span>
                         <span class="kt">size_t</span> <span class="n">length</span><span class="p">,</span> <span class="n">loff_t</span> <span class="o">*</span><span class="n">offset</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="n">simple_read_from_buffer</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span> <span class="n">length</span><span class="p">,</span> <span class="n">offset</span><span class="p">,</span>
                                   <span class="n">message</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">static</span> <span class="k">const</span> <span class="k">struct</span> <span class="n">file_operations</span> <span class="n">mini_fops</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">.</span><span class="n">owner</span> <span class="o">=</span> <span class="n">THIS_MODULE</span><span class="p">,</span>
    <span class="p">.</span><span class="n">read</span> <span class="o">=</span> <span class="n">mini_read</span><span class="p">,</span>
<span class="p">};</span>

<span class="k">static</span> <span class="k">struct</span> <span class="n">miscdevice</span> <span class="n">mini_device</span> <span class="o">=</span> <span class="p">{</span>
    <span class="p">.</span><span class="n">minor</span> <span class="o">=</span> <span class="n">MISC_DYNAMIC_MINOR</span><span class="p">,</span>
    <span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="s">"minidriver"</span><span class="p">,</span>
    <span class="p">.</span><span class="n">fops</span> <span class="o">=</span> <span class="o">&amp;</span><span class="n">mini_fops</span><span class="p">,</span>
    <span class="p">.</span><span class="n">mode</span> <span class="o">=</span> <span class="mo">0444</span><span class="p">,</span>
<span class="p">};</span>

<span class="k">static</span> <span class="kt">int</span> <span class="n">__init</span> <span class="nf">mini_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">result</span> <span class="o">=</span> <span class="n">misc_register</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mini_device</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">result</span><span class="p">)</span>
        <span class="n">pr_err</span><span class="p">(</span><span class="s">"minidriver kaydedilemedi: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
    <span class="k">else</span>
        <span class="n">pr_info</span><span class="p">(</span><span class="s">"minidriver yüklendi</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>

    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>

<span class="k">static</span> <span class="kt">void</span> <span class="n">__exit</span> <span class="nf">mini_exit</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">misc_deregister</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mini_device</span><span class="p">);</span>
    <span class="n">pr_info</span><span class="p">(</span><span class="s">"minidriver kaldırıldı</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">module_init</span><span class="p">(</span><span class="n">mini_init</span><span class="p">);</span>
<span class="n">module_exit</span><span class="p">(</span><span class="n">mini_exit</span><span class="p">);</span>

<span class="n">MODULE_LICENSE</span><span class="p">(</span><span class="s">"GPL"</span><span class="p">);</span>
<span class="n">MODULE_AUTHOR</span><span class="p">(</span><span class="s">"Örnek Geliştirici"</span><span class="p">);</span>
<span class="n">MODULE_DESCRIPTION</span><span class="p">(</span><span class="s">"Basit karakter cihazı modülü"</span><span class="p">);</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">file_operations</code>, sistem çağrıları ile sürücü fonksiyonları arasındaki köprüdür. Kullanıcı <code class="language-plaintext highlighter-rouge">read()</code> çağırdığında çekirdek <code class="language-plaintext highlighter-rouge">mini_read()</code> fonksiyonuna yönelir. <code class="language-plaintext highlighter-rouge">simple_read_from_buffer()</code> ise çekirdek belleğindeki veriyi kullanıcı belleğine kontrollü şekilde aktarır; doğrudan işaretçi kopyalamaktan daha güvenlidir.</p>

<h2 id="derleme-ve-deneme">Derleme ve deneme</h2>

<p>Modülü derlemek için aynı dizine şu <code class="language-plaintext highlighter-rouge">Makefile</code> dosyasını ekleyin:</p>

<div class="language-makefile highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">obj-m</span> <span class="o">+=</span> minidriver.o

<span class="nl">all</span><span class="o">:</span>
	<span class="p">$(</span>MAKE<span class="p">)</span> <span class="nt">-C</span> /lib/modules/<span class="p">$(</span>shell <span class="nb">uname</span> <span class="nt">-r</span><span class="p">)</span>/build <span class="nv">M</span><span class="o">=</span><span class="p">$(</span>PWD<span class="p">)</span> modules

<span class="nl">clean</span><span class="o">:</span>
	<span class="p">$(</span>MAKE<span class="p">)</span> <span class="nt">-C</span> /lib/modules/<span class="p">$(</span>shell <span class="nb">uname</span> <span class="nt">-r</span><span class="p">)</span>/build <span class="nv">M</span><span class="o">=</span><span class="p">$(</span>PWD<span class="p">)</span> clean
</code></pre></div></div>

<p>Ardından geliştirme başlıklarının kurulu olduğundan emin olarak komutları çalıştırın:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>make
<span class="nb">sudo </span>insmod minidriver.ko
<span class="nb">cat</span> /dev/minidriver
<span class="nb">sudo </span>rmmod minidriver
dmesg | <span class="nb">tail</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">insmod</code> modülü doğrudan yüklerken <code class="language-plaintext highlighter-rouge">modprobe</code> bağımlılıkları da çözer. Üretim sistemlerinde Secure Boot imzasız modülleri reddedebilir; ayrıca çekirdek API’leri sürümler arasında değişebilir.</p>

<h2 id="güvenli-geliştirme-alışkanlıkları">Güvenli geliştirme alışkanlıkları</h2>

<p>Her tahsisin karşılığında bir temizleme işlemi yazın, kullanıcıdan gelen uzunluk ve adreslere güvenmeyin, kilit gerektiren ortak verileri koruyun ve günlükleri <code class="language-plaintext highlighter-rouge">dmesg</code> üzerinden izleyin. Gerçek donanım sürücülerinde kesmeler, DMA, aygıt ağacı ve platform veri yolları devreye girer. Ancak temel ritim değişmez: <strong>kaydet, isteği işle, kaynakları eksiksiz bırak ve modülü kaldır</strong>.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="linux" /><category term="kernel" /><category term="çekirdek-modülü" /><category term="cihaz-sürücüsü" /><category term="c" /><category term="sistem-programlama" /><summary type="html"><![CDATA[Linux çekirdeği devasa bir monolitik yapı olsa da her özelliği kalıcı olarak çekirdeğe gömmek zorunda değildir. Yüklenebilir Çekirdek Modülleri (Loadable Kernel Modules veya LKM), çalışan sistemi yeniden başlatmadan sürücü, dosya sistemi ya da ağ özelliği eklememizi sağlar. Bu yazıda küçük bir karakter cihazı geliştirerek modül mimarisini güvenli biçimde keşfedeceğiz.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/cekirdek-modulu-gelistirmeye-69.png" /><media:content medium="image" url="https://program.sonsuz.us/img/cekirdek-modulu-gelistirmeye-69.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">eBPF ile Çekirdeği Yeniden Derlemeden Ağ Paketlerini Manipüle Etmek</title><link href="https://program.sonsuz.us/posts/ebpf-ile-cekirdegi-yeniden-derlemeden-ag-paketlerini-manipule-etmek/" rel="alternate" type="text/html" title="eBPF ile Çekirdeği Yeniden Derlemeden Ağ Paketlerini Manipüle Etmek" /><published>2026-09-27T00:00:00+00:00</published><updated>2026-09-27T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/ebpf-ile-cekirdegi-yeniden-derlemeden-ag-paketlerini-manipule-etmek</id><content type="html" xml:base="https://program.sonsuz.us/posts/ebpf-ile-cekirdegi-yeniden-derlemeden-ag-paketlerini-manipule-etmek/"><![CDATA[<p>Linux ağ yığınında paketleri yakalamak, filtrelemek veya yönlendirmek eskiden çekirdek modülü geliştirmeyi ve bazen çekirdeği yeniden derlemeyi gerektiriyordu. eBPF sayesinde artık doğrulanmış küçük programları çekirdek içinde güvenli biçimde çalıştırabiliyoruz. Böylece DDoS filtrelerinden gecikme ölçümüne kadar pek çok işi, kaynak koduna neşter vurmadan gerçekleştirmek mümkün.</p>

<p>``</p>

<h2 id="ebpf-tam-olarak-nedir">eBPF tam olarak nedir?</h2>

<p>eBPF, kullanıcı alanında hazırlanan programların Linux çekirdeğindeki belirli kancalara yüklenmesini sağlayan bir çalışma ortamıdır. İsmindeki BPF, tarihsel olarak “Berkeley Packet Filter” anlamına gelse de teknoloji bugün ağ paketlerinin çok ötesine uzanır: sistem çağrıları, süreçler, dosya erişimleri ve performans olayları da izlenebilir.</p>

<p>“Çekirdeğe dokunmadan” ifadesi, kodun çekirdek dışında çalıştığı anlamına gelmez. eBPF programı çekirdek bağlamında çalışır; ancak çekirdek kaynak kodunu değiştirmeye veya özel bir modül yüklemeye gerek bırakmaz. Program yüklenmeden önce <strong>verifier</strong> tarafından incelenir. Geçersiz bellek erişimi, güvensiz işaretçi kullanımı veya sonlanmama riski varsa program reddedilir.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Çalışma noktası</th>
      <th style="text-align: right">Performans</th>
      <th>Risk ve esneklik</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Kullanıcı alanı yakalama</td>
      <td>Ağ yığınından sonra</td>
      <td style="text-align: right">Orta</td>
      <td>Güvenli, kopyalama maliyetli</td>
    </tr>
    <tr>
      <td>Netfilter/iptables</td>
      <td>Çekirdek ağ yığını</td>
      <td style="text-align: right">Yüksek</td>
      <td>Kurallarla sınırlı</td>
    </tr>
    <tr>
      <td>Çekirdek modülü</td>
      <td>Çekirdek içinde</td>
      <td style="text-align: right">Çok yüksek</td>
      <td>Hata tüm sistemi etkileyebilir</td>
    </tr>
    <tr>
      <td>eBPF/XDP</td>
      <td>Sürücüye çok yakın</td>
      <td style="text-align: right">Çok yüksek</td>
      <td>Verifier ile denetimli</td>
    </tr>
  </tbody>
</table>

<h2 id="xdp-neden-bu-kadar-hızlı">XDP neden bu kadar hızlı?</h2>

<p>XDP, yani <strong>eXpress Data Path</strong>, paketi ağ sürücüsünden gelir gelmez işleyebilir. Paket henüz <code class="language-plaintext highlighter-rouge">sk_buff</code> yapısına dönüştürülmeden karar verildiği için ayırma, kopyalama ve ağ yığını maliyetleri azaltılır.</p>

<p>Bir paketin yaklaşık işlem maliyetini şöyle düşünebiliriz:</p>

\[T_{toplam} = T_{alma} + T_{ayrıştırma} + T_{karar} + T_{yönlendirme}\]

<p>XDP özellikle $T_{ayrıştırma}$ ve $T_{yönlendirme}$ bileşenlerini küçültür. Program paketi kabul etmek için <code class="language-plaintext highlighter-rouge">XDP_PASS</code>, düşürmek için <code class="language-plaintext highlighter-rouge">XDP_DROP</code>, başka arayüze göndermek için <code class="language-plaintext highlighter-rouge">XDP_REDIRECT</code> döndürebilir.</p>

<p>Aşağıdaki orta düzey örnek, IPv4 UDP paketlerini erken aşamada düşürür:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;linux/bpf.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;linux/if_ether.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;linux/ip.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;linux/udp.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;bpf/bpf_helpers.h&gt;</span><span class="cp">
</span>
<span class="n">SEC</span><span class="p">(</span><span class="s">"xdp"</span><span class="p">)</span>
<span class="kt">int</span> <span class="nf">drop_udp</span><span class="p">(</span><span class="k">struct</span> <span class="n">xdp_md</span> <span class="o">*</span><span class="n">ctx</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">void</span> <span class="o">*</span><span class="n">data</span> <span class="o">=</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)(</span><span class="kt">long</span><span class="p">)</span><span class="n">ctx</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">;</span>
    <span class="kt">void</span> <span class="o">*</span><span class="n">data_end</span> <span class="o">=</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)(</span><span class="kt">long</span><span class="p">)</span><span class="n">ctx</span><span class="o">-&gt;</span><span class="n">data_end</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">ethhdr</span> <span class="o">*</span><span class="n">eth</span> <span class="o">=</span> <span class="n">data</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">((</span><span class="kt">void</span> <span class="o">*</span><span class="p">)(</span><span class="n">eth</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">data_end</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">XDP_ABORTED</span><span class="p">;</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">eth</span><span class="o">-&gt;</span><span class="n">h_proto</span> <span class="o">!=</span> <span class="n">__constant_htons</span><span class="p">(</span><span class="n">ETH_P_IP</span><span class="p">))</span>
        <span class="k">return</span> <span class="n">XDP_PASS</span><span class="p">;</span>

    <span class="k">struct</span> <span class="n">iphdr</span> <span class="o">*</span><span class="n">ip</span> <span class="o">=</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)(</span><span class="n">eth</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
    <span class="k">if</span> <span class="p">((</span><span class="kt">void</span> <span class="o">*</span><span class="p">)(</span><span class="n">ip</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&gt;</span> <span class="n">data_end</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">XDP_ABORTED</span><span class="p">;</span>

    <span class="k">return</span> <span class="n">ip</span><span class="o">-&gt;</span><span class="n">protocol</span> <span class="o">==</span> <span class="n">IPPROTO_UDP</span> <span class="o">?</span> <span class="n">XDP_DROP</span> <span class="o">:</span> <span class="n">XDP_PASS</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">char</span> <span class="n">LICENSE</span><span class="p">[]</span> <span class="n">SEC</span><span class="p">(</span><span class="s">"license"</span><span class="p">)</span> <span class="o">=</span> <span class="s">"GPL"</span><span class="p">;</span>
</code></pre></div></div>

<p>Sınır kontrolleri yalnızca iyi programlama alışkanlığı değildir; verifier, <code class="language-plaintext highlighter-rouge">data_end</code> kontrolü bulunmayan paket erişimini kabul etmez. Kod Clang ile eBPF bytecode’una çevrilip bir arayüze bağlanabilir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>clang <span class="nt">-O2</span> <span class="nt">-g</span> <span class="nt">-target</span> bpf <span class="nt">-c</span> filter.c <span class="nt">-o</span> filter.o
<span class="nb">sudo </span>ip <span class="nb">link set </span>dev eth0 xdp obj filter.o sec xdp
<span class="nb">sudo </span>ip <span class="nb">link set </span>dev eth0 xdp off
</code></pre></div></div>

<p>İlk komut programı derler, ikincisi <code class="language-plaintext highlighter-rouge">eth0</code> arayüzüne yükler, sonuncusu ise bağlantıyı kaldırır. Uzaktan bağlı bir sunucuda bütün UDP trafiğini düşürmeden önce DNS ve VPN kullanımını düşünmek iyi fikirdir; aksi hâlde güvenlik demosu hızla bağlantı kesme demosuna dönüşebilir.</p>

<h2 id="haritalar-ve-gözlemlenebilirlik">Haritalar ve gözlemlenebilirlik</h2>

<p>eBPF haritaları, çekirdek ve kullanıcı alanı arasında paylaşılan anahtar-değer depolarıdır. IP başına paket sayacı tutmak, engelli adresleri dinamik olarak güncellemek veya CPU başına istatistik toplamak için kullanılabilirler. Üretimde C ile doğrudan uğraşmak yerine libbpf, BCC, bpftrace, Cilium ve Rust tabanlı Aya gibi araçlardan yararlanılabilir.</p>

<p>TC kancaları paket değişikliği ve trafik şekillendirme konusunda daha esnekken XDP mümkün olan en erken kararı hedefler. Sonuç olarak eBPF, klasik çekirdek modüllerinin bütün risklerini üstlenmeden çekirdek hızına yaklaşan, programlanabilir bir ağ güvenliği ve izleme katmanı sunar.</p>

<p><img src="/img/ebpf-ile-cekirdegi-78.svg" alt="ebpf-ile-cekirdegi-78" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="ebpf" /><category term="linux" /><category term="xdp" /><category term="ağ güvenliği" /><category term="paket işleme" /><category term="gözlemlenebilirlik" /><summary type="html"><![CDATA[Linux ağ yığınında paketleri yakalamak, filtrelemek veya yönlendirmek eskiden çekirdek modülü geliştirmeyi ve bazen çekirdeği yeniden derlemeyi gerektiriyordu. eBPF sayesinde artık doğrulanmış küçük programları çekirdek içinde güvenli biçimde çalıştırabiliyoruz. Böylece DDoS filtrelerinden gecikme ölçümüne kadar pek çok işi, kaynak koduna neşter vurmadan gerçekleştirmek mümkün.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/ebpf-ile-cekirdegi-78.png" /><media:content medium="image" url="https://program.sonsuz.us/img/ebpf-ile-cekirdegi-78.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">FUSE ile Python Kullanarak Kendi Sanal Dosya Sisteminizi Yazın</title><link href="https://program.sonsuz.us/posts/fuse-ile-python-kullanarak-kendi-sanal-dosya-sisteminizi-yazin/" rel="alternate" type="text/html" title="FUSE ile Python Kullanarak Kendi Sanal Dosya Sisteminizi Yazın" /><published>2026-09-27T00:00:00+00:00</published><updated>2026-09-27T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/fuse-ile-python-kullanarak-kendi-sanal-dosya-sisteminizi-yazin</id><content type="html" xml:base="https://program.sonsuz.us/posts/fuse-ile-python-kullanarak-kendi-sanal-dosya-sisteminizi-yazin/"><![CDATA[<p>Dosya sistemi yazmak denildiğinde akla çekirdek kodu, korkutucu C işaretçileri ve bilgisayarı yeniden başlatma ritüelleri gelebilir. FUSE sayesinde bunların çoğuna gerek kalmadan Python veya Go ile dosya işlemlerine kendi kurallarımızı uygulayabiliriz. Örneğin içeriğini çalışma anında üreten, buluttaki verileri dosya gibi gösteren ya da tüm yazılanları otomatik şifreleyen bir sistem geliştirebiliriz.
``</p>
<h2 id="fuse-tam-olarak-nedir">FUSE tam olarak nedir?</h2>

<p>FUSE, yani <strong>Filesystem in Userspace</strong>, dosya sistemi mantığının kullanıcı alanında çalışan normal bir program tarafından uygulanmasını sağlayan Linux altyapısıdır. Uygulamalar yine <code class="language-plaintext highlighter-rouge">open</code>, <code class="language-plaintext highlighter-rouge">read</code>, <code class="language-plaintext highlighter-rouge">write</code> ve <code class="language-plaintext highlighter-rouge">stat</code> gibi standart sistem çağrılarını kullanır. Çekirdekteki FUSE sürücüsü bu istekleri bizim sürecimize iletir, cevabı alır ve uygulamaya döndürür.</p>

<p>Akış kabaca şöyledir:</p>

<ol>
  <li>Kullanıcı <code class="language-plaintext highlighter-rouge">/mnt/ozel/merhaba.txt</code> dosyasını okur.</li>
  <li>İşletim sistemi isteği FUSE sürücüsüne gönderir.</li>
  <li>FUSE, Python programımızdaki <code class="language-plaintext highlighter-rouge">read()</code> metodunu çağırır.</li>
  <li>Metodun ürettiği veri kullanıcıya teslim edilir.</li>
</ol>

<p>Bir işlemin toplam gecikmesini basitçe $T = T_{kernel} + T_{iletisim} + T_{uygulama}$ şeklinde düşünebiliriz. Kullanıcı alanına geçiş ek maliyet oluşturduğu için FUSE her senaryoda yerel dosya sistemleri kadar hızlı değildir; fakat geliştirme kolaylığı çoğu özel proje için daha değerlidir.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Çekirdek dosya sistemi</th>
      <th>FUSE dosya sistemi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Geliştirme dili</td>
      <td>Genellikle C</td>
      <td>Python, Go, Rust, C++</td>
    </tr>
    <tr>
      <td>Hata etkisi</td>
      <td>Sistemi çökertebilir</td>
      <td>Genellikle süreç kapanır</td>
    </tr>
    <tr>
      <td>Performans</td>
      <td>Çok yüksek</td>
      <td>Ek iletişim maliyeti var</td>
    </tr>
    <tr>
      <td>Geliştirme kolaylığı</td>
      <td>Zor</td>
      <td>Görece kolay</td>
    </tr>
    <tr>
      <td>Kullanım alanı</td>
      <td>Genel amaçlı depolama</td>
      <td>Özel ve sanal sistemler</td>
    </tr>
  </tbody>
</table>

<h2 id="python-ile-çalışan-küçük-bir-örnek">Python ile çalışan küçük bir örnek</h2>

<p>Ubuntu tabanlı bir sistemde gerekli paketleri şu şekilde kurabiliriz:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install </span>fuse3 libfuse3-dev
python3 <span class="nt">-m</span> pip <span class="nb">install </span>fusepy
<span class="nb">mkdir</span> <span class="nt">-p</span> /tmp/benimfs
</code></pre></div></div>

<p>Aşağıdaki dosya sistemi yalnızca <code class="language-plaintext highlighter-rouge">merhaba.txt</code> isimli sanal bir dosya sunar. Dosyanın fiziksel diskte bulunması gerekmez; içerik Python tarafından anlık üretilir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">fuse</span> <span class="kn">import</span> <span class="n">FUSE</span><span class="p">,</span> <span class="n">Operations</span>
<span class="kn">import</span> <span class="n">errno</span>
<span class="kn">import</span> <span class="n">os</span>

<span class="k">class</span> <span class="nc">BenimFS</span><span class="p">(</span><span class="n">Operations</span><span class="p">):</span>
    <span class="n">mesaj</span> <span class="o">=</span> <span class="sa">b</span><span class="sh">"</span><span class="s">Merhaba, bu veri sanal dosya sisteminden geliyor!</span><span class="se">\n</span><span class="sh">"</span>

    <span class="k">def</span> <span class="nf">getattr</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">fh</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">path</span> <span class="o">==</span> <span class="sh">"</span><span class="s">/</span><span class="sh">"</span><span class="p">:</span>
            <span class="k">return</span> <span class="p">{</span>
                <span class="sh">"</span><span class="s">st_mode</span><span class="sh">"</span><span class="p">:</span> <span class="mo">0o40555</span><span class="p">,</span>
                <span class="sh">"</span><span class="s">st_nlink</span><span class="sh">"</span><span class="p">:</span> <span class="mi">2</span>
            <span class="p">}</span>

        <span class="k">if</span> <span class="n">path</span> <span class="o">==</span> <span class="sh">"</span><span class="s">/merhaba.txt</span><span class="sh">"</span><span class="p">:</span>
            <span class="k">return</span> <span class="p">{</span>
                <span class="sh">"</span><span class="s">st_mode</span><span class="sh">"</span><span class="p">:</span> <span class="mo">0o100444</span><span class="p">,</span>
                <span class="sh">"</span><span class="s">st_nlink</span><span class="sh">"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
                <span class="sh">"</span><span class="s">st_size</span><span class="sh">"</span><span class="p">:</span> <span class="nf">len</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">mesaj</span><span class="p">)</span>
            <span class="p">}</span>

        <span class="k">raise</span> <span class="nc">OSError</span><span class="p">(</span><span class="n">errno</span><span class="p">.</span><span class="n">ENOENT</span><span class="p">,</span> <span class="n">os</span><span class="p">.</span><span class="nf">strerror</span><span class="p">(</span><span class="n">errno</span><span class="p">.</span><span class="n">ENOENT</span><span class="p">))</span>

    <span class="k">def</span> <span class="nf">readdir</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">fh</span><span class="p">):</span>
        <span class="k">return</span> <span class="p">[</span><span class="sh">"</span><span class="s">.</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">..</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">merhaba.txt</span><span class="sh">"</span><span class="p">]</span>

    <span class="k">def</span> <span class="nf">open</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">flags</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">path</span> <span class="o">!=</span> <span class="sh">"</span><span class="s">/merhaba.txt</span><span class="sh">"</span><span class="p">:</span>
            <span class="k">raise</span> <span class="nc">OSError</span><span class="p">(</span><span class="n">errno</span><span class="p">.</span><span class="n">ENOENT</span><span class="p">,</span> <span class="sh">"</span><span class="s">Dosya bulunamadı</span><span class="sh">"</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">flags</span> <span class="o">&amp;</span> <span class="p">(</span><span class="n">os</span><span class="p">.</span><span class="n">O_WRONLY</span> <span class="o">|</span> <span class="n">os</span><span class="p">.</span><span class="n">O_RDWR</span><span class="p">):</span>
            <span class="k">raise</span> <span class="nc">OSError</span><span class="p">(</span><span class="n">errno</span><span class="p">.</span><span class="n">EACCES</span><span class="p">,</span> <span class="sh">"</span><span class="s">Dosya salt okunur</span><span class="sh">"</span><span class="p">)</span>
        <span class="k">return</span> <span class="mi">0</span>

    <span class="k">def</span> <span class="nf">read</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">path</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">offset</span><span class="p">,</span> <span class="n">fh</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">mesaj</span><span class="p">[</span><span class="n">offset</span><span class="p">:</span><span class="n">offset</span> <span class="o">+</span> <span class="n">size</span><span class="p">]</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="sh">"</span><span class="s">__main__</span><span class="sh">"</span><span class="p">:</span>
    <span class="nc">FUSE</span><span class="p">(</span><span class="nc">BenimFS</span><span class="p">(),</span> <span class="sh">"</span><span class="s">/tmp/benimfs</span><span class="sh">"</span><span class="p">,</span> <span class="n">foreground</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">getattr()</code> dosyanın türünü, izinlerini ve boyutunu bildirir. <code class="language-plaintext highlighter-rouge">readdir()</code> dizin listesini üretir. <code class="language-plaintext highlighter-rouge">open()</code> erişim kurallarını denetlerken <code class="language-plaintext highlighter-rouge">read()</code> istenen aralıktaki baytları döndürür. Programı <code class="language-plaintext highlighter-rouge">python3 benimfs.py</code> ile çalıştırdıktan sonra başka bir terminalde <code class="language-plaintext highlighter-rouge">cat /tmp/benimfs/merhaba.txt</code> komutu kullanılabilir. Ayırmak için <code class="language-plaintext highlighter-rouge">fusermount3 -u /tmp/benimfs</code> yeterlidir.</p>

<h2 id="tasarımda-dikkat-edilmesi-gerekenler">Tasarımda dikkat edilmesi gerekenler</h2>

<p>Gerçek bir projede eşzamanlı erişim, önbellekleme, dosya tanıtıcıları, kullanıcı kimlikleri ve hata kodları hesaba katılmalıdır. <code class="language-plaintext highlighter-rouge">read()</code> metodunun tüm içeriği değil, yalnızca <code class="language-plaintext highlighter-rouge">offset</code> ile başlayan <code class="language-plaintext highlighter-rouge">size</code> baytı döndürmesi özellikle önemlidir. Aksi hâlde büyük dosyalarda beklenmedik sonuçlar oluşabilir.</p>

<table>
  <thead>
    <tr>
      <th>Amaç</th>
      <th>Uygulanabilecek kural</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Şifreli kasa</td>
      <td><code class="language-plaintext highlighter-rouge">write()</code> sırasında şifreleme</td>
    </tr>
    <tr>
      <td>Bulut sürücüsü</td>
      <td><code class="language-plaintext highlighter-rouge">read()</code> sırasında API isteği</td>
    </tr>
    <tr>
      <td>Denetim sistemi</td>
      <td>Her erişimi günlüğe kaydetme</td>
    </tr>
    <tr>
      <td>Dinamik rapor</td>
      <td>Dosya açıldığında içerik üretme</td>
    </tr>
  </tbody>
</table>

<p>FUSE; prototipler, eğitim araçları, arşiv görüntüleyicileri ve uzak depolama istemcileri için güçlü bir oyun alanıdır. Çekirdeğe dalmadan işletim sisteminin dosya soyutlamasını kullanabilir, hatta bir REST API’yi klasör ve dosyalardan oluşan doğal bir arayüze dönüştürebilirsiniz.</p>

<p><img src="/img/fuse-ile-python-34.svg" alt="fuse-ile-python-34" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Proje" /><category term="fuse" /><category term="python" /><category term="dosya-sistemi" /><category term="linux" /><category term="sanal-dosya-sistemi" /><category term="sistem-programlama" /><summary type="html"><![CDATA[Dosya sistemi yazmak denildiğinde akla çekirdek kodu, korkutucu C işaretçileri ve bilgisayarı yeniden başlatma ritüelleri gelebilir. FUSE sayesinde bunların çoğuna gerek kalmadan Python veya Go ile dosya işlemlerine kendi kurallarımızı uygulayabiliriz. Örneğin içeriğini çalışma anında üreten, buluttaki verileri dosya gibi gösteren ya da tüm yazılanları otomatik şifreleyen bir sistem geliştirebiliriz.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/fuse-ile-python-34.png" /><media:content medium="image" url="https://program.sonsuz.us/img/fuse-ile-python-34.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">İşletim Sistemlerinde Page Cache: Disk Okumaları Neden Sandığımızdan Hızlıdır?</title><link href="https://program.sonsuz.us/posts/isletim-sistemlerinde-page-cache-disk-okumalari-neden-sandigimizdan-hizlidir/" rel="alternate" type="text/html" title="İşletim Sistemlerinde Page Cache: Disk Okumaları Neden Sandığımızdan Hızlıdır?" /><published>2026-09-27T00:00:00+00:00</published><updated>2026-09-27T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/isletim-sistemlerinde-page-cache-disk-okumalari-neden-sandigimizdan-hizlidir</id><content type="html" xml:base="https://program.sonsuz.us/posts/isletim-sistemlerinde-page-cache-disk-okumalari-neden-sandigimizdan-hizlidir/"><![CDATA[<p>Bir dosyayı ilk kez açarken kısa bir bekleme yaşayıp ikinci açılışta şaşırtıcı bir hız görmüş olabilirsiniz. Dosya diskte durduğu hâlde bilgisayarınız nasıl bir anda hızlandı? Çoğu zaman cevap daha hızlı bir disk değil, işletim sisteminin boş RAM alanını akıllıca değerlendirdiği <strong>page cache</strong> mekanizmasıdır.</p>

<p>``</p>

<h2 id="page-cache-nedir">Page cache nedir?</h2>

<p>İşletim sistemi, depolama aygıtındaki dosyaları doğrudan uygulamaların yönetmesine izin vermez. Uygulama bir dosya istediğinde çekirdek, veriyi belirli büyüklükteki bellek sayfaları hâlinde okur. Okunan sayfalar yalnızca programa verilmez; aynı zamanda RAM içindeki page cache alanında tutulur.</p>

<p>Aynı dosya yeniden istendiğinde çekirdek önce önbelleği kontrol eder. Gerekli sayfalar RAM’deyse diske erişmeden sonucu döndürür. Buna <strong>cache hit</strong>, verinin bulunamayıp diskten okunmasına ise <strong>cache miss</strong> denir.</p>

<table>
  <thead>
    <tr>
      <th>Durum</th>
      <th>Veri kaynağı</th>
      <th style="text-align: right">Yaklaşık gecikme</th>
      <th>Sonuç</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Cache hit</td>
      <td>RAM</td>
      <td style="text-align: right">nanosaniye–mikrosaniye</td>
      <td>Çok hızlı okuma</td>
    </tr>
    <tr>
      <td>SSD okuması</td>
      <td>SSD</td>
      <td style="text-align: right">onlarca–yüzlerce mikrosaniye</td>
      <td>Hızlı ama RAM’den yavaş</td>
    </tr>
    <tr>
      <td>HDD okuması</td>
      <td>Mekanik disk</td>
      <td style="text-align: right">milisaniye</td>
      <td>Kafa hareketi nedeniyle yavaş</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/isletim-sistemlerinde-page-33.svg" alt="isletim-sistemlerinde-page-33" /></p>

<p>Basitleştirilmiş toplam erişim süresi şöyle düşünülebilir:</p>

\[T_{ortalama} = H \cdot T_{RAM} + (1-H) \cdot T_{disk}\]

<p>Buradaki $H$, önbellek isabet oranıdır. $H$ değeri 1’e yaklaştıkça ortalama erişim süresi RAM hızına yaklaşır. Küçük görünen bir isabet oranı artışı bile yoğun dosya kullanan sunucularda büyük performans farkı yaratabilir.</p>

<h2 id="boş-ram-neden-gerçekten-boş-değildir">“Boş RAM” neden gerçekten boş değildir?</h2>

<p>Görev yöneticisinde RAM’in büyük bölümünün kullanıldığını görmek her zaman sorun anlamına gelmez. Modern işletim sistemleri kullanılmayan belleği boş bırakmak yerine dosya önbelleği olarak değerlendirir. Çünkü kullanılmayan RAM, performans açısından kaçırılmış bir fırsattır.</p>

<p>Bir uygulama daha fazla belleğe ihtiyaç duyduğunda önbellekteki temiz sayfalar kolayca bırakılabilir. Bu nedenle page cache, uygulamaların belleğini “çalmaz”; ihtiyaç ortaya çıkana kadar boş kapasiteyi ödünç alır.</p>

<p>Linux çıktılarındaki <code class="language-plaintext highlighter-rouge">free</code>, <code class="language-plaintext highlighter-rouge">buff/cache</code> ve özellikle <code class="language-plaintext highlighter-rouge">available</code> değerleri bu yüzden birlikte değerlendirilmelidir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Belleğin uygulamalar ve önbellek arasında nasıl dağıldığını gösterir.</span>
free <span class="nt">-h</span>

<span class="c"># Bir dosyayı okuyarak gerçek süreyi ölçer.</span>
<span class="nb">time cat </span>buyuk-dosya.bin <span class="o">&gt;</span> /dev/null

<span class="c"># Aynı komut ikinci kez çalıştırıldığında veri büyük olasılıkla cache'tedir.</span>
<span class="nb">time cat </span>buyuk-dosya.bin <span class="o">&gt;</span> /dev/null
</code></pre></div></div>

<p>İkinci çalıştırmanın daha hızlı olması, dosyanın değiştiği veya <code class="language-plaintext highlighter-rouge">cat</code> programının özel bir numara yaptığı anlamına gelmez. İlk komut dosya sayfalarını RAM’e taşımış, ikinci komut ise hazır bulunan sayfaları kullanmıştır. Dosya RAM kapasitesinden büyükse veya sistem yoğun bellek baskısı altındaysa fark azalabilir.</p>

<h2 id="yazma-işlemlerinde-de-görev-alır-mı">Yazma işlemlerinde de görev alır mı?</h2>

<p>Evet. Bir uygulama dosyaya yazdığında veri çoğu zaman önce bellekteki sayfalara aktarılır. Değiştirilmiş ve henüz diske gönderilmemiş sayfalara <strong>dirty page</strong> denir. Çekirdek bunları daha sonra toplu biçimde diske yazar. Böylece uygulama her küçük değişiklik için fiziksel disk işlemini beklemez.</p>

<table>
  <thead>
    <tr>
      <th>Sayfa türü</th>
      <th>Anlamı</th>
      <th>Bellekten hemen atılabilir mi?</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Clean page</td>
      <td>Diskteki kopyayla aynı</td>
      <td>Evet</td>
    </tr>
    <tr>
      <td>Dirty page</td>
      <td>Henüz diske yazılmamış değişiklik içerir</td>
      <td>Önce yazılmalıdır</td>
    </tr>
  </tbody>
</table>

<p>Bu yaklaşım performansı artırsa da elektrik kesintisi gibi durumlarda henüz kalıcı depolamaya ulaşmamış veriler kaybolabilir. Veritabanları bu nedenle <code class="language-plaintext highlighter-rouge">fsync</code> benzeri çağrılarla kritik verinin diske ulaştığından emin olur.</p>

<h2 id="page-cache-her-şeyi-hızlandırır-mı">Page cache her şeyi hızlandırır mı?</h2>

<p>Page cache sihirli değildir. İlk okuma yine depolama aygıtının hızına bağlıdır. Çok büyük veri kümeleri önbelleğe sığmayabilir; başka uygulamalar da sık kullanılan sayfaları dışarı itebilir. Ayrıca bazı veritabanları ve özel uygulamalar, kendi önbelleklerini yönetmek için doğrudan I/O kullanabilir.</p>

<p>Yine de günlük kullanımda programların hızlı açılması, kaynak kodlarının çabuk derlenmesi ve aynı videonun tekrar akıcı oynatılması çoğunlukla bu görünmez yardımcı sayesinde gerçekleşir. Kısacası yüksek RAM kullanımı her zaman kötü değildir: İşletim sistemi belleği dosyalarla dolduruyorsa, RAM’iniz tembellik etmek yerine gelecekteki disk okumalarını hızlandırıyordur.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="işletim sistemi" /><category term="page cache" /><category term="ram" /><category term="disk" /><category term="linux" /><category term="performans" /><summary type="html"><![CDATA[Bir dosyayı ilk kez açarken kısa bir bekleme yaşayıp ikinci açılışta şaşırtıcı bir hız görmüş olabilirsiniz. Dosya diskte durduğu hâlde bilgisayarınız nasıl bir anda hızlandı? Çoğu zaman cevap daha hızlı bir disk değil, işletim sisteminin boş RAM alanını akıllıca değerlendirdiği page cache mekanizmasıdır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/isletim-sistemlerinde-page-33.png" /><media:content medium="image" url="https://program.sonsuz.us/img/isletim-sistemlerinde-page-33.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">L1/L2 Cache Dostu Kod: Döngüler ve Veri Yapılarıyla Performansı Katlamak</title><link href="https://program.sonsuz.us/posts/l1l2-cache-dostu-kod-donguler-ve-veri-yapilariyla-performansi-katlamak/" rel="alternate" type="text/html" title="L1/L2 Cache Dostu Kod: Döngüler ve Veri Yapılarıyla Performansı Katlamak" /><published>2026-09-27T00:00:00+00:00</published><updated>2026-09-27T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/l1l2-cache-dostu-kod-donguler-ve-veri-yapilariyla-performansi-katlamak</id><content type="html" xml:base="https://program.sonsuz.us/posts/l1l2-cache-dostu-kod-donguler-ve-veri-yapilariyla-performansi-katlamak/"><![CDATA[<p>Modern işlemciler son derece hızlıdır; ancak ihtiyaç duydukları veriyi ana bellekten beklemek zorunda kaldıklarında pahalı bir spor arabayı trafik ışığında bekletmeye dönüşürler. Döngülerimizi ve veri yapılarımızı işlemci önbelleğine uygun tasarlamak, daha yüksek saat hızına ihtiyaç duymadan programı birkaç kat hızlandırabilir.</p>

<p><img src="/img/l1l2-cache-dostu-54.svg" alt="l1l2-cache-dostu-54" /></p>

<p>``</p>

<h2 id="i̇şlemci-neden-önbelleğe-ihtiyaç-duyar">İşlemci neden önbelleğe ihtiyaç duyar?</h2>

<p>CPU ile RAM aynı hızda çalışmaz. İşlemci bir komutu birkaç çevrimde tamamlayabilirken RAM erişimi yüzlerce çevrim sürebilir. Bu farkı azaltmak için işlemci ile RAM arasına küçük fakat hızlı önbellek katmanları yerleştirilir.</p>

<table>
  <thead>
    <tr>
      <th>Katman</th>
      <th style="text-align: right">Yaklaşık kapasite</th>
      <th style="text-align: right">Göreli hız</th>
      <th>Özellik</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>L1 cache</td>
      <td style="text-align: right">32–128 KB</td>
      <td style="text-align: right">En hızlı</td>
      <td>Genellikle çekirdeğe özeldir</td>
    </tr>
    <tr>
      <td>L2 cache</td>
      <td style="text-align: right">256 KB–2 MB</td>
      <td style="text-align: right">Çok hızlı</td>
      <td>L1’den büyük, biraz daha yavaş</td>
    </tr>
    <tr>
      <td>L3 cache</td>
      <td style="text-align: right">Birkaç MB</td>
      <td style="text-align: right">Orta</td>
      <td>Çekirdekler arasında paylaşılabilir</td>
    </tr>
    <tr>
      <td>RAM</td>
      <td style="text-align: right">GB düzeyi</td>
      <td style="text-align: right">Yavaş</td>
      <td>Büyük veri deposudur</td>
    </tr>
  </tbody>
</table>

<p>Aranan veri önbellekte bulunursa <strong>cache hit</strong>, bulunamazsa <strong>cache miss</strong> oluşur. Basitleştirilmiş ortalama erişim süresi şöyle düşünülebilir:</p>

\[T_{ortalama} = h \cdot T_{cache} + (1-h) \cdot T_{RAM}\]

<p>Burada $h$ cache hit oranıdır. RAM çok daha yavaş olduğundan, $h$ değerindeki küçük bir artış bile toplam süreyi ciddi biçimde azaltabilir.</p>

<h2 id="mekânsal-ve-zamansal-yerellik">Mekânsal ve zamansal yerellik</h2>

<p>Önbellek RAM’den tek bir değişken getirmez; genellikle 64 baytlık bir <strong>cache line</strong> taşır. Bir elemana eriştiğimizde komşu elemanlar da gelir. Ardışık elemanları kullanmak <strong>mekânsal yerellik</strong>, aynı veriyi kısa süre içinde tekrar kullanmak ise <strong>zamansal yerellik</strong> sağlar.</p>

<p>C ve C++ gibi dillerde iki boyutlu diziler satır öncelikli saklanır. Bu nedenle döngü sırası önemlidir:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define N 2048
</span><span class="kt">int</span> <span class="n">matrix</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">];</span>
<span class="kt">long</span> <span class="kt">long</span> <span class="n">toplam</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

<span class="c1">// Cache dostu: Bellekte ardışık elemanlar okunur.</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">N</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">toplam</span> <span class="o">+=</span> <span class="n">matrix</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">];</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>İç döngüde <code class="language-plaintext highlighter-rouge">j</code> değiştiği için <code class="language-plaintext highlighter-rouge">matrix[i][j]</code> elemanları art arda okunur. Döngüleri ters çevirmek ise her erişimde farklı bir satıra sıçrayabilir:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Cache açısından zayıf: Büyük adımlarla bellekte gezinir.</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="n">N</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">N</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">toplam</span> <span class="o">+=</span> <span class="n">matrix</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">];</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Her iki kod da aynı matematiksel sonucu üretir ve zaman karmaşıklıkları $O(N^2)$ olur. Buna rağmen gerçek çalışma süreleri dramatik biçimde farklılaşabilir. Big-O, bellek erişim maliyetini tek başına anlatmaz.</p>

<h2 id="veri-yapısının-dizilişi-aos-ve-soa">Veri yapısının dizilişi: AoS ve SoA</h2>

<p>Bir oyundaki parçacıkları düşünelim:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">Parca</span> <span class="p">{</span>
    <span class="kt">float</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span><span class="p">;</span>
    <span class="kt">float</span> <span class="n">hiz</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">renk</span><span class="p">;</span>
<span class="p">};</span>

<span class="k">struct</span> <span class="n">Parca</span> <span class="n">parcalar</span><span class="p">[</span><span class="mi">1000000</span><span class="p">];</span>
</code></pre></div></div>

<p>Bu yaklaşım <strong>Array of Structures (AoS)</strong> olarak adlandırılır. Yalnızca konumları güncelliyorsak kullanılmayan <code class="language-plaintext highlighter-rouge">renk</code> gibi alanlar da cache line içine taşınır. Alternatif <strong>Structure of Arrays (SoA)</strong> düzeninde alanlar ayrılır:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">Parcalar</span> <span class="p">{</span>
    <span class="kt">float</span> <span class="n">x</span><span class="p">[</span><span class="mi">1000000</span><span class="p">];</span>
    <span class="kt">float</span> <span class="n">y</span><span class="p">[</span><span class="mi">1000000</span><span class="p">];</span>
    <span class="kt">float</span> <span class="n">z</span><span class="p">[</span><span class="mi">1000000</span><span class="p">];</span>
    <span class="kt">float</span> <span class="n">hiz</span><span class="p">[</span><span class="mi">1000000</span><span class="p">];</span>
    <span class="kt">int</span> <span class="n">renk</span><span class="p">[</span><span class="mi">1000000</span><span class="p">];</span>
<span class="p">};</span>
</code></pre></div></div>

<table>
  <thead>
    <tr>
      <th>Düzen</th>
      <th>Güçlü olduğu durum</th>
      <th>Zayıf olduğu durum</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>AoS</td>
      <td>Bir nesnenin tüm alanları birlikte kullanılıyorsa</td>
      <td>Yalnızca birkaç alan işleniyorsa</td>
    </tr>
    <tr>
      <td>SoA</td>
      <td>Aynı alan topluca işleniyorsa, SIMD kullanılıyorsa</td>
      <td>Tek nesnenin tüm alanlarına sık erişiliyorsa</td>
    </tr>
  </tbody>
</table>

<h2 id="büyük-veriyi-bloklar-hâlinde-işlemek">Büyük veriyi bloklar hâlinde işlemek</h2>

<p>Matris çarpımı gibi algoritmalarda veri L1 veya L2’ye sığmayabilir. <strong>Blocking</strong> ya da <strong>tiling</strong>, problemi önbelleğe sığan küçük parçalara ayırır:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="kt">int</span> <span class="n">B</span> <span class="o">=</span> <span class="mi">32</span><span class="p">;</span>

<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">ii</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">ii</span> <span class="o">&lt;</span> <span class="n">N</span><span class="p">;</span> <span class="n">ii</span> <span class="o">+=</span> <span class="n">B</span><span class="p">)</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">kk</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">kk</span> <span class="o">&lt;</span> <span class="n">N</span><span class="p">;</span> <span class="n">kk</span> <span class="o">+=</span> <span class="n">B</span><span class="p">)</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">ii</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">ii</span> <span class="o">+</span> <span class="n">B</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
            <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="n">kk</span><span class="p">;</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="n">kk</span> <span class="o">+</span> <span class="n">B</span><span class="p">;</span> <span class="n">k</span><span class="o">++</span><span class="p">)</span>
                <span class="n">sonuc</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+=</span> <span class="n">matrix</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">*</span> <span class="n">vektor</span><span class="p">[</span><span class="n">k</span><span class="p">];</span>
</code></pre></div></div>

<p>Blok boyutu donanıma ve veri tipine göre ölçülerek seçilmelidir. Gereğinden büyük bloklar önbellekten taşar; çok küçük bloklar ise döngü yönetimi maliyetini artırır.</p>

<p>Sonuç olarak ardışık erişim, tekrar kullanılan veriyi yakın tutma, uygun veri düzeni ve bloklama cache hit oranını yükseltir. En doğru optimizasyon için tahminde bulunmak yerine <code class="language-plaintext highlighter-rouge">perf</code>, Valgrind Cachegrind veya işlemci performans sayaçlarıyla cache miss değerlerini ölçmek gerekir. Çünkü hızlı kod yalnızca daha az işlem yapan değil, işlemciyi verisiz bırakmayan koddur.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="işlemci" /><category term="önbellek" /><category term="cache" /><category term="performans" /><category term="bellek" /><category term="c" /><category term="optimizasyon" /><summary type="html"><![CDATA[Modern işlemciler son derece hızlıdır; ancak ihtiyaç duydukları veriyi ana bellekten beklemek zorunda kaldıklarında pahalı bir spor arabayı trafik ışığında bekletmeye dönüşürler. Döngülerimizi ve veri yapılarımızı işlemci önbelleğine uygun tasarlamak, daha yüksek saat hızına ihtiyaç duymadan programı birkaç kat hızlandırabilir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/l1l2-cache-dostu-54.png" /><media:content medium="image" url="https://program.sonsuz.us/img/l1l2-cache-dostu-54.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Linux Çekirdeğinde Cgroups v2: Kaynak İzolasyonunun Modern Mimarisi</title><link href="https://program.sonsuz.us/posts/linux-cekirdeginde-cgroups-v2-kaynak-izolasyonunun-modern-mimarisi/" rel="alternate" type="text/html" title="Linux Çekirdeğinde Cgroups v2: Kaynak İzolasyonunun Modern Mimarisi" /><published>2026-09-27T00:00:00+00:00</published><updated>2026-09-27T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/linux-cekirdeginde-cgroups-v2-kaynak-izolasyonunun-modern-mimarisi</id><content type="html" xml:base="https://program.sonsuz.us/posts/linux-cekirdeginde-cgroups-v2-kaynak-izolasyonunun-modern-mimarisi/"><![CDATA[<p>Bir konteynere “en fazla 512 MB bellek kullan” veya “işlemcinin yalnızca yarısını tüket” dediğimizde bu kuralları Docker’ın sihirli değneği değil, Linux çekirdeğinin <strong>control groups</strong> mekanizması uygular. Cgroups v2, ilk sürümün yıllar içinde karmaşıklaşan yapısını tek bir hiyerarşide birleştirerek kaynak yönetimini daha tutarlı, güvenli ve öngörülebilir hâle getirir.
``</p>
<h2 id="cgroups-neyi-çözer">Cgroups neyi çözer?</h2>

<p>Cgroups, süreçleri gruplandırır ve CPU, bellek, disk G/Ç ya da süreç sayısı gibi kaynakları bu gruplar üzerinden denetler. Namespace’ler bir konteynerin <em>neyi görebildiğini</em>, cgroups ise <em>ne kadar tüketebildiğini</em> belirler. Dolayısıyla ikisi tamamlayıcıdır: namespace izolasyon perdesiyken cgroups kaynak bütçesidir.</p>

<p>Bir grubun CPU kullanım oranı basitçe</p>

\[R = \frac{Q}{P}\]

<p>ile düşünülebilir. Burada $Q$ izin verilen CPU süresi, $P$ ise periyottur. Örneğin <code class="language-plaintext highlighter-rouge">cpu.max</code> dosyasına <code class="language-plaintext highlighter-rouge">50000 100000</code> yazılması, grubun her 100 milisaniyede en fazla 50 milisaniye CPU kullanabilmesi, yani yaklaşık $R=0.5$ CPU kapasitesi anlamına gelir.</p>

<h2 id="v1-neden-yorucuydu">v1 neden yorucuydu?</h2>

<p>Cgroups v1’de her denetleyici bağımsız bir hiyerarşiye bağlanabiliyordu. Aynı süreç CPU ağacında bir grupta, bellek ağacında başka bir grupta bulunabiliyordu. Esneklik gibi görünen bu model; Docker, systemd ve Kubernetes gibi araçlar aynı makinede çalıştığında yönetim karmaşasına, belirsiz yetki devrine ve tutarsız kaynak davranışlarına yol açıyordu.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Cgroups v1</th>
      <th>Cgroups v2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Hiyerarşi</td>
      <td>Denetleyici başına ayrı olabilir</td>
      <td>Tek ve birleşik</td>
    </tr>
    <tr>
      <td>Süreç organizasyonu</td>
      <td>Farklı ağaçlarda farklı üyelik</td>
      <td>Tek cgroup üyeliği</td>
    </tr>
    <tr>
      <td>Yetki devri</td>
      <td>Karmaşık ve riskli</td>
      <td>Kontrollü delegation</td>
    </tr>
    <tr>
      <td>Bellek denetimi</td>
      <td>Daha parçalı davranış</td>
      <td>Tutarlı limit ve basınç modeli</td>
    </tr>
    <tr>
      <td>Arayüz</td>
      <td>Denetleyiciler arasında düzensiz</td>
      <td>Standartlaştırılmış dosyalar</td>
    </tr>
  </tbody>
</table>

<h2 id="birleşik-hiyerarşi-nasıl-çalışır">Birleşik hiyerarşi nasıl çalışır?</h2>

<p>v2 çoğunlukla <code class="language-plaintext highlighter-rouge">/sys/fs/cgroup</code> altında tek bir ağaç sunar. Bir sürecin kimliği <code class="language-plaintext highlighter-rouge">cgroup.procs</code>, kullanılabilir denetleyiciler <code class="language-plaintext highlighter-rouge">cgroup.controllers</code>, alt gruplara aktarılacak denetleyiciler ise <code class="language-plaintext highlighter-rouge">cgroup.subtree_control</code> üzerinden yönetilir.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Sistemde etkin olan v2 denetleyicilerini gösterir.</span>
<span class="nb">cat</span> /sys/fs/cgroup/cgroup.controllers

<span class="c"># Yeni bir uygulama grubu oluşturur.</span>
<span class="nb">sudo mkdir</span> /sys/fs/cgroup/demo

<span class="c"># Kabuğun PID'sini gruba taşır.</span>
<span class="nb">echo</span> <span class="nv">$$</span> | <span class="nb">sudo tee</span> /sys/fs/cgroup/demo/cgroup.procs
</code></pre></div></div>

<p>v2’nin önemli kurallarından biri <strong>no internal process constraint</strong> ilkesidir. Kaynak denetleyicileri alt gruplara dağıtan bir cgroup, normalde aynı anda doğrudan süreç barındırmaz. Başka bir deyişle dallar organizasyon, yapraklar iş yükü içindir. Bu kural, ebeveyn ve çocuk gruplar arasında kaynak hesabının bulanıklaşmasını önler.</p>

<h2 id="bellek-cpu-ve-süreç-sınırları">Bellek, CPU ve süreç sınırları</h2>

<p>Bellek tarafında <code class="language-plaintext highlighter-rouge">memory.max</code> kesin tavanı, <code class="language-plaintext highlighter-rouge">memory.high</code> ise çekirdeğin agresif geri kazanım uygulamaya başlayacağı yumuşak eşiği ifade eder. Böylece uygulamayı anında öldürmeden önce baskı oluşturmak mümkündür. <code class="language-plaintext highlighter-rouge">memory.current</code> mevcut tüketimi gösterirken <code class="language-plaintext highlighter-rouge">memory.events</code>, OOM gibi olayları sayar.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Kesin bellek limitini 512 MiB yapar.</span>
<span class="nb">echo </span>536870912 | <span class="nb">sudo tee</span> /sys/fs/cgroup/demo/memory.max

<span class="c"># Yaklaşık yarım CPU ve en fazla 100 süreç tanımlar.</span>
<span class="nb">echo</span> <span class="s1">'50000 100000'</span> | <span class="nb">sudo tee</span> /sys/fs/cgroup/demo/cpu.max
<span class="nb">echo </span>100 | <span class="nb">sudo tee</span> /sys/fs/cgroup/demo/pids.max
</code></pre></div></div>

<p>CPU paylaşım önceliği için v1’deki <code class="language-plaintext highlighter-rouge">cpu.shares</code> yerine daha anlaşılır bir aralığa sahip <code class="language-plaintext highlighter-rouge">cpu.weight</code> kullanılır. G/Ç denetimi de <code class="language-plaintext highlighter-rouge">io.max</code> ve <code class="language-plaintext highlighter-rouge">io.weight</code> gibi tutarlı adlarla sunulur.</p>

<h2 id="docker-açısından-anlamı">Docker açısından anlamı</h2>

<p>Docker’daki <code class="language-plaintext highlighter-rouge">--memory</code>, <code class="language-plaintext highlighter-rouge">--cpus</code> ve <code class="language-plaintext highlighter-rouge">--pids-limit</code> seçenekleri sonuçta bu dosyalara dönüştürülür. Modern systemd sürümleri de servisleri cgroup ağacında doğal olarak düzenler. Tek hiyerarşi sayesinde orkestratör, çalışma zamanı ve init sistemi aynı kaynak ağacını paylaşabilir; “bu süreci aslında kim yönetiyor?” bilmecesi büyük ölçüde ortadan kalkar.</p>

<p>Cgroups v2 yalnızca temizlenmiş bir arayüz değildir. Tutarlı muhasebe, güvenli yetki devri, gelişmiş bellek baskısı ve sade hiyerarşi sayesinde konteyner izolasyonunu daha sağlam bir çekirdek sözleşmesine dönüştürür. Kısacası v1 kaynaklara ayrı ayrı kilit vuruyordu; v2 ise bütün binaya düzenli bir erişim planı çiziyor.</p>

<p><img src="/img/linux-cekirdeginde-cgroups-17.svg" alt="linux-cekirdeginde-cgroups-17" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="linux" /><category term="cgroups" /><category term="docker" /><category term="konteyner" /><category term="çekirdek" /><category term="devops" /><summary type="html"><![CDATA[Bir konteynere “en fazla 512 MB bellek kullan” veya “işlemcinin yalnızca yarısını tüket” dediğimizde bu kuralları Docker’ın sihirli değneği değil, Linux çekirdeğinin control groups mekanizması uygular. Cgroups v2, ilk sürümün yıllar içinde karmaşıklaşan yapısını tek bir hiyerarşide birleştirerek kaynak yönetimini daha tutarlı, güvenli ve öngörülebilir hâle getirir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/linux-cekirdeginde-cgroups-17.png" /><media:content medium="image" url="https://program.sonsuz.us/img/linux-cekirdeginde-cgroups-17.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Linux initramfs’in Sırrı: Kök Dosya Sisteminden Önceki Minik Dünya</title><link href="https://program.sonsuz.us/posts/linux-initramfsin-sirri-kok-dosya-sisteminden-onceki-minik-dunya/" rel="alternate" type="text/html" title="Linux initramfs’in Sırrı: Kök Dosya Sisteminden Önceki Minik Dünya" /><published>2026-09-27T00:00:00+00:00</published><updated>2026-09-27T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/linux-initramfsin-sirri-kok-dosya-sisteminden-onceki-minik-dunya</id><content type="html" xml:base="https://program.sonsuz.us/posts/linux-initramfsin-sirri-kok-dosya-sisteminden-onceki-minik-dunya/"><![CDATA[<p><img src="/img/linux-initramfsin-sirri-12.svg" alt="linux-initramfsin-sirri-12" /></p>

<p>Bilgisayarın güç düğmesine bastığınızda Linux doğrudan <code class="language-plaintext highlighter-rouge">/</code> dizinine koşmaz. Çekirdek belleğe yüklense bile gerçek kök dosya sistemine ulaşmak için disk denetleyicisi, dosya sistemi, RAID, LVM veya şifreleme sürücülerine ihtiyaç duyabilir. İşte <strong>initramfs</strong>, bu tavuk-yumurta problemini çözen, RAM üzerinde kurulmuş geçici ve küçük bir kullanıcı alanıdır.
``</p>
<h2 id="açılış-zincirindeki-yeri">Açılış zincirindeki yeri</h2>

<p>Modern bir Linux açılışı kabaca şu sırayı izler:</p>

<ol>
  <li>BIOS veya UEFI donanımı hazırlar.</li>
  <li>GRUB gibi önyükleyici çekirdeği ve initramfs arşivini RAM’e taşır.</li>
  <li>Çekirdek donanımı algılar ve initramfs’i geçici kök olarak açar.</li>
  <li>Initramfs içindeki <code class="language-plaintext highlighter-rouge">/init</code> programı gerekli hazırlıkları yapar.</li>
  <li>Gerçek kök dosya sistemi bağlanır.</li>
  <li><code class="language-plaintext highlighter-rouge">switch_root</code> sonrasında systemd veya başka bir init sistemi başlatılır.</li>
</ol>

<p>Toplam açılış süresini basitleştirerek şöyle düşünebiliriz:</p>

\[T_{boot} = T_{firmware} + T_{loader} + T_{kernel} + T_{initramfs} + T_{userspace}\]

<p>Initramfs aşaması küçük görünür; ancak şifreli diskin parolasını bekliyorsa veya kayıp bir depolama aygıtını arıyorsa $T_{initramfs}$ ciddi biçimde büyüyebilir.</p>

<h2 id="initramfs-gerçekte-nedir">Initramfs gerçekte nedir?</h2>

<p>Initramfs genellikle <code class="language-plaintext highlighter-rouge">cpio</code> biçiminde paketlenmiş ve gzip, xz ya da zstd ile sıkıştırılmış bir arşivdir. Önyükleyici bu arşivi RAM’e yükler; çekirdek de arşivi kendi sağladığı geçici <code class="language-plaintext highlighter-rouge">rootfs</code> üzerine açar. Dolayısıyla klasik anlamda biçimlendirilmiş bir RAM diski olmak zorunda değildir.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>initramfs</th>
      <th>Gerçek kök dosya sistemi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Konum</td>
      <td>RAM</td>
      <td>SSD, HDD, ağ veya başka depolama</td>
    </tr>
    <tr>
      <td>Ömür</td>
      <td>Açılışın erken aşaması</td>
      <td>Sistem kapanana kadar</td>
    </tr>
    <tr>
      <td>İçerik</td>
      <td>Araçlar, betikler, modüller</td>
      <td>Tam Linux kullanıcı alanı</td>
    </tr>
    <tr>
      <td>Temel görev</td>
      <td>Gerçek kökü erişilebilir yapmak</td>
      <td>Uygulamaları ve hizmetleri çalıştırmak</td>
    </tr>
    <tr>
      <td>Boyut</td>
      <td>Genellikle onlarca MB</td>
      <td>GB veya TB düzeyi</td>
    </tr>
  </tbody>
</table>

<p>Bu ortamda BusyBox, <code class="language-plaintext highlighter-rouge">udev</code>, <code class="language-plaintext highlighter-rouge">cryptsetup</code>, LVM araçları, dosya sistemi yardımcıları ve çekirdek modülleri bulunabilir. Amaç masaüstü açmak değil, ana sisteme giden köprüyü kurmaktır.</p>

<h2 id="çekirdek-neden-tek-başına-yetmiyor">Çekirdek neden tek başına yetmiyor?</h2>

<p>Çekirdek bazı sürücüleri doğrudan içine gömülü taşıyabilir. Fakat her sürücüyü çekirdeğe kalıcı olarak eklemek onu büyütür ve esnekliği azaltır. Modüler yaklaşımda gerekli <code class="language-plaintext highlighter-rouge">.ko</code> dosyaları initramfs’e yerleştirilir. Örneğin kök bölümünüz NVMe üzerinde ve ext4 biçimindeyse NVMe denetleyicisi ile ext4 desteğinin gerçek köke ulaşılmadan önce hazır olması gerekir.</p>

<p>Şifreli bir LVM düzeninde süreç daha eğlencelidir: initramfs önce disk sürücüsünü yükler, ardından LUKS kapsayıcısını <code class="language-plaintext highlighter-rouge">cryptsetup</code> ile açar, LVM mantıksal birimlerini etkinleştirir ve ancak bundan sonra kök dosya sistemini bağlar. Ağ üzerinden NFS kökü kullanılıyorsa ağ kartı sürücüsü, IP yapılandırması ve NFS desteği de bu minik çantaya eklenir.</p>

<h2 id="i̇çeriği-nasıl-inceleriz">İçeriği nasıl inceleriz?</h2>

<p>Dağıtıma göre dosya adı değişse de mevcut arşivi listelemek kolaydır:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Çalışan çekirdeğe ait initramfs içeriğini listeler.</span>
lsinitramfs /boot/initrd.img-<span class="si">$(</span><span class="nb">uname</span> <span class="nt">-r</span><span class="si">)</span> | less
</code></pre></div></div>

<p>Fedora ve RHEL ailesinde benzer inceleme <code class="language-plaintext highlighter-rouge">lsinitrd</code> ile yapılır. Debian veya Ubuntu üzerinde initramfs’i yeniden üretmek için:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Kurulu tüm çekirdeklerin initramfs dosyalarını günceller.</span>
<span class="nb">sudo </span>update-initramfs <span class="nt">-u</span> <span class="nt">-k</span> all
</code></pre></div></div>

<p>Dracut kullanan sistemlerde karşılığı çoğunlukla şöyledir:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Mevcut çekirdek için initramfs'i zorla yeniden oluşturur.</span>
<span class="nb">sudo </span>dracut <span class="nt">--force</span>
</code></pre></div></div>

<p>Bu komutlar özellikle yeni depolama sürücüsü eklediğinizde, kök bölüm yapısını değiştirdiğinizde veya açılışta gerekli modül arşive girmediğinde önemlidir.</p>

<h2 id="hata-olduğunda-ne-görürüz">Hata olduğunda ne görürüz?</h2>

<p>Initramfs gerçek kökü bulamazsa sistem acil durum kabuğuna düşebilir; <code class="language-plaintext highlighter-rouge">unable to find root device</code>, <code class="language-plaintext highlighter-rouge">ALERT! UUID does not exist</code> veya LUKS aygıtına ilişkin hatalar görülebilir. Bu noktada <code class="language-plaintext highlighter-rouge">cat /proc/cmdline</code>, <code class="language-plaintext highlighter-rouge">blkid</code>, <code class="language-plaintext highlighter-rouge">ls /dev</code> ve <code class="language-plaintext highlighter-rouge">dmesg</code> komutları güçlü dedektif araçlarıdır. Yanlış UUID, eksik modül ya da hatalı çekirdek parametresi genellikle suçludur.</p>

<p>Kısacası initramfs, Linux açılışının sahne arkasındaki teknik ekip gibidir: dekoru kurar, kapıları açar, gerçek kökü sahneye çıkarır ve işi bittiğinde sessizce ortadan kaybolur.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="linux" /><category term="initramfs" /><category term="kernel" /><category term="önyükleme" /><category term="sistem-yönetimi" /><category term="ramdisk" /><summary type="html"><![CDATA[Bilgisayarın güç düğmesine bastığınızda Linux doğrudan / dizinine koşmaz. Çekirdek belleğe yüklense bile gerçek kök dosya sistemine ulaşmak için disk denetleyicisi, dosya sistemi, RAID, LVM veya şifreleme sürücülerine ihtiyaç duyabilir. İşte initramfs, bu tavuk-yumurta problemini çözen, RAM üzerinde kurulmuş geçici ve küçük bir kullanıcı alanıdır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/linux-initramfsin-sirri-12.png" /><media:content medium="image" url="https://program.sonsuz.us/img/linux-initramfsin-sirri-12.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Meltdown ve Spectre: İşlemcinin Geleceği Tahmin Ederken Sırları Ele Vermesi</title><link href="https://program.sonsuz.us/posts/meltdown-ve-spectre-islemcinin-gelecegi-tahmin-ederken-sirlari-ele-vermesi/" rel="alternate" type="text/html" title="Meltdown ve Spectre: İşlemcinin Geleceği Tahmin Ederken Sırları Ele Vermesi" /><published>2026-09-27T00:00:00+00:00</published><updated>2026-09-27T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/meltdown-ve-spectre-islemcinin-gelecegi-tahmin-ederken-sirlari-ele-vermesi</id><content type="html" xml:base="https://program.sonsuz.us/posts/meltdown-ve-spectre-islemcinin-gelecegi-tahmin-ederken-sirlari-ele-vermesi/"><![CDATA[<p>Modern işlemciler yalnızca hızlı koşmaz; önlerindeki yolu tahmin ederek henüz gerekli olup olmadığı bilinmeyen komutları da çalıştırır. <strong>Meltdown</strong> ve <strong>Spectre</strong>, performans uğruna geliştirilen bu davranışın mimari olarak görünmeyen fakat ölçülebilen izler bırakabildiğini gösterdi. Sonuçta saldırgan, doğrudan okuyamadığı parolaları, anahtarları ve başka süreçlere ait verileri önbellek zamanlamalarını dinleyerek çıkarabilir.</p>

<p>``</p>

<h2 id="i̇şlemci-neden-geleceği-tahmin-eder">İşlemci neden geleceği tahmin eder?</h2>

<p>Bir işlemci bellekten veri beklerken yüzlerce saat çevrimi kaybedebilir. Bu nedenle modern çekirdekler <strong>sıra dışı yürütme</strong> ve <strong>spekülatif yürütme</strong> kullanır. Örneğin bir dallanmanın sonucu henüz hesaplanmadıysa dallanma tahmincisi geçmiş davranışlara bakarak hangi yolun seçileceğini tahmin eder.</p>

<p>Tahmin doğruysa zaman kazanılır. Yanlışsa spekülatif işlemlerin mimari sonuçları iptal edilir. Ancak kritik ayrıntı şudur: Önbelleğe alınan veri gibi <strong>mikromimari etkiler</strong> tamamen geri alınmayabilir.</p>

<p>Basitleştirilmiş performans fikri şöyledir:</p>

\[T_{ortalama} = pT_{isabet} + (1-p)T_{hata}\]

<p>Burada $p$ tahmin doğruluğudur. Yüksek doğruluk ciddi hız kazandırır; fakat yanlış yol üzerinde geçici olarak yürütülen komutlar güvenlik sınırlarına dokunabilir.</p>

<h2 id="önbellek-nasıl-muhbir-olur">Önbellek nasıl muhbir olur?</h2>

<p>İşlemci önbelleğindeki bir veriye erişmek ana belleğe erişmekten daha hızlıdır:</p>

\[T_{cache} &lt; T_{RAM}\]

<p>Saldırgan verinin kendisini göremese bile belirli bir bellek bölgesine erişimin kaç nanosaniye sürdüğünü ölçebilir. Hızlı yanıt, ilgili satırın önbellekte olduğunu düşündürür. Böylece gizli bir bayt, farklı önbellek satırlarından birini seçmek için kullanılır ve değer zamanlama ölçümleriyle tahmin edilir.</p>

<p>Aşağıdaki kod, savunmasız desenin kavramsal ve çalıştırılabilir bir örneğidir; tek başına gerçek bir veri sızdırma saldırısı değildir:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">public_data</span><span class="p">[</span><span class="mi">16</span><span class="p">];</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">probe</span><span class="p">[</span><span class="mi">256</span> <span class="o">*</span> <span class="mi">4096</span><span class="p">];</span>
<span class="kt">size_t</span> <span class="n">public_size</span> <span class="o">=</span> <span class="mi">16</span><span class="p">;</span>

<span class="kt">unsigned</span> <span class="kt">char</span> <span class="nf">read_value</span><span class="p">(</span><span class="kt">size_t</span> <span class="n">index</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">index</span> <span class="o">&lt;</span> <span class="n">public_size</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">value</span> <span class="o">=</span> <span class="n">public_data</span><span class="p">[</span><span class="n">index</span><span class="p">];</span>
        <span class="k">return</span> <span class="n">probe</span><span class="p">[</span><span class="n">value</span> <span class="o">*</span> <span class="mi">4096</span><span class="p">];</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Tahminci, koşulun genellikle doğru olduğuna alıştırılmışsa sınır dışı bir <code class="language-plaintext highlighter-rouge">index</code> geldiğinde gövdeyi geçici olarak çalıştırabilir. Mimari sonuç daha sonra silinse de <code class="language-plaintext highlighter-rouge">value</code> tarafından seçilen <code class="language-plaintext highlighter-rouge">probe</code> satırı önbellekte kalabilir. Saldırgan 256 olası satırın erişim sürelerini karşılaştırarak baytı arar.</p>

<h2 id="meltdown-ve-spectre-aynı-şey-mi">Meltdown ve Spectre aynı şey mi?</h2>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Meltdown</th>
      <th>Spectre</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Temel sorun</td>
      <td>Yetki kontrolünün geç etkili olması</td>
      <td>Tahmin mekanizmasının yanıltılması</td>
    </tr>
    <tr>
      <td>Tipik hedef</td>
      <td>Çekirdek belleği ile kullanıcı alanı sınırı</td>
      <td>Aynı süreç veya farklı güven alanları</td>
    </tr>
    <tr>
      <td>Kullanılan mekanizma</td>
      <td>Sıra dışı, geçici yürütme</td>
      <td>Dallanma ve dolaylı hedef tahmini</td>
    </tr>
    <tr>
      <td>Yazılımla azaltma</td>
      <td>Sayfa tablolarını ayırma</td>
      <td>Bariyerler, retpoline, kod düzenleme</td>
    </tr>
    <tr>
      <td>Etkilenen tasarımlar</td>
      <td>Özellikle bazı eski Intel işlemciler</td>
      <td>Çok sayıda modern işlemci ailesi</td>
    </tr>
  </tbody>
</table>

<p><strong>Meltdown</strong>, işlemcinin yetkisiz bellek okumasını hata üretmeden önce geçici olarak ilerletebilmesinden yararlanır. İşletim sistemi sonunda erişimi reddeder; fakat sır önbelleğe kodlanmış olabilir.</p>

<p><strong>Spectre</strong> ise kurbanın yasal kodunu yanlış tahminlerle kandırır. Sınır kontrolü bulunsa bile işlemci geçici olarak yanlış yola sokulur. Bu nedenle Spectre tek bir donanım hatasından çok, optimizasyon ile güvenlik modeli arasındaki temel bir çatışmadır.</p>

<h2 id="savunma-neden-zor">Savunma neden zor?</h2>

<p>Savunmalar arasında KPTI ile çekirdek sayfa tablolarını ayırmak, hassas noktalara spekülasyon bariyerleri eklemek, mikro kod güncellemeleri ve tarayıcılarda zamanlayıcı hassasiyetini azaltmak bulunur. Ancak her bariyer işlemciye “Burada tahmin etme, bekle” dediği için performans maliyeti doğurabilir.</p>

<p>Meltdown ve Spectre’nin büyük dersi şudur: Bir işlem mimari olarak gerçekleşmemiş sayılsa bile fiziksel sistemde iz bırakabilir. Güvenlik yalnızca programın ürettiği sonuçları değil; önbellekleri, tahmincileri, zamanlamayı ve geçici yürütmenin bütün gölgelerini hesaba katmalıdır.</p>

<p><img src="/img/meltdown-ve-spectre-68.svg" alt="meltdown-ve-spectre-68" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="meltdown" /><category term="spectre" /><category term="işlemci" /><category term="siber güvenlik" /><category term="spekülatif yürütme" /><category term="önbellek" /><category term="yan kanal" /><summary type="html"><![CDATA[Modern işlemciler yalnızca hızlı koşmaz; önlerindeki yolu tahmin ederek henüz gerekli olup olmadığı bilinmeyen komutları da çalıştırır. Meltdown ve Spectre, performans uğruna geliştirilen bu davranışın mimari olarak görünmeyen fakat ölçülebilen izler bırakabildiğini gösterdi. Sonuçta saldırgan, doğrudan okuyamadığı parolaları, anahtarları ve başka süreçlere ait verileri önbellek zamanlamalarını dinleyerek çıkarabilir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/meltdown-ve-spectre-68.png" /><media:content medium="image" url="https://program.sonsuz.us/img/meltdown-ve-spectre-68.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Meta-Learning: Öğrenmeyi Öğrenen Modellerin Kısa Tarihi</title><link href="https://program.sonsuz.us/posts/meta-learning-ogrenmeyi-ogrenen-modellerin-kisa-tarihi/" rel="alternate" type="text/html" title="Meta-Learning: Öğrenmeyi Öğrenen Modellerin Kısa Tarihi" /><published>2026-09-27T00:00:00+00:00</published><updated>2026-09-27T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/meta-learning-ogrenmeyi-ogrenen-modellerin-kisa-tarihi</id><content type="html" xml:base="https://program.sonsuz.us/posts/meta-learning-ogrenmeyi-ogrenen-modellerin-kisa-tarihi/"><![CDATA[<p>Geleneksel makine öğrenmesinde her yeni problem için veri toplar, modeli eğitir ve sabırla sonuç bekleriz. Meta-learning ise bu rutine küçük bir itiraz getirir: Model yalnızca görevleri çözmesin, yeni bir görevi nasıl hızlı öğreneceğini de keşfetsin. Böylece binlerce örnek yerine birkaç örnekle uyum sağlayabilen, deyim yerindeyse eğitim salonunda nasıl antrenman yapacağını öğrenen sistemler ortaya çıkar.</p>

<p><img src="/img/meta-learning-ogrenmeyi-67.svg" alt="meta-learning-ogrenmeyi-67" /></p>

<p>``</p>

<h2 id="fikir-nereden-çıktı">Fikir nereden çıktı?</h2>

<p>“Öğrenmeyi öğrenme” düşüncesi yapay zekâdan daha eskidir. Psikoloji, insanların önceki deneyimlerinden yararlanarak yeni becerileri daha hızlı kazandığını uzun süredir inceliyordu. Makine öğrenmesinde ise erken dönem çalışmalar, algoritmaların kendi öğrenme kurallarını ayarlayıp ayarlayamayacağı sorusuna odaklandı.</p>

<p>1990’larda sinir ağlarının ağırlık güncellemelerini başka ağlarla yönetme fikri belirginleşti. 2000’lerde çoklu görev öğrenmesi ve aktarım öğrenmesi güçlü temeller sağladı. 2010’ların ortasında derin öğrenme, büyük veri kümeleri ve GPU’larla birleşince meta-learning uygulanabilir hâle geldi. 2016 tarihli Matching Networks ve 2017’de yayımlanan MAML, alanın en etkili dönüm noktaları arasında yer aldı.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Temel amaç</th>
      <th>Yeni görevde gereken</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Klasik eğitim</td>
      <td>Tek görevi iyi çözmek</td>
      <td>Çok veri ve yeniden eğitim</td>
    </tr>
    <tr>
      <td>Transfer learning</td>
      <td>Önceden öğrenilmiş özellikleri aktarmak</td>
      <td>İnce ayar ve orta miktarda veri</td>
    </tr>
    <tr>
      <td>Few-shot learning</td>
      <td>Birkaç örnekle tahmin yapmak</td>
      <td>Küçük destek kümesi</td>
    </tr>
    <tr>
      <td>Meta-learning</td>
      <td>Uyum sağlama sürecini öğrenmek</td>
      <td>Birkaç örnek ve az sayıda güncelleme</td>
    </tr>
  </tbody>
</table>

<h2 id="görevler-üzerinden-öğrenmek">Görevler üzerinden öğrenmek</h2>

<p>Normal eğitimde veri noktaları örneklenir. Meta-learning eğitiminde ise <strong>görevler</strong> örneklenir. Her görev genellikle iki parçaya ayrılır:</p>

<ul>
  <li><strong>Destek kümesi:</strong> Modelin göreve uyum sağladığı az sayıdaki örnek.</li>
  <li><strong>Sorgu kümesi:</strong> Uyumun gerçekten işe yarayıp yaramadığını ölçen örnekler.</li>
</ul>

<p>Bir görev $T_i$ için destek kaybı $L_{S_i}$ olsun. Modelin başlangıç parametreleri $θ$ ise tek adımlık uyarlama şöyle yazılabilir:</p>

\[θ'_i = θ - α ∇_θ L_{S_i}(θ)\]

<p>Burada $α$ iç döngünün öğrenme oranıdır. Meta-model, uyarlanmış parametrelerin sorgu kümelerindeki toplam hatasını azaltmaya çalışır:</p>

\[min_θ Σ_i L_{Q_i}(θ'_i)\]

<p>İşin sihri burada yatar: Sistem yalnızca doğru cevabı değil, birkaç gradyan adımından sonra iyi sonuç verecek bir <strong>başlangıç noktası</strong> öğrenir. MAML’ın modelden bağımsız sayılmasının nedeni de bu fikrin sınıflandırma, regresyon veya pekiştirmeli öğrenme gibi farklı alanlara uygulanabilmesidir.</p>

<h2 id="üç-ana-meta-learning-ailesi">Üç ana meta-learning ailesi</h2>

<table>
  <thead>
    <tr>
      <th>Aile</th>
      <th>Öğrendiği şey</th>
      <th>Bilinen örnek</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Optimizasyon tabanlı</td>
      <td>Hızlı uyarlanabilir parametreler</td>
      <td>MAML, Reptile</td>
    </tr>
    <tr>
      <td>Metrik tabanlı</td>
      <td>Örnekler arasındaki benzerlik uzayı</td>
      <td>Prototypical Networks</td>
    </tr>
    <tr>
      <td>Model tabanlı</td>
      <td>Bellek veya öğrenme mekanizması</td>
      <td>Memory-Augmented Networks</td>
    </tr>
  </tbody>
</table>

<p>Metrik tabanlı yöntemlerde her sınıfın prototipi hesaplanabilir. $k$ sınıfına ait destek temsillerinin ortalaması:</p>

\[c_k = (1 / \vert S_k\vert ) Σ_{x ∈ S_k} f_θ(x)\]

<p>Yeni örnek, temsili hangi $c_k$ noktasına daha yakınsa o sınıfa atanır. Bir bakıma model, “Bu fotoğraf hangi aile albümüne daha çok benziyor?” diye sorar.</p>

<h2 id="maml-mantığının-küçük-bir-kod-karşılığı">MAML mantığının küçük bir kod karşılığı</h2>

<p>Aşağıdaki PyTorch taslağı, tek görev için iç güncelleme yapar ve sorgu kaybını hesaplar. <code class="language-plaintext highlighter-rouge">create_graph=True</code>, dış döngünün iç güncelleme üzerinden türev alabilmesini sağlar:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">torch</span>
<span class="kn">from</span> <span class="n">torch.func</span> <span class="kn">import</span> <span class="n">functional_call</span>

<span class="n">support_logits</span> <span class="o">=</span> <span class="nf">model</span><span class="p">(</span><span class="n">x_support</span><span class="p">)</span>
<span class="n">support_loss</span> <span class="o">=</span> <span class="nf">loss_fn</span><span class="p">(</span><span class="n">support_logits</span><span class="p">,</span> <span class="n">y_support</span><span class="p">)</span>

<span class="n">params</span> <span class="o">=</span> <span class="nf">dict</span><span class="p">(</span><span class="n">model</span><span class="p">.</span><span class="nf">named_parameters</span><span class="p">())</span>
<span class="n">grads</span> <span class="o">=</span> <span class="n">torch</span><span class="p">.</span><span class="n">autograd</span><span class="p">.</span><span class="nf">grad</span><span class="p">(</span>
    <span class="n">support_loss</span><span class="p">,</span>
    <span class="n">params</span><span class="p">.</span><span class="nf">values</span><span class="p">(),</span>
    <span class="n">create_graph</span><span class="o">=</span><span class="bp">True</span>
<span class="p">)</span>

<span class="n">fast_params</span> <span class="o">=</span> <span class="p">{</span>
    <span class="n">name</span><span class="p">:</span> <span class="n">param</span> <span class="o">-</span> <span class="n">inner_lr</span> <span class="o">*</span> <span class="n">grad</span>
    <span class="nf">for </span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">param</span><span class="p">),</span> <span class="n">grad</span> <span class="ow">in</span> <span class="nf">zip</span><span class="p">(</span><span class="n">params</span><span class="p">.</span><span class="nf">items</span><span class="p">(),</span> <span class="n">grads</span><span class="p">)</span>
<span class="p">}</span>

<span class="n">query_logits</span> <span class="o">=</span> <span class="nf">functional_call</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">fast_params</span><span class="p">,</span> <span class="p">(</span><span class="n">x_query</span><span class="p">,))</span>
<span class="n">outer_loss</span> <span class="o">=</span> <span class="nf">loss_fn</span><span class="p">(</span><span class="n">query_logits</span><span class="p">,</span> <span class="n">y_query</span><span class="p">)</span>

<span class="n">optimizer</span><span class="p">.</span><span class="nf">zero_grad</span><span class="p">()</span>
<span class="n">outer_loss</span><span class="p">.</span><span class="nf">backward</span><span class="p">()</span>
<span class="n">optimizer</span><span class="p">.</span><span class="nf">step</span><span class="p">()</span>
</code></pre></div></div>

<p>Gerçek uygulamada bu işlem birçok görev için tekrarlanır ve sorgu kayıpları ortalanır. Hesaplama maliyeti özellikle ikinci dereceden türevler nedeniyle yükselebilir; First-Order MAML ve Reptile gibi yöntemler bu yükü azaltmayı hedefler.</p>

<h2 id="neden-önemli">Neden önemli?</h2>

<p>Meta-learning; nadir hastalıkların sınıflandırılması, yeni robot hareketleri, kişiselleştirilmiş öneriler ve az kaynaklı diller gibi verinin pahalı olduğu alanlarda değerlidir. Yine de görev dağılımı kötü seçilirse model yeni koşullara uyum sağlayamaz. Kısacası öğrenmeyi öğrenen bir sistem de öğretmeninin hazırladığı müfredat kadar iyidir. Meta-learning’in büyük vaadi, her şeyi bilen modeller değil; bilmediği bir şeyle karşılaştığında ne yapacağını daha çabuk anlayan modeller üretmesidir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="meta-learning" /><category term="yapay zeka" /><category term="makine öğrenmesi" /><category term="few-shot learning" /><category term="maml" /><category term="derin öğrenme" /><summary type="html"><![CDATA[Geleneksel makine öğrenmesinde her yeni problem için veri toplar, modeli eğitir ve sabırla sonuç bekleriz. Meta-learning ise bu rutine küçük bir itiraz getirir: Model yalnızca görevleri çözmesin, yeni bir görevi nasıl hızlı öğreneceğini de keşfetsin. Böylece binlerce örnek yerine birkaç örnekle uyum sağlayabilen, deyim yerindeyse eğitim salonunda nasıl antrenman yapacağını öğrenen sistemler ortaya çıkar.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/meta-learning-ogrenmeyi-67.png" /><media:content medium="image" url="https://program.sonsuz.us/img/meta-learning-ogrenmeyi-67.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Mutex vs Spinlock: Beklemek mi, Boşuna Dönmek mi Daha Maliyetli?</title><link href="https://program.sonsuz.us/posts/mutex-vs-spinlock-beklemek-mi-bosuna-donmek-mi-daha-maliyetli/" rel="alternate" type="text/html" title="Mutex vs Spinlock: Beklemek mi, Boşuna Dönmek mi Daha Maliyetli?" /><published>2026-09-27T00:00:00+00:00</published><updated>2026-09-27T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/mutex-vs-spinlock-beklemek-mi-bosuna-donmek-mi-daha-maliyetli</id><content type="html" xml:base="https://program.sonsuz.us/posts/mutex-vs-spinlock-beklemek-mi-bosuna-donmek-mi-daha-maliyetli/"><![CDATA[<p>Çok çekirdekli bir sistemde iki iş parçacığı aynı veriye uzandığında küçük bir trafik kavşağı oluşur. Mutex kırmızı ışıkta motoru kapatıp beklemeye, spinlock ise ışık yeşile dönene kadar gaza basmadan motoru çalıştırmaya benzer. Hangisinin daha hızlı olduğu, kilidin ne kadar süre tutulduğuna ve işletim sisteminin bekletme maliyetine bağlıdır.</p>

<p>``</p>

<h2 id="temel-fark-uyku-mu-aktif-bekleme-mi">Temel fark: Uyku mu, aktif bekleme mi?</h2>

<p>Bir <strong>mutex</strong> alınamıyorsa bekleyen iş parçacığı çoğunlukla işletim sistemi tarafından uyutulur. Böylece işlemci başka işler çalıştırabilir. Ancak uyutma ve yeniden uyandırma; sistem çağrıları, zamanlayıcı müdahalesi ve bağlam değişimi gibi maliyetler doğurur.</p>

<p>Bir <strong>spinlock</strong> ise iş parçacığını uyutmaz. İş parçacığı kilidi tekrar tekrar kontrol ederek işlemci üzerinde aktif kalır. Kilit birkaç nanosaniye sonra açılacaksa bu yaklaşım oldukça hızlıdır. Bekleme uzarsa işlemci zamanı ve enerji boşa harcanır.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th>Mutex</th>
      <th>Spinlock</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Bekleme biçimi</td>
      <td>İş parçacığını uyutabilir</td>
      <td>Aktif döngüde bekler</td>
    </tr>
    <tr>
      <td>CPU tüketimi</td>
      <td>Beklerken düşüktür</td>
      <td>Beklerken yüksektir</td>
    </tr>
    <tr>
      <td>Kısa kritik bölüm</td>
      <td>Ek yük oluşturabilir</td>
      <td>Genellikle avantajlıdır</td>
    </tr>
    <tr>
      <td>Uzun kritik bölüm</td>
      <td>Genellikle avantajlıdır</td>
      <td>Oldukça maliyetlidir</td>
    </tr>
    <tr>
      <td>Tek çekirdekli sistem</td>
      <td>Kullanılabilir</td>
      <td>Çoğu durumda anlamsızdır</td>
    </tr>
    <tr>
      <td>Kesme bağlamı</td>
      <td>Genellikle uygun değildir</td>
      <td>Çekirdek kodunda kullanılabilir</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/mutex-vs-spinlock-63.svg" alt="mutex-vs-spinlock-63" /></p>

<h2 id="maliyetin-matematiği">Maliyetin matematiği</h2>

<p>Spinlock seçiminin mantıklı olması için bekleme maliyetinin uyutma maliyetinden küçük olması beklenir. Basitleştirilmiş karar koşulu şöyledir:</p>

\[T_{bekleme} &lt; T_{uyutma} + T_{uyandırma}\]

<p>Kilit ortalama $T_k$ süre tutuluyor ve kilidi dolu bulma olasılığı $P_c$ ise spinlock için yaklaşık bekleme maliyeti $P_c \times T_k$ olarak düşünülebilir. Mutex tarafında ise bağlam değiştirme maliyeti devreye girer. Modern sistemlerde bu değerler sabit değildir; çekirdek sayısı, önbellek mimarisi ve sistem yükü sonucu değiştirir.</p>

<p>Spinlock yalnızca döngü maliyeti de değildir. Kilit değişkeninin farklı çekirdeklerin önbellekleri arasında taşınması <strong>cache coherence</strong> trafiği oluşturur. Çok sayıda çekirdek aynı bellek satırını izliyorsa küçücük bir atomik değişken, sistemin en popüler dedikodu konusu hâline gelebilir.</p>

<h2 id="c-ile-iki-yaklaşım">C++ ile iki yaklaşım</h2>

<p>Aşağıdaki basit spinlock, <code class="language-plaintext highlighter-rouge">atomic_flag</code> kullanarak kilidi atomik biçimde almaya çalışır. <code class="language-plaintext highlighter-rouge">yield</code>, işletim sistemine başka bir iş parçacığını çalıştırabileceğini söyler; fakat kilidi gerçek anlamda uyuyan bir mutex hâline getirmez.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;atomic&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;thread&gt;</span><span class="cp">
</span>
<span class="k">class</span> <span class="nc">SpinLock</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">atomic_flag</span> <span class="n">locked</span> <span class="o">=</span> <span class="n">ATOMIC_FLAG_INIT</span><span class="p">;</span>

<span class="nl">public:</span>
    <span class="kt">void</span> <span class="n">lock</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">while</span> <span class="p">(</span><span class="n">locked</span><span class="p">.</span><span class="n">test_and_set</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">memory_order_acquire</span><span class="p">))</span> <span class="p">{</span>
            <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">yield</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="nf">unlock</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">locked</span><span class="p">.</span><span class="n">clear</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">memory_order_release</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>

<p>Aynı kritik bölüm standart mutex ile daha güvenli ve okunaklı biçimde korunabilir:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;mutex&gt;</span><span class="cp">
</span>
<span class="n">std</span><span class="o">::</span><span class="n">mutex</span> <span class="n">mutex</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">counter</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">increment</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">lock_guard</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">mutex</span><span class="o">&gt;</span> <span class="n">guard</span><span class="p">(</span><span class="n">mutex</span><span class="p">);</span>
    <span class="o">++</span><span class="n">counter</span><span class="p">;</span> <span class="c1">// Paylaşılan veriyi güvenle günceller.</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">std::lock_guard</code>, fonksiyondan istisnayla çıkılsa bile mutex kilidini otomatik bırakır. Üretim kodunda bu RAII yaklaşımı, elle <code class="language-plaintext highlighter-rouge">lock</code> ve <code class="language-plaintext highlighter-rouge">unlock</code> çağırmaktan daha güvenlidir.</p>

<h2 id="hangisini-ne-zaman-seçmeli">Hangisini ne zaman seçmeli?</h2>

<p>Kritik bölüm birkaç atomik işlem kadar kısaysa, çekirdek sayısı yeterliyse ve çakışma düşükse spinlock avantaj sağlayabilir. İşlem bloklayıcı G/Ç yapıyor, bellek ayırıyor veya süresi öngörülemeyen başka kodlar çağırıyorsa mutex daha doğru seçimdir. Spinlock tutulurken uyumak ise performans felaketinin davetiyesidir.</p>

<p>Modern mutex uygulamalarının önce kısa süre dönüp sonra uyuyan <strong>adaptif</strong> stratejiler kullanabildiğini de unutmayın. Dolayısıyla teorik tahmin tek başına yeterli değildir. Gerçek iş yükünü benchmark ve profiler ile ölçün. En hızlı kilit bazen spinlock, bazen mutex; çoğu zamansa paylaşılan veriyi azaltarak hiç ihtiyaç duymadığınız kilittir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="mutex" /><category term="spinlock" /><category term="eşzamanlılık" /><category term="çok çekirdekli programlama" /><category term="performans" /><category term="c++" /><summary type="html"><![CDATA[Çok çekirdekli bir sistemde iki iş parçacığı aynı veriye uzandığında küçük bir trafik kavşağı oluşur. Mutex kırmızı ışıkta motoru kapatıp beklemeye, spinlock ise ışık yeşile dönene kadar gaza basmadan motoru çalıştırmaya benzer. Hangisinin daha hızlı olduğu, kilidin ne kadar süre tutulduğuna ve işletim sisteminin bekletme maliyetine bağlıdır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/mutex-vs-spinlock-63.png" /><media:content medium="image" url="https://program.sonsuz.us/img/mutex-vs-spinlock-63.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>