copy_from_user
Rev.3を表示中。最新版はこちら。
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; }