web-dev-qa-db-ja.com

Linuxカーネルモジュール内のファイルの読み取り/書き込み

カーネルからファイルを読み書きしない理由についてのすべての議論を知っている、代わりに/ procまたはnetlinkを実行します。とにかく読み書きをしたいです。 Driving Me Nuts-カーネルで絶対にすべきでないこと も読みました。

ただし、問題は2.6.30がsys_read()をエクスポートしないことです。むしろ、_SYSCALL_DEFINE3_でラップされています。モジュールで使用すると、次の警告が表示されます。

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

リンクが正しく行われないため、明らかにinsmodはモジュールをロードできません。

質問:

  • 2.6.22以降のカーネル内での読み取り/書き込み方法(sys_read()/sys_open()はエクスポートされません)
  • 一般に、カーネル内からマクロSYSCALL_DEFINEn()にラップされたシステムコールを使用する方法は?
87
Methos

可能であれば、ファイルI/Oを避ける必要があることに注意してください。主なアイデアは、「1レベル深く」行って、syscallハンドラの代わりに VFSレベル関数 を直接呼び出すことです。

含まれるもの:

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

ファイルを開く(開くのと同様):

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

ファイルを閉じます(閉じるのと同様):

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

ファイルからのデータの読み取り(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;
}   

ファイルへのデータの書き込み(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;
}

同期はファイルを変更します(fsyncと同様):

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

[編集]元々、新しいカーネルバージョンではなくなっていたfile_fsyncの使用を提案しました。貧しい人が変更を提案してくれたが、その変更は拒否された。編集を確認する前に拒否されました。

112
dmeister

Linuxカーネルのバージョン4.14以降、vfs_readおよびvfs_write関数はエクスポートされなくなりましたはモジュールで使用されます。代わりに、カーネルのファイルアクセス専用の機能が提供されます。

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

また、filp_openはユーザースペース文字列を受け入れないため、カーネルアクセスに使用できます直接set_fs)。

9
Tsyvarev