copy_from_user
Rev.4を表示中。最新版はこちら。
copy_from_userはで引数のユーザ空間のデータをカーネル空間のメモリに複写し、本質はmemcpy()に過ぎません。システムコールの引数で処理をタスクスイッチ可なワークキュー等のカーネルスレッドで行う場合、ワークキュー下で別のタスクに切り替わり、そこからワークキューに戻ったとすると、そのユーザ空間はシステムコールしたタスクの領域でなく、切り替えたタスクのユーザ空間になってしまいます。従って、ユーザ空間データをカーネル下で参照する場合、すべてのタスクが共有するカーネル空間に、複写して参照する必要があるわけです。
まずmight_sleep()で必要ならタスク切り替えを行い、以降の__copy_from_user()のメモリ複写時にタスク切り替わることを抑制します。
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;
}
__copy_from_user()はアセンブラ記述によるアーキテクチャ依存で、__copy_from_userが定義されていなければ下記の実装となります。__builtin_constant_p()はgccマターで、引数のnが定数かどうのかチェックで、1/2/4ならサイズに応じた変数での処理となり、それ以外はmemcpy()による処理となります。__must_checkはgccマターで、コンパイル時、返り値を参照してないならその旨メッセージを表示すると言うことです。ただし、下記では返値は、必ず0で、ここでの__must_checkは、意味ありません。
なお、アーキテクチャ依存での実装が、ワード単位での転送の場合、転送サイズがワードに満たないとか、転送サイズの大小に関わらず、ケースによってはエラーとなる場合があるようで、その時返り値は、転送できなかったサイズを返します。で、ユーザサイドに関わることでもあり、カーネルコーダにちゃんとチェックしろ。との事だと思います。
#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;
}






