7

データを読み取ってユーザーに渡す小さなドライバーを作成しました。私のドライバーは複数のアプリケーションで使用できます。つまり、再入可能なドライバーであるため、スピン ロックを使用します。しかしcopy_to_user、スピンロックを保持した状態で呼び出すべきではないことがわかりました。char_device_buf次のコードは共有データです。私はそれを守らなければなりません。スピンロックを使用して使用するミューテックス以外のメカニズムはありますcopy_to_userか?

static ssize_t char_dev_read(struct file *file,
                                char *buf,
                                size_t lbuf,
                                loff_t *ppos)
    {
            int maxbytes; /* number of bytes from ppos to MAX_LENGTH */
            int bytes_to_do; /* number of bytes to read */
            int nbytes; /* number of bytes actually read */

            maxbytes = MAX_LENGTH - *ppos;

            if( maxbytes > lbuf ) bytes_to_do = lbuf;
            else bytes_to_do = maxbytes;

            if( bytes_to_do == 0 ) {
                    printk("Reached end of device\n");
                    return -ENOSPC; /* Causes read() to return EOF */
            }

       /* Tesing for accidental release */
    //              accidental_release(); 

            printk(KERN_DEBUG "READER: trying for critical region lock \n");

            spin_lock(&myspin);/*begin of critical region */

                    printk(KERN_DEBUG "READER : acquired lock: executing critical code\n");
                    nbytes = bytes_to_do -
                             copy_to_user( buf, /* to */
                                           char_device_buf + *ppos, /* from */
                                           bytes_to_do ); /* how many bytes */


            spin_unlock(&myspin); /* end of critical region */
            *ppos += nbytes;
            return nbytes;
    }
4

1 に答える 1

8

copy_{to,from}_userスピンロック内で使用すべきではない理由は、これらの関数がスリープ状態になる可能性があるためです。次のシナリオを想像してください (ユニプロセッサ マシン上):

  1. Process A mmap()ed a file
  2. mmap()プロセスは、そのed 領域にアドレスを提供するドライバーを呼び出します
  3. コードが実行され、ロックcopy_to_userされ、そのアドレスでページ フォールトが発生します。メモリが存在しないため、データがディスクから取得されるまでプロセスがスリープ状態になります。
  4. カーネルはプロセス B をスケジュールし、同じ方法でドライバーを呼び出します。
  5. デッドロック- プロセス A は IO がロック内で戻るのを待っていますが、B が同じロックのロックが解除されるのを待っている CPU を保持しているため、スケジュールされません。

segfault が発生しないという 100% の保証がない限りcopy_{to,from}_user、スピン ロックを使用することはできませんが、代わりに「mutex_lock」などのスリープロックを使用する必要があります。スリープ ロックはスケジューラに制御を渡しますが、スピン ロックは制御を渡しません。

于 2012-09-05T04:58:19.183 に答える