O modificare aparent banală în calculul unei cote poate introduce un integer overflow, poate altera starea după o operație respinsă sau poate elibera mai multe resurse decât au fost rezervate. În acest laborator construim quota_guard, un modul Linux minimal care contabilizează o cotă, apoi îi verificăm contractul cu cinci teste KUnit executate direct într-un kernel User Mode Linux — UML.
Rezultatul verificabil este un arbore Linux 6.17 care conține modulul, suita quota_guard și un script automat. Scriptul configurează kernelul, îl compilează, pornește instanța UML, colectează rezultatele KUnit într-un fișier și întoarce cod diferit de zero dacă testele nu trec.
UML izolează testul de kernelul utilizat de stația de lucru. Nu instalăm kernelul compilat și nu încărcăm cod experimental în kernelul gazdă. KUnit rămâne însă un framework de teste unitare: verifică funcțiile și starea internă a componentei, nu înlocuiește testarea integrării cu dispozitive, concurență reală ori subsistemele complete.
Fixăm laboratorul la Linux 6.17 și la un kernel UML fără privilegii root
Varianta concretă folosită aici este Ubuntu 24.04 LTS pe x86_64, sursa oficială Linux 6.17, Python 3.12 și GCC 13. Sunt recomandate cel puțin patru nuclee CPU, 8 GB RAM și 12 GB liberi. Prima compilare durează, în mod obișnuit, între 30 și 60 de minute pe un sistem desktop modern; timpul depinde de procesor și de stocare.
Verifică mediul înainte să descarci sursa:
printf 'Distribuție:n'
grep -E '^(NAME|VERSION_ID)=' /etc/os-release
printf 'nArhitectură:n'
uname -m
printf 'nCompilator:n'
gcc --version | head -n 1
printf 'nPython:n'
python3 --version
printf 'nProcesoare disponibile:n'
nproc
printf 'nSpațiu liber în HOME:n'
df -h "$HOME"
Un exemplu de rezultat compatibil este:
Distribuție:
NAME="Ubuntu"
VERSION_ID="24.04"
Arhitectură:
x86_64
Compilator:
gcc (Ubuntu 13.x...) 13.x
Python:
Python 3.12.x
Procesoare disponibile:
8
Spațiu liber în HOME:
Filesystem Size Used Avail Use% Mounted on
... ... ... 20G ... /home
Numerele de patch ale GCC, Python și distribuției pot diferi după actualizări. Condițiile importante pentru acest laborator sunt Ubuntu 24.04, arhitectura x86_64, Python 3 și o versiune GCC acceptată de Linux 6.17.
Dacă vrei să înțelegi separat procesul de configurare și compilare, ghidul despre compilarea unui kernel Linux personalizat fără eliminarea driverelor esențiale explică relația dintre Kconfig, .config și sistemul Kbuild. Aici nu instalăm kernelul rezultat.
Instalează toate dependențele într-un singur bloc:
sudo apt update
sudo apt install -y
bc
bison
build-essential
flex
git
libelf-dev
libssl-dev
python3
xz-utils
Descarcă exact tagul v6.17 din depozitul oficial al kernelului:
mkdir -p "$HOME/src"
cd "$HOME/src"
git clone --depth 1 --branch v6.17
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
linux-6.17
cd linux-6.17
make kernelversion
git describe --tags --always
Rezultatul relevant trebuie să fie:
6.17
v6.17
Dacă make kernelversion arată altă versiune, oprește laboratorul și verifică directorul curent cu pwd. Toate comenzile următoare se execută din rădăcina linux-6.17.
Șase fișiere separă logica modulului, testele și rularea automată
Proiectul adaugă acest arbore în sursa kernelului:
linux-6.17/
├── drivers/misc/quota_guard/
│ ├── Kconfig # opțiunile modulului și ale suitei KUnit
│ ├── Makefile # regulile Kbuild pentru modul și teste
│ ├── quota_guard.h # contractul public al componentei
│ ├── quota_guard_core.c # contabilizarea cotei
│ ├── quota_guard_module.c # intrarea și ieșirea modulului
│ └── quota_guard_kunit.c # cele cinci cazuri KUnit
├── kunit/
│ └── quota_guard.config # fragmentul Kconfig folosit de kunit.py
├── scripts/
│ └── run-quota-guard-kunit.sh # compilare, execuție și validare
└── artifacts/
└── quota-guard-kunit.log # raportul creat după rulare
quota_guard_core.c nu depinde de hardware și nu expune o interfață către utilizatori. Această delimitare este intenționată: KUnit poate testa rapid regulile interne, iar integrarea reală a unui modul rămâne un nivel separat de testare.
Pasul 1 — Legăm componenta de Kconfig și Kbuild fără să pierdem fișierele originale
De ce: kernelul trebuie să descopere noul director înainte ca fragmentul KUnit să poată activa modulul și testele. Pentru că modificăm două fișiere existente, facem mai întâi copii de siguranță.
Rulează din rădăcina linux-6.17:
set -euo pipefail
test -f drivers/misc/Kconfig
test -f drivers/misc/Makefile
cp drivers/misc/Kconfig drivers/misc/Kconfig.bak
cp drivers/misc/Makefile drivers/misc/Makefile.bak
mkdir -p drivers/misc/quota_guard kunit artifacts
printf 'nsource "drivers/misc/quota_guard/Kconfig"n'
>> drivers/misc/Kconfig
printf 'nobj-$(CONFIG_QUOTA_GUARD) += quota_guard/n'
>> drivers/misc/Makefile
Fișierul nou drivers/misc/quota_guard/Kconfig:
config QUOTA_GUARD
tristate "Quota guard example module"
help
Build a small quota-accounting module used by the KUnit
laboratory.
config QUOTA_GUARD_KUNIT_TEST
tristate "KUnit tests for quota_guard"
depends on KUNIT
depends on QUOTA_GUARD
default KUNIT_ALL_TESTS
help
Build unit tests for quota_guard. Select Y when running the
suite with User Mode Linux.
Fișierul nou drivers/misc/quota_guard/Makefile:
obj-$(CONFIG_QUOTA_GUARD) += quota_guard.o
quota_guard-y := quota_guard_core.o quota_guard_module.o
obj-$(CONFIG_QUOTA_GUARD_KUNIT_TEST) += quota_guard_kunit.o
tristate permite valorile y, m și n. În laborator alegem y, deoarece testele trebuie incluse în imaginea UML și executate la pornire. Numele fișierului de test se termină în _kunit, conform convenției documentate de proiect.
Verifică legăturile introduse:
tail -n 3 drivers/misc/Kconfig
tail -n 3 drivers/misc/Makefile
cat drivers/misc/quota_guard/Kconfig
cat drivers/misc/quota_guard/Makefile
Exemplul relevant este:
source "drivers/misc/quota_guard/Kconfig"
obj-$(CONFIG_QUOTA_GUARD) += quota_guard/
Punct de control: dacă una dintre linii apare de două ori, restaurează fișierul .bak și repetă pasul o singură dată.
Pasul 2 — Implementăm contabilizarea fără overflow și cu eliberare saturată
De ce: componenta trebuie să respingă o rezervare peste limită fără să modifice contorul. Compararea amount > limit - used evită adunarea care ar putea depăși domeniul unui u64.
Fișierul complet drivers/misc/quota_guard/quota_guard.h:
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _QUOTA_GUARD_H
#define _QUOTA_GUARD_H
#include <linux/types.h>
struct quota_guard {
u64 limit;
u64 used;
};
int quota_guard_state_init(struct quota_guard *guard, u64 limit);
int quota_guard_charge(struct quota_guard *guard, u64 amount);
void quota_guard_release(struct quota_guard *guard, u64 amount);
u64 quota_guard_available(const struct quota_guard *guard);
#endif
Fișierul complet drivers/misc/quota_guard/quota_guard_core.c:
// SPDX-License-Identifier: GPL-2.0
#include <linux/errno.h>
#include <linux/export.h>
#include "quota_guard.h"
int quota_guard_state_init(struct quota_guard *guard, u64 limit)
{
if (!guard || !limit)
return -EINVAL;
guard->limit = limit;
guard->used = 0;
return 0;
}
EXPORT_SYMBOL_GPL(quota_guard_state_init);
int quota_guard_charge(struct quota_guard *guard, u64 amount)
{
if (!guard || !amount)
return -EINVAL;
if (guard->used > guard->limit)
return -EUCLEAN;
if (amount > guard->limit - guard->used)
return -EDQUOT;
guard->used += amount;
return 0;
}
EXPORT_SYMBOL_GPL(quota_guard_charge);
void quota_guard_release(struct quota_guard *guard, u64 amount)
{
if (!guard)
return;
if (amount >= guard->used) {
guard->used = 0;
return;
}
guard->used -= amount;
}
EXPORT_SYMBOL_GPL(quota_guard_release);
u64 quota_guard_available(const struct quota_guard *guard)
{
if (!guard || guard->used > guard->limit)
return 0;
return guard->limit - guard->used;
}
EXPORT_SYMBOL_GPL(quota_guard_available);
Fișierul complet drivers/misc/quota_guard/quota_guard_module.c:
// SPDX-License-Identifier: GPL-2.0
#include <linux/init.h>
#include <linux/module.h>
static int __init quota_guard_module_init(void)
{
pr_info("quota_guard: module initializedn");
return 0;
}
static void __exit quota_guard_module_exit(void)
{
pr_info("quota_guard: module removedn");
}
module_init(quota_guard_module_init);
module_exit(quota_guard_module_exit);
MODULE_AUTHOR("Cyber AI Romania");
MODULE_DESCRIPTION("Minimal quota accounting module for KUnit");
MODULE_LICENSE("GPL");
-EINVAL indică un obiect sau un argument invalid, -EDQUOT semnalează depășirea cotei, iar -EUCLEAN protejează funcția dacă structura ajunge într-o stare internă imposibilă. EXPORT_SYMBOL_GPL permite și construirea ulterioară a testului ca modul separat, nu doar legarea sa în imagine.
Verifică faptul că nu au rămas marcaje incomplete:
grep -R -nE 'TODO|FIXME|...' drivers/misc/quota_guard || true
grep -R -n 'EXPORT_SYMBOL_GPL' drivers/misc/quota_guard
Exemplul așteptat conține patru simboluri exportate și niciun rezultat pentru primul grep:
drivers/misc/quota_guard/quota_guard_core.c:...:EXPORT_SYMBOL_GPL(quota_guard_state_init);
drivers/misc/quota_guard/quota_guard_core.c:...:EXPORT_SYMBOL_GPL(quota_guard_charge);
drivers/misc/quota_guard/quota_guard_core.c:...:EXPORT_SYMBOL_GPL(quota_guard_release);
drivers/misc/quota_guard/quota_guard_core.c:...:EXPORT_SYMBOL_GPL(quota_guard_available);
Numerele de linie pot diferi.
Punct de control: dacă lipsește un export sau apare un TODO, corectează fișierul înainte să implici sistemul de build.
Pasul 3 — Codificăm contractul în cinci cazuri KUnit independente
De ce: testele trebuie să acopere atât traseele acceptate, cât și proprietatea esențială că o rezervare respinsă nu alterează starea. Fiecare caz pornește cu propria structură locală, deci rezultatul unuia nu îl contaminează pe următorul.
Fișierul complet drivers/misc/quota_guard/quota_guard_kunit.c:
// SPDX-License-Identifier: GPL-2.0
#include <kunit/test.h>
#include <linux/errno.h>
#include <linux/module.h>
#include "quota_guard.h"
static void quota_guard_init_rejects_zero(struct kunit *test)
{
struct quota_guard guard;
KUNIT_EXPECT_EQ(test,
quota_guard_state_init(&guard, 0),
-EINVAL);
}
static void quota_guard_starts_empty(struct kunit *test)
{
struct quota_guard guard;
KUNIT_ASSERT_EQ(test,
quota_guard_state_init(&guard, 100),
0);
KUNIT_EXPECT_EQ(test, guard.used, (u64)0);
KUNIT_EXPECT_EQ(test,
quota_guard_available(&guard),
(u64)100);
}
static void quota_guard_charges_to_limit(struct kunit *test)
{
struct quota_guard guard;
KUNIT_ASSERT_EQ(test,
quota_guard_state_init(&guard, 100),
0);
KUNIT_ASSERT_EQ(test,
quota_guard_charge(&guard, 40),
0);
KUNIT_ASSERT_EQ(test,
quota_guard_charge(&guard, 60),
0);
KUNIT_EXPECT_EQ(test, guard.used, (u64)100);
KUNIT_EXPECT_EQ(test,
quota_guard_available(&guard),
(u64)0);
}
static void quota_guard_rejection_preserves_state(struct kunit *test)
{
struct quota_guard guard;
KUNIT_ASSERT_EQ(test,
quota_guard_state_init(&guard, 100),
0);
KUNIT_ASSERT_EQ(test,
quota_guard_charge(&guard, 75),
0);
KUNIT_EXPECT_EQ(test,
quota_guard_charge(&guard, 26),
-EDQUOT);
KUNIT_EXPECT_EQ(test, guard.used, (u64)75);
KUNIT_EXPECT_EQ(test,
quota_guard_available(&guard),
(u64)25);
}
static void quota_guard_release_saturates_at_zero(struct kunit *test)
{
struct quota_guard guard;
KUNIT_ASSERT_EQ(test,
quota_guard_state_init(&guard, 100),
0);
KUNIT_ASSERT_EQ(test,
quota_guard_charge(&guard, 30),
0);
quota_guard_release(&guard, 80);
KUNIT_EXPECT_EQ(test, guard.used, (u64)0);
KUNIT_EXPECT_EQ(test,
quota_guard_available(&guard),
(u64)100);
}
static struct kunit_case quota_guard_test_cases[] = {
KUNIT_CASE(quota_guard_init_rejects_zero),
KUNIT_CASE(quota_guard_starts_empty),
KUNIT_CASE(quota_guard_charges_to_limit),
KUNIT_CASE(quota_guard_rejection_preserves_state),
KUNIT_CASE(quota_guard_release_saturates_at_zero),
{}
};
static struct kunit_suite quota_guard_test_suite = {
.name = "quota_guard",
.test_cases = quota_guard_test_cases,
};
kunit_test_suites("a_guard_test_suite);
MODULE_LICENSE("GPL");
KUNIT_ASSERT_EQ oprește numai cazul curent când precondiția nu este îndeplinită. KUNIT_EXPECT_EQ înregistrează abaterea, dar permite continuarea cazului și raportarea altor diferențe. Conversiile (u64) mențin tipurile comparate explicite.
Confirmă numărul cazurilor înregistrate:
grep -c '^[[:space:]]*KUNIT_CASE('
drivers/misc/quota_guard/quota_guard_kunit.c
Rezultatul trebuie să fie:
5
Punct de control: dacă numărul nu este cinci, verifică exclusiv lista quota_guard_test_cases; funcțiile care nu apar acolo nu vor fi executate.
Pasul 4 — Configurăm numai modulul și suita care ne interesează
De ce: un fragment Kconfig restrâns reduce timpul de compilare și împiedică activarea accidentală a tuturor testelor din arbore. kunit.py adaugă configurația necesară pentru rularea UML și validează simbolurile solicitate.
Fișierul complet kunit/quota_guard.config:
CONFIG_KUNIT=y
CONFIG_QUOTA_GUARD=y
CONFIG_QUOTA_GUARD_KUNIT_TEST=y
Verifică fragmentul înainte de build:
cat kunit/quota_guard.config
grep -c '^CONFIG_.*=y$' kunit/quota_guard.config
Rezultatul este:
CONFIG_KUNIT=y
CONFIG_QUOTA_GUARD=y
CONFIG_QUOTA_GUARD_KUNIT_TEST=y
3
Alegerea y face ca suita să fie înregistrată în executorul KUnit și pornită odată cu kernelul UML. Când kunit_test_suites() este construit ca modul, macro-ul folosește inițializarea modulului pentru lansarea testelor; în această rulare izolată îl folosim built-in pentru a evita construirea unui root filesystem dedicat încărcării modulelor.
Punct de control: dacă un simbol este scris cu m, schimbă-l în y; acest laborator validează traseul built-in sub UML, nu încărcarea dinamică pe kernelul gazdă.
Pasul 5 — Automatizăm compilarea, execuția și verificarea raportului
De ce: o comandă reproductibilă trebuie să eșueze clar atât la compilare, cât și la un test KUnit nereușit. Scriptul păstrează raportul complet și verifică sumarul celor cinci cazuri, astfel încât să poată fi folosit ulterior într-un job CI.
Fișierul complet scripts/run-quota-guard-kunit.sh:
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
BUILD_DIR=".kunit-quota-guard"
CONFIG_FILE="kunit/quota_guard.config"
LOG_FILE="artifacts/quota-guard-kunit.log"
cd "$ROOT_DIR"
mkdir -p artifacts
test -f "$CONFIG_FILE"
test -f drivers/misc/quota_guard/quota_guard_kunit.c
test -f tools/testing/kunit/kunit.py
set +e
python3 tools/testing/kunit/kunit.py run
--kunitconfig "$CONFIG_FILE"
--build_dir "$BUILD_DIR"
2>&1 | tee "$LOG_FILE"
kunit_status=${PIPESTATUS[0]}
set -e
if (( kunit_status != 0 )); then
printf 'KUnit a eșuat; vezi %sn' "$LOG_FILE" >&2
exit "$kunit_status"
fi
if ! grep -Eq 'Testing complete.*Ran 5 tests: passed: 5' "$LOG_FILE"; then
printf 'Sumarul pentru cele 5 teste lipsește din %sn'
"$LOG_FILE" >&2
exit 1
fi
printf 'PASS: 5 teste quota_guard; raport: %sn' "$LOG_FILE"
Activează permisiunea de execuție și verifică sintaxa Bash:
chmod 0755 scripts/run-quota-guard-kunit.sh
bash -n scripts/run-quota-guard-kunit.sh
PIPESTATUS[0] păstrează codul întors de kunit.py, nu codul lui tee. Blocul set +e este delimitat strict, după care comportamentul fail-fast este reactivat. Raportul are o cale stabilă și este suprascris la fiecare execuție, ceea ce evită confundarea unui rezultat vechi cu rularea curentă.
Dacă sintaxa este validă, bash -n nu afișează nimic și întoarce codul zero:
Punct de control: dacă bash -n afișează o linie și un mesaj de sintaxă, nu porni compilarea; corectează mai întâi scriptul indicat.
Pasul 6 — Pornim kernelul UML și cerem dovada pentru fiecare caz
De ce: acum validăm întregul traseu: Kconfig, Kbuild, compilarea modulului, boot-ul UML, executorul KUnit, parserul KTAP și verificarea automată a sumarului.
Rulează fără sudo:
./scripts/run-quota-guard-kunit.sh
La prima execuție, kunit.py generează configurația din .kunit-quota-guard, compilează kernelul UML și îl pornește. Un fragment de output reușit arată astfel; prefixele temporale și formatarea pot diferi între reviziile uneltei:
[==========] Running 1 test suite.
[ RUN ] quota_guard
[ RUN ] quota_guard.quota_guard_init_rejects_zero
[ OK ] quota_guard.quota_guard_init_rejects_zero
[ RUN ] quota_guard.quota_guard_starts_empty
[ OK ] quota_guard.quota_guard_starts_empty
[ RUN ] quota_guard.quota_guard_charges_to_limit
[ OK ] quota_guard.quota_guard_charges_to_limit
[ RUN ] quota_guard.quota_guard_rejection_preserves_state
[ OK ] quota_guard.quota_guard_rejection_preserves_state
[ RUN ] quota_guard.quota_guard_release_saturates_at_zero
[ OK ] quota_guard.quota_guard_release_saturates_at_zero
[ PASSED ] quota_guard
Testing complete. Ran 5 tests: passed: 5
PASS: 5 teste quota_guard; raport: artifacts/quota-guard-kunit.log
Confirmă configurația efectivă și raportul, nu doar textul din terminal:
grep -E '^CONFIG_(KUNIT|QUOTA_GUARD|QUOTA_GUARD_KUNIT_TEST)='
.kunit-quota-guard/.config
grep -E 'Testing complete|PASS:|FAILED'
artifacts/quota-guard-kunit.log
Configurația trebuie să conțină:
CONFIG_KUNIT=y
CONFIG_QUOTA_GUARD=y
CONFIG_QUOTA_GUARD_KUNIT_TEST=y
Raportul trebuie să confirme cele cinci teste trecute și să nu conțină un caz FAILED. KUnit produce rezultate în format KTAP, iar kunit.py le transformă într-un sumar ușor de citit.
Punct de control: dacă scriptul întoarce cod diferit de zero, raportul din artifacts/ este sursa de diagnostic; nu modifica testele doar ca să obții verde.
Testul de capăt include și o regresie controlată
Un test automat este util numai dacă poate detecta o implementare greșită. Păstrează mai întâi copia funcțională:
cp drivers/misc/quota_guard/quota_guard_core.c
drivers/misc/quota_guard/quota_guard_core.c.known-good
În quota_guard_core.c, schimbă temporar condiția:
if (amount > guard->limit - guard->used)
în această variantă intenționat greșită:
if (amount >= guard->limit - guard->used)
Rulează din nou:
if ./scripts/run-quota-guard-kunit.sh; then
printf 'EROARE: regresia intenționată nu a fost detectatăn' >&2
exit 1
else
printf 'OK: suita a respins regresia intenționatăn'
fi
Cazul quota_guard_charges_to_limit trebuie să eșueze, deoarece a doua rezervare ajunge exact la limită și ar fi respinsă incorect. Mesajul include valorile observate de KUNIT_ASSERT_EQ; numărul liniei poate diferi:
[ FAILED ] quota_guard.quota_guard_charges_to_limit
Testing complete. Ran 5 tests: passed: 4, failed: 1
KUnit a eșuat; vezi artifacts/quota-guard-kunit.log
OK: suita a respins regresia intenționată
Restaurează imediat implementarea și repetă rularea verde:
mv drivers/misc/quota_guard/quota_guard_core.c.known-good
drivers/misc/quota_guard/quota_guard_core.c
./scripts/run-quota-guard-kunit.sh
Ultima comandă trebuie să revină la:
Testing complete. Ran 5 tests: passed: 5
PASS: 5 teste quota_guard; raport: artifacts/quota-guard-kunit.log
Acesta este testul final: aceeași suită dovedește atât acceptarea implementării corecte, cât și respingerea unei regresii precise.
Cinci mesaje care localizează defectul în acest laborator
fatal error: kunit/test.h: No such file or directory
Cauza este, de regulă, compilarea fișierului cu gcc direct sau folosirea unor headers de distribuție care nu corespund arborelui complet. KUnit este parte din sursa kernelului și trebuie construit prin Kbuild:
cd "$HOME/src/linux-6.17"
./scripts/run-quota-guard-kunit.sh
Nu compila quota_guard_kunit.c separat.
No rule to make target 'drivers/misc/quota_guard/'
Kbuild a găsit intrarea din drivers/misc/Makefile, dar directorul ori Makefile-ul local lipsește sau are alt nume. Verifică exact:
test -d drivers/misc/quota_guard
test -f drivers/misc/quota_guard/Makefile
grep -F 'obj-$(CONFIG_QUOTA_GUARD) += quota_guard/'
drivers/misc/Makefile
Toate comenzile trebuie să întoarcă zero.
Configurația solicitată nu apare în .kunit-quota-guard/.config
O dependență Kconfig nu a fost satisfăcută sau fișierul drivers/misc/Kconfig nu include noua configurație. Curăță numai directorul KUnit și regenerează-l:
rm -rf .kunit-quota-guard
grep -F 'source "drivers/misc/quota_guard/Kconfig"'
drivers/misc/Kconfig
./scripts/run-quota-guard-kunit.sh
Nu folosi make oldconfig peste directorul principal; kunit.py trebuie să gestioneze configurația acestui laborator.
Testing complete. Ran 0 tests
Kernelul a pornit, dar suita nu a fost înregistrată. Verifică valoarea simbolului și macro-ul de înregistrare:
grep '^CONFIG_QUOTA_GUARD_KUNIT_TEST=y'
.kunit-quota-guard/.config
grep -n 'kunit_test_suites'
drivers/misc/quota_guard/quota_guard_kunit.c
Trebuie să existe atât simbolul =y, cât și apelul kunit_test_suites("a_guard_test_suite).
Testing complete. Ran 5 tests: passed: 4, failed: 1
Build-ul și boot-ul au reușit; defectul este într-o așteptare sau în implementare. Identifică primul caz eșuat fără să ascunzi contextul:
grep -n -A12 -B4 'FAILED'
artifacts/quota-guard-kunit.log
Compară valorile expected și actual, apoi modifică logica modulului. Nu elimina cazul și nu slăbi așteptarea pentru a forța succesul.
Dacă o eroare de memorie ar apărea într-o componentă mai complexă, KUnit poate fi combinat ulterior cu kmemleak pentru depistarea pierderilor de memorie din kernel. Pentru un panic produs de o rulare pe hardware real, fluxul potrivit este cel de analiză a unui kernel panic cu kdump și crash, nu simpla relansare repetată a testului.
Restaurăm arborele fără să lăsăm configurații sau rezultate vechi
Avertisment: următoarele comenzi șterg numai fișierele create de acest laborator din copia linux-6.17. Verifică pwd înainte de execuție.
set -euo pipefail
test "$(basename "$PWD")" = "linux-6.17"
test -f drivers/misc/Kconfig.bak
test -f drivers/misc/Makefile.bak
mv drivers/misc/Kconfig.bak drivers/misc/Kconfig
mv drivers/misc/Makefile.bak drivers/misc/Makefile
rm -rf drivers/misc/quota_guard
rm -rf .kunit-quota-guard
rm -f kunit/quota_guard.config
rm -f scripts/run-quota-guard-kunit.sh
rm -f artifacts/quota-guard-kunit.log
rmdir kunit artifacts 2>/dev/null || true
Confirmă că integrarea a dispărut:
test ! -e drivers/misc/quota_guard
! grep -q 'drivers/misc/quota_guard/Kconfig' drivers/misc/Kconfig
! grep -q 'CONFIG_QUOTA_GUARD' drivers/misc/Makefile
printf 'Arborele laboratorului a fost curățatn'
Rezultatul este:
Arborele laboratorului a fost curățat
Bifele care confirmă că suita este reproductibilă
- ☐
make kernelversionraportează6.17. - ☐ Arhitectura gazdei este
x86_64. - ☐
quota_guard_core.cverifică limita prin scădere, fără adunare susceptibilă la overflow. - ☐
quota_guard_kunit.cînregistrează exact cinci cazuri. - ☐ Cele trei simboluri din
quota_guard.configau valoareay. - ☐ Scriptul folosește codul lui
kunit.py, nu doar codul luitee. - ☐ Raportul conține
Ran 5 tests: passed: 5. - ☐ Regresia temporară
>→>=este detectată. - ☐ Implementarea corectă este restaurată după testul negativ.
- ☐ Kernelul gazdă nu a fost înlocuit și niciun modul experimental nu a fost încărcat în el.
Următorul prag util este rularea aceleiași suite ca modul _kunit pe un kernel de test cu CONFIG_KUNIT=m, urmată de colectarea KTAP din kernel log. Pentru cod concurent, adaugă teste KUnit care folosesc API-urile de sincronizare ale subsistemului și rulează separat verificările KCSAN. Pentru integrarea într-un proiect, execută run-quota-guard-kunit.sh într-un job CI pe fiecare schimbare a fișierelor din drivers/misc/quota_guard/, păstrând raportul din artifacts/ ca artefact al jobului.
Întrebări frecvente
Testele KUnit modifică kernelul instalat pe calculator?
Nu. În acest laborator, kunit.py compilează și pornește un kernel User Mode Linux în directorul .kunit-quota-guard; kernelul gazdă nu este instalat din nou și modulul experimental nu este încărcat în el.
De ce modulul și testele sunt configurate cu y, nu cu m?
Suita este inclusă în imaginea UML și rulează automat la pornire, fără un root filesystem pregătit pentru încărcarea modulelor. KUnit acceptă și teste compilate ca module, dar acela este următorul nivel de integrare, nu varianta executată aici.
KUnit poate înlocui testarea modulului pe hardware real?
Nu. KUnit verifică rapid logica internă și cazurile-limită, dar nu reproduce toate interacțiunile cu hardware-ul, concurența reală sau integrarea completă cu alte subsisteme.
Unde rămâne dovada ultimei rulări?
Scriptul scrie output-ul complet în artifacts/quota-guard-kunit.log. O execuție reușită trebuie să conțină sumarul Ran 5 tests: passed: 5.

















































