1

Linuxでのシステムコールについて勉強していて、read()システムコールを読んでいます。

SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
    struct file *file;
    ssize_t ret = -EBADF;
    int fput_needed;

    file = fget_light(fd, &fput_needed);
    if (file) {
        loff_t pos = file_pos_read(file);
        ret = vfs_read(file, buf, count, &pos);
        file_pos_write(file, pos);
        fput_light(file, fput_needed);
    }

    return ret;
}

これはfget_light()の定義です

struct file *fget_light(unsigned int fd, int *fput_needed)
 {
         struct file *file;
         struct files_struct *files = current->files;

         *fput_needed = 0;
         if (likely((atomic_read(&files->count) == 1))) {
                 file = fcheck_files(files, fd);
         } else {
                 rcu_read_lock();
                 file = fcheck_files(files, fd);
                 if (file) {
                         if (atomic_long_inc_not_zero(&file->f_count))
                                 *fput_needed = 1;
                         else
                                 /* Didn't get the reference, someone's freed */
                                 file = NULL;
                 }
                 rcu_read_unlock();
         }

         return file;
 }

私に説明してもらえますか、fget_lightは何をしますか?

4

2 に答える 2

9

各タスクには、ファイル記述子テーブルがあります。このファイル記述子テーブルは、ファイル記述子番号によって索引付けされ、開いている各ファイルに関する情報 (ファイルの説明) が含まれています。

カーネル内の他の多くのオブジェクトと同様に、ファイルの説明は参照カウントされます。これは、カーネルの一部がファイルの説明にアクセスしたい場合、参照を取得し、必要なことをすべて実行し、参照を解放する必要があることを意味します。参照カウントがゼロになると、オブジェクトを解放できます。ファイル記述についてはopen()、参照カウントをインクリメントおよびclose()デクリメントするため、ファイル記述が開いている間、および/またはカーネルがそれらを使用している間は、ファイル記述を解放できません (例:close()別のスレッドがまだファイルを処理している間に、ファイルをread()処理中のスレッドを想像してください) : ファイルの説明は、読み取りがその参照になるまで実際には解放されませんfput())。

ファイル記述子からファイル記述への参照を取得するために、カーネルには関数fget()があり、その参照をfput()解放します。複数のスレッドが異なる CPU で同時に同じファイル記述にアクセスする可能性があるため、適切なロックを使用する必要がありますfget()fput()現代ではRCUを使用しています。ファイル記述子テーブルの単なる読み取りには、コストがかからないか、ほとんどかかりません。

しかし、RCU は十分な最適化ではありません。マルチスレッド化されていないプロセスを持つことは非常に一般的であることを考慮してください。この場合、同じプロセスの他のスレッドが同じファイル記述にアクセスすることを心配する必要はありません。ファイル記述子テーブルにアクセスできる唯一のタスクは私たちです。したがって、最適化として、fget_light()現在fput_light()のファイル記述子テーブルが単一のタスクでのみ使用されている場合は、参照カウントに触れないでください。

struct file *fget_light(unsigned int fd, int *fput_needed)
{
     struct file *file;
     /* The file descriptor table for our _current_ task */
     struct files_struct *files = current->files;

     /* Assume we won't need to touch the reference count, 
      *  since the count won't reach zero (we are not close(), 
      *  and hope we don't run concurrently to close()),
      *  fput_light() won't actually need to fput().
      */
     *fput_needed = 0;

     /* Check whether we are actually the only task with access to the fd table */
     if (likely((atomic_read(&files->count) == 1))) {
             /* Yep, get the reference to the file description */
             file = fcheck_files(files, fd);
     } else {
             /* Nope, we'll need some locking */
             rcu_read_lock();
             /* Get the reference to the file description */
             file = fcheck_files(files, fd);
             if (file) {
                     /* Increment the reference count */
                     if (atomic_long_inc_not_zero(&file->f_count))
                             /* fput_light() will actually need to fput() */
                             *fput_needed = 1;
                     else
                             /* Didn't get the reference, someone's freed */
                             /* Happens if the file was close()d and all the 
                              *  other accessors ended its work and fput().
                              */
                             file = NULL;
             }
             rcu_read_unlock();
     }

     return file;
}
于 2012-10-05T23:23:40.130 に答える
1

基本的に、この関数は、プロセスのファイル テーブル (そのパラメーターとなる)を参照する関数を呼び出すfdことによって、ユーザーから syscall に渡された値をカーネル内部file構造ポインターに変換します。詳細については、こちらをお読みくださいfcheck_filesfiles

于 2012-10-05T17:48:17.810 に答える