¿Cómo puedo identificar la cola de solicitud para un dispositivo de bloque de Linux?
linux-kernel block-device (2)
Estoy trabajando en este controlador que conecta el disco duro a través de la red. Existe un error que indica que si habilito dos o más discos duros en la computadora, solo el primero obtiene las particiones examinadas e identificadas. El resultado es que si tengo 1 partición en hda y 1 partición en hdb, tan pronto como conecto hda hay una partición que se puede montar. Entonces hda1 obtiene un xyz123 blkid tan pronto como se monte. Pero cuando sigo y monte hdb1, también aparece el mismo blkid y, de hecho, el controlador lo lee desde hda, no hdb.
Así que creo que encontré el lugar donde el conductor está estropeando. A continuación se muestra un resultado de depuración que incluye un dump_stack que puse en el primer lugar donde parece estar accediendo al dispositivo equivocado.
Aquí está la sección del código:
/*basically, this is just the request_queue processor. In the log output that
follows, the second device, (hdb) has just been connected, right after hda
was connected and hda1 was mounted to the system. */
void nblk_request_proc(struct request_queue *q)
{
struct request *req;
ndas_error_t err = NDAS_OK;
dump_stack();
while((req = NBLK_NEXT_REQUEST(q)) != NULL)
{
dbgl_blk(8,"processing queue request from slot %d",SLOT_R(req));
if (test_bit(NDAS_FLAG_QUEUE_SUSPENDED, &(NDAS_GET_SLOT_DEV(SLOT_R(req))->queue_flags))) {
printk ("ndas: Queue is suspended/n");
/* Queue is suspended */
#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) )
blk_start_request(req);
#else
blkdev_dequeue_request(req);
#endif
Aquí hay una salida de registro. He agregado algunos comentarios para ayudar a entender qué está sucediendo y dónde parece surgir la mala decisión.
/* Just below here you can see "slot" mentioned many times. This is the
identification for the network case in which the hd is connected to the
network. So you will see slot 2 in this log because the first device has
already been connected and mounted. */
kernel: [231644.155503] BL|4|slot_enable|/driver/block/ctrldev.c:281|adding disk: slot=2, first_minor=16, capacity=976769072|nd/dpcd1,64:15:44.38,3828:10
kernel: [231644.155588] BL|3|ndop_open|/driver/block/ops.c:233|ing bdev=f6823400|nd/dpcd1,64:15:44.38,3720:10
kernel: [231644.155598] BL|2|ndop_open|/driver/block/ops.c:247|slot =0x2|nd/dpcd1,64:15:44.38,3720:10
kernel: [231644.155606] BL|2|ndop_open|/driver/block/ops.c:248|dev_t=0x3c00010|nd/dpcd1,64:15:44.38,3720:10
kernel: [231644.155615] ND|3|ndas_query_slot|netdisk/nddev.c:791|slot=2 sdev=d33e2080|nd/dpcd1,64:15:44.38,3696:10
kernel: [231644.155624] ND|3|ndas_query_slot|netdisk/nddev.c:817|ed|nd/dpcd1,64:15:44.38,3696:10
kernel: [231644.155631] BL|3|ndop_open|/driver/block/ops.c:326|mode=1|nd/dpcd1,64:15:44.38,3720:10
kernel: [231644.155640] BL|3|ndop_open|/driver/block/ops.c:365|ed open|nd/dpcd1,64:15:44.38,3724:10
kernel: [231644.155653] BL|8|ndop_revalidate_disk|/driver/block/ops.c:2334|gendisk=c6afd800={major=60,first_minor=16,minors=0x10,disk_name=ndas-44700486-0,private_data=00000002,capacity=%lld}|nd/dpcd1,64:15:44.38,3660:10
kernel: [231644.155668] BL|8|ndop_revalidate_disk|/driver/block/ops.c:2346|ed|nd/dpcd1,64:15:44.38,3652:10
/* So at this point the hard disk is added (gendisk=c6...) and the identifications
all match the network device. The driver is now about to begin scanning the
hard drive for existing partitions. the little ''ed'', at the end of the previous
line indicates that revalidate_disk has finished it''s job.
Also, I think the request queue is indicated by the output dpcd1 near the very
end of the line.
Now below we have entered the function that is pasted above. In the function
you can see that the slot can be determined by the queue. And the log output
after the stack dump shows it is from slot 1. (The first network drive that was
already mounted.) */
kernel: [231644.155677] ndas-44700486-0:Pid: 467, comm: nd/dpcd1 Tainted: P 2.6.32-5-686 #1
kernel: [231644.155711] Call Trace:
kernel: [231644.155723] [<fc5a7685>] ? nblk_request_proc+0x9/0x10c [ndas_block]
kernel: [231644.155732] [<c11298db>] ? __generic_unplug_device+0x23/0x25
kernel: [231644.155737] [<c1129afb>] ? generic_unplug_device+0x1e/0x2e
kernel: [231644.155743] [<c1123090>] ? blk_unplug+0x2e/0x31
kernel: [231644.155750] [<c10cceec>] ? block_sync_page+0x33/0x34
kernel: [231644.155756] [<c108770c>] ? sync_page+0x35/0x3d
kernel: [231644.155763] [<c126d568>] ? __wait_on_bit_lock+0x31/0x6a
kernel: [231644.155768] [<c10876d7>] ? sync_page+0x0/0x3d
kernel: [231644.155773] [<c10876aa>] ? __lock_page+0x76/0x7e
kernel: [231644.155780] [<c1043f1f>] ? wake_bit_function+0x0/0x3c
kernel: [231644.155785] [<c1087b76>] ? do_read_cache_page+0xdf/0xf8
kernel: [231644.155791] [<c10d21b9>] ? blkdev_readpage+0x0/0xc
kernel: [231644.155796] [<c1087bbc>] ? read_cache_page_async+0x14/0x18
kernel: [231644.155801] [<c1087bc9>] ? read_cache_page+0x9/0xf
kernel: [231644.155808] [<c10ed6fc>] ? read_dev_sector+0x26/0x60
kernel: [231644.155813] [<c10ee368>] ? adfspart_check_ICS+0x20/0x14c
kernel: [231644.155819] [<c10ee138>] ? rescan_partitions+0x17e/0x378
kernel: [231644.155825] [<c10ee348>] ? adfspart_check_ICS+0x0/0x14c
kernel: [231644.155830] [<c10d26a3>] ? __blkdev_get+0x225/0x2c7
kernel: [231644.155836] [<c10ed7e6>] ? register_disk+0xb0/0xfd
kernel: [231644.155843] [<c112e33b>] ? add_disk+0x9a/0xe8
kernel: [231644.155848] [<c112dafd>] ? exact_match+0x0/0x4
kernel: [231644.155853] [<c112deae>] ? exact_lock+0x0/0xd
kernel: [231644.155861] [<fc5a8b80>] ? slot_enable+0x405/0x4a5 [ndas_block]
kernel: [231644.155868] [<fc5a8c63>] ? ndcmd_enabled_handler+0x43/0x9e [ndas_block]
kernel: [231644.155874] [<fc5a8c20>] ? ndcmd_enabled_handler+0x0/0x9e [ndas_block]
kernel: [231644.155891] [<fc54b22b>] ? notify_func+0x38/0x4b [ndas_core]
kernel: [231644.155906] [<fc561cba>] ? _dpc_cancel+0x17c/0x626 [ndas_core]
kernel: [231644.155919] [<fc562005>] ? _dpc_cancel+0x4c7/0x626 [ndas_core]
kernel: [231644.155933] [<fc561cba>] ? _dpc_cancel+0x17c/0x626 [ndas_core]
kernel: [231644.155941] [<c1003d47>] ? kernel_thread_helper+0x7/0x10
/* here are the output of the driver debugs. They show that this operation is
being performed on the first devices request queue. */
kernel: [231644.155948] BL|8|nblk_request_proc|/driver/block/block26.c:494|processing queue request from slot 1|nd/dpcd1,64:15:44.38,3408:10
kernel: [231644.155959] BL|8|nblk_handle_io|/driver/block/block26.c:374|struct ndas_slot sd = NDAS GET SLOT DEV(slot 1)
kernel: [231644.155966] |nd/dpcd1,64:15:44.38,3328:10
kernel: [231644.155970] BL|8|nblk_handle_io|/driver/block/block26.c:458|case READA call ndas_read(slot=1, ndas_req)|nd/dpcd1,64:15:44.38,3328:10
kernel: [231644.155979] ND|8|ndas_read|netdisk/nddev.c:824|read io: slot=1, cmd=0, req=x00|nd/dpcd1,64:15:44.38,3320:10
Espero que esto sea suficiente información de fondo. Quizás una pregunta obvia en este momento es "¿Cuándo y dónde se asignan las request_queues?"
Bueno, eso se maneja un poco antes de la función add_disk. agregar disco, es la primera línea en la salida de registro.
slot->disk = NULL;
spin_lock_init(&slot->lock);
slot->queue = blk_init_queue(
nblk_request_proc,
&slot->lock
);
Hasta donde yo sé, esta es la operación estándar. Volviendo a mi pregunta original. ¿Puedo encontrar la cola de solicitud en alguna parte y asegurarme de que sea incremental o única para cada dispositivo nuevo o el kernel de Linux solo usa una cola para cada número mayor? Quiero descubrir por qué este controlador está cargando la misma cola en dos almacenes de bloque diferentes y determinar si eso está causando el blkid duplicado durante el proceso de registro inicial.
Gracias por mirar esta situación para mí.
Comparto la solución al error que me llevó a publicar esta pregunta. Aunque en realidad no responde la pregunta de cómo identificar la cola de solicitud del dispositivo.
En el código de arriba está el siguiente:
if (test_bit(NDAS_FLAG_QUEUE_SUSPENDED,
&(NDAS_GET_SLOT_DEV(SLOT_R(req))->queue_flags)))
Bueno, ese "SLOT_R (req)" estaba causando el problema. Eso se define más donde devolver el dispositivo gendisk.
#define SLOT_R(_request_) SLOT((_request_)->rq_disk)
Esto devolvió el disco, pero no el valor adecuado para varias operaciones más adelante. Entonces, a medida que se cargaban los dispositivos de bloques adicionales, esta función básicamente seguía retornando 1. (Creo que estaba procesando como un booleano). Por lo tanto, todas las solicitudes se apilaban en la cola de solicitud para el disco 1.
La solución era acceder al valor de identificación de disco correcto que ya estaba almacenado en private_data del disco cuando se agregó al sistema.
Correct identifier definition:
#define SLOT_R(_request_) ( (int) _request_->rq_disk->private_data )
How the correct disk number was stored.
slot->disk->queue = slot->queue;
slot->disk->private_data = (void*) (long) s; <-- ''s'' is the disk id
slot->queue_flags = 0;
Ahora la id del disco correcto se devuelve de los datos privados, por lo que todas las solicitudes a la cola correcta.
Como se mencionó, esto no muestra cómo identificar la cola. Una suposición no educada podría ser:
x = (int) _request_->rq_disk->queue->id;
Árbitro. la función request_queue en linux http://lxr.free-electrons.com/source/include/linux/blkdev.h#L270 & 321
¡Gracias a todos por ayudar!
Queue = blk_init_queue(sbd_request, &Device.lock);