無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

fget関数とfget_light関数


fget/fget_light関数は、ファイルディスクリプタに対応する、file構造体を取得する関数です。file構造体はtask構造体配下のfiles_struc構造体メンバーによるrcuで管理されています。fcheck_files()はそのrcuを走査することで、該当するファイルディスクリプタのfile構造体を取得します。rcuを走査するには、rcuをロックする必要があります。ここでのロックはrcuを走査する旨の宣言みたいなものです。なお、rcuは読み込みにおいてプロセスがロックされる事はありません。

fget()は上記の内容を実現するものですが、そのファイルがオープンされている事および、管理しているfiles_struct構造体を参照しているプロセスが、自分自身1つだけの条件下のもとで、fget_light()はrcuのロック無しにfcheck_files()をコールする事で、file構造体を取得しようとするものです。この条件下では、他のプロセスががこのrcuを走査してくる事はないからです。

fget()はまず、rcu_read_lock()でrcuをロックして、file = fcheck_files(files, fd)でstruct fileを取得します。取得できたらその参照カウンタを、アトミックにインクリメントして0かどうかチェックします。もし0でないならfcheck_files()で取得したstruct fileを返します。

atomic_long_inc_not_zeroはlong型の変数を、アトミックにインクリメントし、0でないなら1を、0なら0を返すマクロです。このメンバーは、プロセスがこのfile構造体を使用している旨の、カウンタとして動作します。もしインクリメントして0になってしまう事は、カンターとして用を成さないという事です。この型longです。long型を超えるような使い方は、さすがスーパコンピュータと言えども、なかろうと、たぶん直接この値を書き込むような悪さをされるケースを想定しての処理かと・・・。

とりあえず、参照カンターが問題なければ、rcuをアンロックして、そのfile構造体を返します。なおこれを呼び出した側では、参照カンターをインクリメントしているので、使用が終了したらfput()で参照カウンターをデクリメントする必要があります。
struct file *fget(unsigned int fd)
{
       struct file *file;
       struct files_struct *files = current->files;

       rcu_read_lock();
       file = fcheck_files(files, fd);
       if (file) {
               if (!atomic_long_inc_not_zero(&file->f_count)) {
                       /* File object ref couldn't be taken */
                       rcu_read_unlock();
                       return NULL;
               }
       }
       rcu_read_unlock();

       return file;
}
fget_light()はそのファイルが既にオープンされている事を前提としています。で、if (likely((atomic_read(&files->count) == 1)で、files_struct構造体が唯一自プロセスだけかどうかチェックします。もしそうなら、rcuをロックしないでfcheck_files()をコールして、そこで取得したfile構造体を返す事になります。ここで注目すべきは、file構造体の参照カウンターをインクリメントしていないと言うことです。 fput_needed=0で、呼び出し元はこの変数から、fputを無視する処理となります。なお、プロセスの参照カウンタは、file構造体を管理する大元のfiles_struct構造体下で行っています。

もし、複数のプロセスがこのfiles_struct構造体を使用してい場合(マルチスレッドアプリケーション)、fcheck_files()を呼び出すにあたって、rcuをロックする必要があります。この処理はfget()と同じ物になります。なおfile構造体が取得できたら、atomic_long_inc_not_zeroマクロで、file参照カンターをインクリメントし、0でないなら、取得OKとして、rcuをアンロックしたのち、それを返値としています。なおこの場合、fput_needed = 1とし、呼び出し側はfput()で参照カウンターをデクリメントする必要があります。
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
                               file = NULL;
               }
               rcu_read_unlock();
       }

       return file;
}

補足

プロセスがこのfiles_struct構造体を参照していて、file構造体がfcheck_files(files, fd)得られたなら、このfile構造体は、すでにopenシステムコールで、その参照カウンタがインクリメントされているため、fget_light()で取得したfile構造体は、あえて参照カウンターをインクリメントする必要がないと言うことです。

fput()はこの参照カウンタをデクリメントし、0なら、設定されたフラグに応じて、ファイルオペレーションのfasyncコールバック関数が、そしてreleaseコールバック関数がコールされた後、file構造体のかかるメンバー(dentry,inode,mnt等)を解放し、そしてfile構造体自体を解放します。

最終更新 2012/02/13 01:08:29 - north
(2012/02/12 17:06:25 作成)