"loff_t" è un "long offset", cioè una posizione di ricerca che unifica la folle diversità di off_t
, off64_t
, e così via, in modo che i conducenti possano semplicemente usare loff_t senza preoccuparsi.
Il puntatore stesso, nel momento in cui entri nel driver, punta all'offset fornito dall'utente (supponendo che sia il codice utente che esegue l'accesso al driver, tecnicamente il kernel può fornire il proprio, ma il caso utente è quello a cui pensare) tramite lseek
o llseek
o lseek64
, ecc., e quindi mediante normali operazioni di lettura e scrittura. Considera il caso di un normale file su disco:quando per la prima volta fai open
il file, tu (come utente) fai in modo che il kernel fornisca una struttura dati che tenga traccia della tua posizione corrente nel file, in modo che se tu read
o write
alcuni byte, il successivo read
o write
riprende da dove eri rimasto.
Inoltre, se dup
il descrittore di file, o fare l'equivalente con (ad es.) fork
e exec
in termini di esecuzione di una sequenza di comandi, quella posizione di ricerca è condivisa da tutti i processi ereditari. Quindi, al prompt della shell, il comando:
(prog1; prog2; prog3) > outputfile
crea un file di output, quindi dup
è il descrittore dei tre programmi, in modo che l'output sia prog2
writes va nel file immediatamente dopo l'output da prog1
e l'output da prog3
segue gli altri due, tutto perché tutti e tre i processi separati condividono la stessa struttura di dati del kernel sottostante con lo stesso loff_t
interno .
Lo stesso vale per i file del driver di dispositivo. Quando vengono chiamate le tue funzioni di lettura e scrittura, ricevi l'"offset corrente" fornito dall'utente e puoi (e dovresti) aggiornarlo secondo necessità ... supponendo che ci sia qualche necessità (ad esempio, vuoi fornire agli utenti l'aspetto di un file normale, incluso il fatto che gli offset di ricerca si spostano durante la lettura e la scrittura). Se il dispositivo ha qualche applicazione logica dell'offset di ricerca, puoi usarlo qui.
Naturalmente, c'è molto di più nei driver di dispositivo, motivo per cui ci sono interi capitoli di libri su questa roba (qv). :-)
La risposta di Torek è eccellente. Basta aggiungere qualche dettaglio/contesto in più... Da un precedente kernel Linux (2.6.28), ecco un esempio di offset in uso in una chiamata di sistema... copia l'offset dallo spazio utente a una variabile temporanea prima di ottenere nel meccanismo di chiamata del driver del kernel, quindi lo copia nuovamente nel file utente. Questo è il modo in cui l'offset che vede il driver viene disaccoppiato dalla vista dell'utente e facilita le situazioni in cui l'offset è NULL nella chiamata di sistema, quindi non si verifica 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);
}