copy_from_user


Rev.2を表示中。最新版はこちら

copy_from_user()の実装は、アーキテクチャに依存していて、ここではasm-genericのそれを見てみます。アーキテクチャに依存したcopy_from_user()が定義されてないと、ここでのcopy_from_user()が使われます。

copy_from_user()はシステムコール時、ユーザ空間の引数をカーネル空間に複写するのに使われます。直接ユーザ空間のデータをカーネルが参照していて、タスクが切り替わり、再び先のパスに戻ってきても、その時のユーザ空間は先のユーザ空間と同じではありません。カーネルは任意のプロセスのメモリー空間で動作しているからです。ただしカーネル空間は共通で、そのためユーザ空間のデータをカーネル空間に複写したのち、そのデータを参照しなければなりません。

__copy_from_user()で、引数に応じた適切なコードを取捨選択するため、copy_from_user()はstatic inlineで、インライン展開の実装となります。
static inline long copy_from_user(void *to,
               const void __user * from, unsigned long n)
{
       might_sleep();
       if (access_ok(VERIFY_READ, from, n))
               return __copy_from_user(to, from, n);
       else
               return n;
}
__builtin_constant_p()はgccの内部関数(コードとして展開されません。)で、引数が定数なら1を返します。従って、gccはnに応じた適切なコード取捨選択して展開することができます。
#define __must_check            __attribute__((warn_unused_result))

static inline __must_check long __copy_from_user(void *to,
               const void __user * from, unsigned long n)
{
       if (__builtin_constant_p(n)) {
               switch(n) {
               case 1:
                       *(u8 *)to = *(u8 __force *)from;
                       return 0;
               case 2:
                       *(u16 *)to = *(u16 __force *)from;
                       return 0;
               case 4:
                       *(u32 *)to = *(u32 __force *)from;
                       return 0;
#ifdef CONFIG_64BIT
               case 8:
                       *(u64 *)to = *(u64 __force *)from;
                       return 0;
#endif
               default:
                       break;
               }
       }

       memcpy(to, (const void __force *)from, n);
       return 0;
}
copy_from_user(to, from, 1)でコールすると、以下のソースをコンパイルするのと同等で、変数間の代入となります。nが2/4/8についても同じです。
static inline __must_check long __copy_from_user(void *to,
               const void __user * from, unsigned long n)
{
                    *(u8 *)to = *(u8 __force *)from;
                       return 0;
}
copy_from_user(to, from, n)でコールすると、以下のソースをコンパイルするのと同等で、memcpy()をコールします。
static inline __must_check long __copy_from_user(void *to,
               const void __user * from, unsigned long n)
{

       memcpy(to, (const void __force *)from, n);
       return 0;
} 
__must_checkは返り値をチェックしなければwarningを表示させる設定ですが、__copy_from_user()は0しか返してません。意味あるのかな?

p/s
カーネルはgccの拡張機能をフルに活用して、些細な些細な事でも、パフォーマンスを最大限にとの実装のようです。カーネル読むに当たって、カーネルの本質的な物でないのですが、GCCの拡張機能について慣れておいた方が、なにかと躓かないでいいかと思います。


最終更新 2013/11/12 16:14:44 - north
(2013/11/12 16:09:32 作成)


検索

アクセス数
3690432
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。