¿Cómo encontrar el controlador (módulo) asociado con un dispositivo en Linux?

50

En Linux, dado:

  • un dispositivo, por ejemplo /dev/sda,
  • y sus números mayores y menores, por ejemplo 8, 0,

¿Cómo puedo saber qué módulo / controlador lo está "manejando"?

¿Puedo profundizar /syso /procdescubrir eso?

Totor
fuente
Una combinación de lsmod, /proc/modulesy modinfo?
44
stackoverflow.com/questions/2911050 tiene el mismo aspecto que esta pregunta.
Michael Tomkins
Totor, agregué la recompensa porque otro usuario publicó la misma pregunta porque sintió que esta no había recibido suficiente atención. Le pedí que borrara su pregunta y ofrecí una recompensa por esta para obtener más respuestas. Recuerde aceptar una de las respuestas a continuación si responden su pregunta.
terdon
@terdon gracias por la recompensa, produjo buenas respuestas. Todavía no he probado todo cuidadosamente, pero mientras tanto aceptaré la respuesta de Graeme .
Totor

Respuestas:

58

Para obtener esta información de sysfsun archivo de dispositivo, primero determine el número mayor / menor mirando la salida de ls -l, p. Ej.

 $ ls -l /dev/sda
 brw-rw---- 1 root disk 8, 0 Apr 17 12:26 /dev/sda

El 8, 0nos dice que el número mayor es 8y el menor es 0. Al bprincipio de la lista también nos dice que es un dispositivo de bloque. Otros dispositivos pueden tener un cdispositivo para caracteres al comienzo.

Si luego mira debajo /sys/dev, verá que hay dos directorios. Uno llamó blocky otro llamó char. La obviedad aquí es que estos son para dispositivos de bloque y de caracteres, respectivamente. Cada dispositivo es accesible por su número mayor / menor es este directorio. Si hay un controlador disponible para el dispositivo, puede encontrarlo leyendo el objetivo del driverenlace en este o en el devicesubdirectorio. Por ejemplo, para mi /dev/sdasimplemente puedo hacer:

$ readlink /sys/dev/block/8\:0/device/driver
../../../../../../../bus/scsi/drivers/sd

Esto muestra que el sdcontrolador se utiliza para el dispositivo. Si no está seguro de si el dispositivo es un dispositivo de bloque o de caracteres, en el shell simplemente puede reemplazar esta parte con a *. Esto funciona igual de bien:

$ readlink /sys/dev/*/8\:0/device/driver
../../../../../../../bus/scsi/drivers/sd

También se puede acceder a los dispositivos de bloque directamente a través de su nombre a través de /sys/blocko /sys/class/block. P.ej:

$ readlink /sys/block/sda/device/driver
../../../../../../../bus/scsi/drivers/sd

Tenga en cuenta que la existencia de varios directorios /syspuede cambiar según la configuración del kernel. Además, no todos los dispositivos tienen una devicesubcarpeta. Por ejemplo, este es el caso de los archivos de dispositivos de partición como /dev/sda1. Aquí debe acceder al dispositivo para todo el disco (desafortunadamente no hay sysenlaces para esto).

Una última cosa que puede ser útil es enumerar los controladores para todos los dispositivos para los que están disponibles. Para esto, puede usar globos para seleccionar todos los directorios en los que están presentes los enlaces del controlador. P.ej:

$ ls -l /sys/dev/*/*/device/driver ls -l /sys/dev/*/*/driver 
ls: cannot access ls: No such file or directory
lrwxrwxrwx 1 root root 0 Apr 17 12:27 /sys/dev/block/11:0/device/driver -> ../../../../../../../bus/scsi/drivers/sr
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/block/8:0/device/driver -> ../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/block/8:16/device/driver -> ../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/block/8:32/device/driver -> ../../../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:0/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:1024/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:128/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:256/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:384/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/189:512/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/189:513/driver -> ../../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/189:514/driver -> ../../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/189:640/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/189:643/driver -> ../../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:768/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 20:38 /sys/dev/char/189:896/driver -> ../../../../bus/usb/drivers/usb
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/21:0/device/driver -> ../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/21:1/device/driver -> ../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:27 /sys/dev/char/21:2/device/driver -> ../../../../../../../bus/scsi/drivers/sr
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/21:3/device/driver -> ../../../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/250:0/device/driver -> ../../../../../../../bus/hid/drivers/hid-generic
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/250:1/device/driver -> ../../../../../../../bus/hid/drivers/hid-generic
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/250:2/device/driver -> ../../../../../../../bus/hid/drivers/hid-generic
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/252:0/device/driver -> ../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/252:1/device/driver -> ../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 12:27 /sys/dev/char/252:2/device/driver -> ../../../../../../../bus/scsi/drivers/sr
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/252:3/device/driver -> ../../../../../../../../../bus/scsi/drivers/sd
lrwxrwxrwx 1 root root 0 Apr 17 19:53 /sys/dev/char/254:0/device/driver -> ../../../bus/pnp/drivers/rtc_cmos
lrwxrwxrwx 1 root root 0 Apr 17 19:53 /sys/dev/char/29:0/device/driver -> ../../../bus/platform/drivers/simple-framebuffer
lrwxrwxrwx 1 root root 0 Apr 17 19:53 /sys/dev/char/4:64/device/driver -> ../../../bus/pnp/drivers/serial
lrwxrwxrwx 1 root root 0 Apr 17 19:53 /sys/dev/char/4:65/device/driver -> ../../../bus/platform/drivers/serial8250
lrwxrwxrwx 1 root root 0 Apr 17 19:53 /sys/dev/char/4:66/device/driver -> ../../../bus/platform/drivers/serial8250
lrwxrwxrwx 1 root root 0 Apr 17 19:53 /sys/dev/char/4:67/device/driver -> ../../../bus/platform/drivers/serial8250
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/6:0/device/driver -> ../../../bus/pnp/drivers/parport_pc
lrwxrwxrwx 1 root root 0 Apr 17 12:26 /sys/dev/char/99:0/device/driver -> ../../../bus/pnp/drivers/parport_pc

Finalmente, para divergir un poco de la pregunta, /sysagregaré otro truco global para obtener una perspectiva mucho más amplia sobre qué controladores están siendo utilizados por qué dispositivos (aunque no necesariamente aquellos con un archivo de dispositivo):

find /sys/bus/*/drivers/* -maxdepth 1 -lname '*devices*' -ls

Actualizar

Mirando más de cerca el resultado de udevadm, parece funcionar al encontrar el /sysdirectorio canónico (como lo haría si desreferenciara los directorios principales / secundarios anteriores), luego avanza hacia arriba en el árbol de directorios, imprimiendo cualquier información que encuentre. De esta forma, obtiene información sobre los dispositivos principales y los controladores que utilizan también.

Para experimentar con esto, escribí el script a continuación para recorrer el árbol de directorios y mostrar información en cada nivel relevante. udevparece buscar archivos legibles en cada nivel, con sus nombres y contenidos incorporados ATTRS. En lugar de hacer esto, muestro el contenido de los ueventarchivos en cada nivel (aparentemente la presencia de esto define un nivel distinto en lugar de solo un subdirectorio). También muestro el nombre base de cualquier enlace de subsistema que encuentre y esto muestra cómo encaja el dispositivo en esta jerarquía. udevadmno muestra la misma información, por lo que esta es una buena herramienta complementaria. La información del dispositivo principal (por ejemplo, PCIinformación) también es útil si desea hacer coincidir la salida de otras herramientas, como lshwdispositivos de nivel superior.

#!/bin/bash

dev=$(readlink -m $1)

# test for block/character device
if [ -b "$dev" ]; then
  mode=block
elif [ -c "$dev" ]; then
  mode=char
else
  echo "$dev is not a device file" >&2
  exit 1
fi

# stat outputs major/minor in hex, convert to decimal
data=( $(stat -c '%t %T' $dev) ) || exit 2
major=$(( 0x${data[0]} ))
minor=$(( 0x${data[1]} ))

echo -e "Given device:     $1"
echo -e "Canonical device: $dev"
echo -e "Major: $major"
echo -e "Minor: $minor\n"

# sometimes nodes have been created for devices that are not present
dir=$(readlink -f /sys/dev/$mode/$major\:$minor)
if ! [ -e "$dir" ]; then
  echo "No /sys entry for $dev" >&2
  exit 3
fi

# walk up the /sys hierarchy one directory at a time
# stop when there are three levels left 
while [[ $dir == /*/*/* ]]; do

  # it seems the directory is only of interest if there is a 'uevent' file
  if [ -e "$dir/uevent" ]; then
    echo "$dir:"
    echo "  Uevent:"
    sed 's/^/    /' "$dir/uevent"

    # check for subsystem link
    if [ -d "$dir/subsystem" ]; then
        subsystem=$(readlink -f "$dir/subsystem")
        echo -e "\n  Subsystem:\n    ${subsystem##*/}"
    fi

    echo
  fi

  # strip a subdirectory
  dir=${dir%/*}
done
Graeme
fuente
¿Hay alguna forma de determinar todos los controladores que se utilizan? Como por ejemplo la udevadmrespuesta te dará sdy ahci. ¿Hay alguna manera de determinar si también ahcise está utilizando?
Patrick
@Patrick, sí, actualizado.
Graeme
Gran respuesta, gracias! Solo para tener en cuenta, en mi caso, el enlace estaba activado device/device/, por lo que mi readlinkcomando se parecía readlink /sys/dev/char/XX\:Y/device/device/driver.
Harry Cutts el
19

Puedes usar la udevadmherramienta para descubrir esto.
El comando sería udevadm info -a -n /dev/sda, y luego mira los DRIVER==parámetros.

# udevadm info -a -n /dev/sda | grep -oP 'DRIVERS?=="\K[^"]+'  
sd
ahci

Esto muestra que en realidad hay 2 controladores involucrados en la provisión de este dispositivo, sdy ahci. El primero, sdes directamente responsable del /dev/sdadispositivo, pero utiliza el ahcicontrolador subyacente.

 

El resultado del udevadmcomando tiene este aspecto e incluye una descripción de cómo funciona.

# udevadm info -a -n /dev/sda      

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda':
    KERNEL=="sda"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{ro}=="0"
    ATTR{size}=="500118192"
    ATTR{stat}=="   84786     1420  3091333    40215   966488    12528 14804028  2357668        0  1146934  2396653"
    ATTR{range}=="16"
    ATTR{discard_alignment}=="0"
    ATTR{events}==""
    ATTR{ext_range}=="256"
    ATTR{events_poll_msecs}=="-1"
    ATTR{alignment_offset}=="0"
    ATTR{inflight}=="       0        0"
    ATTR{removable}=="0"
    ATTR{capability}=="50"
    ATTR{events_async}==""

  looking at parent device '/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0':
    KERNELS=="0:0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS=="sd"
    ATTRS{rev}=="VZJ4"
    ATTRS{type}=="0"
    ATTRS{scsi_level}=="6"
    ATTRS{model}=="LITEONIT LMT-256"
    ATTRS{state}=="running"
    ATTRS{queue_type}=="simple"
    ATTRS{iodone_cnt}=="0x10daad"
    ATTRS{iorequest_cnt}=="0x10ead1"
    ATTRS{queue_ramp_up_period}=="120000"
    ATTRS{device_busy}=="0"
    ATTRS{evt_capacity_change_reported}=="0"
    ATTRS{timeout}=="30"
    ATTRS{evt_media_change}=="0"
    ATTRS{ioerr_cnt}=="0x2"
    ATTRS{queue_depth}=="31"
    ATTRS{vendor}=="ATA     "
    ATTRS{evt_soft_threshold_reached}=="0"
    ATTRS{device_blocked}=="0"
    ATTRS{evt_mode_parameter_change_reported}=="0"
    ATTRS{evt_lun_change_reported}=="0"
    ATTRS{evt_inquiry_change_reported}=="0"
    ATTRS{iocounterbits}=="32"
    ATTRS{eh_timeout}=="10"

  looking at parent device '/devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0':
    KERNELS=="target0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:1f.2/ata1/host0':
    KERNELS=="host0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:1f.2/ata1':
    KERNELS=="ata1"
    SUBSYSTEMS==""
    DRIVERS==""

  looking at parent device '/devices/pci0000:00/0000:00:1f.2':
    KERNELS=="0000:00:1f.2"
    SUBSYSTEMS=="pci"
    DRIVERS=="ahci"
    ATTRS{irq}=="41"
    ATTRS{subsystem_vendor}=="0x144d"
    ATTRS{broken_parity_status}=="0"
    ATTRS{class}=="0x010601"
    ATTRS{enabled}=="1"
    ATTRS{consistent_dma_mask_bits}=="64"
    ATTRS{dma_mask_bits}=="64"
    ATTRS{local_cpus}=="0f"
    ATTRS{device}=="0x1e03"
    ATTRS{msi_bus}==""
    ATTRS{local_cpulist}=="0-3"
    ATTRS{vendor}=="0x8086"
    ATTRS{subsystem_device}=="0xc0d3"
    ATTRS{numa_node}=="-1"
    ATTRS{d3cold_allowed}=="1"

  looking at parent device '/devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""
Patricio
fuente
1
@ECarterYoung ¿Dónde ves que udevadmse elimina (o incluso se recomienda)? No puedo encontrar nada ni siquiera dando una pista sobre eso.
Patrick
1
@ECarterYoung Lo hice, no veo nada por el estilo.
Patrick
Me equivoqué con respecto a la ausencia de UEVENT_HELPER en el kernel. En los sistemas que ejecutan systemd, esta entrada está en blanco, pero la ayuda todavía está presente en el sistema.
eyoung100
4

Utilice el comando hwinfo y el modelo de salida y el controlador. Si no hay controlador, no se mostrará. Por ejemplo para discos:

# hwinfo --bloque | grep -Ei "driver \: | model \:"
  Modelo: "Disquete"
  Modelo: "FUJITSU MHZ2080B"
  Conductor: "ahci", "sd"
  Modelo: "Partición"
  Modelo: "Partición"
  Modelo: "Partición"
  Modelo: "Tarjeta múltiple genérica"
  Controlador: "ums-realtek", "sd"
  Modelo: "Realtek USB2.0-CRW"
  Conductor: "ums-realtek"

Para tarjetas de red:

# hwinfo --netcard | grep -Ei "driver \: | model \:"
  Modelo: "Broadcom NetXtreme BCM5764M Gigabit Ethernet PCIe"
  Conductor: "tg3"
  Modelo: "Intel Wireless WiFi Link 5100"
  Conductor: "iwlwifi"

Para dispositivos USB:

# hwinfo --usb | grep -Ei "driver \: | model \:"
  Modelo: "Linux 3.11.10-7-desktop uhci_hcd UHCI Host Controller"
  Conductor: "hub"
  Modelo: "Linux 3.11.10-7-desktop uhci_hcd UHCI Host Controller"
  Conductor: "hub"
  Modelo: "IDEACOM IDC 6680"
  Conductor: "usbhid"
  [...]

Use hwinfo --help para averiguar qué otros tipos de dispositivos puede consultar. hwinfo se instala de manera predeterminada, por ejemplo, en SUSE Linux.

Thorsten Staerk
fuente
Para relacionar esto con un archivo de dispositivo en particular, una forma es agregar la --onlyopción. Por ej hwinfo --block --only /dev/sda | grep ....
Graeme
3

lshwes una herramienta increíble para enumerar el hardware que se encuentra en su máquina. Deberá instalarlo primero antes de ejecutarlo.

$ yum install lshw
$ apt-get install lshw

Use yumo apt-getdependiendo del sistema que esté usando. Luego, para enumerar específicamente el hardware de almacenamiento:

# lshw -class storage 
*-storage               
   description: SATA controller
   product: 5 Series/3400 Series Chipset 4 port SATA AHCI Controller
   vendor: Intel Corporation
   physical id: 1f.2
   bus info: pci@0000:00:1f.2
   version: 06
   width: 32 bits
   clock: 66MHz
   capabilities: storage msi pm ahci_1.0 bus_master cap_list
   configuration: driver=ahci latency=0
   resources: irq:41 ioport:1830(size=8) ioport:1824(size=4) ioport:1828(size=8) ioport:1820(size=4) ioport:1800(size=32) memory:f0305000-f03057ff

Es posible que desee ejecutarlo rootpara recuperar toda la información.

De lo contrario, lspcitambién puede dar información sobre su hardware:

$ lspci -vv
00:1f.2 SATA controller: Intel Corporation 5 Series/3400 Series Chipset 4 port SATA AHCI Controller (rev 06) (prog-if 01 [AHCI 1.0])
    Subsystem: Dell Device 0434
    Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
    Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
    Latency: 0
    Interrupt: pin B routed to IRQ 41
    Region 0: I/O ports at 1830 [size=8]
    Region 1: I/O ports at 1824 [size=4]
    Region 2: I/O ports at 1828 [size=8]
    Region 3: I/O ports at 1820 [size=4]
    Region 4: I/O ports at 1800 [size=32]
    Region 5: Memory at f0305000 (32-bit, non-prefetchable) [size=2K]
    Capabilities: <access denied>
    Kernel driver in use: ahci

Para averiguar el número mayor y menor de un dispositivo, simplemente ejecútelo ls.

$ ls -l /dev/sda
brw-rw----. 1 root disk 8, 0 13 avril 10:54 /dev/sda

En este producto, el ben brw-rw----.significa que este es un dispositivo de bloque. Los dígitos 8y 0son, respectivamente, el número mayor y menor del dispositivo.

Spack
fuente
1
Mi pregunta es sobre encontrar el enlace entre un dispositivo y su módulo / controlador. ¿Dónde respondes eso?
Totor
1
@Totor En ambas salidas de lshwy lspcipuede ver el módulo utilizado por un dispositivo: configuración: driver = ahci latencia = 0 y controlador Kernel en uso: ahci .
Spack