Ich kenne alle Diskussionen darüber, warum man Dateien nicht aus dem Kernel lesen/schreiben sollte, sondern wie man sie verwendet /proz oder Netzverbindung das zu tun. Ich will trotzdem lesen/schreiben. habe ich auch gelesen
Driving Me Nuts – Dinge, die Sie niemals im Kernel tun sollten.
Das Problem ist jedoch, dass 2.6.30 nicht exportiert sys_read()
. Vielmehr ist es eingepackt SYSCALL_DEFINE3
. Wenn ich es also in meinem Modul verwende, erhalte ich die folgenden Warnungen:
WARNING: "sys_read" [xxx.ko] undefined!
WARNING: "sys_open" [xxx.ko] undefined!
Offensichtlich insmod
kann das Modul nicht laden, da die Verknüpfung nicht korrekt erfolgt.
Fragen:
- Lesen/Schreiben im Kernel nach 2.6.22 (where
sys_read()
/sys_open()
werden nicht exportiert)?
- Im Allgemeinen, wie man in Makros verpackte Systemaufrufe verwendet
SYSCALL_DEFINEn()
aus dem Kernel?
Sie sollten sich bewusst sein, dass Sie Datei-I/O aus dem Linux-Kernel nach Möglichkeit vermeiden sollten. Die Hauptidee ist, „eine Ebene tiefer“ zu gehen und zu rufen Funktionen auf VFS-Ebene anstelle des Syscall-Handlers direkt:
Beinhaltet:
#include <linux/fs.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>
Datei öffnen (ähnlich 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;
}
Schließen Sie eine Datei (ähnlich wie close):
void file_close(struct file *file)
{
filp_close(file, NULL);
}
Daten aus einer Datei lesen (ähnlich wie 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;
}
Daten in eine Datei schreiben (ähnlich 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;
}
Das Synchronisieren ändert eine Datei (ähnlich wie fsync):
int file_sync(struct file *file)
{
vfs_fsync(file, 0);
return 0;
}
[Edit] Ursprünglich schlug ich vor, file_fsync zu verwenden, das in neueren Kernel-Versionen weg ist. Danke an den armen Kerl, der die Änderung vorgeschlagen hat, dessen Änderung aber abgelehnt wurde. Die Änderung wurde abgelehnt, bevor ich sie überprüfen konnte.
Seit Version 4.14 des Linux-Kernels vfs_read
und vfs_write
Funktionen sind nicht mehr exportiert für den Einsatz in Modulen. Stattdessen werden Funktionen ausschließlich für den Dateizugriff des Kernels bereitgestellt:
# 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);
Ebenfalls, filp_open
akzeptiert keinen User-Space-String mehr, kann also für den Kernel-Zugriff verwendet werden direkt (ohne Tanz mit set_fs
).