2017-12-18 26 views
0

カーネルモジュール用のcharデバイスを実装し、その読み込み関数を実装しました。 read関数は、呼び出し元にデータを返すためにcopy_to_userを呼び出します。私はもともとブロック機能(wait_event_interruptible)でread関数を実装しましたが、問題を再現するには、非ブロック的な方法で読み込みを実装しても問題ありません。私のコードはMIPSプロセッサで実行されています。copy_to_userがcharデバイスの読み込み関数でエラーを返します

ユーザー空間プログラムは、charデバイスを開き、スタックに割り当てられたバッファを読み込みます。

私が見つけたことは時々copy_to_userは何バイトもコピーできません。さらに、copy_to_usermemcpy(私はこれが正しいことではないことを知っています)の呼び出しで置き換えても、直ちに宛先バッファを印刷すると、memcpyが失敗したことがわかります任意のバイトをコピーします。

これをさらにデバッグする方法がわかりません。なぜメモリがコピーされていないのかを判断するにはどうすればいいですか?プロセスコンテキストが間違っている可能性はありますか?

EDITは:

ユーザモード(繰り返し実行されます):

char buf[BUF_LEN]; 
FILE *f = fopen(char_device_file, "rb"); 
fread(buf, 1, BUF_LEN, f); 
fclose(f); 

カーネルモード:ここでは、コードが現在どのように見えるかを概説し、いくつかの擬似コードだ

char_device = 
    create_char_device(char_device_name, 
     NULL, 
     read_func, 
     NULL, 
     NULL); 

int read_func(char *output_buffer, int output_buffer_length, loff_t *offset) 
{ 
    int rc; 
    if (*offset == 0) 
    { 
     spin_lock_irqsave(&lock, flags); 

     while (get_available_bytes_to_read() == 0) 
     { 
      spin_unlock_irqrestore(&lock, flags); 
      if (wait_event_interruptible(self->wait_queue, get_available_bytes_to_read() != 0)) 
      { 
       // Got a signal; retry the read 
       return -ERESTARTSYS; 
      } 

      spin_lock_irqsave(&lock, flags); 
     } 

     rc = copy_to_user(output_buffer, internal_buffer, bytes_to_copy); 

     spin_unlock_irqrestore(&lock, flags); 
    } 
    else rc = 0; 

    return rc; 
} 
+1

コードに問題がありますが、表示されません。 – Tsyvarev

+0

@Tsyvarevいくつかの擬似コードを追加しました。うまくいけば、コードによって何が行われているかを十分に示してくれるでしょう。残念ながら、私はそれを小さな、再現する例に絞り込むことはできませんでした(まだ)。 – YSK

+0

@YSKあなたは 'int rc'を2回宣言しました。 'int rc = copy_to_user(output_buffer、internal_buffer、bytes_to_copy);行から' int'を削除してください。 – Gaurav

答えて

0

をそれかなりのデバッグを行いましたが、最終的にTsyvarevのヒント(スピンロックを取ったcopy_to_userを呼び出さないというコメント)その原因になっているようだ。

私たちのプロセスにはバックグラウンドスレッドがあり、ときどき新しいプロセス(fork + exec)がリリースされました。このスレッドを無効にすると、すべてうまくいった。私たちが持っている最良の理論は、フォークがすべてのメモリページをコピーオンライトにしたので、コピーしようとしたときにカーネルはスピンロックではできない作業をしなければならないということでした。うまくいけば、それは少なくとも(私はこれが子プロセスにのみ当てはまると推測していたが、親のプロセスページは単に書き込み可能なままだが、誰が知っているのかはわからないが...)。

コードがロックされずに書き換えられ、問題は消えました。

ここでは、ロックレスコードが実際に異なるアーキテクチャで安全であることを確認するだけです。やさしい。

関連する問題