Bản vá cho trampoline rethook trên LoongArch xóa việc lưu và khôi phục $r21 trong arch/loongarch/kernel/rethook_trampoline.S; thay đổi gồm 0 dòng thêm và 2 dòng xóa (nguồn). Trên LoongArch, quy ước kernel dùng $r21 (còn gọi là $u0) để giữ địa chỉ cơ sở percpu của CPU hiện tại khi thực thi ở chế độ kernel; thanh ghi này phải luôn trỏ tới vùng percpu của lõi hiện tại. Lỗi xảy ra khi tác vụ di chuyển sang CPU khác bên trong handler: trampoline đọc giá trị cũ của thanh ghi từ stack rồi ghi trở lại, khiến thanh ghi trên CPU mới mang địa chỉ cơ sở percpu cũ. Lý do được nêu để bỏ thao tác này là sau khi di chuyển, thanh ghi đã giữ địa chỉ cơ sở đúng của CPU hiện tại (nguồn).
https://www.deepin.org/zh/hands-on-deepin-loongarch-kernel-fixes/
Các triệu chứng được nêu gồm crash scheduling-while-atomic, cảnh báo RCU về việc chạy trên CPU sai, lỗi WARN_ON_ONCE(rq != this_rq()) trong cân bằng tải của CPU nhàn rỗi và CPU bị khóa cứng vì timer không còn được khởi động lại trong vòng lặp idle. Để kích hoạt lỗi cần đồng thời ba điều kiện: hệ thống chạy trên LoongArch; một module đặt probe trên các hàm kernel được gọi thường xuyên; kernel ở chế độ preemption đầy đủ (preempt=full) (nguồn).
Khiếm khuyết này có từ thời triển khai kretprobe cũ trong phiên bản Linux 6.3 và được sao chép nguyên trạng khi mã chuyển sang rethook (nguồn).
Một cách xử lý tạm thời là thêm preempt=none hoặc preempt=voluntary vào tham số khởi động kernel để tránh điểm nhường lịch gây kích hoạt lỗi; cách này yêu cầu kernel được biên dịch với PREEMPT_DYNAMIC, nếu không tham số khởi động sẽ không có hiệu lực. PREEMPT_DYNAMIC, được giới thiệu trong phiên bản Linux 5.12, cho phép kernel vẫn khai báo một chế độ preemption mặc định lúc biên dịch nhưng có thể ghi đè chế độ đó khi khởi động bằng tham số preempt=, miễn là tùy chọn này được bật; nhờ vậy không cần biên dịch lại kernel (nguồn).
Nguồn cảm hứng chủ đề: https://www.deepin.org/zh/hands-on-deepin-loongarch-kernel-fixes/


