2011-09-09 8 views
12

Estoy estudiando el capítulo 3.5 de Linux Device Drivers, 3rd edition. En esta sección se presenta un método para recuperar una estructura a medida que definimos a nosotros mismos de struct inode *inode en la función de apertura:Motivo para pasar datos utilizando struct inode y struct file en la programación del controlador del dispositivo Linux

int scull_open(struct inode *inode, struct file *filp) 
{ 
    struct scull_dev *dev; 

    dev = container_of(inode->i_cdev, struct scull_dev, cdev); 
    filp->private_data = dev; /* for other methods */ 

    } 
    return 0;   
} 

Desde mi entender, mientras que el dispositivo se abre, el struct inode *inode que representa el dispositivo se pasa a scull_open. A continuación, la estructura de encargo dev se extrae y se pasa a filp->private_data de modo que otros métodos como scull_read puede usarlo:

ssize_t scull_read(struct file *filp, char _ _user *buf, size_t count, 
       loff_t *f_pos) 
{ 
    struct scull_dev *dev = filp->private_data; 
    /* other codes that uses *dev */ 
} 

Esto parece ir bien hasta que me di cuenta de que ya teníamos un struct scull_dev *dev durante la inicialización en scull_setup_cdevhere.

estoy bastante confusa ya que pensamos que podemos hacer struct scull_dev *dev una variable global, entonces scull_read y otros métodos con el tiempo a tener acceso a ella sin pasar por todo el paso utilizando inode y file.

Mi pregunta es, ¿por qué no la convertimos en una variable global?

¿Alguien puede proporcionar algunos ejemplos prácticos del uso de este método para pasar datos?

+4

Que esta pregunta/respuesta sea una lección para usted en qué variables globales son malas y nunca debe ser usado excepto cuando no hay otra manera. –

+0

Sí, pero mientras enseña al escritor debe decir por qué y para qué sirve esa función en particular. – mrigendra

Respuesta

8

Seguridad para subprocesos! ¿Qué sucede si dos hilos/procesos usan el controlador simultáneamente?

+1

Subprocesos pares en diferentes procesos de subproceso único. (Que la mayoría de las personas simplemente llamarían ingenuamente "procesos" en lugar de "hilos"). –

+1

Gracias, pero todavía tengo algunas dudas. Digamos que tengo un programa de usuario simple (llamémoslo 'open_device.c') para comunicarnos con mi controlador a través de llamadas al sistema como' open() ',' read() ',' write() ', etc. If I ' Estoy muy seguro de que a la vez, solo usaré ** one ** 'open_device.c' para acceder a mi controlador, ¿todavía tengo que ocuparme del problema de la seguridad del hilo? ¿El problema de seguridad del hilo ocurre solo cuando estoy usando ** dos ** o ** más ** 'open_device.c' para acceder a mi controlador? –

+1

¿Cuál es el tiempo de vida de la estructura, persiste entre las llamadas al sistema? Si lo hace, su programa se romperá si abre un segundo archivo antes de cerrar el primero. –

0

También puede evitar el uso de datos privados para almacenar su dispositivo real, que es una opción común si necesita datos privados para algo diferente. En ese caso, deberá recuperar el número menor en la rutina scull_read. Será algo así:

ssize_t scull_read(struct file *filp, 
        char __user* buf, 
        size_t count, 
        loff_t * f_pos) { 

    int minor = MINOR(filp->f_dentry->d_inode->i_rdev); 
    printk("reading on minor number %d\n", minor); 
    /* use dev[minor] in ur code */ 
    return 0; 
} 
0

No creo que sea un problema de seguridad. Es más como una elección de diseño. Si no me equivoco, la seguridad de la hebra se logra subiendo y bajando el semáforo en scull_dev. Si profundiza en el código, puede ver abrir, leer, escribir todo usado down_interruptible().

Supongo que el autor 1) cree que acceder a scull_dev directamente no se ve bien 2) quiere mostrarnos cómo usar private_data. Al colocar el punto en scull_dev en el archivo struct cuyo puntero se envía a cada operación, cada operación puede acceder a él sin usar la variable global.

10

La razón principal es para que su controlador pueda administrar más de un dispositivo. Por ejemplo, puede crear (mknod) varios dispositivos /dev/scull1, /dev/scull2, /dev/scull3 ... y luego cada uno de ellos tendrá asociado un scull_dev diferente.

Con una variable global, está limitado a uno. E incluso si su controlador solo admite uno de esos dispositivos, hay pocas razones para no diseñar el código a prueba del futuro.

0

El controlador scull se implementa con 4 menores, cada uno de los cuales tiene un scull_dev por separado, cada scull_dev tiene "struct cdev" incrustado en él. Ahora digamos que el usuario ha abierto scull0 desde/dev/scull0. En la función open(), debe apuntar a la estructura scull_dev correcta. Las estructuras scull_dev están dinámicamente asignadas.

se puede ver la aplicación completa aquí https://github.com/mharsch/ldd3-samples/blob/master/scull/main.c#L450