it-swarm-vi.com

Làm thế nào tôi có thể tìm thấy việc thực hiện các cuộc gọi hệ thống nhân Linux?

Tôi đang cố gắng hiểu làm thế nào một hàm, nói mkdir, hoạt động bằng cách xem nguồn kernel. Đây là một nỗ lực để hiểu các phần bên trong kernel và điều hướng giữa các chức năng khác nhau. Tôi biết mkdir được định nghĩa trong sys/stat.h. Tôi tìm thấy nguyên mẫu:

/* Create a new directory named PATH, with permission bits MODE.  */
extern int mkdir (__const char *__path, __mode_t __mode)
     __THROW __nonnull ((1));

Bây giờ tôi cần xem trong đó tập tin C chức năng này được thực hiện. Từ thư mục nguồn, tôi đã thử

ack "int mkdir"

được hiển thị

security/inode.c
103:static int mkdir(struct inode *dir, struct dentry *dentry, int mode)

tools/perf/util/util.c
4:int mkdir_p(char *path, mode_t mode)

tools/perf/util/util.h
259:int mkdir_p(char *path, mode_t mode);

Nhưng không ai trong số họ phù hợp với định nghĩa trong sys/stat.h.

Câu hỏi

  1. Tập tin nào có triển khai mkdir?
  2. Với định nghĩa hàm như trên, làm thế nào tôi có thể tìm ra tệp nào có triển khai? Có bất kỳ mẫu nào mà kernel theo sau trong việc xác định và thực hiện các phương thức không?

LƯU Ý: Tôi đang sử dụng kernel 2.6.36-rc1 .

376
Navaneeth K N

Các cuộc gọi hệ thống không được xử lý như các cuộc gọi chức năng thông thường. Nó cần mã đặc biệt để thực hiện chuyển đổi từ không gian người dùng sang không gian kernel, về cơ bản là một chút mã hội đồng nội tuyến được đưa vào chương trình của bạn tại trang web cuộc gọi. Mã bên nhân "bắt" cuộc gọi hệ thống cũng là thứ cấp thấp mà bạn có thể không cần hiểu sâu, ít nhất là lúc đầu.

Trong include/linux/syscalls.h trong thư mục nguồn kernel của bạn, bạn tìm thấy điều này:

asmlinkage long sys_mkdir(const char __user *pathname, int mode);

Sau đó, trong /usr/include/asm*/unistd.h, Bạn tìm thấy điều này:

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

Mã này đang nói mkdir(2) là cuộc gọi hệ thống # 83. Điều đó có nghĩa là, các cuộc gọi hệ thống được gọi theo số chứ không phải theo địa chỉ như với một cuộc gọi chức năng bình thường trong chương trình của riêng bạn hoặc đến một chức năng trong thư viện được liên kết với chương trình của bạn. Mã keo hội đồng nội tuyến mà tôi đã đề cập ở trên sử dụng điều này để thực hiện chuyển đổi từ người dùng sang không gian kernel, mang theo các tham số của bạn cùng với nó.

Một bằng chứng khác cho thấy mọi thứ hơi kỳ lạ ở đây là không phải lúc nào cũng có một danh sách tham số nghiêm ngặt cho các cuộc gọi hệ thống: open(2), chẳng hạn, có thể lấy 2 hoặc 3 tham số. Điều đó có nghĩa là open(2) is bị quá tải , một tính năng của C++, không phải C, nhưng giao diện syscall tương thích với C. (Đây không giống với C's tính năng varargs , cho phép một hàm duy nhất có số lượng đối số thay đổi.)

Để trả lời câu hỏi đầu tiên của bạn, không có tệp duy nhất có mkdir() tồn tại. Linux hỗ trợ nhiều hệ thống tệp khác nhau và mỗi hệ thống có triển khai riêng hoạt động "mkdir". Lớp trừu tượng cho phép kernel ẩn tất cả những gì đằng sau một lệnh gọi hệ thống duy nhất được gọi là VFS . Vì vậy, bạn có thể muốn bắt đầu đào trong fs/namei.c, Với vfs_mkdir(). Việc triển khai thực tế của mã sửa đổi hệ thống tệp cấp thấp là ở nơi khác. Chẳng hạn, việc triển khai ext4 được gọi là ext4_mkdir(), được định nghĩa trong fs/ext4/namei.c .

Đối với câu hỏi thứ hai của bạn, có có các mẫu cho tất cả điều này, nhưng không phải là một quy tắc duy nhất. Những gì bạn thực sự cần là một sự hiểu biết khá rộng về cách thức hoạt động của hạt nhân để tìm ra nơi bạn nên tìm kiếm bất kỳ cuộc gọi hệ thống cụ thể nào. Không phải tất cả các cuộc gọi hệ thống đều liên quan đến VFS, vì vậy các chuỗi cuộc gọi phía hạt nhân của chúng không bắt đầu bằng fs/namei.c. mmap(2), chẳng hạn, bắt đầu bằng mm/mmap.c , vì đó là một phần của hệ thống con quản lý bộ nhớ ("mm") của kernel.

Tôi khuyên bạn nên lấy một bản sao " Hiểu về hạt nhân Linux " của Bovet và Cesati.

388
Warren Young

Điều này có thể không trả lời trực tiếp câu hỏi của bạn, nhưng tôi đã thấy strace thực sự tuyệt vời khi cố gắng hiểu các cuộc gọi hệ thống cơ bản, thực tế, được thực hiện cho ngay cả các lệnh Shell đơn giản nhất. ví dụ.

strace -o trace.txt mkdir mynewdir

Hệ thống gọi lệnh mkdir mynewdir sẽ được chuyển sang track.txt để bạn thưởng thức.

86
Banjer

Một nơi tốt để đọc nguồn nhân Linux là Tham chiếu chéo Linux (LXR) . Tìm kiếm trả về kết quả khớp được nhập (nguyên mẫu hàm, khai báo biến, v.v.) ngoài kết quả tìm kiếm văn bản miễn phí, do đó, nó xử lý tốt hơn một grep đơn thuần (và cũng nhanh hơn).

LXR không mở rộng định nghĩa tiền xử lý. Các cuộc gọi hệ thống có tên của họ được xử lý bởi bộ tiền xử lý ở khắp mọi nơi. Tuy nhiên, hầu hết các cuộc gọi hệ thống (tất cả?) Được xác định bằng một trong SYSCALL_DEFINEx họ macro. Vì mkdir có hai đối số, nên tìm kiếm SYSCALL_DEFINE2(mkdir dẫn đến khai báo của mkdir syscall :

SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
{
    return sys_mkdirat(AT_FDCWD, pathname, mode);
}

đồng ý, sys_mkdirat có nghĩa là mkdirat sallall, vì vậy nhấp vào nó chỉ dẫn bạn đến khai báo trong include/linux/syscalls.h, nhưng định nghĩa chỉ ở trên.

Công việc chính của mkdirat là gọi vfs_mkdir (VFS là lớp hệ thống tập tin chung). Cliking trên đó cho thấy hai kết quả tìm kiếm: khai báo trong include/linux/fs.h, và định nghĩa một vài dòng trên. Công việc chính của vfs_mkdir là để thực hiện hệ thống tập tin cụ thể: dir->i_op->mkdir. Để tìm cách this được triển khai, bạn cần chuyển sang triển khai hệ thống tệp riêng lẻ và không có quy tắc khó và nhanh - thậm chí có thể là mô-đun bên ngoài cây kernel.

¹ LXR là một chương trình lập chỉ mục. Có một số trang web cung cấp giao diện cho LXR, với các bộ phiên bản đã biết khác nhau và giao diện web hơi khác nhau. Chúng có xu hướng đến và đi, vì vậy nếu cái bạn đã từng sử dụng không có sẵn, hãy thực hiện tìm kiếm trên web cho linux linux tham chiếu chéo để tìm cái khác.

Các cuộc gọi hệ thống thường được gói trong macro SYSCALL_DEFINEx(), đó là lý do tại sao một grep đơn giản không tìm thấy chúng:

fs/namei.c:SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)

Tên hàm cuối cùng sau khi macro được mở rộng kết thúc là sys_mkdir. Macro SYSCALL_DEFINEx() thêm các nội dung soạn sẵn như mã theo dõi mà mỗi định nghĩa tòa nhà cần phải có.

22
stefanha

Lưu ý: tệp .h không xác định hàm. Đó là khai báo trong tệp .h đó và được định nghĩa (triển khai) ở nơi khác. Điều này cho phép trình biên dịch bao gồm thông tin về chữ ký của hàm (nguyên mẫu) để cho phép kiểm tra kiểu đối số và khớp các kiểu trả về với bất kỳ bối cảnh gọi nào trong mã của bạn.

Nói chung, các tệp .h (tiêu đề) trong C được sử dụng để khai báo các hàm và xác định các macro.

mkdir đặc biệt là một cuộc gọi hệ thống. Có thể có một GNU libc trình bao bọc xung quanh lệnh gọi hệ thống đó (gần như chắc chắn là trên thực tế). Có thể tìm thấy triển khai kernel thực sự của mkdir bằng cách tìm kiếm các nguồn kernel và các cuộc gọi hệ thống nói riêng.

Lưu ý rằng cũng sẽ có một triển khai một số loại mã tạo thư mục cho mỗi hệ thống tập tin. Lớp VFS (hệ thống tập tin ảo) cung cấp một API chung mà lớp gọi hệ thống có thể gọi vào. Mọi hệ thống tập tin phải đăng ký các chức năng cho lớp VFS để gọi vào. Điều này cho phép các hệ thống tập tin khác nhau thực hiện ngữ nghĩa riêng của chúng về cách cấu trúc các thư mục (ví dụ: nếu chúng được lưu trữ bằng cách sử dụng một loại lược đồ băm nào đó để giúp tìm kiếm các mục cụ thể hiệu quả hơn). Tôi đề cập đến điều này bởi vì bạn có khả năng gặp phải các chức năng tạo thư mục cụ thể của hệ thống tệp này nếu bạn đang tìm kiếm cây nguồn Linux.

17
Jim Dennis

Không có triển khai nào bạn tìm thấy khớp với nguyên mẫu trong sys/stat.h Có thể tìm kiếm một câu lệnh bao gồm với tệp tiêu đề này sẽ thành công hơn?

8
greg0ire

Dưới đây là một vài bài viết blog thực sự tuyệt vời mô tả các kỹ thuật khác nhau để tìm kiếm mã nguồn hạt nhân cấp thấp.

6
An̲̳̳drew