00 NVMe nedir?
NVMe (Non-Volatile Memory Express), flash bellek tabanlı depolama aygıtları için tasarlanmış bir host controller arayüzü ve komut seti standardıdır. PCIe otobüsü üzerinden çalışır.
SATA ve onun protokolü AHCI, manyetik disk dönemine ait tasarımlardır. SATA kontrolcüsü tek bir komut kuyruğu derinliğine 32 komut sığdırabilir. Flash bellekler ise tamamen farklı fiziksel özellikler sergiler: paralel okuma yapabilir, sıralı ya da rastgele erişimde benzer gecikme gösterir. AHCI bu potansiyeli kullanamamaktadır.
NVMe bu sorunu temelinden çözer. PCIe doğrudan NIC gibi çalışır: CPU belleğine DMA ile doğrudan erişir, donanım komut kuyruğu mekanizması binlerce eşzamanlı I/O isteğini işleyebilir. AHCI'nin 1 × 32 komut kuyruğuna karşın NVMe 64.000 kuyruk × 64.000 komut derinliği destekler.
AHCI (SATA):
┌──────────┐ SATA ┌──────────────┐ PCIe ┌──────┐
│ Uygulama │───────────▶│ AHCI Ctrl. │───────────▶│ CPU │
│ FS+VFS │ 6 Gbps │ 1 kuyruk │ (sürücü) └──────┘
└──────────┘ │ Maks 32 cmd │
└──────────────┘
NVMe:
┌──────────┐ PCIe ┌──────────────────────────┐ DMA ┌──────┐
│ Uygulama │───────────▶│ NVMe Controller │──────────▶│ RAM │
│ FS+VFS │ 16+ GB/s │ 64K kuyruk × 64K cmd │ └──────┘
└──────────┘ │ Admin Queue + I/O Queue │
└──────────────────────────┘
AHCI vs NVMe karşılaştırması
| Özellik | AHCI (SATA) | NVMe (PCIe) |
|---|---|---|
| Arayüz hızı | 6 Gbps (SATA III) | PCIe 4.0 x4 = 64 Gbps |
| Seq. okuma (tipik) | ~550 MB/s | 3500–7000 MB/s |
| Rastgele 4K IOPS | ~100 K IOPS | 500K–1M+ IOPS |
| Komut kuyruğu | 1 × 32 | 64K × 64K |
| Latency (okuma) | ~100 µs | ~20–80 µs |
| CPU yükü | Yüksek (compat. layer) | Düşük (native PCIe) |
| Güç tüketimi | ~2–5 W | ~3–8 W (aktif) |
Raspberry Pi CM4, NVIDIA Jetson serisi, i.MX8, RK3588 gibi modern gömülü platformlar PCIe x1–x4 desteğiyle NVMe kullanımına olanak tanır. Endüstriyel M.2 SSD'ler geniş sıcaklık aralığı (-40 ile +85°C) ve yüksek güvenilirlik için tasarlanmıştır.
01 NVMe mimarisi
NVMe'nin temel bileşenleri Admin Queue, I/O Queue çiftleri (SQ/CQ), doorbell register'ları ve namespace kavramıdır.
┌─────────────────────────────────────────────────────────────────┐
│ NVMe Controller (BAR0) │
│ │
│ Admin SQ ──▶ Admin CQ (yönetim komutları) │
│ │
│ I/O SQ[0] ──▶ I/O CQ[0] (CPU 0 için özel kuyruk) │
│ I/O SQ[1] ──▶ I/O CQ[1] (CPU 1 için özel kuyruk) │
│ I/O SQ[N] ──▶ I/O CQ[N] (CPU N için özel kuyruk) │
│ │
│ Doorbell Registers: │
│ SQ Tail Doorbell → yeni komut eklendi sinyali │
│ CQ Head Doorbell → tamamlanan komut alındı sinyali │
└─────────────────────────────────────────────────────────────────┘
│ PCIe (DMA)
▼
┌──────────────┐
│ Host RAM │
│ SQ: [cmd0] │ ← CPU komut yazar
│ [cmd1] │
│ CQ: [cpl0] │ ← Controller tamamlama yazar
│ [cpl1] │
└──────────────┘
Submission Queue (SQ) ve Completion Queue (CQ)
Controller register haritası (BAR0)
| Register | Offset | Açıklama |
|---|---|---|
| CAP | 0x00 | Controller Capabilities — max kuyruk boyutu, timeout |
| VS | 0x08 | NVMe Version — 1.4, 2.0 |
| INTMS/INTMC | 0x0C/0x10 | Interrupt Mask Set/Clear |
| CC | 0x14 | Controller Configuration — EN biti, komut set seçimi |
| CSTS | 0x1C | Controller Status — RDY biti, CFS (fatal status) |
| AQA | 0x24 | Admin Queue Attributes — ASQ/ACQ boyutları |
| ASQ | 0x28 | Admin SQ Base Address |
| ACQ | 0x30 | Admin CQ Base Address |
| SQ0TDBL | 0x1000 | Admin SQ Tail Doorbell |
| CQ0HDBL | 0x1004 | Admin CQ Head Doorbell |
02 NVMe komut seti
NVMe iki ana komut seti içerir: NVM komut seti (veri I/O) ve Admin komut seti (yönetim). Her komut 64 byte'lık Submission Queue Entry (SQE) olarak temsil edilir.
NVM komutları — veri I/O
| Komut | Opcode | Açıklama |
|---|---|---|
| Read | 0x02 | LBA aralığını oku. SLBA, NLB (sector sayısı), PRP/SGL (hedef buffer adresleri) |
| Write | 0x01 | LBA aralığına yaz. FUA (Force Unit Access) biti write cache'i bypass eder |
| Flush | 0x00 | Write cache'i kalıcı depolamaya zorla. Güç kesintisi güvenliği için kritik |
| Dataset Management | 0x09 | TRIM (deallocate) — SSD'ye kullanılmayan blokları bildir, wear leveling için |
| Write Zeroes | 0x08 | LBA aralığını hızlıca sıfırla (SSD iç TRIM ile) |
| Compare | 0x05 | Disk içeriğini bellekle karşılaştır |
Admin komutları — yönetim
| Komut | Opcode | Açıklama |
|---|---|---|
| Identify | 0x06 | Controller veya namespace kimlik bilgilerini döner. Model, seri no, kapasiteler |
| Get Features | 0x0A | Power state, kuyruk sayısı, write atomicity gibi özellikleri sorgula |
| Set Features | 0x09 | Controller özelliklerini yapılandır |
| Create I/O SQ | 0x01 | Yeni I/O Submission Queue oluştur |
| Create I/O CQ | 0x05 | Yeni I/O Completion Queue oluştur |
| Delete I/O SQ/CQ | 0x00/0x04 | I/O kuyruklarını sil |
| Get Log Page | 0x02 | SMART/Health, Error log, Firmware log sayfaları |
| Firmware Download/Commit | 0x11/0x10 | NVMe controller firmware güncellemesi |
| Format NVM | 0x80 | Namespace'i formatla (güvenli silme dahil) |
SQE yapısı (basitleştirilmiş)
/* NVMe Submission Queue Entry — 64 byte */
struct nvme_command {
/* CDW0: Command opcode, FUSE, PSDT, CID */
__le16 opcode; /* 8 bit opcode + 6 bit reserved + 2 bit FUSE */
__le16 flags; /* PSDT (PRP or SGL) */
__le16 command_id;/* CID — tamamlama eşleştirmesi için */
__le16 reserved0;
/* CDW1: Namespace ID */
__le32 nsid;
/* CDW2–3: Reserved */
__le32 cdw2;
__le32 cdw3;
/* CDW4–5: Metadata pointer */
__le64 metadata;
/* CDW6–9: PRP1, PRP2 (veya SGL) — veri buffer adresleri */
union nvme_data_ptr dptr;
/* CDW10–15: Komuta özgü */
__le32 cdw10; /* Read/Write: SLBA[31:0] */
__le32 cdw11; /* Read/Write: SLBA[63:32] */
__le32 cdw12; /* Read/Write: NLB + FUA + PRINFO */
__le32 cdw13;
__le32 cdw14;
__le32 cdw15;
};
03 Gömülü M.2 seçimi
Gömülü sistemler için M.2 SSD seçerken form faktörü, PCIe nesli, güç tüketimi, sıcaklık aralığı ve dayanıklılık kritik kriterlerdir.
M.2 form faktörleri
| Form faktör | Boyut | Tipik kullanım |
|---|---|---|
| M.2 2230 | 22 × 30 mm | Ultrabook, küçük gömülü kartlar (RPi CM4 HAT) |
| M.2 2242 | 22 × 42 mm | Endüstriyel gömülü sistemler |
| M.2 2260 | 22 × 60 mm | Orta boy sistemler |
| M.2 2280 | 22 × 80 mm | Standart PC/sunucu, yüksek kapasiteli |
Key-M connector ve PCIe şeritleri
M.2 Key-M Konnektör (NVMe için)
┌──────────────────────────────────────────────────────────┐
│ B+M Key: SATA + PCIe x2 (bazı SSD'ler her ikisini destekler)│
│ M Key only: PCIe x4 tam destek │
│ │
│ PCIe Gen 3 x4: ~3.5 GB/s bant genişliği │
│ PCIe Gen 4 x4: ~7.0 GB/s bant genişliği │
│ PCIe Gen 4 x2: ~3.5 GB/s (RPi CM4, bazı SoC'ler) │
│ │
│ Güç pinleri: 3.3V (ana güç) │
│ 3.3V_DUAL: güç yönetimi için ek pin │
└──────────────────────────────────────────────────────────┘
Endüstriyel vs tüketici SSD karşılaştırması
| Özellik | Tüketici SSD | Endüstriyel SSD |
|---|---|---|
| Sıcaklık aralığı | 0°C – 70°C | -40°C – +85°C |
| NAND tipi | TLC/QLC | SLC / MLC / pSLC |
| Yazma dayanıklılığı | 100–600 TBW | 1000–10000+ TBW |
| Güç kesintisi koruması | Genellikle yok | Kapasitör koruması |
| Sabit yazma gecikmesi | Değişken (GC) | Deterministik |
| MTBF | 1.5M saat | 2–3M saat |
| Fiyat (128 GB) | 15–30 USD | 80–300 USD |
Önerilen endüstriyel NVMe SSD'ler
Güç tüketimi yönetimi
Pil veya kısıtlı güç bütçeli gömülü sistemlerde NVMe'nin güç modları kritik önem taşır. Modern NVMe SSD'ler APST (Autonomous Power State Transitions) ile boşta power-down moduna girebilir.
## NVMe güç durumlarını listele
nvme id-ctrl /dev/nvme0 | grep -A5 "psd "
## Örnek çıktı:
## ps 0 : mp:8.00W operational enlat:0 exlat:0
## ps 1 : mp:6.00W operational enlat:0 exlat:0
## ps 2 : mp:5.00W operational enlat:0 exlat:0
## ps 3 : mp:0.0500W non-op enlat:10000 exlat:35000 # PS3: 50 mW
## ps 4 : mp:0.0050W non-op enlat:25000 exlat:25000 # PS4: 5 mW
## APST (Autonomous Power State Transition) etkinleştir
nvme set-feature /dev/nvme0 -f 0x0c -v 1
## Mevcut güç durumunu görüntüle
nvme get-feature /dev/nvme0 -f 0x02
04 Linux NVMe sürücüsü
Linux çekirdeğinin nvme sürücüsü, standart blok cihazı arayüzü üzerinden NVMe'ye erişim sağlar. Her controller /dev/nvmeX, her namespace /dev/nvmeXnY olarak görünür.
Cihaz hiyerarşisi
/dev/nvme0 ← Controller (Admin komutları için)
/dev/nvme0n1 ← Namespace 1 (block device — veri I/O)
/dev/nvme0n1p1 ← Partition 1 (EFI / boot)
/dev/nvme0n1p2 ← Partition 2 (rootfs)
/sys/class/nvme/nvme0/ ← sysfs controller girişi
/sys/class/block/nvme0n1/ ← sysfs block device girişi
nvme-cli — komut satırı aracı
## Kurulum
apt install nvme-cli
## Tüm NVMe cihazlarını listele
nvme list
## Örnek çıktı:
## Node SN Model Namespace
## /dev/nvme0n1 S12345678 Samsung PM9A1 1
## Controller kimlik bilgileri
nvme id-ctrl /dev/nvme0
## mn: Samsung MZVL2256HCHQ-00B00 (model)
## sn: S6ENNF0R... (seri no)
## tnvmcap: 256060514304 (toplam kapasite bayt)
## nn: 1 (namespace sayısı)
## Namespace kimlik bilgileri
nvme id-ns /dev/nvme0n1
## nsze: 500118192 (LBA sayısı)
## lbaf: ms:0 lbads:9 rp:0 (LBA boyutu = 2^9 = 512 B)
## SMART / sağlık logu
nvme smart-log /dev/nvme0
## critical_warning: 0 (0 = sağlıklı)
## temperature: 35 C
## available_spare: 100%
## percentage_used: 0%
## data_units_read: 1,234,567 (512KB birimle)
## data_units_written: 987,654
## Error logu
nvme error-log /dev/nvme0
## Namespace yönetimi
nvme list-ns /dev/nvme0 # tüm namespace'leri listele
nvme create-ns /dev/nvme0 ... # yeni namespace oluştur
nvme attach-ns /dev/nvme0 ... # namespace'i controller'a bağla
sysfs üzerinden erişim
## Controller bilgileri
cat /sys/class/nvme/nvme0/model
cat /sys/class/nvme/nvme0/serial
cat /sys/class/nvme/nvme0/firmware_rev
## PCIe bağlantı hızı
cat /sys/bus/pci/devices/0000:01:00.0/current_link_speed
## 8 GT/s PCIe (Gen 3)
## 16 GT/s PCIe (Gen 4)
cat /sys/bus/pci/devices/0000:01:00.0/current_link_width
## 4 (x4 lanes)
## Kuyruk sayısı
cat /sys/class/nvme/nvme0/queue_count
## Sürücü bilgisi
cat /sys/class/nvme/nvme0/address
05 Performans tuning
NVMe varsayılan Linux konfigürasyonuyla bile etkileyici performans sunar. Ancak doğru I/O scheduler, kuyruk derinliği ve write cache ayarları performansı daha da artırır.
I/O Scheduler seçimi
## Mevcut scheduler ve seçenekleri
cat /sys/block/nvme0n1/queue/scheduler
## [mq-deadline] kyber bfq none
## NVMe için "none" (no-op) önerilir — kendi dahili kuyruklaması var
echo none > /sys/block/nvme0n1/queue/scheduler
## Kalıcı ayar — udev kuralı
cat > /etc/udev/rules.d/60-nvme-scheduler.rules <<'EOF'
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", \
ATTR{queue/scheduler}="none"
EOF
udevadm control --reload
Kuyruk derinliği (Queue Depth)
## Mevcut queue depth
cat /sys/block/nvme0n1/queue/nr_requests
## 1023
## NVMe genellikle varsayılan değer yeterlidir
## Yoğun paralel iş yükü için artırabilirsiniz
echo 2048 > /sys/block/nvme0n1/queue/nr_requests
## Read-ahead — sıralı okuma için
cat /sys/block/nvme0n1/queue/read_ahead_kb
## 128
## Rastgele I/O için read-ahead azalt
echo 0 > /sys/block/nvme0n1/queue/read_ahead_kb
Write cache ve FUA bit
## NVMe write cache durumunu görüntüle
nvme get-feature /dev/nvme0 -f 0x06 -H
## Current value:0x1 (write cache enabled)
## Write cache devre dışı bırak (güvenilir yazma, yavaş)
nvme set-feature /dev/nvme0 -f 0x06 -v 0
## Linux blok katmanı: write cache politikası
hdparm -W /dev/nvme0n1 # write cache durumu
hdparm -W1 /dev/nvme0n1 # write cache etkinleştir
## FUA (Force Unit Access) — tek komutla cache bypass
## O_DSYNC flag ile open() veya fsync() — güçlü garanti
## Uygulama katmanında:
int fd = open("data.bin", O_WRONLY | O_DIRECT | O_DSYNC, 0644);
fio benchmark
## Sıralı okuma (128K block)
fio --name=seq-read \
--filename=/dev/nvme0n1 \
--rw=read \
--bs=128k \
--size=4G \
--numjobs=1 \
--iodepth=32 \
--ioengine=io_uring \
--direct=1 \
--group_reporting
## Rastgele 4K okuma (yüksek IOPS testi)
fio --name=rand-read \
--filename=/dev/nvme0n1 \
--rw=randread \
--bs=4k \
--size=4G \
--numjobs=4 \
--iodepth=64 \
--ioengine=io_uring \
--direct=1 \
--group_reporting \
--runtime=30 \
--time_based
## Beklenen sonuç (PCIe 3.0 x4, Samsung PM981):
## Sıralı okuma : ~3400 MB/s
## Rastgele 4K RD : ~420K IOPS
## Rastgele 4K WR : ~380K IOPS
APST — Autonomous Power State Transitions
## APST etkinleştir (kernel parametresi)
## /etc/default/grub:
## GRUB_CMDLINE_LINUX_DEFAULT="nvme_core.default_ps_max_latency_us=20000"
## Mevcut APST durumu
nvme get-feature /dev/nvme0 -f 0x0c -H
## Manuel power state geçişi (test amaçlı)
nvme set-feature /dev/nvme0 -f 0x02 -v 3 # PS3'e geç
## nvme-power systemd servisi ile otomatik yönetim
cat /sys/devices/virtual/nvme-subsystem/nvme-subsys0/nvme0/power/control
## auto (runtime PM etkin)
06 io_uring ile NVMe
io_uring, Linux 5.1'de tanıtılan yüksek performanslı asenkron I/O mekanizmasıdır. NVMe'nin yüksek IOPS kapasitesini tam olarak kullanmak için geleneksel POSIX aio'ya göre çok daha verimlidir.
Geleneksel aio_read/write:
Uygulama → syscall(io_submit) → kernel → NVMe SQ → NVMe CQ
└── Her I/O için 2 syscall, kontrol transferi kernel↔kullanıcı
io_uring:
┌───────────────────────────────────────────────┐
│ Paylaşımlı Bellek (kullanıcı + kernel) │
│ ┌──────────────┐ ┌──────────────────┐ │
│ │ SQ Ring │ → │ CQ Ring │ │
│ │ (uygulama │ │ (kernel yazar, │ │
│ │ yazar) │ │ uygulama okur) │ │
│ └──────────────┘ └──────────────────┘ │
└───────────────────────────────────────────────┘
└── Sıfır sistem çağrısı (SQPOLL modunda)
IORING_OP_READ / IORING_OP_WRITE
#include <liburing.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define QUEUE_DEPTH 128
#define BLOCK_SIZE 4096
#define NUM_OPS 1024
int main(void)
{
struct io_uring ring;
int fd, ret;
/* 1. io_uring başlat */
ret = io_uring_queue_init(QUEUE_DEPTH, &ring, 0);
if (ret < 0) {
perror("io_uring_queue_init");
return 1;
}
/* 2. NVMe bloğunu aç — O_DIRECT zorunlu */
fd = open("/dev/nvme0n1", O_RDONLY | O_DIRECT);
if (fd < 0) {
perror("open");
return 1;
}
/* 3. Hizalı buffer'lar ayır */
char **bufs = malloc(NUM_OPS * sizeof(char *));
for (int i = 0; i < NUM_OPS; i++) {
posix_memalign((void **)&bufs[i], 4096, BLOCK_SIZE);
}
/* 4. SQE'leri toplu gönder */
for (int i = 0; i < NUM_OPS; i++) {
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_read(sqe, fd,
bufs[i], /* hedef buffer */
BLOCK_SIZE, /* okuma boyutu */
(off_t)i * BLOCK_SIZE); /* ofset */
sqe->user_data = i; /* tanımlayıcı */
}
/* 5. Toplu submit — tek syscall! */
ret = io_uring_submit(&ring);
printf("Gönderilen: %d operasyon\n", ret);
/* 6. Tamamlamaları topla */
struct io_uring_cqe *cqe;
int completed = 0;
while (completed < NUM_OPS) {
ret = io_uring_wait_cqe(&ring, &cqe);
if (ret < 0) break;
if (cqe->res < 0)
fprintf(stderr, "I/O hatası [%lld]: %s\n",
cqe->user_data, strerror(-cqe->res));
io_uring_cqe_seen(&ring, cqe);
completed++;
}
printf("Tamamlanan: %d operasyon\n", completed);
/* Temizle */
close(fd);
for (int i = 0; i < NUM_OPS; i++) free(bufs[i]);
free(bufs);
io_uring_queue_exit(&ring);
return 0;
}
SQPOLL — sıfır syscall modu
/* SQPOLL: kernel thread SQ'yu sürekli izler */
struct io_uring_params params = {
.flags = IORING_SETUP_SQPOLL,
.sq_thread_idle = 2000, /* ms — kernel thread uyku süresi */
};
/* SQPOLL için root yetkisi gereklidir (CAP_SYS_NICE) */
ret = io_uring_queue_init_params(QUEUE_DEPTH, &ring, ¶ms);
/* SQPOLL modunda io_uring_submit() çağrısına gerek yok!
SQE ekledikten sonra kernel thread otomatik görür. */
/* Sabit buffer'lar ile daha da hızlı */
struct iovec iovecs[NUM_OPS];
for (int i = 0; i < NUM_OPS; i++) {
posix_memalign(&iovecs[i].iov_base, 4096, BLOCK_SIZE);
iovecs[i].iov_len = BLOCK_SIZE;
}
io_uring_register_buffers(&ring, iovecs, NUM_OPS);
/* Sabit buffer okuma */
sqe = io_uring_get_sqe(&ring);
io_uring_prep_read_fixed(sqe, fd, iovecs[i].iov_base,
BLOCK_SIZE, offset, i /* buf_index */);
io_uring vs aio karşılaştırması
| Özellik | POSIX aio | Linux aio | io_uring |
|---|---|---|---|
| Syscall sayısı/op | 2+ (submit+wait) | 2 (io_submit+io_getevents) | 0 (SQPOLL) veya 1 |
| Buffer kopyası | Var | Var | Sabit buffer: yok |
| Kernel destekli operasyon | Sınırlı | Blok I/O | 50+ op türü |
| Tipik NVMe IOPS | ~200K | ~300K | ~500K–900K |
| Min kernel versiyonu | 2.6.x | 2.6.x | 5.1+ |
| liburing desteği | — | — | Evet |
Latency histogramı — io_uring vs read()
## io_uring ile latency histogram
fio --name=lat-test \
--filename=/dev/nvme0n1 \
--rw=randread \
--bs=4k \
--iodepth=1 \
--numjobs=1 \
--ioengine=io_uring \
--direct=1 \
--lat_percentiles=1 \
--percentile_list=50:90:99:99.9:99.99 \
--runtime=10 \
--time_based
## Beklenen (Samsung PM9A1, RPi CM4 PCIe 2.0 x1):
## lat (usec): min= 40, avg= 68, max=3820
## 50.00th=[ 58], 90.00th=[ 82], 99.00th=[175],
## 99.90th=[502], 99.99th=[1958]
07 Pratik: RPi CM4 NVMe — M.2 HAT, fio benchmark, wear leveling scripti
Raspberry Pi CM4 üzerinde M.2 HAT ile NVMe SSD kurulumu, performans benchmark ve SSD sağlığı izleme scripti.
Donanım kurulumu
Raspberry Pi CM4 (PCIe Gen 2 x1)
┌──────────────────────────────────────────────────────────┐
│ CM4 modül │
│ PCIe Gen 2 x1 → J2 konnektörü │
│ │
│ Önerilen HAT'lar: │
│ - Waveshare CM4-NVMe-SSD-HAT (M.2 2230/2242/2280) │
│ - Pimoroni NVMe Base (M.2 2230) │
│ - GEEKWORM X1001 (M.2 2242/2280) │
└──────────────────────────────────────────────────────────┘
Bant genişliği: PCIe Gen 2 x1 = ~500 MB/s (pratik ~400 MB/s)
Not: CM4'te PCIe x1 olduğundan NVMe'nin tam kapasitesi kullanılamaz.
Yine de SATA SSD'ye kıyasla 6-8x daha hızlı.
config.txt ayarları
## PCIe'yi etkinleştir (CM4)
dtparam=pciex1
## PCIe Gen 3 dene (CM4 resmi olarak Gen 2, ancak bazı SSD'ler Gen 3 çalışır)
## dtparam=pciex1_gen=3 # DİKKAT: resmi desteklenmez, deneysel
## NVMe bootloader desteği (SD kart olmadan boot)
## EEPROM'u güncelle:
## sudo rpi-eeprom-update -a
## BOOT_ORDER=0xf416 (PCIe NVMe → USB → SD)
## CPU frekansı (benchmark için)
arm_freq=1500
over_voltage=2
NVMe kurulumu doğrulama
## NVMe algılandı mı?
nvme list
## /dev/nvme0n1 Samsung MZVLQ512HBLU-000H1 512.1 GB
## PCIe bağlantı hızı
lspci -vvv | grep -A5 "Non-Volatile memory"
## LnkSta: Speed 5GT/s (Gen 2), Width x1
## Blok cihazı bilgisi
lsblk -o NAME,SIZE,ROTA,SCHED,MODEL
## nvme0n1 476.9G 0 none Samsung MZVLQ512...
fio benchmark scripti
#!/bin/bash
# RPi CM4 NVMe performans benchmark scripti
set -euo pipefail
DEVICE="/dev/nvme0n1"
OUTPUT_DIR="/tmp/nvme_bench_$(date +%Y%m%d_%H%M%S)"
mkdir -p "${OUTPUT_DIR}"
echo "=== RPi CM4 NVMe Benchmark ===" | tee "${OUTPUT_DIR}/results.txt"
date | tee -a "${OUTPUT_DIR}/results.txt"
## Test 1: Sıralı okuma (128KB)
echo -e "\n--- Sıralı Okuma (128KB) ---" | tee -a "${OUTPUT_DIR}/results.txt"
fio --name=seq-read \
--filename="${DEVICE}" \
--rw=read \
--bs=128k \
--size=1G \
--numjobs=1 \
--iodepth=32 \
--ioengine=io_uring \
--direct=1 \
--group_reporting \
--output-format=terse \
2>>&1 | grep "READ:" | tee -a "${OUTPUT_DIR}/results.txt"
## Test 2: Sıralı yazma (128KB)
echo -e "\n--- Sıralı Yazma (128KB) ---" | tee -a "${OUTPUT_DIR}/results.txt"
fio --name=seq-write \
--filename="${DEVICE}" \
--rw=write \
--bs=128k \
--size=1G \
--numjobs=1 \
--iodepth=32 \
--ioengine=io_uring \
--direct=1 \
--group_reporting \
--output-format=terse \
2>>&1 | grep "WRITE:" | tee -a "${OUTPUT_DIR}/results.txt"
## Test 3: Rastgele 4KB okuma (IOPS)
echo -e "\n--- Rastgele 4KB Okuma (IOPS) ---" | tee -a "${OUTPUT_DIR}/results.txt"
fio --name=rand-read \
--filename="${DEVICE}" \
--rw=randread \
--bs=4k \
--size=1G \
--numjobs=4 \
--iodepth=32 \
--ioengine=io_uring \
--direct=1 \
--group_reporting \
--runtime=30 \
--time_based \
--output-format=terse \
2>>&1 | grep "READ:" | tee -a "${OUTPUT_DIR}/results.txt"
## Test 4: Karışık okuma/yazma (%70 okuma)
echo -e "\n--- Karışık R/W (70/30) ---" | tee -a "${OUTPUT_DIR}/results.txt"
fio --name=mixed \
--filename="${DEVICE}" \
--rw=randrw \
--rwmixread=70 \
--bs=4k \
--size=1G \
--numjobs=4 \
--iodepth=16 \
--ioengine=io_uring \
--direct=1 \
--group_reporting \
--runtime=30 \
--time_based \
2>>&1 | tee -a "${OUTPUT_DIR}/results.txt"
echo -e "\nBenchmark tamamlandı: ${OUTPUT_DIR}/results.txt"
SSD wear leveling ve sağlık izleme scripti
#!/bin/bash
# NVMe sağlık izleme — /var/log/nvme_health.log dosyasına yazar
# Systemd timer: her gün çalışır
DEVICE="/dev/nvme0"
LOG_FILE="/var/log/nvme_health.log"
ALERT_SPARE_THRESHOLD=20 # %20 altında uyar
ALERT_TEMP_THRESHOLD=70 # 70°C üstünde uyar
log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> "${LOG_FILE}"; }
## SMART verilerini al
SMART=$(nvme smart-log "${DEVICE}" 2>/dev/null) || {
log "HATA: NVMe SMART logu alınamadı"
exit 1
}
## Değerleri çıkart
TEMP=$(echo "${SMART}" | grep "^temperature" | awk '{print $3}')
SPARE=$(echo "${SMART}" | grep "available_spare " | awk '{print $3}' | tr -d '%')
USED=$(echo "${SMART}" | grep "percentage_used" | awk '{print $3}' | tr -d '%')
WARN=$(echo "${SMART}" | grep "critical_warning" | awk '{print $3}')
UNITS_READ=$(echo "${SMART}" | grep "data_units_read" | awk '{print $4}' | tr -d ',')
UNITS_WRITE=$(echo "${SMART}" | grep "data_units_written" | awk '{print $4}' | tr -d ',')
## Log yaz
log "Sağlık: temp=${TEMP}°C spare=${SPARE}% used=${USED}% warn=${WARN}"
log "Veri: read=${UNITS_READ}×512KB write=${UNITS_WRITE}×512KB"
## Uyarı kontrolü
if [ "${WARN}" != "0" ]; then
log "KRİTİK UYARI: NVMe critical_warning=${WARN}"
logger -p user.crit "NVMe critical warning: ${WARN}"
fi
if [ "${SPARE}" -lt "${ALERT_SPARE_THRESHOLD}" ]; then
log "UYARI: Yedek alan düşük: ${SPARE}% (eşik: ${ALERT_SPARE_THRESHOLD}%)"
logger -p user.warning "NVMe spare low: ${SPARE}%"
fi
if [ "${TEMP}" -gt "${ALERT_TEMP_THRESHOLD}" ]; then
log "UYARI: SSD sıcaklığı yüksek: ${TEMP}°C"
logger -p user.warning "NVMe temperature high: ${TEMP}°C"
fi
systemd timer kurulumu
## /etc/systemd/system/nvme-health.service
[Unit]
Description=NVMe SSD Health Check
[Service]
Type=oneshot
ExecStart=/usr/local/bin/nvme_health_monitor.sh
## /etc/systemd/system/nvme-health.timer
[Unit]
Description=NVMe Health Check — Daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
## Etkinleştir
systemctl daemon-reload
systemctl enable --now nvme-health.timer
systemctl list-timers nvme-health.timer
Beklenen benchmark sonuçları — RPi CM4
| Test | Sonuç | Karşılaştırma (microSD) |
|---|---|---|
| Sıralı okuma | ~390 MB/s | ~45 MB/s |
| Sıralı yazma | ~350 MB/s | ~20 MB/s |
| Rastgele 4K okuma | ~40K IOPS | ~2K IOPS |
| Rastgele 4K yazma | ~30K IOPS | ~1K IOPS |
| Latency (ortalama) | ~80 µs | ~500 µs |
NVMe'nin PCIe doğrudan erişim mimarisi, AHCI'ye göre radikal performans artışı sağlar. Linux NVMe sürücüsü olgun ve kararlıdır; nvme-cli ile tam yönetim mümkündür. io_uring ile NVMe'nin IOPS kapasitesi sistem çağrısı overhead'ı olmadan tam kullanılabilir. Gömülü sistemlerde endüstriyel M.2 SSD seçimi dayanıklılık ve sıcaklık açısından kritik öneme sahiptir.