web-dev-qa-db-ja.com

LinuxカーネルモジュールのファイルI / O

ファイルを開いて読み取る必要があるLinuxカーネルモジュールを書いています。それを達成するための最良の方法は何ですか?

19
mipadi

なぜファイルを開こうとしているのか聞いてもいいですか?

私はLinux開発をフォローするのが好きで(好奇心から、私はカーネル開発者ではなく、Javaをやっています)、この質問についての議論は以前に見たことがあります。私はこれについて LKMLメッセージ を見つけることができました。基本的にはそれは通常悪い考えだと述べています。 LWNが昨年それをカバーしたことはほぼ肯定的ですが、記事を見つけるのに苦労しています。

これがプライベートモジュールである場合(一部のカスタムハードウェアのように、モジュールが配布されない場合)、これを行うことができますが、コードをメインラインに送信する場合は、そうではない可能性があるという印象を受けます。受け付けます。

Evan Teranがsysfsについて言及しましたが、これは私には良い考えのようです。より難しいカスタム作業を本当に行う必要がある場合は、いつでも新しいioctrlを作成できます。

編集:

OK、探していた記事が見つかりました。それは Linux Journal からのものです。この種のことを行うことが一般的に悪い考えである理由を説明し、それからとにかくそれを行う方法を正確に説明します。

31
MBCook

open/read/closeシステムコールへの関連関数ポインターへのポインターを取得できると仮定すると、次のようなことができます。

mm_segment_t fs = get_fs();
set_fs(KERNEL_DS);

fd = (*syscall_open)(file, flags, mode);
if(fd != -1) {
    (*syscall_read)(fd, buf, size);
    (*syscall_close)(fd);
}
set_fs(fs);

ただし、ここで示した「syscall_*」関数ポインタを作成する必要があります。もっと良い方法があると思いますが、これでうまくいくと思います。

9
Evan Teran

一般的に言って、カーネルモジュールからファイルを読み書きする必要がある場合は、アーキテクチャ的に何か間違ったことをしています。

カーネルモジュールがユーザースペースヘルパープロセスと通信できるようにするメカニズム(たとえば、netlink-または単に文字デバイスを登録する)が存在します。そのユーザースペースヘルパープロセスは、必要なことを何でも実行できます。

また、システムコール(または同様のもの)を実装して、ユーザースペースで開かれたファイル記述子を取得し、カーネルから読み取り/書き込みを行うこともできます。

これは、カーネル空間でファイルを開こうとするよりもおそらくうまくいくでしょう。

カーネル空間からすでにファイルを開いているものが他にもいくつかあります。それらを見ることができます(ループドライバーが思い浮かびますか?)。

2
MarkR

Sys_call_openに関するいくつかの情報は、この Linuxカーネルモジュールプログラミングガイド にもあります。

1
VonC

/ procファイルシステムは私的使用にも適しており、簡単です。
http://www.linuxtopia.org/online_books/Linux_Kernel_Module_Programming_Guide/x773.html

1
Denes Tarjan

すべてのカーネル開発者は、カーネル空間からのファイルI/Oは悪いと言っていますが(特にこれらのファイルをパスで参照している場合)、ファームウェアをロードするときにメインストリームカーネルがこれを行います。ファイルから読み取る必要があるだけの場合は、

kernel_read_file_from_path(const char *path, void **buf, loff_t *size, loff_t max_size, enum kernel_read_file_id id)

include/linux/fs.hで宣言された、ファームウェアローダーコードが使用する関数。この関数は、エラー時に負の値を返します。

最後のid変数のポイントはよくわかりません。実際には使用されていないコードを見ると、そこにREADING_FIRMWAREのようなものを入れてください(引用符はありません)。

bufはnullで終了しません。代わりに、sizeでそのサイズを参照してください。 nullで終了する必要がある場合は、size + 1バイト長の文字列を作成してコピーするか、kernel_read_file()関数(kernel_read_file_from_path()で使用、fs/exec.cで定義)を書き換えます。 )そして、メモリが割り当てられているi_sizeに1つ追加します。 (これを行う場合は、モジュール内のkernel_read_file()関数を別の関数名で再定義して、カーネル全体が変更されないようにすることができます。)

ファイルに書き込む必要がある場合は、kernel_write()関数(kernel_read()に類似しており、kernel_read_file()によって使用されるため、kernel_read_file_from_path()によっても使用されます)があります。ただし、kernel_write_file()またはkernel_write_file_from_path()関数はありません。 Linuxカーネルソースツリーのfs/exec.cファイルのコードを見ることができます。ここで、kernel_read_file()kernel_read_file_from_path()は、独自のkernel_write_file()kernel_write_file_from_path()関数。

そしていつものように、この関数をキャストすることで、voidポインターの代わりにcharポインターにファイルの内容を格納できます。

0
Billy