「loff_t」は「長いオフセット」です。つまり、off_t
のクレイジーな多様性を統合するシーク位置です。 、 off64_t
など、ドライバーが loff_t を使用するだけで、気にする必要がないようにします。
ポインター自体は、ドライバーに入った時点で、ユーザーによって提供されたオフセットを指します (ドライバー アクセスを行うユーザー コードであると仮定すると、技術的にはカーネルが独自に提供できますが、ユーザー ケースを考慮する必要があります)。 lseek
経由 または llseek
または lseek64
など、そして通常の読み取りおよび書き込み操作によって。通常のディスク上のファイルの場合を考えてみましょう:最初に open
ファイルを取得すると、(ユーザーとして) ファイル内の現在の位置を追跡するデータ構造を提供するカーネルを取得するため、read
または write
数バイト、次の read
または write
中断したところから再開します。
さらに、あなたが dup
ファイル記述子、または同等のことを行います (例) fork
および exec
一連のコマンドを実行するという点では、そのシーク位置はすべての継承プロセスによって共有されます。したがって、シェル プロンプトで次のコマンドを実行します:
(prog1; prog2; prog3) > outputfile
出力ファイルを作成し、その後 dup
prog2
を出力するように、3 つのプログラムへの記述子を指定します。 prog1
からの出力の直後にファイルに書き込みます 、および prog3
からの出力 他の 2 つに従います — すべての 3 つの別個のプロセスはすべて、同じ内部 loff_t
を持つ同じ基礎となるカーネル データ構造を共有するためです。 .
同じことがデバイス ドライバ ファイルにも当てはまります。読み取り関数と書き込み関数が呼び出されると、ユーザーから提供された「現在のオフセット」を受け取り、必要に応じて更新できます (また、更新する必要があります) ... 必要がある場合 (たとえば、ユーザーに読み取りおよび書き込み時にシーク オフセットが移動するという事実を含む、通常のファイルの外観)。デバイスにシーク オフセットの論理的なアプリケーションがある場合は、ここでそれを使用できます。
もちろん、デバイス ドライバーには他にもたくさんあります。 :-)
Torekの答えは素晴らしいです。少し余分な詳細/コンテキストを追加するだけです...以前のLinuxカーネル(2.6.28)から、システムコールで使用されているオフセットの例を次に示します...取得する前に、ユーザー空間から一時変数にオフセットをコピーしますカーネルドライバー呼び出しメカニズムに挿入し、それをユーザーファイルにコピーして戻します。これにより、ドライバーが認識するオフセットがユーザー ビューから分離され、システム コールでオフセットが NULL である状況が容易になり、SEGVIO が発生しなくなります。
SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd, loff_t __user *, offset, size_t, count)
{
loff_t pos;
ssize_t ret;
if (offset) {
if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t))))
return -EFAULT;
ret = do_sendfile(out_fd, in_fd, &pos, count, 0);
if (unlikely(put_user(pos, offset)))
return -EFAULT;
return ret;
}
return do_sendfile(out_fd, in_fd, NULL, count, 0);
}