10

編集:seq_fileカーネルからユーザー空間への大量のデータの書き込みが容易になることがわかりました。私が探しているのは反対です。ユーザー空間からの大量のデータ (複数ページ) の読み取りを容易にする API。

編集 2 : のポートを<stdio.h>カーネル モジュールとして実装しています。これは、s と/proc同様に (および後で他の仮想ファイル システムを)開き、FILEと同様に入力と出力を処理できます<stdio.h>。プロジェクトはここにあります


カーネルが大量のデータを /proc に書き込む方法 (ユーザー空間のプログラムが取得するため) に関する多くの質問を見つけましたが、その逆については何も見つかりませんでした。詳しく説明しましょう:

この質問は基本的に、データが複数の buffer 間で壊れている可能性があることを考えると、入力がトークン化されるアルゴリズムに関するものです (たとえば、ints またはintと string の混合物など) 。

たとえば、次のデータがカーネル モジュールに送信されているとします。

12345678 81234567 78123456 67812345 5678 1234 45678123 3456 7812 23456781

この例では、Linux が /proc ハンドラーにフィードするページ サイズが (実際の 4KB に対して) 20 バイトであるとします。

/proc (カーネルモジュール内) からデータを読み取る関数は、データを次のように認識します。

call 1:
"12345678 81234567 78"
call 2:
"123456 67812345 5678"
call 3:
" 1234 45678123 3456 "
call 4:
"7812 23456781"

ご覧のとおり78、最初の呼び出しで が読み取られた場合、次のフレームまでまだ処理されず78、整数かフレーム間の 1 カットかを判断する必要があります。

ここで、カーネルがユーザーにデータを読み取るのではなく書き込みseq_fileたい場合にのみ使用するように見える sを見つけました(または、HOWTO がひどく書かれている可能性があります)。

私がやった事

これまでのところ、次の解決策があります (記憶から書いているため、いくつかのエラー チェックを見逃している可能性がありますが、ご容赦ください)。

初期化フェーズ (たとえばinit_module):

initialize mutex1 to 1 and mutex2 to 0
create /proc entry
call data_processor

/proc リーダー:

1. down(mutex1)    /* down_interruptible of course, but let's not get into details */

2. copy_from_user to an internal buffer
   buffer_index = 0
   data_length = whatever the size is

3. strip spaces from end of buffer (except if all left from buffer is 1 space)
   if so, there_was_space_after = 1 else 0

4. up(mutex2)

スペースを取り除く理由は後で説明します

get_int関数:

wait_for_next = 0
number_was_cut = 0
last_number = 0

do
{
    1. down(mutex2)

    2. if (number_was_cut && !isdigit(buffer[buffer_index]))
           break     /* turns out it wasn't really cut
                        as beginning of next buffer is ' ' */
       number_was_cut = 0
       wait_for_next = 0

    3. while (buffer_index < data_length && !isdigit(buffer_index[buffer_index]))
           ++buffer_index;    /* skip white space */

    4. while (buffer_index < data_length && isdigit(buffer[buffer_index]))
           last_number = last_number * 10 + buffer[buffer_index++] - '0';

    5. if (buffer_index >= data_length && !there_was_space_after)
           number_was_cut = 1
           wait_for_next = 1
           up(mutex1)         /* let more data come in */
       else
           up(mutex2)         /* let get_int continue */
           break
} while (wait_for_next)

return last_number

data_processor関数 (例):

int first_num = get_int()
int sencod_num = get_int()
for i = first_num to second_num
    do_whatever(get_int())

説明:まず、 を参照してくださいdata_processor。データの読み取り方法の複雑さに関与しないため、整数を取得して、それらを必要に応じて処理します。/proc リーダーを見てみましょう。基本的に、現在のすべてのデータが消費されるのに十分な回数data_processorを呼び出すのを待機しget_int(ステップ 1)、次のバッファーを内部メモリにコピーして、data_processor続行できるようにします (ステップ 2)。次に、末尾のスペースを削除する必要があるためget_int、少し簡略化できます (ステップ 3)。最後に、get_intデータの読み取りを開始できることを通知します (ステップ 4)。

このget_int関数は、最初にデータが到着するのを待ち (ステップ 1)、(ここではステップ 2 を無視します) 不要な文字をスキップし (ステップ 3)、数値の読み取りを開始します (ステップ 4)。数字の読み取りの終わりには、2 つの可能性があります。バッファの最後に達した場合 (この場合、/proc リーダーがスペースを削除していなければ、数値フレーム間でカットされる) または空白が満たされます。前者の場合、/proc リーダーにさらにデータを読み込み、別のサイクルを待って残りの数値を現在の数値に追加するように通知する必要があり、後者の場合、数値を返します (ステップ 5)。最後のフレームから継続している場合は、新しいフレームが数字で始まるかどうかを確認します。そうでない場合、前の数値は実際には整数であり、返される必要があります。それ以外の場合は、最後の番号に数字を追加し続ける必要があります (ステップ 2)。

問題

この方法の主な問題は、非常に複雑なことです。が追加されると、はるかに複雑になりget_stringます。または、読み取り整数が 16 進数などになる可能性があります。基本的に、再発明する必要がありますsscanf。このsscanf単純な例では、ループのget_int代わりに(または も使用できますが、16 進入力も可能な場合はよりトリッキーになります (16 進数が 0 と x0212ae4 の間でカットされていることを想像してください)。それでも、のステップ 4 を置き換えるだけで、残りのものはそのままにしておく必要があります。whileget_stringget_int

実際には、すべての特殊なケースを完成させるために、多くのバグと厳しいテストが必要でした。それが私にはエレガントに見えないもう一つの理由です。

質問

これを処理するためのより良い方法があれば知りたいです。共有メモリの使用がオプションになる可能性があることは承知していますが、このタスクのアルゴリズムを探しています (既に実用的なソリューションがあるため、好奇心からです)。すなわち:

  • Linux カーネルに、データを取得できる通常の C のように処理FILEでき、データをページ自体に分割する方法が既に実装されていますか?
  • いいえの場合、私は物事を複雑にしすぎていて、明らかな単純な解決策を見逃していますか?
  • fscanf同様の問題に直面していると思います。これはそれによってどのように処理されますか?

副次的な質問: ミューテックスで /proc リーダーをブロックしているのはひどいことですか? つまり、データの書き込みがブロックされる可能性がありますが、それが通常ユーザー空間またはカーネル空間で発生するかどうかはわかりません。

4

3 に答える 3

1

私は最終的に、この問題を解決するために適切なものを書くことにしました。

きお

kiostdio.h要するに、カーネル モジュールの C の標準のポートになります。テキストかバイナリかに関係なく、読み取りモードと書き込みモードの両方で/proc/sysとファイル システムのいずれかをサポートします。標準に厳密に従っていますが、カーネル空間での安全性を確保するために微調整が行われています。/devkio

現在のステータス:

  • /procファイルを作成できます
  • 読み取り機能を実装
  • 書き込み機能を実装
  • ユーザーはファイルを一度に 1 回だけ開くことができます
于 2012-09-27T15:06:34.333 に答える
1

request_firmware() インターフェースに興味があるかもしれません。すべてがカーネルによってバッファリングされてから、ユーザーに渡されます。

それ以外の場合は、sysfs バイナリ属性インターフェイスが proc よりも便利でしょうか?

于 2012-03-22T23:51:36.770 に答える
0

別の関数get_token()を実装します。これは次のとおりです。

  1. スペースが見つかるまで内部バッファから読み取り、それからこれまでのテキストを返します。
  2. バッファの最後にあるとき、ユーザースペースからバッファにさらにデータを読み取ります。

このようにして、他の解析ロジックが大幅に簡素化されます(整数を手動で解析する必要はありません)。返された文字列に対してsscanf()またはstrtol()を呼び出すだけです。

制限は、バッファに収まるように、単一のトークンに最大長を課す必要があることです。

于 2012-09-10T18:17:07.343 に答える