Odczyt/zapis plików w module jądra Linuksa

Znam wszystkie dyskusje o tym, dlaczego nie należy odczytywać/zapisywać plików z jądra, zamiast tego jak używać / proclub netlink do tego. I tak chcę czytać/pisać. Czytałam też doprowadza mnie do szału-rzeczy, których nigdy nie powinieneś robić w jądrze.

Problem polega jednak na tym, że 2.6.30 nie eksportuje sys_read(). Raczej jest zapakowany w SYSCALL_DEFINE3. Więc jeśli używam go w moim module, dostaję następujące ostrzeżenia:

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

Oczywiście insmod nie można załaduj moduł, ponieważ łączenie nie odbywa się poprawnie.

Pytania:

  • Jak odczytywać/zapisywać w jÄ…drze po 2.6.22 (gdzie sys_read()/sys_open() nie sÄ… eksportowane)?
  • ogólnie, jak używać wywoÅ‚aÅ„ systemowych zawiniÄ™tych w makro SYSCALL_DEFINEn() z wnÄ™trza jÄ…dra?
Author: red0ct, 2009-07-26

2 answers

Powinieneś być świadomy, że powinieneś unikać wejścia/wyjścia plików z jądra Linuksa, jeśli to możliwe. Główną ideą jest przejście "o jeden poziom głębiej" i wywołanie funkcji poziomu VFS zamiast bezpośrednio obsługi syscall:

Zawiera:

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

Otwieranie pliku (podobne do open):

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;
}

Zamknij plik (podobnie jak Zamknij):

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

Odczyt danych z pliku (podobny do 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;
}   

Zapis danych do pliku (podobny do 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;
}

Synchronizacja zmienia plik (podobny do fsync):

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

[Edytuj] pierwotnie zaproponowałem użycie file_fsync, którego nie ma w nowszych wersjach jądra. Dzięki biedakowi sugerującemu zmianę, ale którego zmiana została odrzucona. Edycja została odrzucona, zanim mogłem ją przejrzeć.

 127
Author: dmeister,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-27 14:11:32

Od wersji 4.14 jądra Linuksa, funkcje vfs_read i vfs_write nie są już eksportowane do użytku w modułach. Zamiast tego dostępne są funkcje wyłącznie do dostępu do plików jądra:

# 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);

Również, filp_open nie akceptuje już łańcucha przestrzeni użytkownika, więc może być używany do dostępu do jądra bezpośrednio (bez tańca z set_fs).

 26
Author: Tsyvarev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-12-24 20:54:44