"loff_t" es un "desplazamiento largo", es decir, una posición de búsqueda que unifica la loca diversidad de off_t
, off64_t
, y así sucesivamente, para que los conductores puedan simplemente usar loff_t y no preocuparse por eso.
El puntero en sí mismo, en el momento en que ingresa al controlador, apunta al desplazamiento proporcionado por el usuario (suponiendo que es el código de usuario el que accede al controlador; técnicamente, el kernel puede proporcionar el suyo propio, pero el caso del usuario es en el que hay que pensar) vía lseek
o llseek
o lseek64
, etc., y luego mediante operaciones ordinarias de lectura y escritura. Considere el caso de un archivo normal en disco:la primera vez que open
el archivo, usted (como usuario) obtiene el núcleo para proporcionar una estructura de datos que realiza un seguimiento de su posición actual en el archivo, de modo que si read
o write
algunos bytes, el siguiente read
o write
retoma desde donde lo dejó.
Además, si dup
el descriptor del archivo, o hacer el equivalente (por ejemplo) fork
y exec
en términos de ejecutar una secuencia de comandos, esa posición de búsqueda es compartida por todos los procesos heredados. Por lo tanto, en el indicador de shell, el comando:
(prog1; prog2; prog3) > outputfile
crea un archivo de salida, luego dup
s el descriptor de los tres programas, por lo que la salida prog2
escribe va al archivo inmediatamente después de la salida de prog1
y salida desde prog3
sigue a los otros dos, todo porque los tres procesos separados comparten la misma estructura de datos del kernel subyacente con el mismo loff_t
interno .
Lo mismo se aplica a los archivos de controladores de dispositivos. Cuando se llama a sus funciones de lectura y escritura, recibe el "desplazamiento actual" proporcionado por el usuario, y puede (y debe) actualizarlo según sea necesario... suponiendo que haya alguna necesidad (por ejemplo, desea proporcionar a los usuarios la apariencia de un archivo normal, incluido el hecho de que las compensaciones de búsqueda se mueven a medida que lee y escribe). Si el dispositivo tiene alguna aplicación lógica de compensación de búsqueda, puede usarla aquí.
Por supuesto, hay mucho más en los controladores de dispositivos, por lo que hay capítulos de libros completos sobre este tema (q.v.). :-)
La respuesta de Torek es excelente. Solo agregando un poco más de detalle/contexto... De un kernel de Linux anterior (2.6.28), aquí hay un ejemplo de desplazamiento en uso en una llamada al sistema... copia el desplazamiento del espacio del usuario a una variable temporal antes de obtener en el mecanismo de invocación del controlador del núcleo y, a continuación, lo vuelve a copiar en el archivo de usuario. Así es como el desplazamiento que ve el controlador se desacopla de la vista del usuario y facilita las situaciones en las que el desplazamiento es NULL en la llamada al sistema, por lo que no se produce 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);
}