Đọc / ghi tệp trong mô-đun nhân Linux


98

Tôi biết tất cả các cuộc thảo luận về lý do tại sao người ta không nên đọc / ghi tệp từ hạt nhân, thay vào đó là cách sử dụng / proc hoặc netlink để làm điều đó. Tôi muốn đọc / viết bằng mọi cách. Tôi cũng đã đọc Driving Me Nuts - Những điều bạn không bao giờ nên làm trong nhân .

Tuy nhiên, vấn đề là 2,6.30 không xuất sys_read(). Đúng hơn là nó được bọc trong SYSCALL_DEFINE3. Vì vậy, nếu tôi sử dụng nó trong mô-đun của mình, tôi nhận được các cảnh báo sau:

WARNING: "sys_read" [xxx.ko] undefined!
WARNING: "sys_open" [xxx.ko] undefined!

Rõ ràng là insmodkhông thể tải mô-đun vì liên kết không diễn ra chính xác.

Câu hỏi:

  • Làm thế nào để đọc / ghi bên trong kernel sau 2.6.22 (ở đâu sys_read()/ sys_open()không được xuất)?
  • Nói chung, làm thế nào để sử dụng lệnh gọi hệ thống được bao bọc trong macro SYSCALL_DEFINEn()từ bên trong hạt nhân?

Câu trả lời:


121

Bạn nên biết rằng bạn nên tránh I / O tệp từ bên trong nhân Linux khi có thể. Ý tưởng chính là đi sâu hơn "một cấp độ" và gọi các hàm cấp độ VFS thay vì trình xử lý cuộc gọi tổng hợp trực tiếp:

Bao gồm:

#include <linux/fs.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>

Mở tệp (tương tự như mở):

struct file *file_open(const char *path, int flags, int rights) 
{
    struct file *filp = NULL;
    mm_segment_t oldfs;
    int err = 0;

    oldfs = get_fs();
    set_fs(get_ds());
    filp = filp_open(path, flags, rights);
    set_fs(oldfs);
    if (IS_ERR(filp)) {
        err = PTR_ERR(filp);
        return NULL;
    }
    return filp;
}

Đóng tệp (tương tự như đóng):

void file_close(struct file *file) 
{
    filp_close(file, NULL);
}

Đọc dữ liệu từ một tệp (tương tự như pread):

int file_read(struct file *file, unsigned long long offset, unsigned char *data, unsigned int size) 
{
    mm_segment_t oldfs;
    int ret;

    oldfs = get_fs();
    set_fs(get_ds());

    ret = vfs_read(file, data, size, &offset);

    set_fs(oldfs);
    return ret;
}   

Ghi dữ liệu vào tệp (tương tự như pwrite):

int file_write(struct file *file, unsigned long long offset, unsigned char *data, unsigned int size) 
{
    mm_segment_t oldfs;
    int ret;

    oldfs = get_fs();
    set_fs(get_ds());

    ret = vfs_write(file, data, size, &offset);

    set_fs(oldfs);
    return ret;
}

Đồng bộ hóa thay đổi tệp (tương tự như fsync):

int file_sync(struct file *file) 
{
    vfs_fsync(file, 0);
    return 0;
}

[Chỉnh sửa] Ban đầu, tôi đề xuất sử dụng file_fsync, tính năng này đã xuất hiện trong các phiên bản hạt nhân mới hơn. Nhờ anh chàng nghèo gợi ý sự thay đổi, nhưng sự thay đổi của anh ta đã bị từ chối. Bản chỉnh sửa đã bị từ chối trước khi tôi có thể xem lại.


2
Cảm ơn bạn. Tôi đã nghĩ làm điều gì đó tương tự bằng cách sao chép chức năng sys_read / sys_open. Nhưng đây là sự giúp đỡ tuyệt vời. Một sự tò mò, có cách nào để sử dụng lệnh gọi hệ thống được khai báo bằng SYSCALL_DEFINE không?
Methos

5
Tôi đã thử mã này trong kernel 2.6.30 (Ubuntu 9.04) và việc đọc tệp đã làm hệ thống bị treo. Có ai gặp phải vấn đề tương tự không?
Enrico Detoma,

@Enrico Detoma? Tuyệt vời. Điều này có cách nào mà bạn có thể cung cấp cho tôi mô-đun bạn đã sử dụng? Chưa bao giờ thấy điều đó trước đây?
dmeister

2
Điều đó ngay lập tức đặt ra câu hỏi "tại sao bạn lại thực hiện điệu nhảy FS đó, btw", câu trả lời khá hay ở đây: linuxjournal.com/node/8110/print trong phần "Fixing Address Space".
PypeBros

@dmeister, Không tìm thấy đối tượng cho liên kết ur Chức năng cấp VFS
sree

18

Kể từ phiên bản 4.14 của nhân Linux, vfs_readvà các vfs_writechức năng không còn được xuất ra để sử dụng trong các mô-đun. Thay vào đó, các chức năng dành riêng cho quyền truy cập tệp của nhân được cung cấp:

# Read the file from the kernel space.
ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos);

# Write the file from the kernel space.
ssize_t kernel_write(struct file *file, const void *buf, size_t count,
            loff_t *pos);

Ngoài ra, filp_openkhông còn chấp nhận chuỗi không gian người dùng, vì vậy nó có thể được sử dụng để truy cập trực tiếp vào hạt nhân (không cần nhảy với set_fs).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.