2012-06-25 9 views
6

Ho un driver di periferica di carattere Linux che crea una voce /dev/mything e quindi un programma C++/Qt che apre il dispositivo e lo utilizza. Se il programma viene chiuso correttamente, con exit(), il dispositivo viene chiuso e il driver si reimposta correttamente. Ma se il programma esce in modo anomalo, tramite segfault o SIGINT o qualcosa del genere, il dispositivo non viene chiuso correttamente.Come può rilevare un driver di dispositivo di carattere Linux quando un programma che lo utilizza esce in modo anomalo?

mia soluzione attuale è quella di ricaricare il driver se si blocca nello stato "aperto".

Questa linea nel driver cerca di impedire più programmi di utilizzare il dispositivo contemporaneamente:

int mything_open(struct inode* inode, struct file* filp) { 
    ... 
    if (port->rings[bufcount].virt_addr) return -EBUSY; 
    ... 
} 

Allora questo pulisce in su:

int mything_release(struct inode* inode, struct file* filp) { 
    ... 
    port->rings[bufcount].virt_addr = NULL; 
    ... 
} 

Penso exit() sta causando mything_release di essere chiamato, ma SIGINT non è. Come posso rendere il conducente più robusto in questo tipo di situazione?

EDIT:

Qui ci sono le operazioni che ho implementato. Forse mi manca qualcosa?

static struct file_operations fatpipe_fops = { 
    .owner = THIS_MODULE, 
    .open =  mything_open, 
    .release = mything_release, 
    .read =  mything_read, 
    .write = mything_write, 
    .ioctl = mything_ioctl 
}; 
+2

Quando il processo termina o termina, il kernel libererà le risorse. Compreso il conteggio dei riferimenti su qualsiasi descrittore di file aperto. – wildplasser

+0

In questo caso, perché dopo che il mio programma termina con SIGINT/segfault, quando si tenta di riaprire il programma viene visualizzato 'Dispositivo o risorsa occupata? Non vedo questo errore se esco pulito e riaprilo. – Dave

+0

Non conosco il tuo codice. Forse hai un valore sbagliato per il bufcount? Forse non hai implementato una delle funzioni necessarie? – wildplasser

risposta

1

Il problema si riduceva a questa linea in mything_release, messo in aspettare un po 'di memoria scrive per completare:

if (wait_event_interruptible_timeout(port->inq, false, 10)) return -ERESTARTSYS; 

Con un'uscita normale programma, questo sarebbe girare per 10 jiffies e proseguire lungo. Ma con un'uscita anomala da SIGINT o qualcosa del genere, penso che il timeout interrompibile sia stato interrotto e restituito -ERESTARTSYS, causando il mio se restituire lo stesso.

La cosa che ha funzionato per me è stato quello di solo sbarazzarsi del if e aspettare:

wait_event_interruptible_timeout(port->inq, false, 10); 

Questa patch da anni fa mi ha fatto credere che il ritorno ERESTARTSYS da una funzione vicino/_Release non è una buona idea: http://us.generation-nt.com/answer/patch-fix-wrong-error-code-interrupted-close-syscalls-help-181191441.html

2

Non è necessario questo test; il problema non è la terminazione anomala del programma (che, dal punto di vista del tuo conducente, è esattamente come un normale close sul dispositivo), ma piuttosto un problema nella gestione dello stato del tuo dispositivo. In altre parole, se hai inserito close(dev_fd) o anche exit(0) nel punto esatto in cui il programma si blocca, avresti lo stesso problema.

Si dovrebbe capire quale parte del comportamento di guida sta causando a rimanere in uno stato occupato e sistemare le cose.

+0

Ho seguito il consiglio di Wildplasser, sopra, e ho inserito alcune chiamate printk in 'mything_release'. Ho trovato una riga che dice 'if (wait_event_interruptible_timeout (port-> inq, false, 10)) return -ERESTARTSYS;', e ho capito che con una terminazione anomala, non ha mai superato quella linea. Google mi fa pensare che ERESTARTSYS non è una cosa giusta per tornare da una funzione chiusa. – Dave

Problemi correlati