Lấy thông tin từ kernel log buffer Giới thiệu Ở bài học trước, chúng ta thấy rằng, hàm printk in các thông điệp ra console. Tuy nhiên, trong quá trình

Tài liệu tương tự
Chương trình dịch

Chöông 1 (tt.)

Tìm hiểu ngôn ngữ lập trình Visual Basic Tìm hiểu ngôn ngữ lập trình Visual Basic Bởi: Khuyet Danh Tìm hiểu ngôn ngữ lập trình Visual Basic Tổng quan

Trường ĐHBK Hà Nội Khoa Điện Bộ môn Điều khiển Tự động Tài liệu hướng dẫn thực hành: KĨ THUẬT LẬP TRÌNH C/C++ Bài 1: Lập trình cơ sở 1 Mục đích bài th

Lập trình và ngôn ngữ lập trình

08-khoidong.pptx

Animation, Modules 6 - Hoạt hình, tách file

Những cơ sở của ngôn ngữ C# Những cơ sở của ngôn ngữ C# Bởi: phamvanviet truonglapvy Trong chương này sẽ trình bày về hệ thống kiểu trong C#; phân biệ

Hệ điều hành Bài tập tuần 6 1 Quản lý bộ nhớ Bài tập 1 : Xem thông tin bộ nhớ 1. Sử dụng top, ps đọc thông tin về kích thước vùng nhớ của 1 tiến trình

Hàm và lớp template trong Lập trình hướng đối tượng Hàm và lớp template trong Lập trình hướng đối tượng Bởi: unknown Trong phần này, chúng ta tìm hiểu

Microsoft Word - truyen-an-duong-vuong-va-mi-chau-trong-thuy.docx

Template and Exception Template and Exception Bởi: Thanh Hiền Vũ TEMPLATE Trong phần này, chúng ta tìm hiểu về một trong các đặc tính còn lại của C++,

HỘI THI TIN HỌC TRẺ TỈNH AN GIANG ĐỀ CHÍNH THỨC ĐỀ THI LÝ THUYẾT BẢNG A - KHỐI TIỂU HỌC Khóa ngày: Thời gian : 20 phút (không kể thời gian

Slide 1

Slide 1

Chương II - KIẾN TRÚC HỆ ĐIỀU HÀNH

OpenStax-CNX module: m Giới thiệu về ngôn ngữ C và môi trường turbo C 3.0 ThS. Nguyễn Văn Linh This work is produced by OpenStax-CNX and licens

Chương 1:

Slide 1

NGÔN NGƯ LÂ P TRIǸH Biên tập bởi: nguyenvanlinh

Bài 1:

CÂN ĐÔNG ĐÔ

TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI VIỆN CÔNG NGHỆ THÔNG TIN VÀ TRUYỀN THÔNG TIN HỌC ĐẠI CƯƠNG Bài 5. Kiểu dữ liệu và biểu thức trong C Nội dung 1. Các ki

1 Tạo slide trình diễn với Microsoft Powerpoint Tạo slide trình diễn với Microsoft Powerpoint Người thực hiện Hoàng Anh Tú Phạm Minh Tú Nội dung 1 Mục

Moduel 7:Trinh chiếu bài thuyết trình 163 Moduel 7: rình chiếu bài thuyết trình 7.1. rình chiếu bài thuyết trình Thiết lập các tùy ch n cho chế độ Sli

Microsoft Word - emulator_trong_android.docx

05-quanlytientrinh.pptx

IPSec IPSec Bởi: Phạm Nguyễn Bảo Nguyên Chúng ta đã biết khi ta sao chép dữ liệu giữa 2 máy hoặc thông qua mạng VPN để nâng cao chế độ bảo mật người q

Microsoft Word - mot_so_tool_trong_android.docx

Bài 7. Con trỏ Mục tiêu: 1. Luyện tập sử dụng con trỏ và địa chỉ của các biến 2. Sử dụng con trỏ khi thao tác với mảng. Giới hạn: không dùng các thư v

UART0

Câu lệnh (statement) Câu lệnh (statement) Bởi: Khuyet Danh Trong C# một chỉ dẫn lập trình đầy đủ được gọi là câu lệnh. Chương trình bao gồm nhiều câu

Microsoft Word - Huong dan su dung phan mem Evyhome.docx

Lớp và đối tượng-các hàm và các lớp friend Lớp và đối tượng-các hàm và các lớp friend Bởi: Thanh Hiền Vũ CÁC HÀM VÀ CÁC LỚP friend Một hàm friend của

ThemeGallery PowerTemplate

TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI VIỆN CÔNG NGHỆ THÔNG TIN VÀ TRUYỀN THÔNG TIN HỌC ĐẠI CƯƠNG Bài 9. Vào ra dữ liệu trong C Các lệnh vào ra dữ liệu C cun

Hãy chọn phương án đúng CÂU HỎI TRẮC NGHIỆM TIN HỌC 7 HK1 Câu 1: Bảng tính thường được dùng để: a. Tạo bảng điểm của lớp em b. Bảng theo dõi kết quả h

THƯ VIỆN PHÁP LUẬT

HƯỚNG DẪN SỬ DỤNG CÁC SẢN PHẨM CỦA OFFICE 365 Hợp đồng số: 25/KTQD-FPT Cung cấp hệ thống Office trực tuyến và thư điện tử Trường Đại Học Kinh Tế Quốc

Microsoft Word - server_response_trong_servlet.docx

Microsoft Word - Phan 1 - Kien thuc co so IFS-HANU 2011.doc

Bài 3 Tựa bài

Quốc hội CỘNG HÒA DÂN CHỦ NHÂN DÂN LÀO Hòa bình-độc lập-dân chủ-thống nhất-thịnh vượng Số 11/QH Viêng chăn, ngày 9/11/2005 LUẬT DOA

Cách tạo User và Thiết kế Database Cách tạo User và Thiết kế Database Bởi: Khoa CNTT ĐHSP KT Hưng Yên Cách tạo một User Database Chúng ta có thể tạo m

Dell UltraSharp U2518D Trình Quản Lý Màn Hình Dell Sổ tay hướng dẫn sử dụng

100 CÂU TRẮC NGHIỆM TIN HỌC 6 I. CÂU HỎI TRẮC NGHIỆM Câu 1: Để viết đơn đăng kí tham gia câu lạc bộ, em nên sử dụng phần mềm nào dưới đây? A. Chương t

mySQL - Part 1 - Installation

HD reset mật khẩu cho các hệ điều điều hành HƯỚNG DẪN RESET MẬT KHẨU CHO CÁC HỆ ĐIỀU HÀNH MỤC LỤC 1 Hướng dẫn chỉnh boot bằng cd-rom trên vps R

ỨNG DỤNG CNTT TRONG DẠY HỌC MÔN NGỮ VĂN

Làm quen với chương trình Microsoft Excel Làm quen với chương trình Microsoft Excel Bởi: unknown Làm quen với chương trình Những thao tác đầu tiên với

Ví dụ về duyệt đồ thị ưu tiên chiều sâu DFS và ứng dụng Đồ thị ví dụ: Nguyễn Hữu Tuân vimaru.edu.vn Hình 1: Đồ thị vô hướng có 8 đỉnh Với đồ thị trên,

Lập trình cấu trúc trong Visual Basic Lập trình cấu trúc trong Visual Basic Bởi: Nguyễn Sơn Học xong chương này, sinh viên phải nắm bắt được các vấn đ

PHẦN LÝ THUYẾT Câu 1 : Trong Windows Explorer để đánh dấu chọn tất cả các đối tượng ta sử dụng? a. ấn Alt + Click chuột c. Tổ hợp phím Ctrl + A b. Ấn

Slide 1

Bài thực hành 6 trang 106 SGK Tin học 10

Kyõ Thuaät Truyeàn Soá Lieäu

Microsoft Word - cau-truc-du-lieu-hang-doi.docx

Microsoft Word - su_dung_sqlite_voi_php.docx

Microsoft Word - doc_ghi_file_trong_nodejs.docx

NHẬP MÔN CÔNG NGHỆ PHẦN MỀM Giảng viên: Đỗ Thị Thanh Tuyền

Lớp đối tượng String Lớp đối tượng String Bởi: Khuyet Danh Ngôn ngữ C# hỗ trợ khá đầy đủ các chức năng của kiểu chuỗi mà chúng ta có thể thấy được ở c

Một LỊCH-SỬ HÃI-HÙNG! Bị Giấu Kín và Phanh-Phui!!! (Nguyễn-Thông Blog) Bây giờ, thời buổi này, nếu nhắc tới cụm từ Cải-Cách Ruộng Đất, lứa U50, thậm c

Chương trình dịch

Chủ đề :

Microsoft Word - TNC VIETNAM - Huong dan tong quat PM.doc

tài liệu hướng dẫn sử dụng dành cho người dùng cuối

Slide 1

Ch­ng I

Kiến trúc tập lệnh1

Chuỗi Chuỗi Bởi: phamvanviet truonglapvy Chuỗi (string) trong C# là một kiểu dựng sẵn như các kiểu int, long, có đầy đủ tính chất mềm dẻo, mạnh mẽ và

Huong dan su dung phan mem Quan ly chat luong cong trinh GXD

TẬP ĐOÀN ĐIỆN LỰC VIỆT NAM TRUNG TÂM CÔNG NGHỆ THÔNG TIN TÀI LIỆU HƯỚNG DẪN SỬ DỤNG DIM OPERATOR v1.2 (Dành cho Đơn vị phát điện) Hà Nội, tháng 2/2008

(Tái bản lần thứ hai)

Nghị định số 159/2013/NĐ-CP ngày 12/11/2013 quy định xử phạt vi phạm hành chính trong hoạt động báo chí, xuất bản

Tạo máy chủ ảo Linux và cấu hình SSH

Microsoft Word - Huong dan cau hinh mikrotik - Viet Tuan UNIFI.vn

Microsoft Word - bo_tien_xu_ly_trong_c.docx

Microsoft Word - Huong dan su dung Mailchimp.docx

TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI VIỆN CÔNG NGHỆ THÔNG TIN VÀ TRUYỀN THÔNG TIN HỌC ĐẠI CƯƠNG Bài 13. Hàm Nội dung 1. Khái niệm hàm 2. Khai báo và sử dụn

Một số thao tác trong windows XP Một số thao tác trong windows XP Bởi: Vien CNTT DHQG Hanoi MỘT SỐ THAO TÁC TRONG WINDOWS XP Tạo đĩa mềm khởi động DOS

Thỏa Thuận FBS

Lỗi thường gặp ở Windows Lỗi thường gặp ở Windows Bởi: Vien CNTT DHQG Hanoi LỖI THƯỜNG GẶP Ở WINDOWS Khi hệ thống gặp bất ổn, hệ điều hành (HĐH) sẽ cố

Microsoft Word - van-ban-van-hoc.docx

Thử bàn về chiến lược chiến thuật chống quân Minh của vua Lê Lợi Tìm hiểu Thế chiến thứ Hai cùng chiến tranh Triều Tiên, người nghiên cứu lịch sử khâm

Bài 15: QUẢN LÝ BẢNG TÍNH 15.1 Các khái niệm Ô (cell) là đơn vị cơ sở của bảng tính, mỗi ô có địa chỉ riêng, địa chỉ gồm Chỉ số cột Chỉ số dòng, ví dụ

Máy tính cá nhân Máy tính cá nhân Bởi: Wiki Pedia Định nghĩa Máy tính cá nhân (tiếng Anh: personal computer, viết tắt PC) là một máy điện toán siêu nh

Nội dung chương 3 IT1110 Tin học đại cương Phần I: Tin học căn bản Chương 3: Hệ thống máy tính 3.1. Giới thiệu 3.2. Chức năng và các thành phần của má

67_8807.pdf

SÁCH HƯỚNG DẪN SỬ DỤNG SM-G970F/DS SM-G973F/DS SM-G975F/DS Vietnamese. 03/2019. Rev.1.1

TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI VIỆN CÔNG NGHỆ THÔNG TIN VÀ TRUYỀN THÔNG TIN HỌC ĐẠI CƯƠNG Bài 11. Tệp tin Nội dung 1. Khái niệm cơ bản 2. Các thao tá

Công cụ trong VB6 Công cụ trong VB6 Bởi: FPT Software Để tìm hiểu về các công cụ trong VB chúng ta sẽ đề cập tới Add-in Các công cụ trong add-in Trình

quy phạm trang bị điện, chương i.1

Hướng dẫn KHG sử dụng dịch vụ BaaS do Mobifone Global cung cấp Tổng Công ty Viễn thông MOBIFONE là nhà cung cấp dịch vụ Viễn thông và CNTT hàng đầu tạ

Lesson 1

PowerPoint Presentation

CÔNG BÁO/Số ngày PHẦN I. VĂN BẢN QUY PHẠM PHÁP LUẬT BỘ NỘI VỤ BỘ NỘI VỤ Số: 09/2010/TT-BNV CỘNG HÒA XÃ HỘI CHỦ NGHĨA VIỆT NAM Đ

Microsoft Word - Tin hoc dai cuong 2015

Phân tích và thiết kế hệ thống thông tin

Microsoft Word - 10 quy tac then chot ve bao mat.doc

Bản ghi:

Lấy thông tin từ kernel log buffer Giới thiệu Ở bài học trước, chúng ta thấy rằng, hàm printk in các thông điệp ra console. Tuy nhiên, trong quá trình hoạt động, device driver có thể gọi hàm printk rất nhiều lần, nên sẽ có hàng nghìn thông điệp được in ra. Trong khi đó, kích thước của console thì lại hữu hạn. Điều này dẫn tới nhiều thông điệp có giá trị bị trôi mất, gây khó khăn trong quá trình phân tích nguyên nhân gây ra lỗi. Để giải quyết vấn đề trên, hàm printk cũng lưu các thông điệp vào một buffer trong kernel space. Tất cả các thông điệp đều được lưu vào buffer này, dù message log level bằng bao nhiêu. Điều này khác với cơ chế in thông điệp ra console: chỉ những thông điệp có message log level thấp hơn console log level mới được in ra console. Việc lưu tất cả các thông điệp vào trong buffer này rất có ích cho việc phân tích nguyên nhân của lỗi. Phần thứ nhất của bài học này sẽ trình bày về cơ chế lưu thông tin vào buffer nói trên. Phần thứ hai sẽ trình bày các cách thu thập thông tin trong buffer đó. Cuối cùng sẽ là các ví dụ để làm rõ hơn những gì đã trình bày trong bài học. Hàm printk sẽ lưu các thông điệp vào đâu? Hàm printk sẽ ghi các thông điệp vào một ring buffer trong kernel space. Tập hợp tất cả các thông điệp trong trong buffer này được gọi là kernel log. Để phân biệt với các buffer khác, ta gọi nó là kernel log buffer. //Tham khảo file /kernel/printk/printk.c #define LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) static char log_buf[ LOG_BUF_LEN] aligned(log_align); //kernel log buffer static char log_buf = log_buf; //địa chỉ của kernel log buffer static u32 log_buf_len = LOG_BUF_LEN; //kích thước của kernel log buffer Kích thước của kernel log buffer được thiết lập trong quá trình cấu hình kernel trước khi biên dịch. Ví dụ, nếu ta muốn kích thước của kernel log buffer là 128KB=2^1 7 bytes, thì ta thiết lập CONFIG_LOG_BUF_SHIFT=17 trong file.config. Chính vì vậy, để biết kích thước của kernel log buffer trong một hệ thống, ta gõ lệnh sau: grep CONFIG_LOG_BUF_SHIFT /boot/config-`uname -r`. Lũy thừa bậc 2 của CONFIG_LOG_BUF_SHIFT chính là kích thước của kernel log buffer. https://vimentor.com/storage/upload/ckeditor/03-03-2019-23-24-27-image.png Hình 1. Các xác định kích thước của kernel log buffer trong một hệ thống Câu hỏi đặt ra là, sau khi kernel log buffer bị đầy, thì các thông điệp mới sẽ được lưu vào đâu? Để trả lời câu hỏi này, chúng ta cần đọc file /kernel/printk/printk.c để xem hàm printk hoạt động như thế nào. Ta thấy rằng, khi hàm printk được gọi, luồng thực thi sẽ diễn ra như sau: printk > > vprintk_default > > vprintk_emit >> log_store. Hàm log_store có nhiệm vụ ghi thông điệp vào trong kernel log buffer. Trước khi ghi vào, hàm log_store kiểm tra xem còn đủ chỗ trống không. Nếu không còn đủ, log_store sẽ ghi thông điệp này vào vị trí đầu của kernel log buffer, đè lên các thông điệp cũ. Cơ chế này khiến thông tin bị mất sau một khoảng thời gian. Tuy nhiên, thường thì đó là những thông tin quá cũ rồi, không còn giá trị gì để phân tích nữa. file /kernel/printk/printk.c #define PREFIX_MAX 32 #define LOG_LINE_MAX (1024 - PREFIX_MAX) #define LOG_ALIGN 4 Xác định tổng số byte của một bản ghi, bao gồm các byte padding (byte 0). Thêm các byte padding để kích thước của bản ghi chia hết cho LOG_ALIGN. static u32 msg_used_size(u16 text_len, u16 dict_len, u32 pad_len) {

u32 size; size = sizeof(struct printk_log) + text_len + dict_len; pad_len = (-size) & (LOG_ALIGN - 1); size += pad_len; return size; hàm này thêm một bản ghi vào trong kernel log buffer. Nếu kernel log buffer đầy, trở lại vị trí đầu tiên để ghi. Sau khi ghi xong, cập nhật lại vị trí kế tiếp sẽ ghi vào. static int log_store(int facility, int level, enum log_flags flags, u64 ts_nsec, const char dict, u16 dict_len, const char text, u16 text_len) { struct printk_log msg; u32 size, pad_len; u16 trunc_msg_len = 0; size = msg_used_size(text_len, dict_len, &pad_len); nếu không còn đủ chỗ thì vị trí ghi kế tiếp sẽ là vị trí đầu tiên của kernel log buffer if (log_next_idx + size + sizeof(struct printk_log) > log_buf_len) { This message + an additional empty header does not fit at the end of the buffer. Add an empty header with len == 0 to signify a wrap around. memset(log_buf + log_next_idx, 0, sizeof(struct printk_log)); log_next_idx = 0; Lưu thông điệp vào kernel log buffer dưới dạng bản ghi. Bản ghi gồm 2 phần: tiêu đề (message header) và dữ liệu (message data). Bước 1: sao chép thông điệp vào phần message data msg = (struct printk_log )(log_buf + log_next_idx); memcpy(log_text(msg), text, text_len); Bước 2: Điền các thông tin mô tả vào trong message header msg->text_len = text_len; //lưu lại kích thước của phần message data if (trunc_msg_len) { memcpy(log_text(msg) + text_len, trunc_msg, trunc_msg_len); msg->text_len += trunc_msg_len; msg->facility = facility; //lưu lại nơi đã sinh ra thông điệp này msg->level = level & 7; //lưu lại độ ưu tiên của thông điệp này msg->flags = flags & 0x1f; if (ts_nsec > 0) msg->ts_nsec = ts_nsec; else msg->ts_nsec = local_clock(); //lưu lại timestamp memset(log_dict(msg) + dict_len, 0, pad_len); //Thêm các byte padding msg->len = size; //lưu lại kích thước của bản ghi cập nhật lại vị trí kế tiếp sẽ ghi vào log_next_idx += msg->len; log_next_seq++; return msg->text_len; Cũng từ quá trình tìm hiểu trên mà ta thấy rằng, các thông điệp được lưu vào kernel log buffer theo dạng bản ghi. Kích thước của mỗi bản ghi không vượt quá 1024 byte và phải chia hết cho LOG_ALIGN. Mỗi bản ghi gồm

2 thành phần: Thành phần tiêu đề (message header): Thành phần này chứa các thông tin mô tả thông điệp như kích thước của bản ghi, kích thước của phần message data, log level của thông điệp, timestamp của thông điệp Thành phần này được đại diện bởi cấu trúc printk_log. Cấu trúc này có kích thước không vượt quá PREFIX_MAX = 32 byte. Thành phần dữ liệu (message data): Thành phần này chính là thông điệp mà ta muốn in ra. Kích thước tối đa của phần này được quy định bởi macro LOG_LINE_MAX = 1024 - PREFIX_MAX byte. Làm thế nào để lấy được kernel log? Hình 2. Cách bố trí các thông điệp trong kernel log buffer Khi xảy ra lỗi, điều đầu tiên cần làm đó là thu thập các thông điệp trong kernel log buffer. Để làm được điều này, ta có 3 cách. Đọc kernel log thông qua /proc/kmsg Hiện nay, có nhiều tiến trình trên user space hỗ trợ việc đọc kernel log thông qua /proc/kmsg. Ví dụ, hệ điều hành Ubuntu 16.04 sử dụng tiến trình rsyslogd. Đối với các hệ thống khác, tiến trình syslog-ng hoặc klogd cũng có thể được sử dụng. Xét hệ điều hành Ubuntu 16.04. Tiến hành kiểm tra file cấu hình của tiến trình rsyslogd, ta thấy rằng: tiến trình rsyslogd sẽ đọc kernel log thông qua /proc/kmsg rồi lưu vào file /var/log/kern.log. Vì vậy, khi device driver của bạn xảy ra lỗi, bạn chỉ cần mở file này ra và phân tích thông tin để tìm ra nguyên nhân của lỗi. Hình 3. Hệ điều hành Ubuntu 16.04 sử dụng tiến trình rsyslogd để đọc kernel log thông qua /proc/kmsg Trong trường hợp mà hệ thống của bạn không có tiến trình nào lấy kernel log thông qua /proc/kmsg, bạn nên làm như sau:

Bước 1: Trước khi chạy device driver trên hệ thống, bạn cần chắc chắn rằng không có một tiến trình nào đang đọc file /proc/kmsg. Lý do là vì, mỗi một thông điệp chỉ có thể được đọc thông qua /proc/kmsg một lần duy nhất. Do đó, nếu một thông điệp đã được đọc bởi một một tiến trình, thì các tiến trình khác không thể có được thông điệp đó nữa. Bạn có thể đọc hàm kmsg_read trong /fs/proc/kmsg.c để rút ra điều này. Bước 2: Gõ lệnh cat /proc/kmsg > /YourDirectory/kernel.log & để tạo một tiến trình chạy ngầm thu thập kernel log. Bước 3: Cho device driver của bạn bắt đầu hoạt động. Bước 4: Khi xảy ra lỗi, bạn chỉ cần lấy file kernel.log trong thư mục YourDirectory ra để phân tích tìm nguyên nhân gây ra lỗi. Tại bước 2, chúng ta đã lưu kernel log vào trong một file trên ổ cứng. Việc làm này có hai mục đích: Thứ nhất, ngay cả khi phải kiểm tra device driver trong một thời gian dài, ta cũng không cần lo vấn đề tràn kernel log buffer. Vì file trên ổ cứng được xem như có dung lượng "vô hạn". Thứ hai, kể cả khi device driver của bạn gây ra lỗi nghiêm trọng khiến hệ thống của bạn bị treo, buộc phải khởi động lại, bạn cũng không lo bị mất thông tin, vì file được lưu trên ổ cứng. Đọc kernel log thông qua /dev/kmsg Ngoài /proc/kmsg, Linux còn cung cấp giao diện /dev/kmsg để đọc kernel log. Đây là một character device file. Để biết chi tiết hơn về /dev/kmsg, các bạn có thể tham khảo tài liệu và mã nguồn trên mạng Internet. Các bản phân phối của Linux thường cung cấp chương trình dmesg để đọc kernel log thông qua file /dev/kmsg. Đối với những hệ thống như vậy, bạn tiến hành lấy kernel log như sau: Bước 1: Gõ lệnh dmesg -C để lờ đi những thông điệp đã xuất hiện từ trước khi chạy device driver của bạn. Chú ý rằng, đứng từ góc nhìn của người dùng, thì lệnh này sẽ "xóa" kernel log buffer. Nhưng đứng từ góc nhìn của kernel, thì không có thông điệp nào bị xóa cả, chỉ là các thông điệp hiện tại sẽ bị lờ đi. Bước 2: Gõ lệnh dmesg -w > /YourDirectory/kernel.log & để tạo một tiến trình chạy ngầm thu thập kernel log. Bước 3: Cho device driver của bạn bắt đầu hoạt động. Bước 4: Khi xảy ra lỗi, bạn chỉ cần lấy file kernel.log trong thư mục YourDirectory ra để phân tích tìm nguyên nhân gây ra lỗi. Nếu hệ thống chưa cài đặt dmesg, bạn có thể làm như sau: Bước 1: Gõ lệnh echo "my device driver start here" > /dev/kmsg để đánh dấu thời điểm bắt đầu chạy device driver của bạn. Bước 2: Gõ lệnh cat /dev/kmsg > /YourDirectory/kernel.log & để tạo một tiến trình chạy ngầm thu thập kernel log. Bước 3: Cho device driver của bạn bắt đầu hoạt động. Bước 4: Khi xảy ra lỗi, bạn chỉ cần lấy file kernel.log trong thư mục YourDirectory ra để phân tích tìm nguyên nhân gây ra lỗi. Những gì bạn cần quan tâm là các thông điệp bắt đầu từ "my device driver start here". Khác với đọc kernel log thông qua /proc/kmsg, bạn không cần phải quan tâm có tiến trình nào đang đọc file /dev/kmsg hay không. Lý do là vì, một thông điệp có thể được đọc thông qua /dev/kmsg bao nhiêu lần cũng được và bởi bao nhiêu tiến trình cũng được. Bạn có thể đọc hàm devkmsg_read trong file /kernel/printk/printk.c để rút ra điều này. Sử dụng system call syslog để đọc kernel log Nếu không thích sử dụng các công cụ có sẵn ở trên, ta có thể viết một chương trình sử dụng system call syslog. System call này cho phép ta làm việc với kernel log buffer. Do system call syslog có tên trùng với một library call trong thư viện C, nên thư viện C đã tạo ra một hàm có tên là klogctl bao bọc system call này. Vì vậy, khi viết chương trình lấy kernel log, ta nên sử dụng hàm klogctl để tránh nhầm lẫn. Dưới đây là cách sử dụng hàm klogctl để làm việc với kernel log buffer. #include <sys/klog.h> Hàm này dùng để làm việc với kernel log buffer, và làm việc với console log level. Tham số đầu vào: type: kiểu thao tác làm việc với kernel log buffer. Các thao tác này bao gồm:

(0) SYSLOG_ACTION_CLOSE: đóng kernel log buffer (hiện tại chưa triển khai) (1) SYSLOG_ACTION_OPEN: mở kernel log buffer (hiện tại chưa triển khai) (2) SYSLOG_ACTION_READ: đọc kernel log. Kiểu thao tác này sẽ đợi cho tới khi xuất hiện thông điệp mới trong kernel log buffer. Sau đó, thông điệp này sẽ được sao chép vào [bufp] (không quá [len] byte). Chú ý rằng, mỗi một thông điệp chỉ có thể được đọc theo kiểu này 1 lần. Điều này cũng giống như một tiến trình đọc kernel log thông qua /proc/kmsg. Ví dụ: giả sử kernel log buffer đang có hai thông điệp A và B. Nếu tiến trình 1 đọc kernel log theo kiểu này, hai thông điệp sẽ được đọc vào [bufp]. Sau đó tiến trình 1 sẽ đợi cho tới khi có thông điệp mới. Nếu sau đó, tiến trình 2 cũng đọc kernel log theo kiểu này, thì nó sẽ không đọc được hai thông điệp A và B nữa. (3) SYSLOG_ACTION_READ_ALL: đọc các thông điệp (kể từ lần gần nhất thực hiện thao tác SYSLOG_ACTION_CLEAR) trong kernel log buffer vào trong buffer có địa chỉ [bufp]. Nếu tổng kích thước của các thông điệp vượt quá [len] byte, thì chỉ đọc[len] byte cuối cùng. Khác với SYSLOG_ACTION_READ, về sau, các thông điệp này vẫn có thể được đọc bởi các tiến trình khác. Ví dụ, trong kernel log buffer đang có hai thông điệp A và B. Bây giờ, tiến trình gửi lệnh SYSLOG_ACTION_CLEAR xuống. Sau đó, xuất hiện thêm ba thông điệp C, D, E. Nếu lúc này, tiến trình 1 đọc kernel log theo kiểu SYSLOG_ACTION_READ_ALL, thì chỉ có ba thông điệp C, D, E được đọc vào user buffer (tại địa chỉ [bufp]), miễn là tổng kích thước ba thông điệp không vượt quá [len] byte. Nếu sau đó, tiến trình 2 cũng đọc kernel log theo kiểu này, thì nó vẫn sẽ đọc được ba thông điệp C, D và E. (4) SYSLOG_ACTION_READ_CLEAR: kết hợp giữa thao tác SYSLOG_ACTION_READ_ALL và SYSLOG_ACTION_CLEAR. (5) SYSLOG_ACTION_CLEAR: thực hiện "xóa" các thông điệp trong kernel log buffer. Đối với thao tác này, ta không cần quan tâm [bufp] và [len]. Chú ý, thực tế, không có thông điệp nào bị xóa cả. Thao tác này chỉ thay đổi các biến quản lý kernel log buffer, giúp thay đổi kết quả trả về của thao tác SYSLOG_ACTION_READ_ALL và SYSLOG_ACTION_READ_CLEAR. Điều này khiến cho người dùng cảm thấy: tất cả các thông điệp trước khi thực hiện thao tác này đã bị "xóa" mất. Các thao tác SYSLOG_ACTION_READ và SYSLOG_ACTION_SIZE_UNREAD không bị ảnh hưởng bởi thao tác này. (6) SYSLOG_ACTION_CONSOLE_OFF: lưu lại console log level hiện tại rồi thiết lập console log level bằng mimimum console log level. Mục đích của việc này là để không có thông điệp nào được in ra console. Đối với thao tác này, ta không cần quan tâm [bufp] và [len]. (7) SYSLOG_ACTION_CONSOLE_ON: nếu đã thực hiện SYSLOG_ACTION_CONSOLE_OFF trước đó, thì thao tác này giúp khôi phục console log level về như giá trị ban đầu. Đối với thao tác này, ta không cần quan tâm [bufp] và [len]. (8) SYSLOG_ACTION_CONSOLE_LEVEL: thiết lập console log level = [len]. Chú ý, [len] phải có giá trị nguyên trong khoảng từ 1 đến 8. Nếu tham số [len] nhỏ hơn giá trị minimum console log level thì console log level chỉ được thiết lập bằng minimum console log level. Đối với thao tác này, ta không cần quan tâm [bufp]. (9) SYSLOG_ACTION_SIZE_UNREAD: trả về số byte có thể đọc được từ kernel log buffer trong trường hợp sử dụng SYSLOG_ACTION_READ. Đối với thao tác này, ta không cần quan tâm [bufp] và [len]. (10) SYSLOG_ACTION_SIZE_BUFFER: trả về kích thước của kernel log buffer. Đối với thao tác này, ta không cần quan tâm [bufp] và [len]. bufp: địa chỉ của buffer trên user space dùng để chứa kernel log. len : kích thước của buffer trên user space. Giá trị trả về: Đối với các thao tác (2), (3), (4), hàm này trả về số byte đọc được từ kernel log buffer. Đối với thao tác (9), hàm này trả về số byte có thể đọc được nếu sử dụng thao tác (2). Đối với thao tác (10), hàm này trả về kích thước của kernel log buffer. Đối với các thao tác còn lại, hàm này trả về 0 nếu thực hiện thành công. Nếu xảy ra lỗi, hàm này sẽ trả về -1 và biến errno sẽ chứa mã lỗi.

int klogctl(int type, char bufp, int len); Trên thực tế, klogd và dmesg cũng có thể đọc kernel log bằng phương pháp này: Nếu ta biên dịch klogd với cờ ENABLE_FEATURE_KLOGD_KLOGCTL được bật, thì klogd sẽ lấy kernel log bằng phương pháp này thay vì đọc thông qua /proc/kmsg. Nếu ta gõ lệnh dmesg -S, thì tiến trình dmesg sẽ lấy kernel log bằng phương pháp này thay vì đọc thông qua /dev/kmsg. Case study Phần này hướng dẫn các bạn thực hành lấy kernel log theo các cách khác nhau. Để phục vụ quá trình thực hành, vchar driver trong bài học trước sẽ được sử dụng. Đọc kernel log thông qua /proc/kmsg Như đã trình bày ở trên, trong hệ điều hành Ubuntu 16.04, tiến trình rsyslogd đọc kernel log thông qua /proc/kmsg rồi lưu vào file /var/log/kern.log. Để minh chứng cho điều này, chúng ta cùng thực hiện những bước sau: Bước 1: Nhấn tổ hợp phím Ctrl + Alt + T để mở một terminal, sau đó nhập vào lệnh tailf -n 0 /var/log/kern.log. Bước 2: Nhấn tổ hợp phím Ctrl + Alt + T để mở một terminal khác, sau đó di chuyển tới thư mục phan_3/bai_3_1/ rồi nhập vào lệnh sudo insmod vchar_driver.ko để lắp vchar driver vào trong kernel. Quan sát trên terminal thứ nhất, ta thấy có các thông điệp của vchar driver được in ra (hình 4). Hình 4. Tiến trình rsyslogd lấy kernel log thông qua /proc/kmsg rồi lưu vào /var/log/kern.log Nếu không thích tiến trình rsyslogd, bạn có thể dùng lệnh cat /proc/kmsg để lấy kernel log. Các bước làm như sau: Bước 1: Gõ lệnh sudo service rsyslog stop để hủy tiến trình rsyslog. Nếu không hủy tiến trình này, bạn không thể đọc được kernel log. Bởi vì một thông điệp chỉ có thể được đọc qua /proc/kmsg một lần duy nhất và bởi một tiến trình duy nhất. Bước 2: Gõ lệnh sudo cat /proc/kmsg > kernel.txt &. Sau khi nhập lệnh này, tiến trình cat sẽ chạy ngầm để đọc kernel log thông qua /proc/kmsg. Kernel log sẽ được lưu vào file kernel.txt trong thư mục hiện tại. Bước 3: Gõ lệnh sudo insmod vchar_driver.ko để lắp vchar driver vào kernel. Bước 4: Gõ lệnh cat kernel.txt thì sẽ thu được kết quả tương tự như hình 5. Điều này chứng tỏ rằng, ta đã lấy kernel log thành công thông qua /proc/kmsg.

Đọc kernel log thông qua /dev/kmsg Hình 5. Sử dụng lệnh cat /proc/kmsg để lấy kernel log Hệ điều hành Ubuntu 16.04 có công cụ dmesg. Mặc định, dmesg sẽ lấy kernel log thông qua /dev/kmsg. Để minh họa cho việc lấy kernel log bằng dmesg, ta thực hiện các bước sau: Bước 1: Gõ lệnh dmesg -C để lờ đi những thông điệp hiện tại đang có trong kernel log buffer. Bước 2: Gõ lệnh dmesg -w > kernel.log &. Sau khi nhập lệnh này, tiến trình dmesg sẽ chạy ngầm để đọc kernel log thông qua /dev/kmsg. Kernel log sẽ được lưu vào file kernel.log trong thư mục hiện tại. Bước 3: Gõ lệnh sudo insmod vchar_driver.ko để lắp vchar driver vào kernel. Bước 4: Gõ lệnh cat kernel.log thì sẽ thu được kết quả tương tự như hình 6. Điều này chứng tỏ rằng, ta đã lấy kernel log thành công thông qua /dev/kmsg. Hình 6. Sử dụng dmesg để lấy kernel log thông qua /dev/kmsg Nếu không thích sử dụng dmesg để lấy kernel log thông qua /dev/kmsg, ta có thể làm như sau: Bước 1: Gõ lệnh echo "vchar driver start here" > /dev/kmsg. Thông điệp này sẽ được ghi vào kernel log buffer. Mục đích của việc này là để đánh dấu thời điểm bắt đầu chạy device driver của bạn. Bước 2: Gõ lệnh cat /dev/kmsg > kernel.log &. Sau khi nhập lệnh này, tiến trình cat sẽ chạy ngầm để đọc kernel log thông qua /dev/kmsg. Kernel log sẽ được lưu vào file kernel.log trong thư mục hiện tại. Bước 3: Gõ lệnh sudo insmod vchar_driver.ko để lắp vchar driver vào kernel.

Hình 7. Sử dụng cat để lấy kernel log thông qua /dev/kmsg Bây giờ, ta gõ lệnh cat kernel.log để xem những gì đã lưu vào trong file kernel.log. Ta có thể thấy rằng, toàn bộ kernel log được lấy ra. Hầu hết các dòng đều có định dạng: <message log level>,<sequence number>, <timestamp>,<flag>;<nội dung>. Các thông điệp của vchar driver được in ra kể từ thông điệp "vchar driver start here". Thông điệp này có message log level bằng 12, thể hiện đây là thông điệp đến từ user space. Đọc kernel log bằng system call Hình 8. Kernel log thu thập được khi sử dụng lệnh cat /dev/kmsg Trong phần này, chúng ta sẽ cùng tìm hiểu cách mà chương trình klogd lấy kernel log bằng system call. Dựa trên mã nguồn của klogd, bạn có thể viết chương trình của riêng bạn để lấy kernel log bằng phương pháp system call. Hiện nay, nhiều hệ thống nhúng vẫn sử dụng Busybox để cung cấp các công cụ cơ bản (basic utility), hai trong số đó là klogd và syslogd. klogd là một chương trình trên user space. Nhiệm vụ của nó là lấy kernel log, sau đó gửi cho tiến trình syslogd thông qua một UNIX socket có tên là /dev/log. Thông qua UNIX socket /dev/log, tiến trình syslogd sẽ nhận được kernel log cùng với log của các tiến trình khác, rồi ghi vào một file trên ổ cứng. Thông thường, file đó là /var/log/message.

Hình 9. Sơ đồ của quá trình thu thập log trong hệ thống sử dụng Busybox Trong quá trình biên dịch Busybox, ta có thể thiết lập cấu hình ENABLE_FEATURE_KLOGD_KLOGCTL. Nếu cấu hình này không được bật, thì klogd sẽ đọc kernel log thông qua giao diện /proc/kmsg. Còn nếu được bật, thì klogd sẽ đọc kernel log bằng phương pháp system call syslog. Mã nguồn triển khai cho cả hai cách này như sau: #include "libbb.h" #include <syslog.h> The Linux-specific klogctl(3) interface does not rely on the filesystem and allows us to change the console loglevel. Alternatively, we read the messages from _PATH_KLOG. #if ENABLE_FEATURE_KLOGD_KLOGCTL # include <sys/klog.h> static int klogd_read(char bufp, int len) { return klogctl(2, bufp, len); #else # include <paths.h> enum { klogfd = 3 ; static void klogd_open(void) { _PATH_KLOG được định nghĩa trong thư viện <paths.h> int fd = xopen(_path_klog, O_RDONLY); xmove_fd(fd, klogfd); static int klogd_read(char bufp, int len) { return read(klogfd, bufp, len); #endif

Kết luận Hàm printk sẽ ghi các thông điệp vào một ring buffer trong kernel space. Tập các thông điệp trong ring buffer này được gọi là kernel log. Do đó, buffer này được gọi là kernel log buffer. Kích thước của kernel log buffer phụ thuộc vào tham số CONFIG_LOG_BUF_SHIFT. Ta có thể điều chỉnh được tham số này lúc biên dịch kernel. Khi xảy ra lỗi, ta cần phải lấy kernel log. Có ba cách cho phép lấy kernel log từ user space. Cách thứ nhất là đọc kernel log thông qua /proc/kmsg. Cách thứ hai là đọc kernel log thông qua /dev/kmsg. Cách thứ ba là đọc kernel log thông qua system call syslog. Các hệ thống hiện tại đã có nhiều công cụ trên user space để lấy kernel log, ví dụ như klogd, rsyslog, syslogng, dmesg. Các công cụ này lấy kernel log theo một trong ba cách nói trên.