Syllabus học Linux
Phase 0 - Setup (2 ngày)
Ngày 1: Cài đặt môi trường ảo hóa
Khái niệm
Type-1 vs Type-2 hypervisor - vì sao KVM (Type-1, tích hợp kernel) nhanh hơn VirtualBox (Type-2) trên Linux host.
Virtualization extension:
Intel VT-x/AMD-V- kiểm traegrep -c '(vmx|svm)' /proc/cpuinfo.
Thực hành và quan sát
Cài
libvirt+qemu-kvm(nếu host là Linux) hoặc VirtualBox.Tải ISO Rocky Linux minimal, cài đặt thủ công - partition bằng tay, không dùng auto-partition (để hiểu rõ layout).
Advanced concepts
- Nested virtualization: nếu bạn cài VM trong VM (VD lab trong máy ảo công ty), cần bật
kvm_intel nested=1.
- Nested virtualization: nếu bạn cài VM trong VM (VD lab trong máy ảo công ty), cần bật
Ngày 2: SSH & Snapshot
Khái niệm
SSH key-pair: asymmetric crypto, vì sao an toàn hơn password.
authorized_keys,known_hosts, cơ chế host key verification chống MITM.
Thực hành và quan sát
Generate keypair (
ed25519), copy key bằngssh-copy-id, disablePasswordAuthenticationtrongsshd_config.~/.ssh/config- alias host,IdentityFile,Portcustom.
Advanced concepts
- Snapshot VM ngay sau bước này (LVM snapshot hoặc hypervisor snapshot) - điểm khôi phục cho toàn bộ lab sau này.
Phase 1 - Nền tảng hệ thống (6 tuần)
Tuần 1: Shell & Filesystem
Ngày 1: Filesystem Hierarchy Standard & cơ chế mount
Cơ chế
FHS:
/etc /var /usr /opt /proc /sys /tmp /run- vai trò từng thư mục, cái nào persistent, cái nào tmpfs (RAM-backed)./procvà/syskhông phải file thật - chúng là giao diện kernel expose ra userspace (procfs, sysfs là pseudo-filesystem).Mount point là gì - cơ chế 1 filesystem được "gắn" vào 1 thư mục trong cây thư mục gốc.
Thực hành và quan sát
mountkhông tham số - đọc toàn bộ danh sách mount hiện tại, phân biệt real disk vs tmpfs vs proc/sysfs.cat /proc/mountsso với lệnhmount- hiểu vì sao 2 output gần giống nhau (mountđọc từ/proc/self/mounts).
Advanced concepts
stat -f /xem filesystem type của root.Bind mount:
mount --bind- 1 thư mục xuất hiện ở 2 chỗ khác nhau, dùng nhiều trong container.
Ngày 2: Bash cơ bản & Shell expansion
Cơ chế
Shell là 1 chương trình đọc-thực thi (REPL), không phải "hệ điều hành mini" - hiểu rõ ranh giới shell built-in vs external command (
type ls,type cd).Thứ tự expansion của bash: brace → tilde → parameter → command substitution → arithmetic → word splitting → pathname (glob).
Thực hành và quan sát
Biến môi trường vs biến shell (
exportkhác gì không export).~/.bashrcvs~/.bash_profilevs/etc/profile- thứ tự load khi login shell vs non-login shell.
Advanced concepts
set -xđể trace từng lệnh thực thi trong script - công cụ debug quan trọng nhất của shell script.
Ngày 3: Pipes & Redirection
Cơ chế
Pipe (
|) tạo ra 1 anonymous pipe trong kernel - thực chất là 1 buffer trong bộ nhớ kernel, không phải file.File descriptor: 0 (stdin), 1 (stdout), 2 (stderr) - redirection thực chất là thao tác trên bảng file descriptor của process.
Thực hành và quan sát
>,>>,2>,2>&1,&>- phân biệt rõ thứ tựcmd > file 2>&1kháccmd 2>&1 > file.tee- vừa ghi file vừa in stdout, giải thích cơ chế nó đọc stdin và ghi ra 2 nơi.
Advanced concepts
- Process substitution
<(cmd)- kernel tạo 1 file descriptor ảo trỏ tới output của command, không cần tạo file tạm thật.
- Process substitution
Ngày 4: grep & find
Cơ chế
Regex cơ bản (BRE) vs extended (ERE,
grep -E) - vì sao+,?,|cần escape trong BRE.findduyệt cây thư mục theo depth-first, mỗi kết quả trigger-execlà 1 lần fork+exec (chậm) vs-exec ... +gom batch (nhanh hơn).
Thực hành và quan sát
- 10 bài tập: tìm file >100MB, tìm file sửa đổi trong 24h qua, tìm text trong nhiều file kèm số dòng.
Advanced concepts
find -exec cmd {} +vs| xargs- so sánh performance khi xử lý hàng nghìn file.
Ngày 5: sed & awk
Cơ chế
sedlà stream editor - xử lý từng dòng theo pattern space, không load toàn bộ file vào RAM (khác với việc mở file bằng editor).awklà ngôn ngữ xử lý dữ liệu theo field/record -$0, $1, NF, NRlà gì.
Thực hành và quan sát
- Parse 1 file log Apache mẫu: trích IP, status code, đếm request theo status.
Advanced concepts
sed -iin-place edit thực chất tạo file tạm rồi rename - hiểu vì sao an toàn hơn ghi đè trực tiếp.
Ngày 6: Ôn tập tuần 1
Viết 1 script bash tổng hợp log: đếm request theo IP, sort theo số lượng giảm dần, xuất top 10.
Không nhìn lại note - tự nhớ syntax.
Tuần 2: Package management & RPM internals
Ngày 1: dnf & repo
Cơ chế
Repo metadata:
dnfkhông cài trực tiếp từ file rpm, mà tải metadata (danh sách package + dependency graph) từ repo trước, cache tại/var/cache/dnf.Dependency resolution: SAT solver bên trong dnf giải quyết xung đột version.
Thực hành và quan sát
dnf install/remove/update/history/repolist,dnf history undo <id>(rollback transaction).Thêm EPEL repo, quan sát
/etc/yum.repos.d/.
Advanced concepts
dnftransaction là atomic - nếu 1 package fail, toàn bộ transaction rollback (không giống cài package rời rạc).
Ngày 2: RPM internals
Cơ chế
Cấu trúc file
.rpm: lead + signature + header (metadata + file list) + payload (cpio archive nén).RPM database:
/var/lib/rpm- nơi lưu trạng thái package đã cài, dùng Berkeley DB (RHEL8+) hoặc sqlite (RHEL9+).
Thực hành và quan sát
rpm -qa,rpm -qf <file>(tìm package sở hữu 1 file),rpm -qi,rpm -ql.rpm -qf /bin/ls- tìm ra packagecoreutils.
Advanced concepts
rpm -V <package>- verify checksum các file đã cài, phát hiện file bị chỉnh sửa ngoài ý muốn (dùng trong security audit thật).
Ngày 3: Users & Groups - cấu trúc file
Cơ chế
/etc/passwd: 7 field (username:x:UID:GID:GECOS:home:shell) - vì sao password field làx(đã chuyển sang shadow)./etc/shadow: password hash (thuật toán, salt, hash - format$id$salt$hash), password aging fields./etc/group,/etc/gshadow- primary group vs supplementary group.
Thực hành và quan sát
useradd/usermod/groupadd, tạo user với UID cố định, home dir custom.chage -l <user>xem password aging policy.
Advanced concepts
getent passwd- vì sao dùnggetentthay vì đọc trực tiếp/etc/passwd(hỗ trợ NSS: LDAP, SSSD, không chỉ file local).
Ngày 4: Permissions cơ bản - deep dive (mở rộng theo yêu cầu)
Cơ chế
rwx cho owner/group/other - octal representation, vì sao
755=rwxr-xr-x.SUID: process chạy với quyền của owner file thay vì user gọi nó - cơ chế
/usr/bin/passwdcần SUID root để ghi/etc/shadow.SGID: trên file → chạy với quyền group owner; trên thư mục → file mới tạo trong đó tự động thừa hưởng group của thư mục (dùng cho shared team folder).
Sticky bit: trên thư mục → chỉ owner của file mới được xóa file đó dù thư mục có quyền write chung (VD
/tmp).umask- cơ chế trừ quyền mặc định khi tạo file mới (umask 022→ file mới644, thư mục mới755).
Thực hành và quan sát
Tạo file SUID thử nghiệm (
chmod u+s), giải thích rủi ro bảo mật cụ thể: nếu SUID root gắn vào 1 binary có lỗi (VD gọisystem()không sanitize input) → privilege escalation.Tạo thư mục SGID cho team share, test file mới tạo tự động đúng group.
Advanced concepts
capabilities(POSIX capabilities) - cách hiện đại thay thế SUID toàn quyền root:getcap /usr/bin/ping(chỉ cầnCAP_NET_RAWthay vì full root).setcap/getcapthực hành trên 1 binary tự viết.Vì sao capabilities an toàn hơn SUID: giới hạn đúng quyền cần thiết thay vì "tất cả hoặc không gì" (root or nothing).
Ngày 5: ACL & PAM
Cơ chế
ACL (Access Control List): mở rộng permission model truyền thống (owner/group/other) - cho phép set quyền riêng cho từng user/group cụ thể trên 1 file.
PAM (Pluggable Authentication Modules): cơ chế "cắm module xác thực" - vì sao đổi chính sách password (độ dài, độ phức tạp) không cần sửa code từng app, chỉ sửa
/etc/pam.d/.
Thực hành và quan sát
setfacl -m u:user2:rx file,getfacl file- case thực tế: thư mục nhiều user cần quyền khác nhau mà group model không đủ linh hoạt.Đọc
/etc/pam.d/sshd- trace qua các dòngauth,account,password,session.
Advanced concepts
pam_faillock- cấu hình khóa account sau N lần login sai (chống brute-force), thực hành cấu hình thật.
Ngày 6: Ôn tập tuần 2
Dựng 3 user, 1 group chung, thư mục share dùng SGID + ACL cho 1 user ngoài group được quyền đọc riêng.
Set capabilities cho 1 binary tự viết thay vì chạy nó bằng
sudo.
Tuần 3: Authentication & Package Distribution (tuần mới)
Ngày 1: LDAP khái niệm & SSSD
Cơ chế
LDAP (Lightweight Directory Access Protocol): directory service tập trung - thay vì mỗi server tự quản lý
/etc/passwdriêng, toàn bộ user/group nằm ở 1 nơi (Active Directory hoặc OpenLDAP), server chỉ query.SSSD (System Security Services Daemon): cache + broker giữa hệ thống local và backend (LDAP/AD/Kerberos) - vì sao cần cache: nếu mất kết nối tới directory server, user vẫn login được bằng cache gần nhất (offline authentication).
Thực hành và quan sát
Cài
sssd,realmd, quan sát file cấu hình/etc/sssd/sssd.confmẫu (không cần AD thật, đọc cấu trúc domain/id_provider/auth_provider).getent passwd <user_ldap>- nếu có LDAP server test, thấy user "ảo" xuất hiện dù không có trong/etc/passwd.
Advanced concepts
sssdcache location/var/lib/sss/db-sss_cache -Eđể force expire cache khi cần đồng bộ lại ngay.
Ngày 2: Kerberos cơ bản
Cơ chế
Kerberos: giao thức authentication dùng ticket thay vì gửi password qua mạng mỗi lần - KDC (Key Distribution Center) cấp TGT (Ticket Granting Ticket) sau khi xác thực 1 lần, sau đó dùng TGT để xin service ticket cho từng service cụ thể mà không cần nhập lại password.
Vì sao Kerberos quan trọng trong RHEL doanh nghiệp: tích hợp trực tiếp với Active Directory (đa số công ty dùng Windows AD làm domain controller), SSO (Single Sign-On) giữa nhiều Linux server.
Thực hành và quan sát
kinit <user>(nếu có KDC test/AD test) - lấy TGT,klistxem ticket hiện có, thời hạn hết hạn.
Advanced concepts
realm join- lệnh RHEL hiện đại để join domain AD chỉ với vài dòng lệnh (SSSD + Kerberos + LDAP được cấu hình tự động phía sau) - hiểu nó làm gì "bên dưới" quan trọng hơn thuộc lệnh, vì khi lỗi bạn cần biết debug từng lớp (LDAP query fail hay Kerberos ticket fail hay SSSD cache stale).
Ngày 3: Repo nội bộ & GPG signing
Cơ chế
GPG signing: mỗi RPM package có thể ký bằng private key, client verify bằng public key trong
/etc/pki/rpm-gpg/- đảm bảo package không bị chỉnh sửa giữa đường (supply-chain integrity), lý do repo nội bộ doanh nghiệp luôn cần ký package tự build.createrepo- sinh metadata (repodata/) từ 1 thư mục chứa file.rpm, biến nó thành repodnfcó thể dùng được.
Thực hành và quan sát
Tạo GPG keypair (
gpg --gen-key), ký 1 RPM bằngrpm --addsign, verify bằngrpm -K.Dựng 1 repo nội bộ đơn giản (thư mục +
createrepo+ serve quahttpdhoặcpython -m http.server), thêm vào/etc/yum.repos.d/của VM khác,dnf installtừ đó.
Advanced concepts
repotrack/mirror sync - cách doanh nghiệp lớn mirror toàn bộ repo RHEL/EPEL nội bộ để không phụ thuộc internet mỗi lần cài package (air-gapped environment phổ biến trong ngành tài chính/chính phủ).
Ngày 4: Build RPM cơ bản
Cơ chế
RPM build dùng spec file: định nghĩa metadata, dependency, script pre/post-install, và danh sách file -
rpmbuildđọc spec + source tarball để tạo ra.rpm.%prep,%build,%install,%files- 4 section cốt lõi của spec file, tương ứng đúng 4 giai đoạn: chuẩn bị source → compile → "install" vào thư mục tạm (buildroot) → khai báo file nào thuộc package.
Thực hành và quan sát
- Viết spec file đơn giản cho 1 script bash của bạn (không cần compile),
rpmbuild -bb file.spec, cài thử package vừa build.
- Viết spec file đơn giản cho 1 script bash của bạn (không cần compile),
Advanced concepts
%post/%postunscriptlet - script chạy tự động sau khi cài/gỡ package (VD tự tạo systemd service, tự enable) - hiểu cơ chế này giải thích vì sao 1 số package "tự cấu hình" sau khi cài mà không cần bạn làm gì thêm.
Ngày 5: Ôn tập tuần 3
- Mini-project: dựng 1 VM có user đăng nhập qua SSSD (giả lập hoặc LDAP test server), đồng thời tự build + ký (GPG) + publish 1 RPM package lên repo nội bộ tự dựng, cài package đó qua
dnftừ chính repo này.
Ngày 6: Buffer/đọc thêm
- Đọc tài liệu chính thức Red Hat về
realmd/sssdđể mở rộng hiểu biết ngoài phạm vi lab.
Tuần 4: systemd
Ngày 1: Unit & Target
Cơ chế
systemd thay thế SysV init: parallel startup (không tuần tự), dependency-based thay vì runlevel cứng.
Unit types:
.service,.socket,.mount,.target,.timer- target là "tập hợp unit", tương đương runlevel cũ nhưng linh hoạt hơn.
Thực hành và quan sát
systemctl status/start/stop/enable/disable,systemctl list-units --type=service.systemctl get-default, đổi default target giữamulti-user.targetvàgraphical.target.
Advanced concepts
systemd-analyze blame- đo thời gian boot của từng service, tìm bottleneck.
Ngày 2: journald
Cơ chế
journald lưu log dạng binary có cấu trúc (không phải text thuần như syslog cũ) - cho phép query structured (theo field:
_PID,_SYSTEMD_UNIT...).Volatile (RAM,
/run/log/journal) vs persistent (/var/log/journal) storage.
Thực hành và quan sát
journalctl -u <service>,--since,-p err,-f(follow, giốngtail -f).journalctl -o json-prettyxem cấu trúc field thật của 1 log entry.
Advanced concepts
journalctl --disk-usage,SystemMaxUse=trongjournald.conf- giới hạn dung lượng log tránh full disk.
Ngày 3: Viết Service Unit
Cơ chế
Type=simplevsType=forkingvsType=oneshot- vì sao systemd cần biết process có tự fork ra background hay không để track đúng PID chính.ExecStart,ExecStop,ExecReload,WorkingDirectory,User=/Group=(chạy service không cần root).
Thực hành và quan sát
- Viết 1 unit file service chạy script Python/bash, chạy dưới user riêng (không phải root).
Advanced concepts
Restart=on-failure,RestartSec=- test bằng cách kill process, quan sát systemd tự restart.
Ngày 4: Timer Unit & Dependency
Cơ chế
Timer unit thay cron:
OnCalendar=(giống cron expression nhưng dễ đọc hơn) vsOnBootSec=/OnUnitActiveSec=(relative timer).After=,Before=,Requires=,Wants=- phân biệt ordering (After/Before) vs dependency thật (Requires/Wants: nếu Requires fail thì unit này cũng fail, Wants thì không).
Thực hành và quan sát
- Viết timer unit chạy script mỗi 5 phút, so sánh với crontab tương đương.
Advanced concepts
systemd-run --on-calendar=... --unit=test- chạy 1 lệnh theo timer mà không cần viết file unit.
Ngày 5: Resource control qua systemd (cầu nối sang cgroups)
Cơ chế
systemd tự động tạo cgroup cho mỗi unit - đây là cách RHEL8+ quản lý resource limit hiện đại, thay
ulimit.CPUQuota=,MemoryMax=,TasksMax=trong unit file - set trực tiếp không cần biết cgroup filesystem thủ công.
Thực hành và quan sát
Thêm
MemoryMax=100Mvào service tự viết, viết chương trình cố tình ăn nhiều RAM, quan sát bị OOM-kill đúng giới hạn.systemd-cgtop- xem resource usage theo từng cgroup/unit real-time.
Advanced concepts
systemctl set-property <unit> CPUQuota=50%- đổi giới hạn resource runtime, không cần restart service.
Ngày 6: Socket activation
Cơ chế
Socket activation: systemd tự mở port thay cho app, chỉ thực sự khởi động process khi có connection đầu tiên đến - app không cần tự gọi
bind()/listen(), systemd truyền sẵn file descriptor đã bind cho nó.Lợi ích thật: khởi động server nhanh hơn (port sẵn sàng ngay cả khi app chưa load xong - connection được queue chờ), parallel boot tốt hơn (không cần chờ đúng thứ tự service A phải chạy trước service B nếu B chỉ cần port của A đã mở), và app có thể được restart mà không mất connection đang chờ (port vẫn do systemd giữ).
Thực hành và quan sát
Viết 1
.socketunit +.serviceunit tương ứng, app nhận file descriptor từ systemd (sd_listen_fds()hoặc đơn giản hơn: dùng socat/inetd-style demo) thay vì tự bind port.Test: dừng service, gửi request tới port đó - quan sát systemd tự khởi động service khi có connection đến (thay vì connection refused).
Advanced concepts
- Đây chính là cơ chế
sshdcó thể dùng (dù mặc định RHEL chạy sshd thường trực, không socket-activated) và là cơ chế D-Bus dùng triệt để - hiểu nó giúp giải thích vì sao nhiều service hệ thống "luôn sẵn sàng" dù process thực tế chưa chạy.
- Đây chính là cơ chế
Ngày 7: Ôn tập tuần 4
- Service của bạn: tự restart khi crash, chạy dưới user riêng, có giới hạn memory qua cgroup, có timer trigger định kỳ.
Tuần 5: Process management
Ngày 1: ps & process state
Cơ chế
Process state:
R(running),S(sleeping, interruptible),D(uninterruptible sleep - thường đang chờ I/O, không kill được bằng SIGKILL),Z(zombie),T(stopped).VSZ(virtual memory size) vsRSS(resident set size - phần thực sự nằm trong RAM) - vì sao VSZ luôn lớn hơn RSS nhiều.
Thực hành và quan sát
ps aux,ps -ef, đọc từng cột, so sánh VSZ/RSS của vài process khác nhau.
Advanced concepts
- Tự tạo 1 process ở state
D(VDddđọc từ device chậm) - hiểu vì sao đây là dấu hiệu I/O bottleneck khi troubleshoot production.
- Tự tạo 1 process ở state
Ngày 2: Signals
Cơ chế
Signal là cơ chế kernel gửi thông báo bất đồng bộ tới process - mỗi signal có default action (terminate, ignore, core dump, stop).
SIGTERM (có thể catch, cho process dọn dẹp trước khi thoát) vs SIGKILL (kernel force kill ngay, process không kịp làm gì) vs SIGHUP (truyền thống: terminal đóng, nay thường dùng để reload config).
Thực hành và quan sát
kill -lxem toàn bộ danh sách signal, thử SIGTERM vs SIGKILL vs SIGHUP trên 1 process demo (viết signal handler bằng bashtrap).
Advanced concepts
- Vì sao process ở state
Dkhông phản hồi SIGKILL - signal chỉ được deliver khi process quay lại từ kernel-space (uninterruptible sleep nghĩa là đang trong 1 syscall kernel không cho phép ngắt).
- Vì sao process ở state
Ngày 3: Job control
Cơ chế
Foreground/background job, process group, controlling terminal - vì sao
Ctrl+Cchỉ gửi SIGINT tới foreground process group.nohup- chặn SIGHUP khi terminal đóng, giữ process sống.
Thực hành và quan sát
&,jobs,fg/bg,nohup command &,disown.
Advanced concepts
setsid- tạo session mới hoàn toàn tách khỏi terminal (dùng khi viết daemon thủ công không qua systemd).
Ngày 4: nice/priority & process tree
Cơ chế
nicevalue (-20 đến 19) ảnh hưởng đến weight trong CFS scheduler (chi tiết học sâu ở Phase 3) - nice thấp hơn = ưu tiên CPU cao hơn.Process tree: mọi process (trừ PID 1) đều có parent - khi parent chết trước, child bị "reparent" cho PID 1 (hoặc subreaper).
Thực hành và quan sát
nice/renice,pstree -pquan sát cây process thật.
Advanced concepts
- Tự tạo 1 zombie process (parent không gọi
wait()) - quan sát bằngpsstateZ, giải thích vì sao zombie không tốn RAM/CPU nhưng vẫn chiếm 1 PID slot.
- Tự tạo 1 zombie process (parent không gọi
Ngày 5: /proc - soi process sống
Cơ chế
/proc/<pid>/chứa toàn bộ thông tin runtime của 1 process, do kernel expose trực tiếp (không phải file thật trên disk).
Thực hành và quan sát
/proc/<pid>/status(memory, state, thread),/proc/<pid>/cmdline,/proc/<pid>/environ,/proc/<pid>/fd/(danh sách file descriptor đang mở).
Advanced concepts
/proc/<pid>/limits- xem toàn bộ resource limit áp dụng cho process đó (ulimit + cgroup limit gộp lại).
Ngày 6: Ôn tập tuần 4
- Viết script daemon hóa 1 process thủ công bằng
setsid+ xử lý signal đúng cách trong bash (trap 'cleanup' SIGTERM SIGINT).
Ngày 7 (mới): strace & ltrace nhập môn
Cơ chế
stracedùngptrace()để intercept mọi syscall của process - cùng cơ chế GDB dùng để attach (sẽ học kỹ ở Tuần 18), nhưng mục đích là log thay vì debug tương tác.ltraceintercept library call (hàm libc nhưmalloc,strcpy) thay vì syscall - tầng cao hơn strace.
Thực hành và quan sát
strace ls- đọc output, nhận diệnopen,read,write,close,exit_group.strace -c <cmd>- thống kê số lần gọi + thời gian mỗi loại syscall, tìm syscall tốn thời gian nhất.
Advanced concepts
strace -f -p <PID>- attach vào process đang chạy (kể cả child fork ra sau), dùng để debug "tại sao service bị treo" mà không cần restart nó - kỹ năng troubleshooting production cực kỳ thực tế, học sớm để dùng xuyên suốt các phase sau (không cần đợi tới Phase 3 Internals mới biết công cụ này tồn tại).
Tuần 6: Networking cơ bản + review Phase 1
Ngày 1: Địa chỉ IP & Interface
Cơ chế
ip addrthayifconfig- vì sao (ifconfigthuộc bộnet-toolscũ, không hỗ trợ tính năng mạng hiện đại như VRF, network namespace).CIDR notation -
/24nghĩa là gì, cách tính network address/broadcast address từ IP + subnet mask.
Thực hành và quan sát
ip addr show,ip route show, gán thêm 1 IP phụ vào interface.
Advanced concepts
- Subnetting thực hành: chia 1 mạng
/24thành 4 mạng/26, tính toán network/broadcast/usable range cho từng subnet.
- Subnetting thực hành: chia 1 mạng
Ngày 2: Routing table
Cơ chế
Kernel routing table quyết định packet đi ra interface nào - longest prefix match (route cụ thể nhất thắng, không phải route đầu tiên khớp).
Default gateway là 1 route đặc biệt (
0.0.0.0/0).
Thực hành và quan sát
ip route show, thêm 1 static route thủ công giữa 2 VM (ip route add ... via ...).
Advanced concepts
ip route get <IP>- hỏi kernel "packet tới IP này sẽ đi theo route nào" mà không cần gửi thật, rất hữu ích khi debug routing phức tạp.
Ngày 3: DNS resolution
Cơ chế
/etc/resolv.conf,/etc/nsswitch.conf- thứ tự resolve (files trước hay DNS trước)./etc/hostsoverride cục bộ.
Thực hành và quan sát
dig,host,getent hosts- so sánh 3 công cụ, hiểugetentđi qua NSS (tôn trọng/etc/hosts+ cache), còndigquery DNS server trực tiếp bỏ qua NSS.
Advanced concepts
dig +trace- xem toàn bộ quá trình resolve từ root DNS server xuống tới authoritative server.
Ngày 4: TCP state & ss
Cơ chế
TCP 3-way handshake (SYN → SYN-ACK → ACK), 4-way close (FIN/ACK).
TCP state machine:
LISTEN,SYN_SENT,ESTABLISHED,TIME_WAIT(vì sao tồn tại - tránh packet cũ của connection trước lẫn vào connection mới).
Thực hành và quan sát
ss -tulnp(thaynetstat), đọc từng state, đếm số connection ởTIME_WAITtrên 1 server thật.
Advanced concepts
net.ipv4.tcp_tw_reuse- sysctl tuning liên quan TIME_WAIT, khi nào cần chỉnh trong production (server nhiều short-lived connection).
Ngày 5: firewalld cơ bản
Cơ chế
- Zone-based firewall: mỗi interface thuộc 1 zone (
public,internal,trusted...), mỗi zone có policy riêng - khác iptables truyền thống (chain tuyến tính).
- Zone-based firewall: mỗi interface thuộc 1 zone (
Thực hành và quan sát
firewall-cmd --list-all, mở 1 port cụ thể (--add-port=8080/tcp --permanent), reload.
Advanced concepts
firewall-cmd --get-active-zones- xem interface nào đang thuộc zone nào, quan trọng khi server có nhiều NIC (VD 1 NIC public, 1 NIC internal).
Ngày 6: Mini-project 1 - Review toàn bộ Phase 1
Cài đặt 1 VM sạch từ đầu, tạo 3 user với permission/capabilities hợp lý, 1 service tự viết chạy bằng systemd (có giới hạn memory qua cgroup), mở đúng 1 port qua firewalld, ghi log ra journald, verify bằng
ss+journalctl.Không nhìn lại note.
Phase 2 - Kỹ năng Production (10 tuần)
Tuần 7-8: Storage & LVM
Ngày 1: Partition table
Cơ chế
- MBR (giới hạn 2TB, 4 partition primary) vs GPT (không giới hạn thực tế, có backup header) - vì sao RHEL hiện đại mặc định GPT.
Thực hành và quan sát
fdisk/partedtạo partition mới trên disk ảo thêm vào VM.
Advanced concepts
partprobe- báo kernel đọc lại partition table mà không cần reboot.
Ngày 2: LVM - Physical Volume
Cơ chế
- LVM thêm 1 lớp abstraction giữa disk vật lý và filesystem: PV (Physical Volume) → VG (Volume Group, gộp nhiều PV) → LV (Logical Volume, cắt ra từ VG) - cho phép resize linh hoạt không bị giới hạn bởi ranh giới disk vật lý.
Thực hành và quan sát
pvcreate,pvdisplaytrên disk ảo mới thêm.
Advanced concepts
- PE (Physical Extent) - đơn vị cấp phát nhỏ nhất trong LVM (mặc định 4MB), mọi resize đều theo bội số PE.
Ngày 3: Volume Group & Logical Volume
Cơ chế
- VG là "pool" dung lượng gộp từ nhiều PV - LV được cắt ra từ pool này, có thể nằm rải rác trên nhiều disk vật lý khác nhau (linear, striped, hoặc mirrored).
Thực hành và quan sát
vgcreate,lvcreate, format xfs, mount thủ công.
Advanced concepts
lvcreate --type striped- striping qua nhiều disk để tăng throughput (giống RAID 0 ở tầng LVM).
Ngày 4: fstab & persistent mount
Cơ chế
- UUID vs device path (
/dev/sda1) trong/etc/fstab- vì sao dùng UUID (device path có thể đổi thứ tự giữa các lần boot nếu thêm/bớt disk).
- UUID vs device path (
Thực hành và quan sát
- Thêm entry vào
/etc/fstab, test bằngmount -a, reboot thật để verify không lỗi (lỗi fstab là nguyên nhân phổ biến khiến server không boot được).
- Thêm entry vào
Advanced concepts
nofailoption - tránh boot bị treo nếu 1 mount point (VD network storage) không sẵn sàng lúc boot.
Ngày 5: Resize LV không downtime
Cơ chế
- xfs hỗ trợ online grow (mở rộng khi đang mount) nhưng không hỗ trợ shrink - khác ext4 (hỗ trợ cả hai nhưng phải unmount để shrink).
Thực hành và quan sát
lvextend+xfs_growfs(không cần unmount) - thực hành mở rộng dung lượng trong khi service vẫn chạy.
Advanced concepts
- Giải thích vì sao production luôn ưu tiên "chỉ grow, không shrink" - thiết kế capacity dư ra từ đầu thay vì phụ thuộc shrink.
Ngày 6: Swap
Cơ chế
- Swap là vùng disk dùng làm "RAM ảo" khi RAM vật lý đầy - kernel chọn page ít dùng nhất để swap out (liên quan LRU, học sâu ở Phase 3).
Thực hành và quan sát
- Tạo swap file (
fallocate+mkswap+swapon) và swap partition, so sánh cách cấu hình.
- Tạo swap file (
Advanced concepts
vm.swappinesssysctl - điều chỉnh mức độ "sẵn sàng swap" của kernel (0-100), production DB server thường set thấp để ưu tiên giữ data trong RAM.
Ngày 7 (tuần 7 ngày 1): LVM Snapshot
Cơ chế
- Snapshot dùng copy-on-write: khi tạo snapshot, không copy toàn bộ data ngay - chỉ khi block gốc bị ghi đè, block cũ mới được copy sang snapshot (tiết kiệm dung lượng).
Thực hành và quan sát
lvcreate --snapshot, ghi thêm data vào LV gốc, so sánh nội dung snapshot vs LV gốc, thử rollback (lvconvert --merge).
Advanced concepts
- Snapshot đầy (hết dung lượng dành riêng cho nó) sẽ tự động invalid - hiểu rủi ro này trước khi dùng snapshot làm backup thật trong production.
Ngày 8: xfs vs ext4
Cơ chế
- xfs: tối ưu cho file lớn, parallel I/O tốt hơn (RHEL mặc định từ RHEL7). ext4: journal đơn giản hơn, hỗ trợ shrink, phổ biến hơn ngoài RHEL ecosystem.
Thực hành và quan sát
xfs_info,tune2fs -l(ext4) - đọc metadata filesystem.
Advanced concepts
- Journaling mode của ext4 (
data=orderedmặc định vsdata=journal- full journal chậm hơn nhưng an toàn hơn khi crash).
- Journaling mode của ext4 (
Ngày 9: Ôn tập LVM full flow
- Thêm ổ đĩa mới vào VM đang chạy → PV → extend VG → extend LV → grow filesystem - toàn bộ không downtime.
Ngày 10: Checkpoint
- Viết note giải thích LVM cho người mới (dùng đúng thuật ngữ PV/VG/LV/PE), tự đánh giá độ hiểu bằng cách không nhìn tài liệu.
Tuần 9-10: Networking
Ngày 1 (T8): NetworkManager
Cơ chế
- NetworkManager quản lý connection profile (không phải interface trực tiếp) - 1 interface có thể có nhiều profile, switch qua lại.
Thực hành và quan sát
nmcli con add/mod/up/down, set static IP qua nmcli (không sửa file trực tiếp).
Advanced concepts
nmcli con show <name>- xem toàn bộ property của 1 connection profile, so sánh với file backing thật trong/etc/NetworkManager/system-connections/.
Ngày 2: Bonding & Teaming
Cơ chế
- Bonding: gộp nhiều NIC vật lý thành 1 interface logic - mode
active-backup(failover) vs802.3ad/LACP (load balancing thật, cần switch hỗ trợ).
- Bonding: gộp nhiều NIC vật lý thành 1 interface logic - mode
Thực hành và quan sát
- Tạo bond interface từ 2 NIC ảo trong VM (mode active-backup), test failover bằng cách down 1 NIC.
Advanced concepts
- Vì sao LACP cần cấu hình đồng bộ ở switch - nếu chỉ cấu hình phía server mà switch không hỗ trợ, bonding sẽ không hoạt động đúng.
Ngày 3: VLAN
Cơ chế
- VLAN tag (802.1Q) cho phép nhiều mạng logic chạy chung 1 hạ tầng vật lý - trunk port mang nhiều VLAN, access port chỉ 1 VLAN.
Thực hành và quan sát
- Tạo VLAN interface (
ip link add link eth0 name eth0.100 type vlan id 100), test connectivity.
- Tạo VLAN interface (
Advanced concepts
- Vì sao VLAN là nền tảng để hiểu network isolation trong container/k8s sau này (mỗi namespace network tương tự về mặt khái niệm cô lập).
Ngày 4: nftables
Cơ chế
- nftables thay iptables (RHEL9+ mặc định): 1 framework thống nhất thay vì 4 công cụ riêng (iptables/ip6tables/arptables/ebtables). Table → chain → rule.
Thực hành và quan sát
nft list ruleset, viết 1 table/chain custom chặn 1 IP cụ thể.
Advanced concepts
nftset - nhóm nhiều IP/port vào 1 set để rule gọn hơn, update động không cần reload toàn bộ ruleset (khác iptables cũ).
Ngày 5: firewalld + nftables backend
Cơ chế
- firewalld trên RHEL9+ dùng nftables làm backend (trước đó là iptables) - firewalld là lớp abstraction cao hơn, nft là cơ chế thực thi thật bên dưới.
Thực hành và quan sát
firewall-cmd --directđể chèn rule nft thô khi zone-based không đủ linh hoạt.
Advanced concepts
nft list rulesetsau khi cấu hình firewalld - đối chiếu để hiểu firewalld dịch config của nó thành nft rule cụ thể như thế nào.
Ngày 6: Ôn tập T8
- 2 VM, firewall chỉ mở đúng port cần dùng nftables trực tiếp, verify bằng
tcpdump.
Ngày 7 (T9): tcpdump & packet analysis
Cơ chế
tcpdumpcapture packet ở tầng kernel (dùnglibpcap/AF_PACKET socket) trước khi bị firewall lọc hoặc sau - filter expression BPF (Berkeley Packet Filter).
Thực hành và quan sát
tcpdump -i eth0 port 80 -w capture.pcap, đọc output cơ bản (SYN/ACK flag).
Advanced concepts
- Capture ở 2 điểm khác nhau (client + server) cùng lúc - kỹ thuật debug "packet có đến nơi không" kinh điển trong production networking.
Ngày 8: Network namespace
Cơ chế
- Network namespace: mỗi namespace có bảng routing, interface, firewall rule hoàn toàn riêng - đây chính là nền tảng networking của container.
Thực hành và quan sát
ip netns add test1, tạo veth pair nối namespace với host, cấu hình IP, test ping qua lại.
Advanced concepts
- Đây là bài tập quan trọng nhất tuần: hiểu network namespace = hiểu cách Docker/Podman tạo network riêng cho mỗi container mà không cần VM thật.
Ngày 9: DNS server thật (BIND hoặc unbound cơ bản)
Cơ chế
- Recursive resolver vs authoritative server - vì sao 1 DNS server công ty thường chỉ làm resolver (forward ra ngoài) chứ không authoritative cho domain public.
Thực hành và quan sát
- Cài
unboundhoặcbind, cấu hình forward zone đơn giản, test resolve qua server tự dựng.
- Cài
Advanced concepts
- DNS caching TTL - vì sao đổi DNS record không có hiệu lực ngay lập tức trên toàn mạng.
Ngày 10: chrony & time sync
Cơ chế
Time drift: đồng hồ phần cứng server luôn trôi dần theo thời gian (crystal oscillator không hoàn hảo) - nếu không đồng bộ, chênh lệch tích lũy vài giây tới vài phút sau nhiều ngày.
Vì sao lệch giờ gây sự cố nghiêm trọng: Kerberos ticket có timestamp check (lệch >5 phút mặc định là auth fail ngay), TLS certificate validation dựa vào thời gian hệ thống, log correlation giữa nhiều server sai lệch làm troubleshooting gần như bất khả thi, distributed database (etcd, Cassandra...) có thể corrupt data nếu lệch giờ nghiêm trọng.
chrony (thay
ntpdcũ trên RHEL hiện đại): đồng bộ nhanh hơn, xử lý tốt hơn với mạng không ổn định hoặc VM (VM thường có clock drift lớn hơn máy vật lý do CPU steal time).
Thực hành và quan sát
chronyc sources -v- xem nguồn NTP đang dùng, độ lệch hiện tại.chronyc tracking- xem chi tiết offset, đồng hồ hệ thống đang nhanh/chậm bao nhiêu.Cố tình đổi giờ hệ thống sai (
date -s), quan sát chrony tự điều chỉnh dần (không nhảy đột ngột - tránh phá vỡ ứng dụng dựa vào thời gian đơn điệu tăng).
Advanced concepts
makesteptrongchrony.conf- cấu hình khi nào chrony được phép "nhảy" giờ đột ngột (VD chỉ lúc boot) thay vì luôn điều chỉnh từ từ - quan trọng vì nhảy giờ đột ngột giữa lúc service đang chạy có thể gây lỗi logic (VD lock timeout tính sai).
Ngày 11: Mini-project - Network troubleshooting layer-by-layer
- Giả lập lỗi network (sai route, sai firewall rule, sai DNS) trên 2 VM, tự chẩn đoán bằng cách đi từng layer:
ip addr(L2/L3 config đúng chưa) →ip route→ping(L3 connectivity) →ss/nc(L4 port) →curl/dig(L7). Không hint.
Tuần 11: SELinux
Ngày 1: MAC vs DAC
Cơ chế
DAC (Discretionary Access Control - permission rwx truyền thống): owner tự quyết định ai được access. MAC (Mandatory Access Control - SELinux): policy hệ thống quyết định, owner không override được.
Vì sao đây là lớp bảo vệ thứ 2 quan trọng: dù 1 process bị exploit và có quyền root, SELinux policy vẫn có thể chặn nó làm việc ngoài phạm vi được định nghĩa.
Thực hành và quan sát
getenforce,sestatus- xem mode hiện tại (Enforcing/Permissive/Disabled).
Advanced concepts
- Vì sao tuyệt đối không nên
setenforce 0trong production để "cho nhanh" - đây là thói quen sai phổ biến nhất khi mới học SELinux.
- Vì sao tuyệt đối không nên
Ngày 2: Security Context
Cơ chế
- Context format:
user:role:type:level- trong đó type (VDhttpd_sys_content_t) là phần quan trọng nhất, quyết định policy áp dụng.
- Context format:
Thực hành và quan sát
ls -Z,ps -Z- xem context của file và process.
Advanced concepts
- Type Enforcement: policy định nghĩa "type nào của process được phép access type nào của file/resource" - đây là core mechanism, không phải theo user như DAC.
Ngày 3: Context mismatch thực tế
Cơ chế
- Khi copy file vào thư mục mới, context không tự đổi theo thư mục trừ khi dùng
mvtrong cùng filesystem hoặc explicit relabel - đây là nguyên nhân phổ biến nhất gây lỗi "403 do SELinux" dù permission rwx đúng.
- Khi copy file vào thư mục mới, context không tự đổi theo thư mục trừ khi dùng
Thực hành và quan sát
- Đổi web root sang thư mục custom, copy file HTML vào, quan sát lỗi 403 dù chmod đúng.
Advanced concepts
cp -Zvscpthường - so sánh context của file sau copy.
Ngày 4: Đọc AVC denial
Cơ chế
- AVC (Access Vector Cache) denial được ghi vào audit log mỗi khi SELinux chặn 1 hành động - đây là "bằng chứng" để fix đúng thay vì đoán mò.
Thực hành và quan sát
ausearch -m avc -ts recent,sealert -a /var/log/audit/audit.log(đọc gợi ý fix bằng ngôn ngữ tự nhiên).
Advanced concepts
audit2allow -a- sinh policy module tùy chỉnh từ log denial (dùng cẩn thận, chỉ khi hiểu rõ denial đó có hợp lý hay không).
Ngày 5: Fix đúng cách
Cơ chế
semanage fcontextđịnh nghĩa rule context cho 1 path pattern (persistent qua relabel), cònchconchỉ đổi context tạm thời (mất khi relabel toàn hệ thống).
Thực hành và quan sát
semanage fcontext -a -t httpd_sys_content_t "/custom/web(/.*)?", sau đórestorecon -Rv /custom/webđể áp dụng.
Advanced concepts
- Boolean SELinux (
getsebool -a,setsebool) - bật/tắt 1 nhóm hành vi cụ thể (VDhttpd_can_network_connect) mà không cần viết policy module riêng.
- Boolean SELinux (
Ngày 6: Viết SELinux policy module từ đầu
Cơ chế
- Khác
audit2allow(sinh policy từ log denial - reactive, dễ tạo policy quá rộng nếu không kiểm tra kỹ), viết policy module thủ công (.tefile - Type Enforcement) cho phép định nghĩa chính xác type mới + rule allow cụ thể ngay từ đầu - cách làm đúng chuẩn khi phát triển 1 ứng dụng cần chạy dưới SELinux enforcing với custom behavior.
- Khác
Thực hành và quan sát
Viết 1 file
.teđơn giản định nghĩa 1 type mới cho ứng dụng tự viết (VDmyapp_t), rule cho phép nó network connect + đọc 1 thư mục cụ thể.checkmodule,semodule_package,semodule -i- quy trình compile và install policy module.
Advanced concepts
- So sánh policy bạn viết thủ công (chỉ đúng rule cần thiết) với policy
audit2allowsinh ra tự động (thường quá rộng vì chỉ dựa trên denial log, không hiểu ý định thật của ứng dụng) - đây là lý do các RHEL policy chính thức (selinux-policypackage) luôn viết tay bởi maintainer, không sinh tự động.
- So sánh policy bạn viết thủ công (chỉ đúng rule cần thiết) với policy
Ngày 7: Ôn tập tuần 11
- Dựng service custom port + custom web root, để SELinux chặn tự nhiên, tự fix bằng đúng quy trình: đọc AVC →
semanage fcontext→restorecon→ verify, không dùngsetenforce 0.
Tuần 12: cgroups - Resource Control
Ngày 1: Khái niệm cgroup & cgroup v1 vs v2
Cơ chế
cgroup (control group) là cơ chế kernel nhóm các process lại để giới hạn/đo lường resource (CPU, memory, I/O, số lượng process) - đây chính là nền tảng mà container (Docker/Podman) dùng để cô lập resource, không phải namespace (namespace lo việc cô lập "nhìn thấy gì", cgroup lo việc "được dùng bao nhiêu").
cgroup v1: mỗi controller (cpu, memory...) có hierarchy riêng, phức tạp khi quản lý đồng thời. cgroup v2 (mặc định RHEL8+/9): unified hierarchy - 1 cây duy nhất cho tất cả controller, đơn giản và nhất quán hơn nhiều.
Thực hành và quan sát
mount | grep cgroup- xem cgroup v2 mount ở đâu (/sys/fs/cgroup).cat /sys/fs/cgroup/cgroup.controllers- danh sách controller khả dụng.
Advanced concepts
systemdchính là cgroup v2 manager mặc định trên RHEL hiện đại - mọi service systemd tự động có 1 cgroup riêng (đã chạm ở Tuần 4 Ngày 5, giờ đào sâu cơ chế thật).
Ngày 2: CPU controller
Cơ chế
cpu.max(cgroup v2): giới hạn CPU time trong 1 chu kỳ (VD50000 100000= 50% của 1 core).cpu.weight: phân bổ CPU tương đối giữa các cgroup khi tranh chấp tài nguyên (kháccpu.maxlà giới hạn tuyệt đối).
Thực hành và quan sát
- Tạo 1 cgroup thủ công (
mkdir /sys/fs/cgroup/mytest), thêm PID của 1 chương trình stress-CPU tự viết vàocgroup.procs, setcpu.max, quan sát bằngtop- CPU usage bị giới hạn đúng %.
- Tạo 1 cgroup thủ công (
Advanced concepts
- So sánh
cpu.max(hard limit, throttle cứng) vớinice/priority (chỉ ảnh hưởng khi có tranh chấp, không giới hạn tuyệt đối) - 2 cơ chế hoàn toàn khác nhau dù cùng liên quan đến CPU.
- So sánh
Ngày 3: Memory controller
Cơ chế
memory.max: hard limit, process bị OOM-kill nếu vượt quá - khácmemory.high: soft limit, kernel sẽ throttle/reclaim memory trước, không kill ngay.memory.current,memory.stat- breakdown chi tiết loại memory đang dùng (anon, file cache, kernel stack...).
Thực hành và quan sát
- Viết chương trình C nhỏ liên tục
mallockhông giới hạn, chạy trong cgroup cómemory.max=50M, quan sát bị kill và log trongdmesg.
- Viết chương trình C nhỏ liên tục
Advanced concepts
memory.oom.group- khi bật, toàn bộ process trong cgroup bị kill cùng lúc khi OOM (thay vì chỉ 1 process) - dùng khi các process trong cùng cgroup phụ thuộc lẫn nhau (VD multi-process app).
Ngày 4: I/O & PIDs controller
Cơ chế
io.max: giới hạn throughput đọc/ghi (BPS) hoặc IOPS theo từng device, tránh 1 process "nuốt" hết I/O bandwidth ảnh hưởng process khác trên cùng disk.pids.max: giới hạn số process/thread tối đa trong cgroup - chống fork-bomb hiệu quả hơnulimit -utruyền thống (ulimit áp dụng per-user, dễ bị bypass bằng cách chạy nhiều session).
Thực hành và quan sát
- Set
pids.max=10, thử chạy fork-bomb (:(){ :|:& };:) trong cgroup đó - quan sát nó bị chặn ngay thay vì làm treo cả server.
- Set
Advanced concepts
- So sánh mức độ an toàn: fork-bomb ngoài cgroup có thể làm treo toàn bộ VM; fork-bomb trong cgroup có
pids.maxchỉ crash trong phạm vi cgroup đó.
- So sánh mức độ an toàn: fork-bomb ngoài cgroup có thể làm treo toàn bộ VM; fork-bomb trong cgroup có
Ngày 5: systemd + cgroup - resource control thực chiến
Cơ chế
- Ôn lại và đào sâu Tuần 4 Ngày 5:
systemd-cgtop,systemctl status <unit>hiện luôn cgroup path - mọiMemoryMax=/CPUQuota=trong unit file chính là wrapper của cgroup filesystem operation vừa học thủ công.
- Ôn lại và đào sâu Tuần 4 Ngày 5:
Thực hành và quan sát
systemd-cgls- xem toàn bộ cây cgroup của hệ thống (mọi service, mọi user session, mọi container nếu có).Tạo 1 slice riêng (
systemctl edit --force myapp.slice) để nhóm nhiều service con vào 1 giới hạn resource chung.
Advanced concepts
- Liên hệ trực tiếp tới container: khi chạy
podman run --memory=100m, Podman thực chất tạo 1 cgroup vớimemory.max=100m- không có "phép màu" nào khác, chỉ là cùng cơ chế bạn vừa làm thủ công.
- Liên hệ trực tiếp tới container: khi chạy
Ngày 6: Ôn tập tuần 11
- Mini-project: viết 1 service systemd chạy app tự viết, giới hạn đồng thời CPU (
cpu.maxquaCPUQuota=), memory (memory.maxquaMemoryMax=), và số process con (pids.maxquaTasksMax=) - verify từng giới hạn bằng cách cố tình vượt ngưỡng và quan sát hành vi kernel.
Tuần 13: Logging & Backup
Ngày 1: rsyslog
Cơ chế
- rsyslog là syslog daemon hiện đại - hỗ trợ filter theo facility/priority, forward log qua TCP/UDP tới server tập trung (centralized logging).
Thực hành và quan sát
- Cấu hình rsyslog forward log sang 1 VM khác (đóng vai trò log server).
Advanced concepts
RELPprotocol - reliable log forwarding (đảm bảo không mất log ngay cả khi network gián đoạn tạm thời), khác UDP syslog truyền thống có thể mất packet.
Ngày 2: journald persistent & giới hạn
Cơ chế
Storage=persistenttrongjournald.conf- quyết định log sống sót qua reboot hay không.
Thực hành và quan sát
SystemMaxUse=,SystemKeepFree=- giới hạn dung lượng, test bằng cách generate log lớn.
Advanced concepts
journalctl --vacuum-size=500M- chủ động dọn log cũ, dùng trong script maintenance định kỳ.
Ngày 3: logrotate
Cơ chế
- logrotate dùng cho log của app không qua journald (VD app tự ghi file log riêng) - rotate theo size hoặc thời gian, có thể nén, giữ N bản cũ.
Thực hành và quan sát
- Viết config
/etc/logrotate.d/myappcho app tự viết, test bằnglogrotate -f.
- Viết config
Advanced concepts
postrotatescript - gửi signal cho app reload file handle sau khi rotate (nhiều app giữ file descriptor cũ nếu không được báo).
Ngày 4: Chiến lược backup
Cơ chế
rsyncdùng delta algorithm - chỉ transfer phần thay đổi của file, không copy toàn bộ mỗi lần (kháccp/tarfull copy).tarincremental (--listed-incremental) - backup đầy đủ lần đầu, sau đó chỉ backup phần thay đổi.
Thực hành và quan sát
rsync -avz --deletegiữa 2 VM,tarincremental backup 2 lần liên tiếp, so sánh dung lượng.
Advanced concepts
rsync --dry-run- luôn test trước khi chạy lệnh có--delete(xóa file đích không có ở nguồn) trong production.
Ngày 5: Script backup tự động + test restore
Thực hành
Viết script backup + systemd timer chạy định kỳ.
Test restore thật - quan trọng hơn cả việc backup, vì backup không test restore = không backup.
Advanced concepts
- Backup 3-2-1 rule: 3 bản copy, 2 loại media khác nhau, 1 bản off-site - nguyên tắc kinh điển dù đơn giản.
Ngày 6: Ôn tập - Mini disaster recovery
- Giả lập mất dữ liệu (xóa nhầm thư mục quan trọng), restore từ backup, đo thời gian recovery (RTO - Recovery Time Objective).
Tuần 14: Container Primitives
Ngày 1: chroot
Cơ chế
chrootđổi root directory (/) mà 1 process nhìn thấy - process bên trong không thể truy cập file ngoài thư mục chroot (về mặt path resolution), nhưng không cô lập process ID, network, hay user (đây chỉ là 1 phần rất nhỏ của "container thật").Giới hạn bảo mật nổi tiếng: chroot không phải security boundary hoàn chỉnh - process có quyền root bên trong chroot vẫn có thể "thoát" ra ngoài bằng nhiều kỹ thuật (đây là lý do container thật cần thêm namespace + capabilities).
Thực hành và quan sát
- Tạo 1 thư mục chứa mini root filesystem (copy
/bin/bash+ thư viện cần thiết bằnglddđã học),chrootvào đó, quan sátls /chỉ thấy nội dung thư mục con.
- Tạo 1 thư mục chứa mini root filesystem (copy
Advanced concepts
- Thử
ps auxbên trong chroot - vẫn thấy toàn bộ process của host, chứng minh chroot không cô lập PID (cần PID namespace, học ngày sau).
- Thử
Ngày 2: pivot_root
Cơ chế
pivot_rootkhácchroot: nó thực sự đổi root filesystem ở mức mount point (swap old root và new root), dọn sạch old root hoàn toàn khỏi tầm nhìn - đây là cơ chế container runtime thật (runc, containerd) dùng, không phảichrootđơn thuần.
Thực hành và quan sát
- Thực hành
pivot_roottrong 1 mount namespace riêng (kết hợpunsharengày sau) - quan sát old root biến mất hoàn toàn khỏi/proc/mountssau khi unmount.
- Thực hành
Advanced concepts
- Vì sao
pivot_rootyêu cầu new root phải là 1 mount point riêng biệt (không thể trực tiếp trên rootfs hiện tại) - ràng buộc kỹ thuật quan trọng khi tự viết container runtime.
- Vì sao
Ngày 3: unshare - tự tạo namespace
Cơ chế
unsharetạo 1 hoặc nhiều namespace mới cho process - ôn lại PID namespace, network namespace (đã học Tuần 10 Ngày 8, giờ dùng trực tiếp), mount namespace, UTS namespace (hostname riêng), IPC namespace, user namespace.
Thực hành và quan sát
unshare --pid --fork --mount-proc bash- vào 1 shell với PID namespace riêng,ps auxbên trong giờ chỉ thấy vài process (PID 1 là chính bash này).unshare --uts bash, đổi hostname bên trong (hostname test123) - verify hostname ngoài host không đổi.
Advanced concepts
unshare --user --map-root-user bash- user namespace: bên trong thấy mình là UID 0 (root) nhưng bên ngoài host thực chất là UID không đặc quyền - chính cơ chế Podman rootless dùng (đã nhắc ở Tuần 14 cũ, giờ thấy rõ cơ chế thật).
Ngày 4: nsenter - bước vào namespace có sẵn
Cơ chế
nsentercho phép 1 process join vào namespace đã tồn tại của process khác (ngược lại vớiunsharelà tạo namespace mới) - dùng để debug container đang chạy từ host mà không cầnexecvào qua Podman/Docker.
Thực hành và quan sát
- Tìm PID của 1 container Podman đang chạy (
podman inspect --format '{{.State.Pid}}'), dùngnsenter -t <PID> -n -pđể "bước vào" đúng network + PID namespace của nó từ host trực tiếp bằng tool Linux thuần, không quapodman exec.
- Tìm PID của 1 container Podman đang chạy (
Advanced concepts
- Đây chính xác là cách
podman exec/docker exechoạt động bên dưới - không có phép màu, chỉ là gọinsenter(hoặc syscall tương đươngsetns()) vào namespace của container process.
- Đây chính xác là cách
Ngày 5: Tự dựng "container mini"
Thực hành - dự án chính của ngày
Kết hợp toàn bộ:
unshare(PID + mount + UTS + network namespace) +pivot_root(đổi root filesystem) + cgroup thủ công (cgroup.procs+memory.max, đã học Tuần 11) +chroot/pivot_rootvào 1 rootfs mini (VD Alpine minirootfs tải sẵn) → chạy 1 process bên trong với: PID riêng, hostname riêng, filesystem riêng, giới hạn memory riêng.Đây chính là toàn bộ "công thức" của container - không dùng Podman/Docker, chỉ dùng primitive Linux thuần túy.
Advanced concepts
- So sánh độ phức tạp: bạn vừa làm bằng tay trong 1 ngày những gì
runc(low-level container runtime thật, mà Podman/Docker/Kubernetes đều dùng bên dưới) làm tự động - hiểu rõ container runtime "thật ra làm gì" chứ không phải hộp đen.
- So sánh độ phức tạp: bạn vừa làm bằng tay trong 1 ngày những gì
Ngày 6: Ôn tập tuần 13
- Viết script bash tự động hóa toàn bộ "container mini" ở Ngày 5 thành 1 lệnh duy nhất (giống 1 phiên bản
runcsiêu đơn giản của riêng bạn).
Tuần 15: Container Internals & Podman
Ngày 1: Podman vs Docker - kiến trúc
Cơ chế
Docker dùng daemon chạy nền (dockerd) với quyền root - mọi lệnh docker đều đi qua daemon này (single point of failure + security risk).
Podman daemonless: mỗi container là process con trực tiếp của lệnh
podman run, không qua daemon trung gian - dùng chính namespace + cgroup vừa học ở Tuần 10 & 12.
Thực hành và quan sát
podman info, so sánh kiến trúc bằng cách quan sátps auxkhi container đang chạy (thấy container process là con trực tiếp, không phải con của 1 daemon).
Advanced concepts
- Rootless container: Podman chạy container không cần root, dùng user namespace (UID trong container map tới UID không đặc quyền ở host) - bảo mật tốt hơn Docker truyền thống đáng kể.
Ngày 2: Container đầu tiên
Cơ chế
- Image layer: mỗi instruction trong Containerfile tạo 1 layer riêng, các layer là read-only và chia sẻ được giữa nhiều image (tiết kiệm dung lượng, tăng tốc build/pull).
Thực hành và quan sát
podman run,podman ps/logs/exec -it.
Advanced concepts
podman inspect- xem chi tiết cgroup path, namespace ID của 1 container đang chạy, đối chiếu trực tiếp với kiến thức Tuần 10/12.
Ngày 3: Containerfile
Cơ chế
- Build cache: Docker/Podman cache từng layer, chỉ rebuild từ layer bị thay đổi trở đi - vì sao thứ tự instruction trong Containerfile ảnh hưởng tốc độ build (đặt
COPYcode sauRUNinstall dependency).
- Build cache: Docker/Podman cache từng layer, chỉ rebuild từ layer bị thay đổi trở đi - vì sao thứ tự instruction trong Containerfile ảnh hưởng tốc độ build (đặt
Thực hành và quan sát
- Viết Containerfile cho app tự viết, build, quan sát cache khi build lại sau khi chỉ sửa code.
Advanced concepts
- Multi-stage build - dùng 1 stage để build, chỉ copy artifact cần thiết sang stage runtime cuối, giảm kích thước image production đáng kể.
Ngày 4: systemd + Podman
Thực hành và quan sát
podman generate systemd- tạo unit file quản lý container bằng systemd (kết hợp trực tiếp kiến thức Tuần 3).
Advanced concepts
- Quadlet (RHEL9+) - cách hiện đại hơn để định nghĩa container như 1 systemd unit trực tiếp bằng file
.container, không cần generate thủ công.
- Quadlet (RHEL9+) - cách hiện đại hơn để định nghĩa container như 1 systemd unit trực tiếp bằng file
Ngày 5: Volume & Network trong Podman
Cơ chế
Volume: bind mount (map trực tiếp thư mục host) vs named volume (Podman tự quản lý location) - khi nào dùng loại nào.
Container network: Podman tự tạo network namespace riêng cho mỗi container (trừ khi dùng
--network=host), NAT ra ngoài qua bridge.
Thực hành và quan sát
- Mount volume cho app cần persist data, tạo network riêng cho nhiều container giao tiếp với nhau qua tên container (DNS nội bộ Podman).
Advanced concepts
podman network inspect- đối chiếu trực tiếp vớiip netnsđã học Tuần 10 Ngày 8, thấy rõ container network chỉ là network namespace + veth pair được tự động hóa.
Ngày 6: Ôn tập tuần 13
- Chạy 1 app thật (VD web app + DB) trong 2 container riêng, kết nối qua Podman network, quản lý cả 2 bằng systemd, verify resource limit qua cgroup.
Ngày 7 (mới, thêm vào cuối tuần): Đối chiếu Podman với primitive tuần trước
Thực hành và quan sát
podman run1 container, dùngnsenter(học Tuần 14 Ngày 4) để tự "bước vào" namespace của nó từ host, không quapodman exec.cat /sys/fs/cgroup/.../memory.maxcủa cgroup mà Podman tự tạo cho container đó - đối chiếu với thao tác thủ công ở Tuần 11.
Advanced concepts
- Kết luận toàn bộ mạch: Podman = tự động hóa (namespace qua
unshare-equivalent syscall +pivot_root+ cgroup + image layer management) - mọi thứ bạn đã tự tay làm ở Tuần 13, giờ chỉ là 1 lệnhpodman run.
- Kết luận toàn bộ mạch: Podman = tự động hóa (namespace qua
Tuần 16: Performance & Troubleshooting
Ngày 1: vmstat
Cơ chế
- Cột
r(process chờ CPU),b(process blocked I/O),si/so(swap in/out) - đọc đúng thứ tự ưu tiên khi chẩn đoán bottleneck.
- Cột
Thực hành và quan sát
vmstat 2chạy liên tục trong khi stress-test CPU/memory, đọc thay đổi real-time.
Advanced concepts
si/sokhác 0 liên tục là dấu hiệu rất xấu (thrashing) - RAM thực sự thiếu, không phải vấn đề tạm thời.
Ngày 2: iostat & sar
Cơ chế
%utiltrong iostat gần 100% không hẳn là disk quá tải nếu là SSD (khác HDD) - cần đối chiếu vớiawait(thời gian chờ trung bình) để kết luận đúng.
Thực hành và quan sát
iostat -x 2, cấu hìnhsarthu thập số liệu lịch sử (sysstatservice) để so sánh xu hướng theo thời gian.
Advanced concepts
sar -n DEV- lịch sử network throughput, hữu ích khi cần chứng minh "server chậm vào giờ nào trong ngày" cho báo cáo incident.
Ngày 3: Tìm process bất thường
Thực hành và quan sát
ps aux --sort=-%mem,ps aux --sort=-%cpu, kết hợp/proc/<pid>/statusđã học Tuần 5.
Advanced concepts
pidstat- breakdown CPU/memory theo từng thread của 1 process (hữu ích khi app multi-thread có 1 thread cụ thể bị leak).
Ngày 4: iotop & phân biệt CPU-bound vs I/O-bound
Cơ chế
- CPU-bound:
%CPUcao, process ở stateR. I/O-bound:%CPUthấp nhưng process ở stateDthường xuyên,iostatcho thấyawaitcao.
- CPU-bound:
Thực hành và quan sát
iotop -o- chỉ hiện process đang thực sự có I/O.
Advanced concepts
- Kết hợp
vmstat+iostat+topcùng lúc trong 1 buổi troubleshooting thật - không công cụ đơn lẻ nào đủ, luôn cần đối chiếu nhiều nguồn.
- Kết hợp
Ngày 5: Xây checklist troubleshooting
- Tổng hợp toàn bộ Phase 2 thành 1 checklist cá nhân: "server chậm → check gì trước, gì sau" (CPU → memory/swap → I/O → network, theo đúng thứ tự loại trừ).
Ngày 6: sosreport
Cơ chế
sosreportlà công cụ chính thức của Red Hat: tự động thu thập hàng trăm file config/log/output lệnh chẩn đoán (dmesg, journalctl, rpm -qa, network config, SELinux status...) thành 1 archive duy nhất - đây là thứ đầu tiên Red Hat Support yêu cầu khi bạn mở ticket hỗ trợ.
Thực hành và quan sát
sosreport(hoặcsos reporttrên bản mới), chạy thử, giải nén archive kết quả, khám phá cấu trúc thư mục - nhận ra phần lớn nội dung chính là output của các lệnh bạn đã học suốt từ Phase 1 (chỉ là được tự động hóa và đóng gói).
Advanced concepts
sosreport -o <plugin>- chỉ chạy 1 plugin cụ thể (VD chỉ network, chỉ SELinux) khi không cần full report, hoặc--case-idđể gắn số ticket khi gửi Red Hat Support.
Ngày 7: tuned
Cơ chế
tuned: daemon áp dụng profile tối ưu hệ thống theo use-case (throughput-performance, latency-performance, virtual-guest, powersave...) - mỗi profile chỉnh hàng loạt sysctl/I/O scheduler/CPU governor cùng lúc thay vì tự set thủ công từng cái.
Thực hành và quan sát
tuned-adm list,tuned-adm active,tuned-adm profile throughput-performance- đổi profile, quan sát thay đổi (VDcat /proc/sys/vm/swappinesstrước/sau).
Advanced concepts
tuned-adm recommend- tuned tự đề xuất profile phù hợp dựa trên phát hiện môi trường (VM, bare-metal, laptop) - và viết 1 custom profile riêng cho ứng dụng đặc thù (kế thừa từ 1 profile có sẵn, override vài tham số).
Ngày 8: Mini-project 2 - Chẩn đoán không hint
- VM bị "load cao giả lập" (script stress CPU/IO/network ẩn), tự chẩn đoán nguyên nhân bằng công cụ đã học, viết báo cáo root cause như 1 incident report thật.
Ngày 9: Ghi chú cầu nối - kexec/kdump Phase 4 (Tuần 35-36) có kdump đầy đủ (cấu hình, trigger crash, phân tích bằng crash). Theo đề xuất "nối mạch production → kernel", nên thêm 1 đoạn giới thiệu khái niệm (chưa cần lab sâu) ngay tại cuối Phase 2:
Cơ chế (giới thiệu, lab đầy đủ vẫn ở Phase 4)
kexec: cơ chế boot thẳng vào 1 kernel mới từ bên trong kernel đang chạy, bỏ qua toàn bộ BIOS/bootloader - vì sao nhanh hơn reboot thật nhiều (bỏ qua POST, firmware init).kdumpdùng chính cơ chếkexec: khi kernel chính panic, nókexecngay vào 1 kernel dự phòng nhỏ đã load sẵn trong vùng RAM riêng, kernel dự phòng này dump memory của kernel bị crash ra disk rồi mới reboot thật.
Ghi chú
Đây là lý do kdump cần 1 phần RAM riêng dành sẵn (
crashkernel=trong GRUB) - kernel dự phòng phải chạy được ngay cả khi kernel chính vừa crash, không thể dùng chung vùng nhớ.Lab thực hành đầy đủ (cấu hình, trigger, phân tích bằng
crash) → xem Phase 4 Tuần 35-36.
Phase 2.5 - Toolchain, Debugging & Git
Tuần 17: Compilation Pipeline & ELF
Ngày 1: Cơ chế biên dịch, liên kết và vòng đời của một chương trình C++
Pipeline Biên dịch
Preprocessing: Cách
#include,#define,#ifdefhoạt động. Hiểu "Translation Unit".Compilation: Parsing, Code Generation. Cách trình biên dịch chuyển mã nguồn thành Assembly.
Assembling: Chuyển Assembly thành mã máy (Object file
.o/.obj). Cấu trúc Object file.Linking: Static vs dynamic linking (DLL/SO). Symbol table và lỗi
undefined reference.
Thực hành và quan sát
CLI: biên dịch tay với
g++/clang++(flag-E,-S,-cđể xem từng bước).Tách chương trình thành nhiều
.cpp/.h. Tự tạo thư viện tĩnh (.a) và liên kết.
Advanced concepts
One Definition Rule (ODR): tại sao quan trọng để tránh lỗi liên kết.
Link-Time Optimization (LTO): tối ưu hóa xuyên file.
Ngày 2: Cấu trúc ELF
Cơ chế
ELF header, Program header table (dùng khi load - kernel/loader đọc để biết map segment nào vào đâu), Section header table (dùng khi link/debug - không cần thiết để chạy).
Segment (
.text,.data,.bss,.rodata) - vì sao.bsskhông chiếm dung lượng file dù chiếm RAM lúc runtime.
Thực hành và quan sát
readelf -h,readelf -S,readelf -ltrên 1 binary tự compile - đối chiếu từng phần với lý thuyết.size <binary>- xem nhanh kích thước text/data/bss.
Advanced concepts
file <binary>- cách nó nhận diện ELF 32/64-bit, kiến trúc CPU, static/dynamic linked chỉ từ vài byte đầu (magic number).
Ngày 3: objdump & nm - soi mã máy
Cơ chế
Disassembly: chuyển ngược mã máy về assembly - vì sao không thể khôi phục 100% source gốc (mất tên biến, comment, cấu trúc control-flow cấp cao).
Symbol table: local vs global symbol, vì sao
staticfunction trong C không xuất hiện khi link từ file khác.
Thực hành và quan sát
objdump -d <binary>- đọc disassembly của 1 hàm C đơn giản, đối chiếu với source.nm <binary>- phân loại symbol (Ttext/defined,Uundefined,tlocal).
Advanced concepts
objdump -d -S- interleave source code với assembly (cần compile bằng-g) - kỹ thuật dùng nhiều khi optimize hot path.
Ngày 4: Dynamic linking & ldd
Cơ chế
Dynamic linker (
ld.so) resolve symbol lúc runtime, không phải lúc link - đây là lý do 1 binary dynamic-linked nhỏ hơn nhiều nhưng cần đúng version thư viện trên máy chạy.LD_LIBRARY_PATH,rpath,/etc/ld.so.conf- thứ tự tìm kiếm thư viện.so.
Thực hành và quan sát
ldd <binary>- xem toàn bộ thư viện dependency, thử xóa/đổi tên 1.soxem lỗierror while loading shared libraries.Tự build 1 thư viện
.so, link chương trình dùng nó, quan sát bằngldd.
Advanced concepts
LD_PRELOAD- inject 1 thư viện override function có sẵn (VD overridemallocđể log mọi lần cấp phát) - kỹ thuật debug/hack kinh điển, cũng là nền tảng hiểu 1 số malware hoạt động.
Ngày 5: Makefile cơ bản
Cơ chế
- Make dùng dependency graph + timestamp - chỉ rebuild target có dependency mới hơn nó, không rebuild toàn bộ mỗi lần (khác build script tuần tự).
Thực hành và quan sát
- Viết Makefile cho project nhiều file
.cpp, dùng pattern rule (%.o: %.cpp).
- Viết Makefile cho project nhiều file
Advanced concepts
make -j$(nproc)- build parallel, và vì sao cần khai báo đúng dependency (thiếu dependency → race condition khi build parallel, lỗi rất khó debug).
Ngày 6: Ôn tập tuần 15
Từ 1 project C nhiều file: build bằng tay từng bước (preprocess → compile → assemble → link) không dùng Makefile, sau đó viết lại bằng Makefile, đối chiếu.
readelf/objdump/nm/lddtrên chính binary vừa build - giải thích được từng phần không cần tra cứu.
Tuần 18: GDB & Core Dump
Ngày 1: GDB cơ bản
Cơ chế
- Breakpoint hoạt động bằng cách GDB ghi đè 1 byte đầu instruction bằng
int3(x86) - khi CPU chạy tới đó, trap vào GDB, GDB khôi phục byte gốc để hiển thị đúng.
- Breakpoint hoạt động bằng cách GDB ghi đè 1 byte đầu instruction bằng
Thực hành và quan sát
- Compile với
-g(giữ debug symbol),gdb ./binary, set breakpoint,step/next/continue, in giá trị biến (print).
- Compile với
Advanced concepts
-glevels (-g1/-g2/-g3) - tradeoff giữa kích thước binary và độ chi tiết debug info.
Ngày 2: GDB nâng cao - watchpoint & backtrace
Cơ chế
- Watchpoint: GDB dùng hardware debug register (không phải software trap) để dừng khi 1 vùng nhớ thay đổi - hiệu quả hơn nhiều so với step qua từng dòng để tìm chỗ biến bị đổi.
Thực hành và quan sát
watch <variable>,backtrace(xem call stack đầy đủ khi crash hoặc dừng tại breakpoint).Debug 1 chương trình có bug thật (VD buffer overflow tự tạo) bằng GDB.
Advanced concepts
bt full- in cả local variable của từng frame trong call stack, hữu ích khi crash sâu trong nhiều lớp hàm gọi nhau.
Ngày 3: Core dump - cơ chế
Cơ chế
Core dump: khi process nhận signal gây crash (SIGSEGV, SIGABRT...) mà không có handler, kernel dump toàn bộ memory image của process ra file - chứa đủ thông tin để debug sau khi process đã chết (khác GDB attach vào process đang sống).
ulimit -c- giới hạn kích thước core dump (mặc định 0 = tắt trên nhiều distro).
Thực hành và quan sát
ulimit -c unlimited, chạy chương trình cố tình segfault, tìm file core (/var/lib/systemd/coredump/trên RHEL hiện đại thay vì filecorecùng thư mục).
Advanced concepts
/proc/sys/kernel/core_pattern- kernel parameter quyết định core dump được ghi ở đâu/theo format nào (systemd-coredump can thiệp vào đây).
Ngày 4: Phân tích core dump bằng GDB
Thực hành và quan sát
gdb ./binary core- load core dump,backtraceđể tìm chính xác dòng code gây crash dù process đã chết từ lâu.coredumpctl list,coredumpctl gdb <PID>- cách RHEL hiện đại quản lý core dump qua systemd-coredump, tiện hơn tìm file thủ công.
Advanced concepts
- Core dump của binary đã optimize (
-O2) thường khó debug hơn nhiều (biến bị inline/loại bỏ) - vì sao production build đôi khi giữ lại-gdù vẫn optimize, tách riêng debug symbol ra file.debug(objcopy --only-keep-debug).
- Core dump của binary đã optimize (
Ngày 5: GDB attach vào process đang chạy
Cơ chế
gdb -p <PID>- GDB dùngptrace()syscall để attach vào process sống, tạm dừng nó lại - cùng nền tảngptracemàstrace(đã làm quen ở Tuần 5, sẽ đào sâu ở Tuần 22-23) dùng để trace syscall.
Thực hành và quan sát
- Attach vào 1 service đang chạy (không phải production thật!), đặt breakpoint, quan sát service "đứng hình" cho tới khi
continue.
- Attach vào 1 service đang chạy (không phải production thật!), đặt breakpoint, quan sát service "đứng hình" cho tới khi
Advanced concepts
- Vì sao không nên attach GDB vào production service tùy tiện - process bị dừng hoàn toàn trong lúc GDB attach, có thể gây timeout/cascade failure ở service phụ thuộc.
Ngày 6: Ôn tập tuần 16
- Cố tình viết 1 chương trình có bug (use-after-free hoặc buffer overflow), để nó tự crash tạo core dump, dùng
coredumpctl+ GDB xác định chính xác dòng code lỗi mà không nhìn source trước.
Tuần 19: Git
Ngày 1: Object model của Git
Cơ chế
Git lưu data dạng 4 loại object: blob (nội dung file), tree (thư mục), commit (snapshot + metadata), tag - mỗi object được hash bằng SHA (content-addressable storage, giống hệ thống file dedupe).
Commit không lưu "diff" - mỗi commit là snapshot toàn bộ cây thư mục tại thời điểm đó (diff chỉ là cách hiển thị, tính toán lúc
git log -p).
Thực hành và quan sát
git cat-file -p <hash>- xem trực tiếp nội dung object (blob/tree/commit) không qua lệnh git thông thường.git log --oneline --graphđể thấy cấu trúc DAG (Directed Acyclic Graph) của commit history.
Advanced concepts
.git/objects- tự tìm 1 object bằng tay qua hash prefix, hiểu vì sao Git nén object cũ vào packfile định kỳ (git gc).
Ngày 2: Branching & Merge
Cơ chế
Branch chỉ là 1 con trỏ (file text chứa commit hash) trỏ vào 1 commit - cực nhẹ, đây là lý do Git khuyến khích branch liên tục (khác SVN branch nặng).
Merge commit có 2 parent - khác fast-forward merge (không tạo commit mới, chỉ di chuyển con trỏ branch).
Thực hành và quan sát
- Tạo conflict thật giữa 2 branch, tự resolve, hiểu ký hiệu
<<<<<<<,=======,>>>>>>>.
- Tạo conflict thật giữa 2 branch, tự resolve, hiểu ký hiệu
Advanced concepts
git merge --no-ff- ép tạo merge commit dù có thể fast-forward, giữ lại lịch sử rõ ràng feature branch nào merge khi nào (dùng trong quy trình release nghiêm ngặt).
Ngày 3: Rebase
Cơ chế
Rebase viết lại lịch sử: lấy từng commit trên branch của bạn, áp lại (replay) lên đầu 1 base mới - mỗi commit sau rebase có hash mới hoàn toàn (vì parent thay đổi → hash thay đổi, do commit hash tính từ content + parent).
Vì sao không rebase branch đã push public - người khác đã pull commit cũ, rebase tạo commit trùng nội dung nhưng khác hash → history phân kỳ.
Thực hành và quan sát
git rebase -i HEAD~3- interactive rebase: squash, reword, reorder commit.
Advanced concepts
git rebase --onto- rebase 1 đoạn commit cụ thể sang base khác, không phải toàn bộ branch (dùng khi cherry-pick nguyên cụm commit sang nhánh khác).
Ngày 4: Bisect
Cơ chế
git bisectdùng binary search trên lịch sử commit để tìm chính xác commit gây ra bug - O(log n) thay vì kiểm tra tuần tự từng commit.
Thực hành và quan sát
- Tạo 1 repo giả có bug được insert ở 1 commit giữa lịch sử 20 commit, dùng
git bisect start/good/badđể tìm ra.
- Tạo 1 repo giả có bug được insert ở 1 commit giữa lịch sử 20 commit, dùng
Advanced concepts
git bisect run <script>- tự động hóa hoàn toàn: script trả exit code 0 (good) hoặc 1 (bad), Git tự chạy qua toàn bộ history và báo commit lỗi - dùng thật khi debug kernel regression (chính kernel dev dùng kỹ thuật này thường xuyên).
Ngày 5: format-patch & am - quy trình gửi patch kiểu kernel
Cơ chế
- Kernel Linux không dùng Pull Request như GitHub - quy trình chuẩn là tạo patch file bằng
git format-patch, gửi qua email (git send-email) tới mailing list, maintainer review qua email,git amđể apply patch nhận được.
- Kernel Linux không dùng Pull Request như GitHub - quy trình chuẩn là tạo patch file bằng
Thực hành và quan sát
git format-patch -1 HEAD- tạo file.patchtừ 1 commit, xem cấu trúc file (header email-style + diff).git am < file.patchtrên 1 repo khác - áp dụng patch nhận được, giữ nguyên author/message gốc.
Advanced concepts
git format-patch --cover-letter- tạo patch series nhiều commit kèm 1 email mô tả tổng quan, đúng chuẩn khi gửi feature lớn lên LKML (sẽ dùng thật ở Phase 6 khi gửi patch kernel).
Ngày 6: Ôn tập tuần 17
- Mini-project: tạo 1 repo giả lập quy trình kernel contribution - vài commit trên branch riêng, rebase sạch sẽ lên
main, tạo patch series bằngformat-patch --cover-letter, tựgit amsang 1 clone khác để verify patch áp dụng đúng.
Phase 3 - Linux Internals (9 tuần)
Tuần 20: Process Model
Ngày 1: Process là gì - đọc OSTEP
Cơ chế
Đọc OSTEP chương Process (miễn phí, remzi.github.io) - process là 1 abstraction: chương trình đang chạy có riêng virtual CPU + virtual memory, dù CPU vật lý bị chia sẻ giữa hàng trăm process qua context switch.
Process Control Block (PCB) - kernel lưu toàn bộ state của 1 process (registers, program counter, memory mapping) ở đâu khi nó không chạy.
Thực hành và quan sát
ps -eLf- đếm số process đang chạy trên máy, so sánh với số CPU core thật.
Advanced concepts
- Vì sao "process" và "program" là 2 khái niệm khác nhau - 1 program (file thực thi trên disk) có thể chạy thành nhiều process cùng lúc (VD mở 3 tab Chrome).
Ngày 2: fork()/exec()/wait()
Cơ chế
fork()tạo bản sao gần như y hệt process gọi nó (copy-on-write, không copy thật ngay) - trả về 2 lần: 0 cho child, PID con cho parent.exec()thay thế hoàn toàn image của process hiện tại bằng chương trình mới (không tạo process mới) - đây là lý dofork()+exec()tách biệt cho phép làm việc ở giữa (redirect stdout trước khi exec, VD shell pipe).
Thực hành và quan sát
- Viết chương trình C nhỏ dùng
fork(), phân biệt code chạy ở nhánh parent vs child dựa trên giá trị trả về, quan sát bằngstrace -f.
- Viết chương trình C nhỏ dùng
Advanced concepts
wait()/waitpid()- vì sao parent cần gọiwait()để "thu hoạch" exit status của child, nếu không child trở thành zombie (đã học Phase 1 Tuần 5, giờ thấy rõ cơ chế syscall gốc).
Ngày 3: Process states & context switch
Cơ chế
Context switch: kernel lưu toàn bộ register state của process đang chạy vào PCB, load state của process tiếp theo - tốn thời gian thật (vài microsecond), đây là lý do quá nhiều thread/process gây overhead.
Đọc
/proc/<pid>/status- giải thích từng field (State,VmRSS,Threads,voluntary_ctxt_switches).
Thực hành và quan sát
- So sánh
voluntary_ctxt_switches(process tự nhường CPU, VD chờ I/O) vsnonvoluntary_ctxt_switches(bị scheduler ngắt giữa chừng) của vài process khác nhau.
- So sánh
Advanced concepts
- Vì sao context switch giữa 2 thread cùng process rẻ hơn giữa 2 process khác nhau - thread chia sẻ page table, không cần flush TLB (Translation Lookaside Buffer).
Ngày 4: Virtual memory khái niệm
Cơ chế
Đọc OSTEP chương Memory Virtualization - mỗi process có không gian địa chỉ ảo riêng (0 đến giới hạn), kernel dùng page table để dịch địa chỉ ảo sang địa chỉ vật lý thật.
Paging: chia memory thành các trang cố định (thường 4KB) - vì sao paging tốt hơn cấp phát liên tục (tránh external fragmentation).
Thực hành và quan sát
getconf PAGE_SIZE- xem kích thước page mặc định của hệ thống.
Advanced concepts
- Multi-level page table - vì sao không dùng 1 bảng dịch phẳng khổng lồ (tốn RAM khủng khiếp với không gian địa chỉ 64-bit), mà chia thành nhiều cấp (4 cấp trên x86-64).
Ngày 5: Soi vùng nhớ process thật
Cơ chế
/proc/<pid>/mapsliệt kê từng vùng nhớ (segment) của process: địa chỉ bắt đầu-kết thúc, quyền (rwxp), file backing (nếu có).
Thực hành và quan sát
/proc/<pid>/maps,pmap -x <pid>- soi vùng nhớ 1 process thật (VDsleep 100 &rồi pmap PID đó), nhận diện heap, stack, shared library.
Advanced concepts
- Vùng
[stack]phát triển xuống (địa chỉ giảm dần), heap phát triển lên - đây là lý do 2 vùng này thường được đặt ở 2 đầu không gian địa chỉ, tối đa hóa khoảng trống có thể grow.
- Vùng
Ngày 6: mmap() trực tiếp
Cơ chế
mmap()map trực tiếp 1 vùng memory (có thể backing bởi file hoặc anonymous/RAM thuần) vào không gian địa chỉ process -malloc()với block lớn thực chất gọimmap()bên dưới (glibc), block nhỏ dùngbrk()/heap.
Thực hành và quan sát
- Viết chương trình dùng
mmap()trực tiếp thay vìmalloc, quan sát vùng nhớ mới xuất hiện trong/proc/self/mapsngay sau khi gọi.
- Viết chương trình dùng
Advanced concepts
MAP_SHAREDvsMAP_PRIVATE- shared memory giữa 2 process không liên quan dùng chính flag này (nền tảng của IPC shared memory sẽ học ở Tuần 27-28).
Tuần 21: Memory sâu, OOM, Namespaces
Ngày 1: OOM killer
Cơ chế
Khi hệ thống hết RAM (kể cả swap), kernel không thể từ chối cấp phát mãi - OOM killer chọn 1 process để kill nhằm giải phóng memory, tránh toàn hệ thống deadlock.
oom_scoređược tính từ nhiều yếu tố (memory usage, thời gian chạy,oom_score_adj) - process dùng nhiều RAM nhất chưa chắc bị kill nếu cóoom_score_adjthấp.
Thực hành và quan sát
/proc/<pid>/oom_score,/proc/<pid>/oom_score_adj- chỉnh giảm khả năng bị kill cho 1 service quan trọng (VD database).
Advanced concepts
echo f > /proc/sysrq-trigger- trigger OOM killer thủ công để test hành vi mà không cần thực sự làm cạn RAM.
Ngày 2: Cgroups v2 & memory reclaim (góc nhìn kernel)
Cơ chế
- Ôn lại cgroups (đã học sâu Phase 2 Tuần 12) từ góc độ kernel:
memory.maxkhông chỉ là con số giới hạn - khi chạm ngưỡng, kernel trigger reclaim (drop page cache, swap) trước khi tính đến OOM-kill trong cgroup đó.
- Ôn lại cgroups (đã học sâu Phase 2 Tuần 12) từ góc độ kernel:
Thực hành và quan sát
- Giới hạn memory 1 process bằng cgroup thủ công, quan sát
memory.statđể thấyreclaimdiễn ra trước khi process bị kill.
- Giới hạn memory 1 process bằng cgroup thủ công, quan sát
Advanced concepts
- Page cache (file cache) tính vào
memory.currentnhưng có thể reclaim được (không như anon memory) - đây là lý domemory.maxkhông tương đương RSS thô.
- Page cache (file cache) tính vào
Ngày 3: Namespaces sâu hơn (góc nhìn kernel)
Cơ chế
- Ôn lại (đã dùng thực chiến ở Phase 2 Tuần 14 Container Primitives) từ góc kernel: mỗi namespace type có 1 cấu trúc dữ liệu kernel riêng (
struct pid_namespace,struct net...) -clone()với flag tương ứng (CLONE_NEWPID,CLONE_NEWNET...) là cách kernel thật sự tạo namespace mới.
- Ôn lại (đã dùng thực chiến ở Phase 2 Tuần 14 Container Primitives) từ góc kernel: mỗi namespace type có 1 cấu trúc dữ liệu kernel riêng (
Thực hành và quan sát
unshare --pid --fork bash, quan sát/proc/self/ns/- mỗi symlink trỏ tới 1 inode đại diện cho namespace mà process đang thuộc về.
Advanced concepts
- 2 process share cùng namespace nếu symlink trong
/proc/<pid>/ns/có cùng inode number - đây là cách kernel/tool kiểm tra 2 container có cùng network namespace hay không.
- 2 process share cùng namespace nếu symlink trong
Ngày 4: Ôn tập process lifecycle
Thực hành
- Giải thích bằng lời (không nhìn note) toàn bộ vòng đời 1 process từ
fork()→exec()→ chạy →exit()→wait()bởi parent, kèm theo trạng thái memory/namespace tại mỗi bước.
- Giải thích bằng lời (không nhìn note) toàn bộ vòng đời 1 process từ
Ngày 5: Buffer/ôn tập mở rộng
Thực hành
- Viết 1 chương trình C dùng
fork()+mmap(MAP_SHARED)để 2 process (parent/child) chia sẻ 1 vùng nhớ, giao tiếp qua đó (không dùng pipe) - bài tập kết hợp toàn bộ tuần.
- Viết 1 chương trình C dùng
Tuần 22: Filesystem internals
Ngày 1: VFS layer
Cơ chế
- Đọc OSTEP chương File System - VFS (Virtual File System) là lớp abstraction cho phép
read()/write()hoạt động giống nhau bất kể filesystem thật bên dưới là xfs, ext4, hay NFS - mỗi filesystem implement 1 bộ operations (read,write,lookup...) mà VFS gọi qua function pointer.
- Đọc OSTEP chương File System - VFS (Virtual File System) là lớp abstraction cho phép
Thực hành và quan sát
cat /proc/filesystems- liệt kê toàn bộ filesystem type kernel hiện tại hỗ trợ.
Advanced concepts
- VFS là lý do bạn có thể
mount1 USB FAT32, ext4 disk, và NFS share cùng lúc và dùng chung 1 bộ lệnhls/cp- ứng dụng userspace hoàn toàn không biết filesystem thật bên dưới là gì.
- VFS là lý do bạn có thể
Ngày 2: inode vs dentry
Cơ chế
- inode chứa metadata thật của file (owner, permission, size, con trỏ tới block dữ liệu) - không chứa tên file. dentry (directory entry) là cấu trúc map tên file → inode, đây là lý do 1 file có thể có nhiều tên (hardlink).
Thực hành và quan sát
- Tạo 2 hardlink cùng inode (
ln file1 file2), quan sát bằngstat file1 file2(cùng số inode),ls -i.
- Tạo 2 hardlink cùng inode (
Advanced concepts
- Xóa
file1không xóa data thật - inode chỉ bị giải phóng khi link count về 0 (ls -lcột thứ 2 chính là link count) - đây là cơ chế thật của "xóa file" trên Linux.
- Xóa
Ngày 3: Journaling filesystem
Cơ chế
Journaling: trước khi ghi thay đổi thật vào filesystem, ghi 1 bản "ý định" (journal/log) trước - nếu crash giữa chừng, khi mount lại filesystem replay journal để hoàn tất hoặc rollback thao tác dang dở, tránh corrupt.
xfs/ext4 đều journal metadata mặc định; ext4 có tùy chọn journal cả data (
data=journal, chậm hơn nhưng an toàn hơn).
Thực hành và quan sát
dmesg | grep -i journalsau khi reboot "cứng" 1 VM (force reset) - thấy filesystem tự động replay journal lúc mount.
Advanced concepts
- Journaling bảo vệ filesystem consistency, không bảo vệ data mới nhất chưa flush - đây là lý do
fsync()vẫn cần thiết cho ứng dụng cần đảm bảo data đã ghi xuống đĩa thật.
- Journaling bảo vệ filesystem consistency, không bảo vệ data mới nhất chưa flush - đây là lý do
Ngày 4: Block layer & I/O scheduler
Cơ chế
- Block layer nằm giữa filesystem và device driver - gom, sắp xếp lại I/O request (merge các request liền kề, reorder theo vị trí trên đĩa) trước khi gửi xuống device thật, đặc biệt quan trọng với HDD (giảm seek time).
Thực hành và quan sát
cat /sys/block/sda/queue/scheduler- xem I/O scheduler đang dùng (mq-deadline,none/noop cho SSD/NVMe,bfqcho desktop).
Advanced concepts
- SSD/NVMe thường dùng scheduler
nonevì không có "seek time" thật để tối ưu - việc reorder request chỉ thêm overhead không cần thiết cho non-rotational storage.
- SSD/NVMe thường dùng scheduler
Ngày 5: strace sâu - đếm syscall I/O
Cơ chế
- Ôn lại
strace(đã làm quen Phase 1 Tuần 5) ở mức sâu hơn: mỗi lệnhcpthực chất là chuỗi syscallopenat→ nhiều lầnread/writetheo block size →close.
- Ôn lại
Thực hành và quan sát
strace -c cp bigfile.txt copy.txt- đếm số lần gọi + tổng thời gian mỗi loại syscall, xác địnhread/writechiếm bao nhiêu % tổng thời gian.
Advanced concepts
- So sánh số lần syscall
read/writekhicpfile 100MB với block size mặc định củacp(thường 128KB) - tính ra số lần gọi lý thuyết, đối chiếu vớistrace -cthực tế.
- So sánh số lần syscall
Ngày 6: dd & block size
Cơ chế
ddcho phép chỉnhbs=(block size) - block size nhỏ (4K) tạo nhiều syscall hơn (overhead per-call cao), block size lớn (1M) giảm số syscall nhưng có thể không tận dụng hết bandwidth nếu quá lớn so với queue depth của device.
Thực hành và quan sát
dd if=/dev/zero of=test bs=4K count=100000, rồibs=1M count=400(cùng tổng dung lượng) - đo throughput bằng flagstatus=progress, so sánh.
Advanced concepts
- Giải thích vì sao I/O size ảnh hưởng performance không tuyến tính - có 1 "sweet spot" (thường 128K-1M cho SSD) mà vượt qua đó throughput không tăng thêm đáng kể.
Tuần 23: perf, ftrace & tổng hợp I/O path
Ngày 1: perf cơ bản
Cơ chế
perfdùng hardware performance counter (CPU cycle, cache miss, branch misprediction) có sẵn trong CPU - cho phép đo hiệu năng ở mức rất thấp mà gần như không có overhead (khácstracephải dừng process ở mỗi syscall).
Thực hành và quan sát
perf top- xem function nào đang tốn CPU nhất real-time trên toàn hệ thống.perf stat <cmd>trên 1 chương trình CPU-bound tự viết (VD tính số nguyên tố brute-force) - đọcinstructions,cycles,cache-misses.
Advanced concepts
- IPC (Instructions Per Cycle) tính từ
instructions/cycles- IPC thấp thường là dấu hiệu chương trình bị nghẽn ở cache miss hoặc branch misprediction, không phải thiếu CPU power.
- IPC (Instructions Per Cycle) tính từ
Ngày 2: ftrace giới thiệu
Cơ chế
ftrace: framework tracing tích hợp sẵn trong kernel (không cần công cụ ngoài), cho phép trace function call bên trong kernel qua/sys/kernel/debug/tracing/- nền tảng mà nhiều công cụ cấp cao hơn (kể cảperf) dựa vào.
Thực hành và quan sát
echo function > /sys/kernel/debug/tracing/current_tracer,cat /sys/kernel/debug/tracing/trace- xem stream function call trong kernel (mức quan sát, chưa cần hiểu code).
Advanced concepts
trace-cmd- wrapper thân thiện hơn cho ftrace, tương tự cáchbpftrace(sẽ học Tuần 24) là wrapper thân thiện cho eBPF.
Ngày 3: Vẽ lại toàn bộ I/O path
Thực hành
- Tự vẽ sơ đồ (giấy hoặc tool vẽ) đầy đủ: app gọi
read()→ syscall trap → VFS → filesystem (xfs/ext4) → block layer/I/O scheduler → device driver → disk thật, và chiều ngược lại khi data trả về.
- Tự vẽ sơ đồ (giấy hoặc tool vẽ) đầy đủ: app gọi
Ngày 4: Checkpoint - viết bài giải thích
Thực hành
- Viết 1 bài (không cần publish) giải thích "điều gì xảy ra khi bạn gõ
cat file.txt" từ syscall đến disk, dùng đúng thuật ngữ đã học suốt Tuần 22-23 (VFS, inode, dentry, journal, block layer, scheduler).
- Viết 1 bài (không cần publish) giải thích "điều gì xảy ra khi bạn gõ
Ngày 5: Buffer/ôn tập
Thực hành
- Chạy
perf record/perf reporttrên chính chương trìnhdd/cpđã test ở Tuần 22, xác nhận phần lớn thời gian nằm ở syscallread/write(kernel-space) chứ không phải code userspace.
- Chạy
Tuần 24: eBPF & bpftrace
Ngày 1: Khái niệm eBPF
Cơ chế
eBPF (extended Berkeley Packet Filter): cho phép chạy chương trình nhỏ bên trong kernel một cách an toàn (verified bởi eBPF verifier trước khi load - không thể crash kernel hay vòng lặp vô hạn) mà không cần viết kernel module hay recompile kernel.
So với
ftrace/perfđã học: những công cụ đó có sẵn tracepoint cố định; eBPF cho phép viết logic tùy ý tại các hook point đó (filter, aggregate, histogram ngay trong kernel trước khi trả dữ liệu ra userspace - hiệu năng cao hơn nhiều so với trace toàn bộ rồi xử lý ở userspace).
Thực hành và quan sát
bpftool prog list- xem các eBPF program đang chạy sẵn trong kernel (nhiều thứ RHEL đã dùng eBPF nội bộ, VD firewall/network policy hiện đại).
Advanced concepts
- eBPF dùng rộng rãi ngoài tracing: networking (Cilium trong Kubernetes), security (Falco), packet filtering hiệu năng cao (XDP - eXpress Data Path, xử lý packet trước cả khi vào network stack thông thường).
Ngày 2: bpftrace - ngôn ngữ tracing cấp cao
Cơ chế
bpftracelà ngôn ngữ script cấp cao (giốngawkcho tracing) compile xuống eBPF bytecode - không cần viết eBPF bằng C/verifier thủ công.
Thực hành và quan sát
bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args->filename)); }'- trace mọi lệnh gọiopentrên toàn hệ thống real-time, in ra tên process + file đang mở.
Advanced concepts
- So sánh với
strace:stracechỉ trace 1 process cụ thể và có overhead lớn (dừng process ở mỗi syscall);bpftracetrace toàn hệ thống với overhead thấp hơn nhiều - công cụ đúng cho production (không thểstracetoàn bộ server, nhưng có thể chạybpftracean toàn).
- So sánh với
Ngày 3: One-liner thực chiến
Thực hành và quan sát
- Chạy các bpftrace one-liner kinh điển (có sẵn trong
bpftraceexamples): đo latency syscall theo histogram, đếm số lần page fault theo process, trace TCP connection mới real-time toàn hệ thống.
- Chạy các bpftrace one-liner kinh điển (có sẵn trong
Advanced concepts
bpftrace -l 'tracepoint:*'- khám phá toàn bộ tracepoint khả dụng trong kernel đang chạy, hiểu đây chính là các "điểm móc" mà ftrace/perf/bpftrace đều dựa vào.
Ngày 4: Viết script bpftrace cho use-case thật
Thực hành - dự án
- Viết 1 script bpftrace theo dõi latency của 1 loại syscall cụ thể (VD
read) cho 1 process cụ thể, xuất histogram phân bố latency - bài toán thật khi production cần biết "I/O có bao giờ bị spike latency không, tần suất thế nào" màstracekhông trả lời được hiệu quả ở quy mô lớn.
- Viết 1 script bpftrace theo dõi latency của 1 loại syscall cụ thể (VD
Advanced concepts
- So sánh kết quả với
iostat/vmstatđã học ở Phase 2 - eBPF cho độ chi tiết per-syscall, per-process mà công cụ aggregate truyền thống không có.
- So sánh kết quả với
Ngày 5: XDP khái niệm
Cơ chế
- XDP: eBPF program chạy ở tầng driver network, trước khi packet đi vào kernel network stack - cho phép drop/redirect packet với latency cực thấp (dùng trong DDoS mitigation, load balancer hiệu năng cao như Cilium/Katran của Facebook).
Thực hành và quan sát
- Đọc 1 ví dụ XDP program đơn giản (drop packet theo điều kiện), không cần tự viết từ đầu - mục tiêu là hiểu vị trí XDP nằm ở đâu trong packet flow đã học Tuần 9-10 (Networking).
Advanced concepts
- Liên hệ với
nftables/netfilter hooks đã học: XDP nằm trước netfilter hoàn toàn, packet có thể bị drop ở XDP mà không bao giờ chạm tới iptables/nftables rule.
- Liên hệ với
Ngày 6: Ôn tập tuần eBPF
- Mini-project: viết 1 bpftrace script hoàn chỉnh giải quyết 1 bài toán troubleshooting cụ thể tự đặt ra (VD "tìm process nào đang mở file nhiều nhất trong 10 giây"), so sánh cách làm tương đương (khó hơn nhiều) nếu chỉ dùng
strace/lsof.
Tuần 25: Scheduler & Boot process
Ngày 1: CFS - Completely Fair Scheduler
Cơ chế
CFS không dùng time-slice cố định - nó theo dõi
vruntime(virtual runtime) của từng process/thread, luôn chọn process cóvruntimethấp nhất để chạy tiếp, đảm bảo mọi process nhận CPU "công bằng" theo thời gian.nicevalue ảnh hưởng đến weight dùng để tính tốc độ tăngvruntime- nice thấp hơn (ưu tiên cao hơn) khiếnvruntimetăng chậm hơn, nên được chọn chạy thường xuyên hơn.
Thực hành và quan sát
- Chạy 2 process CPU-bound cùng lúc với
nicekhác nhau (VD 0 và 19), quan sát tỷ lệ CPU time bằngtop.
- Chạy 2 process CPU-bound cùng lúc với
Advanced concepts
- CFS dùng cấu trúc dữ liệu red-black tree để luôn tìm process có
vruntimethấp nhất trong O(log n) - lựa chọn cấu trúc dữ liệu này là lý do CFS scale tốt với hàng nghìn process.
- CFS dùng cấu trúc dữ liệu red-black tree để luôn tìm process có
Ngày 2: Realtime scheduling
Cơ chế
SCHED_FIFO/SCHED_RR(realtime) khác hẳnSCHED_OTHER(CFS mặc định) - process realtime luôn được ưu tiên hơn mọi process CFS, không bịvruntimechi phối, dùng cho ứng dụng cần latency cực thấp và có thể đoán trước (audio processing, control system).
Thực hành và quan sát
chrt -f 50 <cmd>- chạy 1 chương trình vớiSCHED_FIFOpriority 50, quan sát bằngchrt -p <pid>.
Advanced concepts
- Rủi ro thật: 1 process
SCHED_FIFOchạy vòng lặp vô hạn có thể chiếm CPU vĩnh viễn, khiến toàn bộ process CFS khác (kể cả SSH daemon) không bao giờ được chạy - đây là lý do realtime scheduling cần dùng cực kỳ cẩn trọng trong production.
- Rủi ro thật: 1 process
Ngày 3: Boot process
Cơ chế
- Chuỗi boot đầy đủ: BIOS/UEFI (POST, tìm bootloader) → GRUB2 (đọc config, load kernel + initramfs vào RAM) → kernel khởi tạo (mount root tạm từ initramfs) → chuyển sang root filesystem thật → systemd (PID 1) → target (multi-user/graphical).
Thực hành và quan sát
systemd-analyze,systemd-analyze blame- đo thời gian từng giai đoạn boot thật trên VM.
Advanced concepts
- UEFI khác BIOS ở chỗ có thể đọc trực tiếp filesystem FAT32 (EFI System Partition) mà không cần MBR bootloader chain phức tạp - đây là lý do UEFI boot nhanh và linh hoạt hơn (secure boot, boot nhiều OS dễ hơn).
Ngày 4: Thực hành rescue mode
Cơ chế
- Rescue mode boot với target tối giản (
rescue.target), single-user mode còn tối giản hơn - cả hai cho phép sửa hệ thống khi service bình thường không khởi động được.
- Rescue mode boot với target tối giản (
Thực hành và quan sát
- Sửa GRUB config (thêm tham số kernel
systemd.unit=rescue.targetlúc boot), boot vào rescue mode, mount root filesystem ở chế độ read-write để sửa file.
- Sửa GRUB config (thêm tham số kernel
Advanced concepts
rd.break- dừng boot ngay trong initramfs (trước cả khi chuyển sang root thật) - dùng khi lỗi nghiêm trọng hơn (VD quên password root, cần reset qua chroot vào root filesystem thật).
Ngày 5: initramfs
Cơ chế
- initramfs: 1 filesystem tạm (nén, load vào RAM) chứa driver + tool tối thiểu cần để tìm và mount root filesystem thật - cần thiết vì driver cho disk/RAID/LVM/encryption có thể chưa được compile sẵn vào kernel, phải load như module trước khi root thật khả dụng.
Thực hành và quan sát
lsinitrd- xem nội dung initramfs hiện tại của VM, tìm driver/module nào được đóng gói trong đó.
Advanced concepts
dracut- công cụ RHEL dùng để build initramfs, tự động phát hiện driver cần thiết dựa trên phần cứng/cấu hình filesystem hiện tại - đây là lý do initramfs cần rebuild lại (dracut -f) sau khi đổi cấu hình storage quan trọng (VD thêm LUKS encryption).
Ngày 6: Ôn tập - cố tình làm hỏng boot
Thực hành
- Cố tình làm hỏng boot (sai entry trong
/etc/fstabtrỏ tới device không tồn tại), tự fix bằng rescue mode - bài tập rất thực tế cho production (đây là 1 trong những sự cố phổ biến nhất khi thao tác storage sai).
- Cố tình làm hỏng boot (sai entry trong
Tuần 26: Networking stack internals
Ngày 1: TCP/IP stack trong kernel
Cơ chế
- Tổng quan tầng: application (socket API) → transport (TCP/UDP, quản lý port, reliability) → network (IP, routing) → link (device driver, Ethernet) - mỗi tầng thêm header riêng khi đóng gói packet đi xuống, bóc header khi nhận lên.
Thực hành và quan sát
ss -i- xem chi tiết TCP internals của 1 connection đang mở (cwnd,rtt,retrans).
Advanced concepts
- Congestion control algorithm (
cubicmặc định RHEL) - kernel tự điều chỉnh tốc độ gửi dựa trên packet loss/RTT,sysctl net.ipv4.tcp_congestion_controlđể xem/đổi.
- Congestion control algorithm (
Ngày 2: Socket syscall
Cơ chế
socket()→bind()→listen()→accept()(server) hoặcconnect()(client) - mỗi lệnh là 1 syscall thật, kernel tạo/quản lý toàn bộ state TCP bên trong, userspace chỉ giữ 1 file descriptor.
Thực hành và quan sát
- Viết 1 chương trình C dùng raw
socket()+bind()+listen()(không dùng thư viện cao cấp), trace toàn bộ bằngstrace, đối chiếu với lý thuyết TCP handshake đã học Phase 1 Tuần 6.
- Viết 1 chương trình C dùng raw
Advanced concepts
SO_REUSEADDR- vì sao cần set option này khi restart nhanh 1 server (tránh lỗi "Address already in use" do connection cũ còn ởTIME_WAIT).
Ngày 3: /proc/net
Cơ chế
/proc/net/tcp,/proc/net/dev- kernel expose toàn bộ connection tracking table và interface statistics trực tiếp qua procfs, không cần syscall riêng - đây là cáchss/netstatlấy dữ liệu thật.
Thực hành và quan sát
cat /proc/net/tcp- đọc raw format (địa chỉ/port dạng hex), viết 1 script Python nhỏ parse nó thành dạng đọc được, đối chiếu với outputss.
Advanced concepts
/proc/net/dev- đếm packet/byte theo interface ở mức kernel counter, chính xác hơn nhiều so với ước lượng qua công cụ ngoài.
Ngày 4: Netfilter hooks
Cơ chế
- Netfilter định nghĩa 5 hook point cố định trong packet flow (
PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING) - iptables/nftables (đã học Phase 2 Tuần 9-10) chỉ là 1 trong nhiều consumer đăng ký callback vào các hook này.
- Netfilter định nghĩa 5 hook point cố định trong packet flow (
Thực hành và quan sát
- Vẽ lại vị trí 5 hook trong sơ đồ packet flow, đối chiếu với chain
INPUT/OUTPUT/FORWARDtrongnft list rulesetđã dùng trước đó.
- Vẽ lại vị trí 5 hook trong sơ đồ packet flow, đối chiếu với chain
Advanced concepts
- XDP (đã học Tuần 24) nằm trước cả
PREROUTING- đây là lý do XDP nhanh hơn netfilter: packet có thể bị xử lý/drop trước khi netfilter framework thậm chí được khởi động cho packet đó.
- XDP (đã học Tuần 24) nằm trước cả
Ngày 5: Đo latency & RTT
Cơ chế
pingđo RTT (Round Trip Time) - ở mức kernel, mỗi gói ICMP request/reply đi qua interrupt (NIC báo có packet đến) → softirq (xử lý packet ở context không chặn hoàn toàn CPU) → deliver lên userspace.
Thực hành và quan sát
ping -c 100 <host>, phân tích độ lệch chuẩn RTT - RTT dao động lớn thường là dấu hiệu network congestion hoặc CPU bị nghẽn xử lý softirq (topcột%si).
Advanced concepts
/proc/interrupts- đếm interrupt theo từng CPU core cho từng NIC, mất cân bằng interrupt (irqbalance) là nguyên nhân phổ biến gây latency cao trên server nhiều core.
Ngày 6: Ôn tập - vẽ full packet path
Thực hành
- Vẽ sơ đồ full path 1 packet TCP đi từ app gửi (2 máy VM) đến app nhận: app → socket → TCP stack → netfilter hooks → routing → device driver → NIC → dây mạng → NIC máy nhận → device driver → netfilter → TCP stack → socket → app.
Tuần 27-28: Kerrisk (The Linux Programming Interface)
Ngày 1: Process Creation
Cơ chế
- Đọc chương Process Creation - đào sâu hơn
fork()/vfork()/clone():clone()là syscall gốc thật sự,fork()chỉ là 1 cách gọiclone()với bộ flag mặc định (copy toàn bộ), thread (pthread_create) cũng dùngclone()với flag chia sẻ memory/file descriptor.
- Đọc chương Process Creation - đào sâu hơn
Thực hành và quan sát
- Code lại ví dụ trong sách:
fork()nhiều lần liên tiếp, đếm chính xác số process con được tạo (bài toán kinh điển dễ nhầm với "fork bomb" nếu tính sai).
- Code lại ví dụ trong sách:
Advanced concepts
CLONE_VM,CLONE_FILES,CLONE_FS- từng flag riêng lẻ củaclone()kiểm soát việc chia sẻ gì giữa parent/child, đây chính xác là cách phân biệt "process" và "thread" ở mức kernel: thread chỉ là process shareCLONE_VM.
Ngày 2: Signals
Cơ chế
- Ôn lại signal (Phase 1 Tuần 5) ở mức API sâu hơn:
sigaction()thaysignal()cũ - cho phép kiểm soát chính xác signal mask, block signal trong lúc handler đang chạy, tránh race condition.
- Ôn lại signal (Phase 1 Tuần 5) ở mức API sâu hơn:
Thực hành và quan sát
- Code demo signal handler custom dùng
sigaction(), test race condition khi không block đúng signal (2 lần SIGINT liên tiếp gây gọi handler chồng lên nhau nếu không mask).
- Code demo signal handler custom dùng
Advanced concepts
- Async-signal-safe function - danh sách hàm được phép gọi an toàn bên trong signal handler (VD
write()an toàn,malloc()không an toàn vì có thể đang giữ lock khi signal đến).
- Async-signal-safe function - danh sách hàm được phép gọi an toàn bên trong signal handler (VD
Ngày 3: Threads (pthread)
Cơ chế
pthread_create()tạo thread mới share toàn bộ address space với thread gốc - đây là lý do race condition dễ xảy ra: 2 thread cùng đọc/ghi 1 biến global mà không đồng bộ.
Thực hành và quan sát
- Viết chương trình multi-thread đơn giản (2 thread cùng tăng 1 biến counter global 1 triệu lần, không dùng mutex) - chạy nhiều lần, quan sát kết quả sai khác nhau mỗi lần (race condition thật).
Advanced concepts
- Fix bằng
pthread_mutex_lock/unlock, đo lại thấy kết quả luôn đúng nhưng chậm hơn - đánh đổi correctness vs performance khi đồng bộ hóa.
- Fix bằng
Ngày 4: Process Groups & Sessions
Cơ chế
- Ôn lại job control (Phase 1 Tuần 5) ở mức khái niệm chính thức: session (thường 1 terminal login) chứa nhiều process group, mỗi process group có 1 process group leader -
Ctrl+Cgửi SIGINT tới toàn bộ foreground process group, không phải 1 process đơn lẻ.
- Ôn lại job control (Phase 1 Tuần 5) ở mức khái niệm chính thức: session (thường 1 terminal login) chứa nhiều process group, mỗi process group có 1 process group leader -
Thực hành và quan sát
ps -o pid,pgid,sid,comm- xem process group ID và session ID thật của các process trong 1 pipeline (cmd1 | cmd2 | cmd3- cả 3 cùng process group).
Advanced concepts
- Controlling terminal - vì sao daemon thật sự (viết đúng chuẩn) phải
setsid()để tách khỏi session gốc, tránh nhận signal không mong muốn khi terminal đóng.
- Controlling terminal - vì sao daemon thật sự (viết đúng chuẩn) phải
Ngày 5: File I/O
Cơ chế
O_DIRECT- bypass hoàn toàn page cache, đọc/ghi thẳng xuống disk - dùng khi ứng dụng (VD database) tự quản lý cache riêng tốt hơn kernel generic page cache, tránh double caching.
Thực hành và quan sát
- So sánh throughput đọc file lớn với và không có
O_DIRECT(dùngddvớiiflag=direct) - lần đọc thứ 2 không cóO_DIRECTnhanh hơn hẳn nhờ page cache, cóO_DIRECTluôn đọc thật từ disk.
- So sánh throughput đọc file lớn với và không có
Advanced concepts
posix_fadvise()- gợi ý cho kernel về pattern truy cập sắp tới (POSIX_FADV_SEQUENTIAL,POSIX_FADV_RANDOM) để kernel tối ưu readahead phù hợp mà không cần bypass cache hoàn toàn nhưO_DIRECT.
Ngày 6: Ôn tập tuần 27
Thực hành
- Tổng hợp lại toàn bộ Ngày 1-5: viết 1 chương trình multi-process + multi-thread kết hợp, có signal handling đúng chuẩn, dùng
O_DIRECTcho phần ghi log - review code chéo với chính mình sau 1 ngày.
- Tổng hợp lại toàn bộ Ngày 1-5: viết 1 chương trình multi-process + multi-thread kết hợp, có signal handling đúng chuẩn, dùng
Ngày 7: IPC - pipe & FIFO
Cơ chế
- Pipe (đã dùng ở shell, Phase 1 Tuần 1) ở mức syscall:
pipe()tạo 2 file descriptor (đọc/ghi) trỏ vào cùng 1 buffer kernel. FIFO (named pipe) là pipe có tên trên filesystem, cho phép 2 process không quan hệ cha-con giao tiếp qua pipe.
- Pipe (đã dùng ở shell, Phase 1 Tuần 1) ở mức syscall:
Thực hành và quan sát
- Code 2 process giao tiếp qua
mkfifo+open()/read()/write(), chạy 2 terminal riêng biệt (không phải fork từ nhau).
- Code 2 process giao tiếp qua
Advanced concepts
- Pipe có buffer giới hạn (thường 64KB trên Linux) -
write()sẽ block nếu buffer đầy và chưa có airead(), đây là cơ chế "backpressure" tự nhiên trong pipeline shell.
- Pipe có buffer giới hạn (thường 64KB trên Linux) -
Ngày 8: Shared memory
Cơ chế
shmget()/shmat()(System V IPC cũ) vsmmap()vớiMAP_SHARED(POSIX, hiện đại hơn, đã chạm ở Tuần 20 Ngày 6) - cả 2 đều cho phép nhiều process không quan hệ họ hàng chia sẻ cùng 1 vùng memory vật lý, nhanh hơn pipe/socket vì không copy data qua kernel.
Thực hành và quan sát
- Code 2 process độc lập cùng
mmap()1 file vớiMAP_SHARED, ghi từ process A, đọc thấy ngay từ process B.
- Code 2 process độc lập cùng
Advanced concepts
- Shared memory không tự đồng bộ - cần kết hợp semaphore/mutex (Ngày 9) để tránh race condition khi nhiều process đọc/ghi cùng lúc.
Ngày 9: Semaphore/Mutex liên-process
Cơ chế
- Mutex thường (pthread) chỉ hoạt động giữa các thread cùng process; để đồng bộ giữa nhiều process cần semaphore đặt trong shared memory (
sem_initvớipshared=1) hoặc named semaphore (sem_open).
- Mutex thường (pthread) chỉ hoạt động giữa các thread cùng process; để đồng bộ giữa nhiều process cần semaphore đặt trong shared memory (
Thực hành và quan sát
- Đồng bộ hóa 2 process truy cập shared memory (Ngày 8) bằng semaphore, verify không còn race condition dù chạy nhiều lần.
Advanced concepts
- Deadlock kinh điển: 2 process cùng giữ 1 semaphore và chờ semaphore của process kia - cách phát hiện (
psstate, hoặc timeout khi acquire) và tránh (luôn acquire theo cùng 1 thứ tự).
- Deadlock kinh điển: 2 process cùng giữ 1 semaphore và chờ semaphore của process kia - cách phát hiện (
Ngày 10: Mini-project 3 - Producer-Consumer
Thực hành - dự án tổng hợp Tuần 27-28
- Viết 1 chương trình đa tiến trình (producer-consumer) hoàn chỉnh: producer ghi data vào shared memory (
mmap MAP_SHARED), consumer đọc ra, đồng bộ bằng semaphore, không dùng bất kỳ thư viện IPC high-level nào (tự tay dùng đúng syscall gốc đã học suốt 2 tuần).
- Viết 1 chương trình đa tiến trình (producer-consumer) hoàn chỉnh: producer ghi data vào shared memory (
Phase 4 - Kernel Source & Build (10 tuần)
Tuần 29: Setup build environment & compile kernel
Ngày 1: Clone kernel source
Cơ chế
- Kernel Linux là 1 git repo khổng lồ (~30 triệu dòng, hàng chục nghìn file) -
git clonefull history rất nặng,--depth=1chỉ lấy snapshot mới nhất (đủ dùng cho mục đích build/học, không cần full history trừ khi làm việc vớigit bisecttrên kernel thật sau này).
- Kernel Linux là 1 git repo khổng lồ (~30 triệu dòng, hàng chục nghìn file) -
Thực hành và quan sát
git clone --depth=1 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git, cài dependencies build (gcc,make,bc,bison,flex,openssl-devel,elfutils-libelf-devel).
Advanced concepts
- Kernel source có nhiều "tree" khác nhau (mainline của Linus, stable, linux-next chứa code sắp merge) - clone mainline là điểm khởi đầu chuẩn cho việc học.
Ngày 2: menuconfig
Cơ chế
make menuconfigđọc fileKconfigrải rác khắp source tree (mỗi subsystem cóKconfigriêng định nghĩa option của nó) - kết quả chọn lưu vào.config, quyết định phần nào của 30 triệu dòng code thực sự được compile.
Thực hành và quan sát
- Đi qua từng mục lớn (Processor type, Device Drivers, File systems, Networking) - không cần bật hết, chỉ cần hiểu cấu trúc phân cấp menu.
Advanced concepts
y(built-in),m(module, compile riêng .ko load sau), hoặc để trống (không compile) - 3 trạng thái này cho mỗi option, ảnh hưởng trực tiếp kích thước kernel image và thời gian boot.
Ngày 3: Build
Cơ chế
make -j$(nproc)build song song theo dependency graph (giống Make đã học Phase 2.5 Tuần 17, nhưng ở quy mô hàng chục nghìn file) - lần build đầu tiên chậm nhất vì chưa có object file nào được cache.
Thực hành và quan sát
- Build kernel lần đầu trên VM (dùng nhiều CPU core, chuẩn bị chờ 30 phút - vài giờ tùy cấu hình
.configvà số core).
- Build kernel lần đầu trên VM (dùng nhiều CPU core, chuẩn bị chờ 30 phút - vài giờ tùy cấu hình
Advanced concepts
ccache- cache compiler output giữa các lần build khác nhau (kể cả saumake clean), giảm đáng kể thời gian rebuild khi chỉ sửa vài file.
Ngày 4: Cài đặt kernel mới
Cơ chế
make modules_installcopy toàn bộ.komodule vào/lib/modules/<version>/,make installcopy kernel image + tự động chạydracut/grub2-mkconfigđể tạo initramfs mới và thêm entry GRUB mới - kernel cũ vẫn còn nguyên trong GRUB menu.
Thực hành và quan sát
make modules_install && make install, kiểm tra GRUB config có entry kernel mới, reboot vào đó.
Advanced concepts
- GRUB mặc định boot entry mới nhất - nếu kernel mới lỗi, cần biết cách chọn entry cũ ngay tại màn hình GRUB (phím mũi tên trước khi countdown hết) mà không cần rescue mode.
Ngày 5: Debug boot lỗi
Cơ chế
- Đây là bài học thực tế quan trọng nhất tuần: build kernel tự custom rất dễ thiếu driver cần thiết (VD driver cho virtio disk trên VM) nếu tắt nhầm option trong
menuconfig, dẫn đến kernel boot nhưng không tìm thấy root filesystem.
- Đây là bài học thực tế quan trọng nhất tuần: build kernel tự custom rất dễ thiếu driver cần thiết (VD driver cho virtio disk trên VM) nếu tắt nhầm option trong
Thực hành và quan sát
- Nếu boot lỗi (rất hay xảy ra lần đầu) - debug bằng GRUB rescue (chọn kernel cũ ở boot menu), so sánh
.configcũ/mới để tìm option bị thiếu.
- Nếu boot lỗi (rất hay xảy ra lần đầu) - debug bằng GRUB rescue (chọn kernel cũ ở boot menu), so sánh
Advanced concepts
zcat /proc/config.gz(nếu kernel hỗ trợ) - đọc.configcủa kernel đang chạy để so sánh chính xác với.configbạn vừa build, tìm ra option nào bị tắt nhầm.
Ngày 6: Ôn tập - tự động hóa build
Thực hành
- Build lại từ đầu, ghi lại toàn bộ quy trình (clone → menuconfig → build → install → reboot) thành 1 script bash tự động, để lần build sau không cần nhớ lại từng bước.
Tuần 30: QEMU boot-test & debug config
Ngày 1: QEMU thay VM thật
Cơ chế
- Boot-test kernel mới trực tiếp bằng QEMU (
qemu-system-x86_64 -kernel bzImage -initrd initramfs -append "console=ttyS0") nhanh hơn nhiều so với cài vào VM thật rồi reboot - không cần GRUB, không risk phá VM chính.
- Boot-test kernel mới trực tiếp bằng QEMU (
Thực hành và quan sát
- Cấu hình QEMU boot thẳng kernel vừa build với 1 rootfs tối giản (busybox), lặp lại chu trình sửa-build-test trong vài giây thay vì vài phút.
Advanced concepts
-append "console=ttyS0"- redirect kernel console output ra serial port thay vì VGA, cho phép xem log ngay trong terminal host mà không cần giao diện đồ họa.
Ngày 2: printk debug
Cơ chế
printk()là "printf của kernel" - ghi message vào kernel ring buffer (đọc bằngdmesg), có log level (KERN_INFO,KERN_ERR...) quyết định message có hiện ra console ngay hay chỉ nằm trong buffer.
Thực hành và quan sát
- Thêm
printk(KERN_INFO "checkpoint reached\n")vào 1 file kernel bất kỳ (VD trong hàm khởi tạo 1 driver), build lại, xem trongdmesgsau khi boot.
- Thêm
Advanced concepts
pr_info()/pr_err()- macro wrapper hiện đại hơnprintktrực tiếp, tự động thêm prefix tên module/file, là convention chuẩn trong kernel code ngày nay.
Ngày 3: Custom version string
Cơ chế
EXTRAVERSIONtrong fileMakefilegốc của kernel source cho phép thêm hậu tố tùy chỉnh vào version string - hữu ích để phân biệt kernel tự build với kernel chính thức khi có nhiều bản cùng cài trên 1 máy.
Thực hành và quan sát
- Đổi
EXTRAVERSION = -mylab, build, verify bằnguname -rsau khi boot vào kernel này.
- Đổi
Advanced concepts
scripts/setlocalversion- script tự động thêm hash git commit vào version string nếu build từ git repo có thay đổi chưa commit, giúp trace chính xác kernel đang chạy được build từ commit/state nào.
Ngày 4: Config tối giản
Cơ chế
make localmodconfig- tự động tạo.configchỉ chứa module đang thực sự được load trên hệ thống hiện tại (dựa trênlsmod), loại bỏ hàng nghìn driver không liên quan - giảm đáng kể thời gian build và kích thước kernel.
Thực hành và quan sát
- Build kernel với config tối giản này, so sánh thời gian build và boot time với kernel full-config ở Tuần 29.
Advanced concepts
- Đánh đổi: config tối giản build nhanh nhưng kém "portable" (thiếu driver nếu chuyển kernel image sang máy khác có phần cứng khác) - phù hợp cho lab/VM cố định, không phù hợp cho kernel distro chính thức.
Ngày 5: Checkpoint đo boot time
Thực hành
- So sánh boot time (dùng
systemd-analyze) giữa kernel full-config (Tuần 29) và kernel tối giản (Ngày 4) - định lượng cụ thể tác động của việc giảm số driver/module được compile.
- So sánh boot time (dùng
Ngày 6: Buffer/ôn tập QEMU workflow
Thực hành
- Viết script tự động hóa toàn bộ chu trình QEMU boot-test (build → copy kernel image → khởi động QEMU → capture log) thành 1 lệnh duy nhất, chuẩn bị workflow nhanh cho các tuần module/syscall tiếp theo.
Tuần 31: Kernel module - Hello World & proc entry
Ngày 1: Module Hello World
Cơ chế
- Kernel module (
.ko) là code có thể load/unload vào kernel đang chạy mà không cần reboot -module_init()/module_exit()là 2 macro đăng ký hàm callback chạy khiinsmod/rmmod.
- Kernel module (
Thực hành và quan sát
- Viết module "Hello World" kinh điển (in message qua
printkkhi load/unload), build bằngMakefilekiểu kernel module (dùngobj-m, gọi vào kernel build system quaKDIR).
- Viết module "Hello World" kinh điển (in message qua
Advanced concepts
- Module phải build với đúng version kernel đang chạy (dùng chung header/symbol) - đây là lý do
.kobuild cho kernel A thường không load được vào kernel B khác version.
- Module phải build với đúng version kernel đang chạy (dùng chung header/symbol) - đây là lý do
Ngày 2: insmod/rmmod/lsmod
Cơ chế
insmodload module thô (cần đường dẫn đầy đủ, không tự resolve dependency);modprobethông minh hơn (tự tìm trong/lib/modules/, tự load dependency).
Thực hành và quan sát
insmod hello.ko,lsmod | grep hello,rmmod hello, xem log quadmesgở cả 2 sự kiện load/unload.
Advanced concepts
modinfo hello.ko- xem metadata module (author, license, dependency) mà không cần load nó - kernel từ chối load module thiếuMODULE_LICENSE()khai báo đúng (tainted kernel warning nếu license không phải GPL-compatible).
Ngày 3: Module tham số
Cơ chế
module_param()cho phép truyền tham số lúcinsmod(VDinsmod hello.ko count=5) - giá trị này map trực tiếp vào biến C trong module, không cần hardcode.
Thực hành và quan sát
- Thêm 1 tham số integer vào module, load với giá trị khác nhau, verify qua
printkin ra giá trị nhận được.
- Thêm 1 tham số integer vào module, load với giá trị khác nhau, verify qua
Advanced concepts
/sys/module/hello/parameters/- tham số có thể đọc (và 1 số ghi được runtime) qua sysfs sau khi module đã load, không cần unload/reload để xem giá trị hiện tại.
Ngày 4: proc entry
Cơ chế
- Module có thể tạo file ảo trong
/proc(proc_create()) với callbackread/writetùy chỉnh - đây chính là cơ chế mà rất nhiều thông tin hệ thống bạn đã dùng suốt các phase trước (/proc/meminfo,/proc/net/tcp...) được implement.
- Module có thể tạo file ảo trong
Thực hành và quan sát
- Tạo 1 proc entry đơn giản (VD
/proc/hello_counter) tăng giá trị mỗi lần bị đọc, verify bằngcat /proc/hello_counternhiều lần.
- Tạo 1 proc entry đơn giản (VD
Advanced concepts
seq_fileAPI - cách chuẩn hiện đại để implement proc entry trả về nhiều dòng output an toàn (tránh lỗi buffer nếu output lớn hơn 1 page, vấn đề của API cũ hơn).
Ngày 5: Character device driver
Cơ chế
register_chrdev()đăng ký 1 major number cho driver, kernel route mọiopen()/read()/write()trên file device tương ứng (/dev/mydevice) vào các hàm callback của driver - đây là cách driver thật (VD driver bàn phím, chuột) hoạt động ở mức khái niệm.
Thực hành và quan sát
- Viết character device driver đơn giản,
mknod /dev/mydevice c <major> 0để tạo file device thủ công.
- Viết character device driver đơn giản,
Advanced concepts
udevtự động tạo file trong/devkhi driver đăng ký đúng chuẩn (class_create/device_create) thay vì phảimknodthủ công - đây là cách driver thật hoạt động trong production.
Ngày 6: Test device từ userspace
Thực hành
- Viết chương trình user-space đơn giản dùng
open()/read()/write()vào/dev/mydevice, verify data đi qua đúng chiều (ghi từ userspace, driver nhận được trongprintk; đọc từ userspace, nhận đúng data driver trả về).
- Viết chương trình user-space đơn giản dùng
Tuần 32: Đọc source
Ngày 1: kernel/sched/core.c
Cơ chế
- Đọc source
kernel/sched/core.ccó định hướng (không cần hiểu 100%) - tìm hàmschedule(), đối chiếu với lý thuyết CFS đã học Phase 3 Tuần 25 (vruntime, red-black tree).
- Đọc source
Thực hành và quan sát
grep -n "vruntime" kernel/sched/fair.c | head -30- tìm các đoạn code trực tiếp thao tácvruntime, đọc comment xung quanh.
Advanced concepts
- Kernel source có rất nhiều comment giải thích "vì sao" (design rationale), không chỉ "làm gì" - đọc comment thường hiệu quả hơn đọc từng dòng code logic khi mới bắt đầu.
Ngày 2: mm/page_alloc.c
Cơ chế
- Đọc
mm/page_alloc.c- tìm hiểu buddy allocator ở mức khái niệm: kernel quản lý free memory theo block kích thước lũy thừa 2 (1, 2, 4, 8... page), khi cần block nhỏ mà chỉ còn block lớn, chia đôi (split) - khi free, gộp lại (coalesce) nếu "buddy" (block liền kề cùng kích thước) cũng free.
- Đọc
Thực hành và quan sát
cat /proc/buddyinfo- xem trực tiếp số lượng free block theo từng "order" (kích thước) hiện tại trên hệ thống, đối chiếu với lý thuyết buddy allocator.
Advanced concepts
- External fragmentation - vì sao hệ thống chạy lâu có thể "còn nhiều RAM free tổng" nhưng không cấp phát được 1 block lớn liên tục (không đủ buddy pair để gộp lên order cao).
Ngày 3: fs/read_write.c
Cơ chế
- Đọc
fs/read_write.c- trace đường đi từ syscallread()(SYSCALL_DEFINE3(read, ...)) vào VFS (vfs_read()) rồi gọi tớifile->f_op->read(con trỏ hàm cụ thể của filesystem đang mount).
- Đọc
Thực hành và quan sát
- Đối chiếu đường đi vừa đọc với sơ đồ I/O path đã tự vẽ ở Phase 3 Tuần 23 - giờ thấy rõ từng bước tương ứng với dòng code cụ thể nào.
Advanced concepts
struct file_operations- đây chính là cơ chế "polymorphism kiểu C" (dùng function pointer trong struct) mà toàn bộ VFS dựa vào để hoạt động thống nhất trên nhiều filesystem khác nhau.
Ngày 4: Module hoàn chỉnh - viết
Thực hành - dự án
- Viết 1 module hoàn chỉnh kết hợp toàn bộ Tuần 31: có proc entry (đọc/ghi), nhận module parameter, character device driver, log đầy đủ qua
printk/pr_info.
- Viết 1 module hoàn chỉnh kết hợp toàn bộ Tuần 31: có proc entry (đọc/ghi), nhận module parameter, character device driver, log đầy đủ qua
Ngày 5: Module hoàn chỉnh - document
Thực hành
- Document lại code: comment giải thích từng hàm, viết README mô tả cách build/load/test module, chuẩn bị style tương tự code kernel thật (Kerrisk-style comment, không phải comment tự nhiên ngôn ngữ tùy tiện).
Ngày 6: Checkpoint
Thực hành
- Review lại module đã viết sau 1 ngày nghỉ - tự đặt câu hỏi "nếu người khác đọc code này mà không có tôi giải thích, họ có hiểu được luồng chạy không?".
Tuần 33: Thêm syscall mới - phần 1
Ngày 1: Cơ chế syscall table
Cơ chế
- Tìm hiểu cơ chế syscall table:
arch/x86/entry/syscalls/syscall_64.tbllà file ánh xạ số hiệu syscall → tên hàm kernel thật (sys_xxx) - đây là bảng mà CPU tra cứu khi userspace gọisyscallinstruction với số hiệu tương ứng trong register.
- Tìm hiểu cơ chế syscall table:
Thực hành và quan sát
grep sys_read arch/x86/entry/syscalls/syscall_64.tbl- tìm số hiệu syscall củaread(0), đối chiếu vớiman 2 syscallsliệt kê toàn bộ syscall có sẵn.
Advanced concepts
- Số hiệu syscall không được đổi thứ tự hay xóa sau khi đã public - đây là ABI (Application Binary Interface) ổn định mà Linux cam kết duy trì vĩnh viễn để không phá vỡ binary cũ.
Ngày 2: Viết định nghĩa syscall
Cơ chế
SYSCALL_DEFINE0()(không tham số) là macro chuẩn để định nghĩa 1 syscall mới, xử lý đúng calling convention và kernel/userspace boundary tự động thay vì viết hàm C thường.
Thực hành và quan sát
- Viết định nghĩa syscall mới đơn giản (VD trả về 1 số cố định, dùng
SYSCALL_DEFINE0), đặt trong 1 file.cmới trong kernel source.
- Viết định nghĩa syscall mới đơn giản (VD trả về 1 số cố định, dùng
Advanced concepts
- Vì sao không thể định nghĩa syscall bằng hàm C thường - macro
SYSCALL_DEFINEntự sinh thêm code kiểm tra/chuyển đổi tham số đúng chuẩn kernel calling convention.
- Vì sao không thể định nghĩa syscall bằng hàm C thường - macro
Ngày 3: Thêm vào bảng & build
Cơ chế
- Sau khi viết hàm, cần đăng ký nó vào
syscall_64.tbl(gán số hiệu mới) và khai báo prototype trong header tương ứng (include/linux/syscalls.h) trước khi build lại kernel.
- Sau khi viết hàm, cần đăng ký nó vào
Thực hành và quan sát
- Thêm syscall vào bảng, build lại kernel (dùng workflow QEMU đã tự động hóa ở Tuần 30 để test nhanh).
Advanced concepts
- Số hiệu syscall test/lab nên chọn ở vùng chưa dùng (thường cuối bảng) để tránh xung đột với syscall thật - kernel thật thêm syscall mới rất hiếm và qua quy trình review LKML nghiêm ngặt.
Ngày 4: Gọi syscall từ userspace
Cơ chế
- Chưa có wrapper glibc cho syscall tự viết - phải gọi trực tiếp qua
syscall(number, ...)(hàm generic trong glibc nhận số hiệu bất kỳ) thay vì gọi tên hàm quen thuộc.
- Chưa có wrapper glibc cho syscall tự viết - phải gọi trực tiếp qua
Thực hành và quan sát
- Viết chương trình C gọi syscall mới qua
syscall()trực tiếp, verify kết quả trả về đúng như hàm kernel đã viết.
- Viết chương trình C gọi syscall mới qua
Advanced concepts
- Vì sao syscall thật (đã ổn định) luôn có wrapper glibc (VD
read()) - wrapper xử lý thêm việc seterrnođúng chuẩn C library, syscall tự viết của bạn phải tự làm việc này nếu muốn dùng như hàm C bình thường.
- Vì sao syscall thật (đã ổn định) luôn có wrapper glibc (VD
Ngày 5: Debug lỗi build/runtime
Cơ chế
- Đây mới là phần học thật của bài tập - lỗi thường gặp: quên khai báo prototype đúng header, sai số tham số trong macro
SYSCALL_DEFINEn, hoặc build thành công nhưng gọi ra-ENOSYS(chưa được register đúng vào bảng đang dùng thật).
- Đây mới là phần học thật của bài tập - lỗi thường gặp: quên khai báo prototype đúng header, sai số tham số trong macro
Thực hành và quan sát
- Cố tình gây 2-3 lỗi phổ biến kể trên, quan sát thông báo lỗi build/runtime tương ứng, ghi chú lại cách nhận diện.
Advanced concepts
stracelên chính chương trình gọi syscall tự viết - xem syscall number thật được gọi, đối chiếu với bảng đã đăng ký để chắc chắn không nhầm số hiệu.
Ngày 6: Buffer/ôn tập
Thực hành
- Review lại toàn bộ chu trình Ngày 1-5, viết checklist cá nhân "các bước thêm 1 syscall mới" để dùng lại nhanh ở Tuần 34.
Tuần 34: Thêm syscall mới - phần 2 (tham số & validate)
Ngày 1: Syscall nhận tham số
Cơ chế
- Mở rộng: syscall nhận tham số từ user-space dùng
copy_from_user()- đây là hàm bắt buộc khi kernel cần đọc dữ liệu từ con trỏ userspace, vì kernel không được tin tưởng địa chỉ đó hợp lệ (userspace có thể truyền con trỏ rác/độc hại).
- Mở rộng: syscall nhận tham số từ user-space dùng
Thực hành và quan sát
- Mở rộng syscall Tuần 33 để nhận 1 chuỗi string từ userspace qua
copy_from_user(), in ra bằngprintk.
- Mở rộng syscall Tuần 33 để nhận 1 chuỗi string từ userspace qua
Advanced concepts
copy_to_user()- chiều ngược lại, dùng khi syscall cần trả dữ liệu về userspace qua con trỏ - cả 2 hàm đều tự kiểm tra địa chỉ hợp lệ và trả lỗi thay vì crash kernel nếu con trỏ sai.
Ngày 2: Validate input
Cơ chế
- Test edge case: tham số NULL, tham số sai (con trỏ trỏ vào vùng nhớ kernel thay vì userspace, độ dài âm...) - hiểu vì sao kernel luôn validate input nghiêm ngặt: 1 lỗi validate ở kernel-space có thể crash toàn hệ thống hoặc mở lỗ hổng bảo mật, khác lỗi ở userspace chỉ crash 1 process.
Thực hành và quan sát
- Test syscall tự viết với tham số NULL, con trỏ sai - verify hàm trả về lỗi đúng chuẩn (
-EFAULT,-EINVAL) thay vì kernel panic.
- Test syscall tự viết với tham số NULL, con trỏ sai - verify hàm trả về lỗi đúng chuẩn (
Advanced concepts
access_ok()- hàm kiểm tra nhanh 1 con trỏ có nằm trong vùng địa chỉ userspace hợp lệ trước khi thực sự copy, tránh side-effect không cần thiết nếu tham số rõ ràng sai ngay từ đầu.
Ngày 3: So sánh với syscall thật
Cơ chế
- So sánh cách bạn implement với 1 syscall thật đơn giản trong kernel (VD
getpid- gần như không làm gì ngoài đọccurrent->pid) - nhận ra syscall thật trong kernel thường rất ngắn gọn, phần lớn logic phức tạp nằm ở layer khác (VFS, scheduler) mà syscall chỉ gọi vào.
- So sánh cách bạn implement với 1 syscall thật đơn giản trong kernel (VD
Thực hành và quan sát
grep -A 5 "SYSCALL_DEFINE0(getpid)" kernel/sys.c- đọc implementation thật củagetpid, so sánh độ phức tạp với syscall tự viết của bạn.
Advanced concepts
currentmacro - cách kernel luôn biết "process nào đang gọi syscall này" mà không cần truyền tham số - trỏ tớitask_structcủa process hiện tại, lưu trong 1 vùng đặc biệt (thường qua register hoặc per-CPU variable) mà kernel maintain tại mọi thời điểm.
Ngày 4: Viết note tổng hợp flow
Thực hành
- Viết note giải thích toàn bộ flow: user gọi
syscall()→ CPU trap vào kernel mode (đổi privilege level) → kernel tra syscall table → gọi hàm tương ứng → xử lý (có thểcopy_from_user/copy_to_user) → trả về → CPU quay lại user mode.
- Viết note giải thích toàn bộ flow: user gọi
Ngày 5: Test case & stability
Thực hành
- Checkpoint: syscall của bạn hoạt động ổn định qua nhiều lần gọi liên tiếp, có test case cụ thể (input hợp lệ, input NULL, input biên) - chạy loop gọi syscall hàng nghìn lần không gây leak/crash.
Ngày 6: Ôn tập tổng hợp Tuần 33-34
Thực hành
- Mini-review: giải thích lại toàn bộ (không nhìn note) sự khác biệt giữa syscall bạn thêm ở đây và syscall bạn sẽ thêm vào xv6 sau này (Phase 5 Tuần 40) - dự đoán trước cái nào dễ hơn và vì sao.
Tuần 35: Debug kernel - panic & oops
Ngày 1: kgdb setup
Cơ chế
kgdbcho phép GDB (đã học Phase 2.5 Tuần 18) attach trực tiếp vào kernel đang chạy trong QEMU qua serial/network - khác GDB thường chỉ debug được userspace process.
Thực hành và quan sát
- Cấu hình QEMU + kernel debugging qua
kgdb(boot kernel với tham sốkgdboc=, kết nối GDB từ host).
- Cấu hình QEMU + kernel debugging qua
Advanced concepts
kgdbdừng toàn bộ hệ thống khi breakpoint trúng (không chỉ 1 process như GDB userspace) - vì kernel không có khái niệm "process khác vẫn chạy độc lập" ở mức thấp nhất khi đang debug chính nó.
Ngày 2: Gây kernel panic
Cơ chế
- Kernel panic xảy ra khi kernel gặp lỗi không thể phục hồi (null pointer dereference trong kernel-space, không giống userspace chỉ segfault 1 process) - toàn hệ thống dừng lại, in ra oops message.
Thực hành và quan sát
- Cố tình gây kernel panic (null pointer dereference trong module tự viết ở Tuần 31-32), đọc oops message hiện ra trên console.
Advanced concepts
- Oops (recoverable, kernel có thể tiếp tục nếu lỗi ở 1 subsystem không quan trọng) khác panic (không thể tiếp tục) - đọc kỹ message để phân biệt 2 loại.
Ngày 3: Đọc call stack trong oops
Cơ chế
- Oops message chứa call stack thô (địa chỉ instruction) - cần
addr2line/scripts/decode_stacktrace.sh(đi kèm kernel source) để dịch địa chỉ đó về tên hàm + số dòng source thật.
- Oops message chứa call stack thô (địa chỉ instruction) - cần
Thực hành và quan sát
- Dùng
addr2linevới đúngvmlinux(kernel image có debug symbol) để dịch địa chỉ trong oops vừa gây ra, xác nhận đúng dòng code đã cố tình gây lỗi.
- Dùng
Advanced concepts
- Kernel build với
CONFIG_DEBUG_INFO=ymới giữ đủ debug symbol đểaddr2linehoạt động chính xác - production kernel thường build không có debug info (để giảm kích thước), cần symbol table riêng để debug crash thật.
- Kernel build với
Ngày 4: crash utility
Cơ chế
crashlà công cụ chính thức RHEL dùng để phân tích kernel dump (khác GDB,crashhiểu cấu trúc dữ liệu kernel nhưtask_struct, có thể liệt kê toàn bộ process, memory state tại thời điểm crash).
Thực hành và quan sát
crashutility - phân tích kernel dump (RHEL dùng công cụ này cho production debugging thật, đây là công cụ Red Hat Support yêu cầu khi xử lý ticket liên quan kernel crash).
Advanced concepts
crashcần đúngvmlinux+ dump file khớp version - đây là lý do RHEL luôn giữ lại debuginfo package tương ứng từng kernel version đã release, để có thể phân tích dump từ khách hàng bất kỳ lúc nào.
Ngày 5: Thực hành phân tích dump
Thực hành và quan sát
- Tạo kernel panic có chủ đích (khác lỗi Ngày 2, dùng
crashđể phân tích lại dump thay vì đọc oops message trực tiếp trên console) - so sánh 2 cách tiếp cận.
- Tạo kernel panic có chủ đích (khác lỗi Ngày 2, dùng
Ngày 6: Ôn tập checklist panic
Thực hành
- Viết checklist "khi server RHEL bị kernel panic, làm gì đầu tiên" (kiểm tra kdump có được cấu hình không → thu thập dump →
sosreportđã học Phase 2 → phân tích bằngcrashhoặc gửi Red Hat Support).
- Viết checklist "khi server RHEL bị kernel panic, làm gì đầu tiên" (kiểm tra kdump có được cấu hình không → thu thập dump →
Tuần 36: kdump
Ngày 1: Đọc tài liệu kdump chính thức
Cơ chế
- Ôn lại khái niệm đã giới thiệu ở Phase 2 Tuần 16 (kexec/kdump bridge note) - giờ đọc
Documentation/admin-guide/kdump/để hiểu đầy đủ cấu hình thật:crashkernel=reserve 1 vùng RAM riêng cho kernel dự phòng,kdump.servicetự động trigger khi panic xảy ra.
- Ôn lại khái niệm đã giới thiệu ở Phase 2 Tuần 16 (kexec/kdump bridge note) - giờ đọc
Thực hành và quan sát
- Đọc tài liệu, xác định dung lượng
crashkernel=phù hợp với RAM của VM lab (thường vài trăm MB tối thiểu).
- Đọc tài liệu, xác định dung lượng
Advanced concepts
- Vì sao cần reserve RAM trước (lúc boot kernel chính), không thể cấp phát sau khi panic xảy ra - kernel chính đã panic nghĩa là memory allocator của nó không còn tin cậy được.
Ngày 2: Cấu hình kdump thật
Thực hành và quan sát
- Thêm
crashkernel=256Mvào GRUB kernel parameter, enable + startkdump.service, verify bằngkdumpctl status/systemctl status kdump.
- Thêm
Advanced concepts
/etc/kdump.conf- cấu hình nơi lưu dump (local disk, NFS, SSH remote) - production thường lưu dump ra remote để tránh trường hợp local disk cũng bị ảnh hưởng bởi nguyên nhân gây crash.
Ngày 3: Test kdump
Cơ chế
sysrq trigger(echo c > /proc/sysrq-trigger) là cách chuẩn để test kdump có hoạt động đúng hay không mà không cần chờ crash thật xảy ra tự nhiên.
Thực hành và quan sát
- Test kdump: trigger crash bằng
sysrq trigger, verify dump được ghi lại đúng vị trí đã cấu hình sau khi hệ thống tự reboot.
- Test kdump: trigger crash bằng
Advanced concepts
- SysRQ có nhiều lệnh debug khác ngoài trigger crash (
echo win stack trace mọi task,echo min memory info) - hữu ích để chẩn đoán hệ thống "đứng hình" (hang) mà chưa tới mức panic thật.
- SysRQ có nhiều lệnh debug khác ngoài trigger crash (
Ngày 4: Phân tích dump vừa tạo
Thực hành và quan sát
- Phân tích dump vừa tạo bằng
crash(đã học cách dùng Tuần 35), xác nhận thấy đúng call stack tại điểmsysrq triggerđược gọi.
- Phân tích dump vừa tạo bằng
Ngày 5: So sánh 2 luồng debug
Thực hành
- Đối chiếu luồng "đọc oops trực tiếp trên console" (Tuần 35) với luồng "kdump → phân tích offline bằng crash" - nhận ra production luôn cần luồng thứ 2 vì console log thường không được giữ lại sau khi hệ thống tự reboot.
Ngày 6: Mini-project 4 - Production incident giả lập
Thực hành - dự án tổng hợp
- Toàn bộ flow "production incident giả lập": kernel panic (trigger có chủ đích) → kdump tự động capture → dùng
crashphân tích dump → viết root cause report đầy đủ (thời điểm crash, call stack, nguyên nhân, khuyến nghị khắc phục) như 1 báo cáo incident thật gửi cho team.
- Toàn bộ flow "production incident giả lập": kernel panic (trigger có chủ đích) → kdump tự động capture → dùng
Tuần 37-38: Đọc Linux Kernel Development (Robert Love) song song thực hành
Ngày 1: Chương Introduction & Process Management
Cơ chế
- Đọc chương giới thiệu kiến trúc tổng thể kernel + chương Process Management - đối chiếu trực tiếp với
task_struct,fork()/clone()đã thực hành ở Phase 3 Tuần 20-21.
- Đọc chương giới thiệu kiến trúc tổng thể kernel + chương Process Management - đối chiếu trực tiếp với
Thực hành và quan sát
- Tự tóm tắt chương bằng 5 dòng, highlight điểm khác với những gì đã tự tìm hiểu qua source code trước đó.
Ngày 2: Chương Process Scheduling
Cơ chế
- Đọc sâu hơn về CFS so với những gì đã học Phase 3 Tuần 25 - sách giải thích thêm về scheduling class (
SCHED_NORMAL,SCHED_FIFO,SCHED_RR) và cách kernel chọn class nào chạy trước.
- Đọc sâu hơn về CFS so với những gì đã học Phase 3 Tuần 25 - sách giải thích thêm về scheduling class (
Thực hành và quan sát
- Đối chiếu nội dung sách với code
kernel/sched/core.cđã đọc ở Tuần 32.
- Đối chiếu nội dung sách với code
Ngày 3: Chương System Calls
Cơ chế
- Đọc chương System Calls - so sánh cách sách giải thích quy trình thêm syscall mới với kinh nghiệm thực tế bạn đã làm ở Tuần 33-34, ghi chú lại điểm sách nói mà bạn chưa để ý lúc thực hành.
Ngày 4: Chương Kernel Data Structures
Cơ chế
- Đọc về
linked list,red-black tree(đã chạm khi học CFS),radix tree- cấu trúc dữ liệu kernel dùng nội bộ, khác thư viện chuẩn C thường dùng ở userspace (kernel không có STL/glibc container).
- Đọc về
Ngày 5: Chương Memory Management
Cơ chế
- Đọc sâu hơn buddy allocator (đã đọc source Tuần 32) và giới thiệu thêm slab allocator (cấp phát object nhỏ, cùng kích thước, tần suất cao - VD
task_structmới mỗi lần fork) - buddy allocator không hiệu quả cho việc này vì luôn cấp theo page.
- Đọc sâu hơn buddy allocator (đã đọc source Tuần 32) và giới thiệu thêm slab allocator (cấp phát object nhỏ, cùng kích thước, tần suất cao - VD
Ngày 6: Ôn tập tuần 37
Thực hành
- Tổng hợp 5 chương đã đọc, viết bản đồ liên kết giữa lý thuyết sách và phần thực hành tương ứng đã làm ở Phase 3-4.
Ngày 7: Chương Virtual Filesystem
Cơ chế
- Đọc sâu hơn VFS (đã đọc source Tuần 32, khái niệm Phase 3 Tuần 22) - sách giải thích rõ hơn mối quan hệ giữa
struct super_block,struct inode,struct dentry,struct file.
- Đọc sâu hơn VFS (đã đọc source Tuần 32, khái niệm Phase 3 Tuần 22) - sách giải thích rõ hơn mối quan hệ giữa
Ngày 8: Chương Block I/O
Cơ chế
- Đọc sâu hơn block layer (đã học khái niệm Phase 3 Tuần 22) -
struct biolà đơn vị I/O request cơ bản kernel dùng nội bộ, không phải "1 lệnh read/write" đơn giản như userspace nhìn thấy.
- Đọc sâu hơn block layer (đã học khái niệm Phase 3 Tuần 22) -
Ngày 9: Chương Kernel Synchronization
Cơ chế
- Đọc về spinlock, semaphore, RCU (Read-Copy-Update) - kernel cần nhiều cơ chế đồng bộ khác nhau tùy ngữ cảnh (interrupt context không được ngủ, nên phải dùng spinlock chứ không phải mutex).
Thực hành và quan sát
- Đối chiếu với race condition đã tự tạo và fix ở Phase 3 Tuần 27 (pthread mutex ở userspace) - nhận ra kernel-space có nhiều ràng buộc hơn hẳn (không được block tùy tiện trong 1 số context).
Ngày 10: Tổng kết Phase 4
Thực hành
- Viết 1 tài liệu tổng kết cá nhân: liệt kê toàn bộ khái niệm kernel đã học qua Phase 3-4 (process, memory, scheduler, VFS, block I/O, syscall, module, debug), đánh giá mức độ tự tin với từng mảng trước khi bước vào Phase 5 (xv6).
Phase 5 - Capstone: Tự xây OS (8 tuần)
Đây là phần trả lời trực tiếp câu hỏi "không tự làm OS thì không hiểu hết". Không cần viết từ số 0 hoàn toàn - dùng xv6 (kernel giáo dục của MIT, ~10.000 dòng C, dùng trong khóa 6.1810) làm nền, qua bộ lab chính thức của MIT (miễn phí, public: pdos.csail.mit.edu/6.1810/).
Tuần 39: Làm quen xv6
Ngày 1: Clone & build
Cơ chế
- xv6-riscv build bằng RISC-V cross-compiler (không phải x86 như toàn bộ Phase 1-4) - chạy trên QEMU giả lập RISC-V, đây là lựa chọn kiến trúc đơn giản hơn x86 rất nhiều (ít legacy, ít mode chuyển đổi phức tạp), phù hợp mục đích giáo dục.
Thực hành và quan sát
- Clone xv6-riscv, cài
riscv64-unknown-elf-gcctoolchain,make qemu- build và chạy trên QEMU trong 1 lệnh.
- Clone xv6-riscv, cài
Advanced concepts
- So sánh độ phức tạp toolchain: build kernel Linux thật (Phase 4 Tuần 29) cần hàng chục dependency và
.configkhổng lồ; xv6 build chỉ cần 1Makefilengắn gọn - đây chính là lý do xv6 phù hợp để đọc hết trong vài tuần.
- So sánh độ phức tạp toolchain: build kernel Linux thật (Phase 4 Tuần 29) cần hàng chục dependency và
Ngày 2: Đọc toàn bộ source 1 lượt
Cơ chế
- Đọc toàn bộ source (chỉ ~10k dòng, khả thi) một lượt để có bức tranh tổng thể - không cần hiểu sâu từng dòng, mục tiêu là nhận diện cấu trúc thư mục (
kernel/,user/) và tên file tương ứng với subsystem nào (proc.c,vm.c,fs.c,trap.c).
- Đọc toàn bộ source (chỉ ~10k dòng, khả thi) một lượt để có bức tranh tổng thể - không cần hiểu sâu từng dòng, mục tiêu là nhận diện cấu trúc thư mục (
Thực hành và quan sát
wc -l kernel/*.c | sort -n- liệt kê file theo độ dài, ưu tiên đọc file ngắn trước để làm quen coding style.
Advanced concepts
- So sánh trực tiếp với Linux thật (30 triệu dòng vs 10 nghìn dòng) - xv6 loại bỏ gần như toàn bộ driver, tối ưu hóa, và edge-case handling mà Linux thật cần cho production, chỉ giữ lại "bộ khung" khái niệm cốt lõi.
Ngày 3: xv6 book - OS interfaces
Cơ chế
- Đọc "xv6 book" (tài liệu chính thức đi kèm) chương 1-2: OS interfaces - giới thiệu triết lý thiết kế Unix-like (mọi thứ là file descriptor,
fork/exectách biệt) mà bạn đã thực hành trên Linux thật ở Phase 3 Tuần 20, giờ xem lại từ góc độ "implement nó từ đầu trông như thế nào".
- Đọc "xv6 book" (tài liệu chính thức đi kèm) chương 1-2: OS interfaces - giới thiệu triết lý thiết kế Unix-like (mọi thứ là file descriptor,
Thực hành và quan sát
- Đọc song song source code
kernel/proc.ckhi đọc chương sách tương ứng, đối chiếu code thật với mô tả trong sách.
- Đọc song song source code
Ngày 4: Trace boot process xv6
Cơ chế
- Boot process xv6 đơn giản hơn Linux thật nhiều (không có BIOS/UEFI/GRUB phức tạp - QEMU load thẳng kernel image vào RAM ở địa chỉ cố định) - dễ theo dõi từng dòng từ
entry.S(assembly đầu tiên chạy) đếnmain()trong C.
- Boot process xv6 đơn giản hơn Linux thật nhiều (không có BIOS/UEFI/GRUB phức tạp - QEMU load thẳng kernel image vào RAM ở địa chỉ cố định) - dễ theo dõi từng dòng từ
Thực hành và quan sát
- Đọc
kernel/entry.S→kernel/main.c, đặtprintfdebug ở đầu mỗi hàm khởi tạo subsystem (kinit,procinit,trapinit...), quan sát thứ tự khởi tạo thật khi boot.
- Đọc
Advanced concepts
- So sánh với boot process Linux thật đã học Phase 3 Tuần 25 (BIOS/UEFI → GRUB → initramfs → systemd) - xv6 bỏ qua toàn bộ phần "tìm và load kernel", chỉ tập trung vào phần "kernel tự khởi tạo chính nó" mà Linux thật cũng phải làm tương tự sau khi GRUB load xong.
Ngày 5: Utilities lab
Thực hành - lab chính thức MIT
- Utilities lab - viết vài chương trình user-space cho xv6 (VD
sleep,pingpong,find,xargs) dùng đúng syscall xv6 cung cấp - bài tập làm quen viết code chạy trên OS tự build, không phải Linux thật.
- Utilities lab - viết vài chương trình user-space cho xv6 (VD
Advanced concepts
- xv6 cung cấp tập syscall rất nhỏ (khoảng 20 syscall) so với Linux thật (hơn 300) - nhưng đủ để viết được
find/xargscơ bản, cho thấy phần lớn syscall Linux thật là để tối ưu/tiện lợi, không phải "bắt buộc" về mặt nguyên lý.
- xv6 cung cấp tập syscall rất nhỏ (khoảng 20 syscall) so với Linux thật (hơn 300) - nhưng đủ để viết được
Ngày 6: Ôn tập - giải thích flow boot đến shell
Thực hành
- Giải thích được toàn bộ flow boot → init → shell chạy được lệnh đầu tiên (không nhìn note) - đây là nền tảng bắt buộc trước khi bắt đầu sửa/mở rộng kernel ở các tuần sau.
Tuần 40: System calls trong xv6
Ngày 1-2: Đọc chương Traps
Cơ chế
- Đọc xv6 book chương Traps - cơ chế syscall trong xv6 đơn giản hơn Linux thật (không có nhiều lớp tối ưu như vDSO), dễ nắm cơ chế gốc: user gọi
ecall(RISC-V instruction tương đươngsyscalltrên x86) → trap vào kernel →usertrap()xử lý → dispatch tới hàm syscall tương ứng qua bảngsyscalls[].
- Đọc xv6 book chương Traps - cơ chế syscall trong xv6 đơn giản hơn Linux thật (không có nhiều lớp tối ưu như vDSO), dễ nắm cơ chế gốc: user gọi
Thực hành và quan sát
- Đọc
kernel/syscall.c, đối chiếu bảngsyscalls[]vớiarch/x86/entry/syscalls/syscall_64.tblđã dùng ở Phase 4 Tuần 33 - cùng khái niệm, quy mô nhỏ hơn rất nhiều.
- Đọc
Ngày 3-5: System calls lab
Thực hành - lab chính thức MIT, dự án chính của tuần
- System calls lab - tự thêm syscall mới vào xv6 (giống bài tập Phase 4 Tuần 33-34 nhưng trên kernel nhỏ hơn nhiều, dễ debug hơn: không cần chờ build 30 phút, không cần lo thiếu driver gây boot lỗi).
Advanced concepts
- Vì xv6 không có
copy_from_user/copy_to_userphức tạp như Linux thật (dùng hàm đơn giản hơncopyin/copyoutdo chính bạn đọc được toàn bộ implementation), đây là cơ hội hiểu tại sao Linux thật cần các cơ chế bảo vệ phức tạp hơn (nhiều kiến trúc CPU, nhiều edge case bảo mật) mà xv6 lược bỏ.
- Vì xv6 không có
Ngày 6: So sánh xv6 vs Linux thật
Thực hành
- So sánh: syscall bạn thêm vào xv6 vs syscall bạn thêm vào Linux thật (Phase 4 Tuần 33-34) - ghi chú khác biệt cụ thể (độ phức tạp code, thời gian build-test cycle, số bước validate cần thiết).
Tuần 41: Page tables (Memory)
Ngày 1-2: Đọc chương Page tables
Cơ chế
- Đọc xv6 book chương Page tables - RISC-V dùng page table 3 cấp (Sv39), đơn giản hơn 4 cấp của x86-64 (đã học khái niệm Phase 3 Tuần 20) nhưng cùng nguyên lý dịch địa chỉ ảo → vật lý.
Thực hành và quan sát
- Đọc
kernel/vm.c, tìm hàmwalk()(hàm duyệt page table qua từng cấp) - đối chiếu với lý thuyết multi-level page table đã đọc ởmm/page_alloc.c(Phase 4 Tuần 32).
- Đọc
Ngày 3-6: Page tables lab
Thực hành - lab chính thức MIT
- Page tables lab - implement thêm tính năng liên quan virtual memory (VD: in ra nội dung page table của 1 process ở dạng đọc được, hoặc superpages tùy version lab hiện tại của MIT).
Advanced concepts
- Sau khi implement, bạn có thể tận mắt in ra đúng những gì
/proc/<pid>/maps(Phase 3 Tuần 20) hiển thị trên Linux thật - nhưng lần này là code bạn tự viết để tạo ra thông tin đó, không phải đọc output có sẵn.
- Sau khi implement, bạn có thể tận mắt in ra đúng những gì
Tuần 42: Traps & Interrupts
Ngày 1-2: Đọc chương Traps sâu hơn
Cơ chế
- Interrupt, exception, và syscall đều đi qua cùng 1 cơ chế trap trong xv6 - CPU chuyển từ user mode sang supervisor mode, lưu lại state, nhảy vào 1 điểm entry cố định (
kernelvec/uservec), sau đó kernel phân loại đây là loại trap nào (timer interrupt, page fault, syscall...) để xử lý đúng.
- Interrupt, exception, và syscall đều đi qua cùng 1 cơ chế trap trong xv6 - CPU chuyển từ user mode sang supervisor mode, lưu lại state, nhảy vào 1 điểm entry cố định (
Thực hành và quan sát
- Đọc
kernel/trap.c, đối chiếu cách phân loại trap trongusertrap()với khái niệm "unified trap mechanism" - giải thích được vì sao 1 cơ chế duy nhất có thể xử lý cả 3 loại sự kiện rất khác nhau này.
- Đọc
Ngày 3-6: Traps lab
Thực hành - lab chính thức MIT
- Traps lab - thường bao gồm: implement stack backtrace (in call stack thủ công không dùng debugger, tự đọc frame pointer), xử lý alarm (kernel gọi lại 1 hàm userspace định kỳ dựa trên timer interrupt - tương tự khái niệm
SIGALRMtrên Linux thật).
- Traps lab - thường bao gồm: implement stack backtrace (in call stack thủ công không dùng debugger, tự đọc frame pointer), xử lý alarm (kernel gọi lại 1 hàm userspace định kỳ dựa trên timer interrupt - tương tự khái niệm
Advanced concepts
- Implement backtrace thủ công ở đây giúp hiểu sâu hơn cách GDB (Phase 2.5 Tuần 18) tự động làm việc tương tự khi bạn gõ
backtrace- bạn vừa tự tay làm cái mà GDB làm ẩn đằng sau.
- Implement backtrace thủ công ở đây giúp hiểu sâu hơn cách GDB (Phase 2.5 Tuần 18) tự động làm việc tương tự khi bạn gõ
Tuần 43: Copy-on-write/Multithreading
Ngày 1-2: Đọc chương Scheduling
Cơ chế
- xv6 dùng round-robin scheduler đơn giản (khác hẳn CFS phức tạp của Linux thật đã học Phase 3 Tuần 25) - mỗi process được cấp 1 time-slice cố định theo vòng, không có khái niệm "fairness" tinh vi dựa trên
vruntime.
- xv6 dùng round-robin scheduler đơn giản (khác hẳn CFS phức tạp của Linux thật đã học Phase 3 Tuần 25) - mỗi process được cấp 1 time-slice cố định theo vòng, không có khái niệm "fairness" tinh vi dựa trên
Thực hành và quan sát
- Đọc
kernel/proc.chàmscheduler()- so sánh độ đơn giản vớikernel/sched/core.c(Linux thật) đã đọc ở Phase 4 Tuần 32.
- Đọc
Ngày 3-6: Copy-on-write fork lab
Thực hành - lab chính thức MIT, bài kinh điển
- Copy-on-write fork lab - tối ưu hóa
fork(): thay vì copy toàn bộ memory của parent ngay lập tức (như implementation xv6 gốc rất ngây thơ), chỉ copy page table và đánh dấu page read-only + shared, thật sự copy dữ liệu (page fault handler xử lý) chỉ khi 1 trong 2 bên ghi vào.
- Copy-on-write fork lab - tối ưu hóa
Advanced concepts
- Đây chính là cơ chế thật sự mà
fork()trên Linux dùng (đã học khái niệm ở Phase 1 Tuần 5 khi nói "copy-on-write, không copy thật ngay") - giờ bạn tự tay implement chính xác cơ chế đó, hiểu rõ vì saofork()trên Linux thật rất nhanh dù process có hàng GB memory.
- Đây chính là cơ chế thật sự mà
Tuần 44: Lock & Multiprocessor
Ngày 1-2: Đọc chương Lock
Cơ chế
- Race condition trong kernel thật (không phải chỉ userspace pthread đã học Phase 3 Tuần 27) - tại sao cần spinlock: trên hệ thống nhiều CPU core (xv6 hỗ trợ multiprocessor giả lập qua QEMU), 2 core có thể cùng lúc chạy code kernel và đụng độ cấu trúc dữ liệu chung (VD
struct proclist).
- Race condition trong kernel thật (không phải chỉ userspace pthread đã học Phase 3 Tuần 27) - tại sao cần spinlock: trên hệ thống nhiều CPU core (xv6 hỗ trợ multiprocessor giả lập qua QEMU), 2 core có thể cùng lúc chạy code kernel và đụng độ cấu trúc dữ liệu chung (VD
Thực hành và quan sát
- Đọc
kernel/spinlock.c- implementation spinlock rất ngắn gọn (dùng atomic instructionamoswapcủa RISC-V), so sánh khái niệm vớipthread_mutex(userspace, có thể ngủ) đã dùng Phase 3 Tuần 27.
- Đọc
Ngày 3-6: Lock lab
Thực hành - lab chính thức MIT
- Lock lab - fix race condition trong xv6 (thường liên quan tới memory allocator hoặc buffer cache dùng chung 1 lock cho toàn bộ hệ thống, gây bottleneck khi nhiều core cùng cần cấp phát/đọc block) - bài tập bắt buộc hiểu concurrency ở mức kernel.
Advanced concepts
- Kỹ thuật chia nhỏ lock (per-CPU allocator thay vì 1 global lock) - chính là ý tưởng cốt lõi mà Linux thật dùng ở quy mô lớn hơn rất nhiều (per-CPU variable, RCU đã đọc khái niệm ở Phase 4 Tuần 37-38) để scale tới hàng trăm core.
Tuần 45: File system
Ngày 1-2: Đọc chương File System
Cơ chế
- inode, log-based crash recovery trong xv6 (bản mini của journaling thật đã học khái niệm Phase 3 Tuần 22) - xv6 filesystem có layer rõ ràng: disk → buffer cache → logging layer (đảm bảo crash-safety) → inode layer → directory layer → file descriptor layer, mỗi layer 1 file
.criêng, dễ đọc tuần tự.
- inode, log-based crash recovery trong xv6 (bản mini của journaling thật đã học khái niệm Phase 3 Tuần 22) - xv6 filesystem có layer rõ ràng: disk → buffer cache → logging layer (đảm bảo crash-safety) → inode layer → directory layer → file descriptor layer, mỗi layer 1 file
Thực hành và quan sát
- Đọc
kernel/fs.c,kernel/log.ctheo đúng thứ tự layer trong sách - đối chiếu trực tiếp với khái niệm VFS/inode/journaling đã học ở Linux thật.
- Đọc
Ngày 3-6: File system lab
Thực hành - lab chính thức MIT
- File system lab - thêm tính năng vào xv6 fs (VD large files - hỗ trợ indirect block cấp 2 để file lớn hơn giới hạn gốc, hoặc symlinks - liên kết mềm giống
ln -sđã dùng suốt các phase trước).
- File system lab - thêm tính năng vào xv6 fs (VD large files - hỗ trợ indirect block cấp 2 để file lớn hơn giới hạn gốc, hoặc symlinks - liên kết mềm giống
Advanced concepts
- Sau khi implement large file support, bạn hiểu chính xác vì sao filesystem thật (ext4/xfs) cần cấu trúc block pointer phức tạp hơn nhiều (multi-level indirect, extent-based ở xfs) để hỗ trợ file terabyte mà vẫn tra cứu nhanh.
Tuần 46: Tổng kết & (tùy chọn) bare-metal OSDev
Ngày 1-3: Ôn tập toàn bộ xv6
Thực hành
- Viết 1 tài liệu tổng kết kiến trúc xv6 hoàn chỉnh bằng lời của bạn: process (fork/exec/scheduling), memory (page table/copy-on-write), fs (inode/log), syscall (trap mechanism), lock (spinlock/concurrency) - đồng thời chú thích mỗi phần tương ứng với khái niệm nào đã học ở Linux thật (Phase 3-4).
Advanced concepts
- Đây là bài tập tổng hợp quan trọng nhất Phase 5: khả năng map kiến thức từ 1 kernel nhỏ (xv6, đọc hết được) sang kernel lớn (Linux, không đọc hết được) chính là kỹ năng thật sự hữu ích - bạn sẽ dùng kỹ năng "map khái niệm" này suốt sự nghiệp khi gặp bất kỳ hệ thống phức tạp mới nào.
Ngày 4-6: Tùy chọn nâng cao - bare-metal OSDev
Thực hành (tùy chọn)
- Nếu muốn trải nghiệm viết bootloader thật từ x86 assembly (điều xv6 đã làm sẵn cho bạn qua QEMU boot thẳng), theo OSDev.org "Bare Bones" tutorial - viết bootloader + nhảy vào 32-bit protected mode + in ra "Hello World" lên màn hình VGA trực tiếp bằng assembly + C.
Advanced concepts
- Đây là trải nghiệm "từ số 0 tuyệt đối" - nhưng làm sau khi đã hiểu xv6 sẽ hiệu quả hơn nhiều vì bạn đã biết bức tranh lớn (process/memory/fs/syscall) và chỉ còn thiếu mảnh ghép "làm sao CPU đi từ trạng thái vừa bật nguồn đến chạy được C code" - đúng phạm vi mà bare-metal tutorial này lấp đầy.
Phase 6 - Tự định hướng
Không còn lịch ngày cụ thể - đây là giai đoạn tự định hướng dựa trên toàn bộ nền tảng đã xây dựng qua Phase 1-5:
Theo dõi LKML (lore.kernel.org) hàng tuần, đọc thread liên quan mảng bạn thích - giờ bạn đã có đủ vốn từ vựng kỹ thuật (process, memory, VFS, syscall, lock) để hiểu phần lớn thảo luận thay vì chỉ đọc lướt.
Chọn 1 mảng để đào sâu thành chuyên gia: networking stack (Phase 3 Tuần 26 + Phase 3 Tuần 24 eBPF), cgroups/namespaces (Phase 2 Tuần 12 + Tuần 14), hoặc filesystem (Phase 3 Tuần 22 + Phase 5 Tuần 45) - mỗi mảng đều đã có nền tảng vững từ lộ trình.
Sửa 1 bug nhỏ trong kernel thật (coding style/doc typo), gửi patch đầu tiên qua
git send-email- quy trình đóng góp thật, dùng đúng kỹ năng Git đã học ở Phase 2.5 Tuần 19 (format-patch,am).Tham gia kernelnewbies.org - cộng đồng dành riêng cho người mới muốn đóng góp kernel.