Các hệ thống tệp ảo trong Linux: tại sao chúng cần thiết và chúng hoạt động như thế nào? Phần 2

Xin chào mọi người, chúng tôi đang chia sẻ với các bạn phần thứ hai của ấn phẩm “Hệ thống tệp ảo trong Linux: tại sao chúng lại cần thiết và chúng hoạt động như thế nào?” Bạn có thể đọc phần đầu tiên đây. Hãy để chúng tôi nhắc bạn rằng loạt ấn phẩm này được ấn định trùng với thời điểm ra mắt một luồng mới về khóa học "Quản trị viên Linux", bắt đầu rất sớm.

Cách giám sát VFS bằng công cụ eBPF và bcc

Cách dễ nhất để hiểu cách kernel hoạt động trên các tập tin sysfs là xem nó trong thực tế và cách dễ nhất để xem ARM64 là sử dụng eBPF. eBPF (viết tắt của Berkeley Packet Filter) bao gồm một máy ảo chạy trong cốt lõi, mà người dùng đặc quyền có thể yêu cầu (query) từ dòng lệnh. Các nguồn hạt nhân cho người đọc biết hạt nhân có thể làm gì; việc chạy các công cụ eBPF trên một hệ thống đã tải sẽ hiển thị những gì kernel thực sự đang làm.

Các hệ thống tệp ảo trong Linux: tại sao chúng cần thiết và chúng hoạt động như thế nào? Phần 2

May mắn thay, việc bắt đầu sử dụng eBPF khá dễ dàng với sự trợ giúp của các công cụ bcc, có sẵn dưới dạng gói từ bản phân phối chung Linux và được ghi chép chi tiết Bernard Gregg. Công cụ bcc là các tập lệnh Python có chèn thêm mã C, có nghĩa là bất kỳ ai quen thuộc với cả hai ngôn ngữ đều có thể dễ dàng sửa đổi chúng. TRONG bcc/tools Có 80 tập lệnh Python, có nghĩa là rất có thể nhà phát triển hoặc quản trị viên hệ thống sẽ có thể chọn thứ gì đó phù hợp để giải quyết vấn đề.
Để có được ít nhất một ý tưởng hời hợt về công việc mà VFS thực hiện trên hệ thống đang chạy, hãy thử vfscount hoặc vfsstat. Giả sử, điều này sẽ hiển thị rằng hàng tá cuộc gọi vfs_open() và “bạn bè của anh ấy” xảy ra theo đúng nghĩa đen mỗi giây.

Các hệ thống tệp ảo trong Linux: tại sao chúng cần thiết và chúng hoạt động như thế nào? Phần 2

vfsstat.py là một tập lệnh Python có chèn mã C chỉ đơn giản là đếm các lệnh gọi hàm VFS.

Hãy đưa ra một ví dụ đơn giản hơn và xem điều gì sẽ xảy ra khi chúng ta cắm ổ flash USB vào máy tính và hệ thống phát hiện ra nó.

Các hệ thống tệp ảo trong Linux: tại sao chúng cần thiết và chúng hoạt động như thế nào? Phần 2

Sử dụng eBPF bạn có thể thấy điều gì đang xảy ra trong /syskhi ổ flash USB được lắp vào. Một ví dụ đơn giản và phức tạp được hiển thị ở đây.

Trong ví dụ hiển thị ở trên, bcc dụng cụ trace.py in thông báo khi lệnh được chạy sysfs_create_files(). Chúng ta thấy rằng sysfs_create_files() đã được đưa ra bằng cách sử dụng kworker phát trực tuyến để đáp lại việc ổ đĩa flash đã được lắp vào, nhưng tập tin nào đã được tạo? Ví dụ thứ hai cho thấy sức mạnh của eBPF. Đây trace.py In dấu vết ngược kernel (tùy chọn -K) và tên của tệp đã được tạo sysfs_create_files(). Chèn câu lệnh đơn là mã C bao gồm chuỗi định dạng dễ nhận biết được cung cấp bởi tập lệnh Python chạy LLVM trình biên dịch đúng lúc. Nó biên dịch dòng này và thực thi nó trong một máy ảo bên trong kernel. Chữ ký đầy đủ chức năng sysfs_create_files () phải được sao chép trong lệnh thứ hai để chuỗi định dạng có thể tham chiếu đến một trong các tham số. Các lỗi trong đoạn mã C này dẫn đến các lỗi có thể nhận biết được từ trình biên dịch C. Ví dụ: nếu tham số -l bị bỏ qua, bạn sẽ thấy "Không thể biên dịch văn bản BPF". Các nhà phát triển quen thuộc với C và Python sẽ tìm thấy các công cụ bcc dễ dàng mở rộng và thay đổi.

Khi cắm ổ USB vào, dấu vết ngược của kernel sẽ hiển thị rằng PID 7711 là một luồng kworkerđã tạo ra tập tin «events» в sysfs. Theo đó, cuộc gọi từ sysfs_remove_files() sẽ hiển thị rằng việc xóa ổ đĩa dẫn đến tập tin bị xóa events, tương ứng với khái niệm chung về tính tham chiếu. Đồng thời, xem sysfs_create_link () với eBPF khi cắm ổ USB sẽ hiển thị ít nhất 48 liên kết tượng trưng đã được tạo.

Vậy mục đích của tệp sự kiện là gì? Cách sử dụng cscope để tìm kiếm __device_add_disk(), cho biết nguyên nhân gây ra disk_add_events (), và một trong hai "media_change"Hoặc "eject_request" có thể được ghi lại trong một tập tin sự kiện. Ở đây, lớp khối kernel thông báo cho không gian người dùng rằng một "đĩa" đã xuất hiện và được đẩy ra. Lưu ý mức độ thông tin của phương pháp nghiên cứu này bằng cách cắm ổ USB, so với việc cố gắng tìm hiểu cách mọi thứ hoạt động hoàn toàn từ nguồn.

Hệ thống tập tin gốc chỉ đọc cho phép các thiết bị nhúng

Tất nhiên, không ai tắt máy chủ hoặc máy tính của mình bằng cách rút phích cắm ra khỏi ổ cắm. Nhưng tại sao? Điều này là do hệ thống tệp được gắn trên thiết bị lưu trữ vật lý có thể bị chậm khi ghi và cấu trúc dữ liệu ghi lại trạng thái của chúng có thể không được đồng bộ hóa với quá trình ghi vào bộ lưu trữ. Khi điều này xảy ra, chủ sở hữu hệ thống phải đợi đến lần khởi động tiếp theo để khởi chạy tiện ích. fsck filesystem-recovery và trong trường hợp xấu nhất là mất dữ liệu.

Tuy nhiên, tất cả chúng ta đều biết rằng nhiều thiết bị IoT, cũng như bộ định tuyến, bộ điều nhiệt và ô tô hiện đang chạy Linux. Nhiều thiết bị trong số này có rất ít hoặc không có giao diện người dùng và không có cách nào để tắt chúng một cách "một cách sạch sẽ". Hãy tưởng tượng khởi động một chiếc ô tô bị hết ắc quy khi nguồn điện của bộ điều khiển bị ngắt. Linux nhảy lên nhảy xuống liên tục. Làm thế nào mà hệ thống khởi động mà không lâu fsckkhi nào thì động cơ bắt đầu chạy? Và câu trả lời rất đơn giản. Thiết bị nhúng dựa vào hệ thống tập tin gốc chỉ để đọc (viết tắt ro-rootfs (hệ thống tập tin gốc chỉ đọc)).

ro-rootfs mang lại nhiều lợi ích ít rõ ràng hơn tính xác thực. Một ưu điểm là phần mềm độc hại không thể ghi vào /usr hoặc /lib, nếu không có tiến trình Linux nào có thể ghi vào đó. Một điều nữa là hệ thống tệp hầu như không thể thay đổi là rất quan trọng để hỗ trợ tại hiện trường cho các thiết bị từ xa, vì nhân viên hỗ trợ dựa vào các hệ thống cục bộ về mặt danh nghĩa giống hệt với hệ thống tại hiện trường. Có lẽ lợi ích quan trọng nhất (nhưng cũng nguy hiểm nhất) là ro-rootfs buộc các nhà phát triển phải quyết định đối tượng hệ thống nào sẽ không thay đổi ở giai đoạn thiết kế của hệ thống. Làm việc với ro-rootfs có thể khó khăn và rắc rối, vì các biến const thường có trong các ngôn ngữ lập trình, nhưng lợi ích của chúng dễ dàng bù đắp cho chi phí bổ sung.

sự sáng tạo rootfs Chỉ đọc đòi hỏi một số nỗ lực bổ sung đối với các nhà phát triển nhúng và đây là lúc VFS xuất hiện. Linux yêu cầu các tập tin phải ở dạng /var có thể ghi được và ngoài ra, nhiều ứng dụng phổ biến chạy hệ thống nhúng sẽ cố gắng tạo cấu hình dot-files в $HOME. Một giải pháp cho các tập tin cấu hình trong thư mục chính thường là tạo trước và xây dựng chúng thành rootfs. Đối với /var Một cách tiếp cận khả thi là gắn nó vào một phân vùng có thể ghi riêng biệt, trong khi / được gắn chỉ đọc. Một giải pháp thay thế phổ biến khác là sử dụng các giá treo liên kết hoặc lớp phủ.

Các giá đỡ có thể liên kết và xếp chồng lên nhau, việc sử dụng chúng bằng các thùng chứa

Thực hiện lệnh man mount là cách tốt nhất để tìm hiểu về các giá treo có thể liên kết và có thể xếp chồng, cung cấp cho các nhà phát triển và quản trị viên hệ thống khả năng tạo hệ thống tệp trong một đường dẫn và sau đó hiển thị nó cho các ứng dụng trong một đường dẫn khác. Đối với các hệ thống nhúng, điều này có nghĩa là khả năng lưu trữ các tập tin trong /var trên ổ đĩa flash chỉ đọc, nhưng có lớp phủ hoặc đường dẫn gắn kết có thể liên kết từ tmpfs в /var khi tải nó sẽ cho phép ứng dụng viết ghi chú vào đó (nguệch ngoạc). Lần tiếp theo bạn bật các thay đổi đối với /var sẽ bị mất. Một lớp phủ gắn kết tạo ra sự kết hợp giữa tmpfs và hệ thống tệp cơ bản và cho phép bạn thực hiện các thay đổi bề ngoài đối với các tệp hiện có trong ro-tootf trong khi một giá treo có thể gắn kết có thể làm trống những cái mới tmpfs các thư mục hiển thị dưới dạng có thể ghi trong ro-rootfs cách. Trong khi overlayfs đây là cái đúng (proper) loại hệ thống tệp, việc gắn kết có thể liên kết được triển khai trong Không gian tên VFS.

Dựa trên mô tả về lớp phủ và giá đỡ có thể liên kết, không ai ngạc nhiên rằng Vùng chứa Linux chúng được sử dụng tích cực. Hãy xem điều gì xảy ra khi chúng ta sử dụng systemd-nspawn để chạy container bằng công cụ mountsnoop từ bcc.

Gọi system-nspawn khởi động container trong khi chạy mountsnoop.py.

Hãy xem những gì đã xảy ra:

Ra mắt mountsnoop trong khi vùng chứa đang "khởi động" cho thấy thời gian chạy của vùng chứa phụ thuộc nhiều vào giá trị gắn kết được liên kết (Chỉ hiển thị phần đầu của đầu ra dài).

Здесь systemd-nspawn cung cấp các tập tin đã chọn trong procfs и sysfs lưu trữ vào vùng chứa dưới dạng đường dẫn đến nó rootfs. Ngoại trừ MS_BIND cờ thiết lập gắn kết liên kết, một số cờ khác trên gắn kết xác định mối quan hệ giữa các thay đổi đối với không gian tên máy chủ và vùng chứa. Ví dụ: một mount được liên kết có thể bỏ qua các thay đổi đối với /proc и /sys vào thùng chứa hoặc ẩn chúng tùy theo cuộc gọi.

Kết luận

Hiểu hoạt động bên trong của Linux có vẻ như là một nhiệm vụ bất khả thi, vì bản thân kernel chứa một lượng mã khổng lồ, bỏ qua các ứng dụng không gian người dùng Linux và giao diện cuộc gọi hệ thống trong các thư viện C như glibc. Một cách để đạt được tiến bộ là đọc mã nguồn của một hệ thống con kernel, tập trung vào việc hiểu các lệnh gọi hệ thống và các tiêu đề vùng người dùng, cũng như các giao diện kernel bên trong chính, chẳng hạn như bảng file_operations. Các thao tác với tệp cung cấp nguyên tắc "mọi thứ đều là một tệp", khiến chúng trở nên đặc biệt thú vị khi quản lý. Các tập tin nguồn kernel C trong thư mục cấp cao nhất fs/ trình bày cách triển khai hệ thống tệp ảo, là lớp bao bọc cung cấp khả năng tương thích rộng rãi và tương đối đơn giản giữa các hệ thống tệp phổ biến và thiết bị lưu trữ. Liên kết và gắn lớp phủ thông qua các không gian tên Linux là điều kỳ diệu của VFS giúp tạo ra các vùng chứa chỉ đọc và hệ thống tệp gốc. Kết hợp với việc kiểm tra mã nguồn, công cụ lõi eBPF và giao diện của nó bcc
làm cho việc khám phá cốt lõi trở nên dễ dàng hơn bao giờ hết.

Các bạn ơi, viết đi, bài viết này có hữu ích với bạn không? Có lẽ bạn có bất kỳ ý kiến ​​​​hoặc nhận xét? Và những ai quan tâm đến khóa học Quản trị viên Linux xin mời tham gia Ngày khai trương, sẽ diễn ra vào ngày 18 tháng XNUMX.

Phần đầu tiên.

Nguồn: www.habr.com

Thêm một lời nhận xét