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


98

私はなぜカーネルからファイルを読み書きすべきではないかについてのすべての議論を知っています。代わりに/ 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()カーネル内からマクロにラップされたシステムコールを使用する方法は?

回答:


121

Linuxカーネル内からのファイルI / Oは可能な限り回避する必要があることに注意してください。主な考え方は、「1レベル深く」、syscallハンドラーの代わりにVFSレベルの関数を直接呼び出すことです。

含まれるもの:

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

ファイルを開く(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;
}

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

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を使用することを提案しましたが、これは新しいカーネルバージョンではなくなりました。変更を提案した貧しい男のおかげで、その変更は拒否されました。確認する前に編集が拒否されました。


2
ありがとうございました。私はsys_read / sys_open機能を複製することで同様のことをすることを考えていました。しかし、これは大きな助けです。好奇心、SYSCALL_DEFINEを使用して宣言されたシステムコールを使用する方法はありますか?
Methos

5
カーネル2.6.30(Ubuntu 9.04)でこのコードを試し、ファイルを読み取るとシステムがクラッシュします。誰かが同じ問題を経験しましたか?
Enrico Detoma

@エンリコデトマ?ああすごい。これはあなたが使用したモジュールを私に与えることができる方法はありますか?これまで見たことがない?
dmeister 2009年

2
これは、「なぜFSダンスをやっているのか」という質問をすぐに提起します。これは、「アドレス空間の修正」セクションのlinuxjournal.com/node/8110/printで非常にうまく答えられています。
PypeBros 2011

@ dmeister、ur link VFSレベル関数のオブジェクトが見つかりません
sree

18

Linuxカーネルのバージョン4.14以降vfs_readvfs_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ユーザー空間文字列を受け入れなくなったため、カーネルアクセスに直接使用できます(danceを使用せずにset_fs)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.