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?
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ć.
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
).
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