ฮายยยยชาว Linux และสาย Maker ทุกคน! มีท่อนหนึ่งในเพลงของ Weird Al ร้องไว้ว่า "ฉันอัปเกรดระบบอย่างน้อยวันละสองรอบ..." ซึ่งใครที่ใช้ Linux แบบ Rolling Release อย่าง OpenSuse Tumbleweed น่าจะเข้าใจฟีลลิ่งนี้ดีเลยครับ เวลาที่เจอปัญหาอะไรกวนใจแล้วขี้เกียจหาทางแก้ เรามักจะเลือกกดอัปเดตระบบแล้วหวังว่ามันจะแก้ปัญหาให้เอง (ฮา)
แต่แน่นอนครับ... ปัญหาใหม่มักเกิดจากการอัปเดตครั้งก่อนหน้าเสมอ! เมื่อไม่นานมานี้หลังจากต่อสู้กับปัญหาไดรเวอร์การ์ดจอ NVIDIA และอัปเดต Kernel ตัวล่าสุด สิ่งที่ตามมาคือ อะแดปเตอร์ Bluetooth ของ MediaTek ที่ฝังมากับชิปเซ็ต WiFi บนเมนบอร์ด ดันใช้งานไม่ได้ซะงั้น! วันนี้เราเลยจะมาแชร์ทริคการเอาตัวรอดชั่วคราว ด้วยการคอมไพล์ Kernel Module ขึ้นมาใหม่เองเลยครับ!
ภาพปก: วิชา Linux กังฟู การแก้ปัญหาเคอร์เนลด้วยตัวเอง
💡
Globalbyte Trick: การใช้ระบบปฏิบัติการ Linux บนคอมพิวเตอร์ หรือบนบอร์ด Microprocessor อย่าง Raspberry Pi มักจะต้องเจอกับการคอนฟิกฮาร์ดแวร์อยู่เสมอครับ หากเพื่อนๆ สายเทคกำลังมองหา
บอร์ดพัฒนา (Development Boards) หรือโมดูลเซนเซอร์ต่างๆ เพื่อเอาไปฝึกวิชา Linux หรือทำระบบโฮมเซิร์ฟเวอร์ แวะมาเลือกช้อปสินค้าอิเล็กทรอนิกส์คุณภาพเยี่ยมได้ที่ร้าน
Globalbyte ของเราได้เลยครับ!
ความผิดฉันเอง... ที่ไม่ได้ใช้ BTRFS (My Own Fault)
ต้องยอมรับก่อนว่าส่วนหนึ่งของปัญหาเกิดจากการตั้งค่าของผมเองครับ เพราะผมใช้การจัดแบ่งพาร์ทิชันดิสก์ที่ค่อนข้างซับซ้อน และ ไม่ได้ใช้ระบบไฟล์ (File system) แบบ btrfs ในพาธ Root ตามที่เขาแนะนำ ทำให้ผมไม่สามารถใช้ฟีเจอร์ Snapshot เพื่อ "ย้อนเวลากลับไป (Rollback)" ก่อนอัปเดตได้ง่ายๆ
นอกจากนี้ พวกไดรเวอร์ที่เป็นกรรมสิทธิ์ (Proprietary) อย่าง NVIDIA มักจะมีปัญหากวนใจคือ ตัว User space (สิ่งที่ผู้ใช้เห็น) กับ Kernel module (สิ่งที่คุยกับฮาร์ดแวร์) มันต้องเวอร์ชันตรงกันเป๊ะ! ทำให้การถอยกลับไปใช้ Kernel เก่าๆ เป็นเรื่องน่าปวดหัว ผมเลยตัดสินใจว่า "เดินหน้าลุยแก้โค้ดเองเลยดีกว่า!"
เริ่มปฏิบัติการ: แพตช์และคอมไพล์แบบ Modular
หลังจากค้นหาในอินเทอร์เน็ต ผมไปเจอบทความเมื่อ 4 วันก่อนที่เจอปัญหา Error ข้อความเดียวกันเป๊ะ! ซึ่งทางแก้ก็คือการ Patch โค้ดของ Kernel module (btmtk) โดยแก้โค้ดแค่ 2 บรรทัดเท่านั้นเองครับ
สเต็ปการทำงานจะแบ่งเป็น 4 ขั้นตอนหลักๆ คือ:
ติดตั้งเครื่องมือสำหรับการ Build Kernel และ Source Code บน Linux
ดึงไฟล์ .config และ Module.symvers ของ Kernel ปัจจุบันมาใช้
แก้ไขไฟล์ภาษา C (btmtk.c) ตามที่โพสต์แนะนำ
สั่งคอมไพล์ (Make) และนำไฟล์ .ko ไปติดตั้งในระบบ
⚠️
คำเตือน: เนื้อหาโค้ดมีความซับซ้อนระดับ Kernel! เนื่องจากการแก้ไข Source Code ของ Kernel และการใช้คำสั่ง Terminal ใน Linux (เช่น zypper, apt, make, depmod) เป็นเรื่องที่มีความซับซ้อนสูง และอาจทำให้ระบบรวนได้หากพิมพ์ผิด
เราจึงขอเชียร์ให้เพื่อนๆ สายเทคที่สนใจ
เข้าไปอ่านขั้นตอนโดยละเอียดจากต้นฉบับ เพื่อความแม่นยำครับ (แต่ถ้าอยากแอบดูตัวอย่างคำสั่งที่เราใช้แก้ปัญหา สามารถกดดูได้ที่ปุ่ม View More ด้านล่างเลย!)
💻 ดูตัวอย่างคำสั่ง Terminal และโค้ดภาษา C ที่ใช้แก้ปัญหา (View More)
1. เตรียมเครื่องมือสำหรับการ Build (สำหรับ Tumbleweed)
Copy Code
sudo zypper in -t pattern devel_kernel
sudo zypper in kernel-source kernel-default-devel kernel-syms gcc make bc flex bison openssl-devel dwarves
(สำหรับสาย Ubuntu/Debian จะใช้คำสั่งประมาณนี้ครับ):
Copy Code
sudo apt update
sudo apt install build-essential linux-headers-$(uname -r) linux-source bc flex bison libssl-dev libelf-dev dwarves rsync
2. ดึง Source Code และตั้งค่า Config
สร้างโฟลเดอร์สำหรับทำงาน คัดลอก Source มาไว้ที่ Home directory และดึง Config ปัจจุบันมาใช้:
Copy Code
mkdir -p ~/kernel-local
rsync -a --delete /usr/src/linux/ ~/kernel-local/linux-btmtk/
cd ~/kernel-local/linux-btmtk
cp /lib/modules/$(uname -r)/build/.config .
cp /lib/modules/$(uname -r)/build/Module.symvers . 2>/dev/null || true
3. แก้ไขไฟล์โค้ด (The Patch)
เปิดไฟล์ btmtk.c แล้วค้นหาโค้ดส่วนนี้:
Copy Code
case BTMTK_WMT_FUNC_CTRL:
if (!skb_pull_data(data->evt_skb, sizeof(wmt_evt_funcc->status))) {
err = -EINVAL;
goto err_free_skb;
}
แล้วแทนที่บรรทัด err = ... และ goto ... ด้วยโค้ดใหม่ด้านล่างนี้:
Copy Code
status = BTMTK_WMT_ON_UNDONE;
break;
4. สั่งคอมไพล์และติดตั้ง (The Build & Run)
ทำการ Build โมดูล (ใช้ -j=8 เพื่อใช้ 8 คอร์ช่วยให้เร็วขึ้น) จากนั้นก็อปปี้ไฟล์ .ko ไปไว้ในโฟลเดอร์อัปเดต แล้วสั่ง depmod -a ครับ:
Copy Code
make olddefconfig
make modules_prepare
make M=drivers/bluetooth modules -j=8
sudo mkdir -p /lib/modules/$(uname -r)/updates/drivers/bluetooth
sudo cp drivers/bluetooth/btmtk.ko /lib/modules/$(uname -r)/updates/drivers/bluetooth/
sudo depmod -a
เช็คความเรียบร้อยด้วยคำสั่ง modinfo -n btmtk ถ้ามันชี้ไปที่ไฟล์ตัวใหม่ที่เราเพิ่งคอมไพล์ ก็ถือว่าพร้อมใช้งาน! ปิดท้ายด้วยการ Reboot เครื่องได้เลยครับ
บทสรุปส่งท้าย
หากคุณใช้ระบบปฏิบัติการ (Distro) อื่น คำสั่งอาจจะแตกต่างกันออกไปเล็กน้อยนะครับ และแน่นอนว่าถ้าวันหน้ามีการอัปเดต Kernel อีกรอบ คุณอาจจะต้องมานั่งทำกระบวนการนี้ใหม่ซ้ำอีกครั้ง (เว้นแต่ว่าปัญหานี้จะถูกแก้ใน Kernel ตัวใหม่แล้ว)
นอกจากนี้ ถ้าเพื่อนๆ ชอบการปรับแต่งระบบลึกๆ เรามีบทความน่าสนใจเกี่ยวกับการเขียนและใช้งาน Kernel Modules มาฝากให้อ่านเพลินๆ ด้วยครับ ไม่ว่าจะเป็น การทดลองจัดการดองเกิล USB WiFi หรือ เรื่องของสิทธิพิเศษ (Privileges) ที่ Kernel Modules มี ลองเข้าไปศึกษากันได้เลยครับ!
🚀 ลุยโปรเจกต์ IoT และอิเล็กทรอนิกส์ไปกับ Globalbyte!
กำลังหาบอร์ดพัฒนา (Development Boards), โมดูลเสริม หรืออุปกรณ์อิเล็กทรอนิกส์เพื่อเอาไปต่อยอดทำระบบ Home Server หรือฝึกวิชา Linux ของตัวเองอยู่หรือเปล่า? ทักมาให้เราดูแลสิครับ!
คำเตือน / ข้อมูลอ้างอิง: บทความนี้เป็นการสรุปและแปลเนื้อหาจากบทความภาษาอังกฤษ (Hackaday) การแก้ไขไฟล์ระบบและการคอมไพล์เคอร์เนล (Kernel module) อาจทำให้ระบบปฏิบัติการไม่สามารถบูตได้หากเกิดข้อผิดพลาด ขอแนะนำให้สำรองข้อมูล (Backup) และศึกษาคู่มือการแก้ปัญหาตามเว็บไซต์ต้นฉบับอย่างละเอียดก่อนลงมือทำครับ
ที่มาต้นฉบับ: Linux Fu: The Bluetooth Regression (Hackaday)