Archivi tag: UUID

CentOS 6: gestione delle periferiche removibili mediante UDEV

Scenario

Macchina CentOS 6 dotata di 2 dischi rigidi, ovvero:

1) /dev/sda dove è presente la partizione di boot (sda1) e quella di root (sda2);

2) /dev/sdb che consta di un’unica partizione dedicata al salvataggio di dati.

CentOSProblema

Collegando una memoria flash di tipo USB (che funge da dongle per un applicativo in esecuzione sul server) essa viene inizialmente mappata come /dev/sdc. Dopo un riavvio della macchina, però, il kernel name assegnato alla stessa diventa /dev/sda e di conseguenza i 2 dischi rigidi vengono mappati come /dev/sdb e /dev/sdc. Ciò, fortunatamente, non va ad inficiare il funzionamento del server, in quanto il file /etc/fstab contiene gli UUID (univoci e soprattutto statici) assegnati a ciascuna partizione (anzichè il kernel name che, come abbiamo visto, può variare).

Nel mio caso, però, esiste un problema: poichè utilizzo uno specifico tool per monitorare lo stato delle partizioni, le quali vengono interrogate mediante il loro kernel name, dovrei modificare tale parametro di volta in volta, distinguendo il caso in cui i dischi rigidi vengono mappati in modo “standard”, ovvero come /dev/sda e /dev/sdb, dal caso in cui vengono riconosciuti come /dev/sdb e /dev/sdc (con la memoria flash che fa le veci di /dev/sda). Ergo, devo fare in modo che la memoria flash venga mappata sempre e comunque come /dev/sdd.

Soluzione

Quanto sopra può essere realizzato configurando opportunamente udev. Tale applicativo si basa su alcuni file di configurazione, dislocati su 2 directory differenti, ovvero:

1) /lib/udev/rules.d/ che contiene i file di configurazione di default (non vanno editati);

2) /etc/udev/rules.d che contiene i file di configurazione “customizzabili” dall’utente (il cui contenuto ha una maggiore priorità rispetto a quello dei file di default, “scavalcandoli” all’occorrenza).

Tutti i suddetti file vengono dati in pasto ad udev seguendo un ordine crescente dettato esclusivamente dal loro filename. Da ciò si capisce come mai il contenuto tipico della directory /etc/udev/rules.d è simile al seguente:

[root@linuxbox ~]# ls /etc/udev/rules.d/
60-pcmcia.rules  70-persistent-cd.rules    90-hal.rules
60-fprint-autosuspend.rules  60-raw.rules     70-persistent-net.rules  90-alsa.rules                98-kexec.rules

dove le direttive presenti nel file 60-pcmcia.rules vengono lette (ed eseguite) prima di quelle relative a 70-persistent-cd.rules.

Poichè vogliamo che il file contenente le nostre direttive custom venga valutato per primo, dobbiamo nominarlo come 10-local.rules. Creiamolo quindi utilizzando il comando:

[root@linuxbox ~]# touch /etc/udev/rules.d/10-local.rules

per poi popolarlo come vi indicherò più avanti.

Dopo aver creato il suddetto file, occorre individuare le caratteristiche tipiche di ciascun disco rigido e della memoria flash, utilizzando il comando:

[root@linuxbox ~]# udevadm info -a -n /dev/sdXY

dove X è la lettera che identifica il device ed Y (facoltativo) è il numero di partizione.

Ad esempio, per /dev/sda possiamo utilizzare il comando:

[root@linuxbox ~]# udevadm info -a -n /dev/sda

il cui output sarà simile al seguente:

custom logging function 0x7f90ec575030 registered
udevadm[29910]: custom logging function 0x7f90ec575030 registered
selinux=1
udevadm[29910]: selinux=1
calling: info
udevadm[29910]: calling: info
device 0x7f90ec599460 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0/block/sda'
udevadm[29910]: device 0x7f90ec599460 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0/block/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:0b.0/host0/target0:0:0/0:0:0:0/block/sda':
    KERNEL=="sda"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{range}=="16"
    ATTR{ext_range}=="256"
    ATTR{removable}=="0"
    ATTR{ro}=="0"
    ATTR{size}=="976773168"
    ATTR{alignment_offset}=="0"
    ATTR{discard_alignment}=="0"
    ATTR{capability}=="52"
    ATTR{stat}==" 7302543  1320445 841562942 71451185  6119635 28157362 271395642 272451897        0 51376878 343882883"
    ATTR{inflight}=="       0        0"

device 0x7f90ec59ff90 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0'
udevadm[29910]: device 0x7f90ec59ff90 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0'
  looking at parent device '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0':
    KERNELS=="0:0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS=="sd"
    ATTRS{device_blocked}=="0"
    ATTRS{type}=="0"
    ATTRS{scsi_level}=="6"
    ATTRS{vendor}=="ATA     "
    ATTRS{model}=="TOSHIBA HDWJ105 "
    ATTRS{rev}=="AX00"
    ATTRS{state}=="running"
    ATTRS{timeout}=="30"
    ATTRS{eh_timeout}=="10"
    ATTRS{iocounterbits}=="32"
    ATTRS{iorequest_cnt}=="0xd13eaf"
    ATTRS{iodone_cnt}=="0xcfd529"
    ATTRS{ioerr_cnt}=="0x1e"
    ATTRS{modalias}=="scsi:t-0x00"
    ATTRS{evt_media_change}=="0"
    ATTRS{evt_inquiry_change_reported}=="0"
    ATTRS{evt_capacity_change_reported}=="0"
    ATTRS{evt_soft_threshold_reached}=="0"
    ATTRS{evt_mode_parameter_change_reported}=="0"
    ATTRS{evt_lun_change_reported}=="0"
    ATTRS{dh_state}=="detached"
    ATTRS{queue_depth}=="31"
    ATTRS{queue_ramp_up_period}=="120000"
    ATTRS{queue_type}=="simple"
    ATTRS{unload_heads}=="0"

device 0x7f90ec5a1b20 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0'
udevadm[29910]: device 0x7f90ec5a1b20 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0'
  looking at parent device '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0':
    KERNELS=="target0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

device 0x7f90ec5b3e10 has devpath '/devices/pci0000:00/0000:00:0b.0/host0'
udevadm[29910]: device 0x7f90ec5b3e10 has devpath '/devices/pci0000:00/0000:00:0b.0/host0'
  looking at parent device '/devices/pci0000:00/0000:00:0b.0/host0':
    KERNELS=="host0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

device 0x7f90ec595fb0 has devpath '/devices/pci0000:00/0000:00:0b.0'
udevadm[29910]: device 0x7f90ec595fb0 has devpath '/devices/pci0000:00/0000:00:0b.0'
  looking at parent device '/devices/pci0000:00/0000:00:0b.0':
    KERNELS=="0000:00:0b.0"
    SUBSYSTEMS=="pci"
    DRIVERS=="ahci"
    ATTRS{vendor}=="0x10de"
    ATTRS{device}=="0x0ab4"
    ATTRS{subsystem_vendor}=="0x1043"
    ATTRS{subsystem_device}=="0x83e2"
    ATTRS{class}=="0x010185"
    ATTRS{irq}=="25"
    ATTRS{local_cpus}=="f"
    ATTRS{local_cpulist}=="0-3"
    ATTRS{modalias}=="pci:v000010DEd00000AB4sv00001043sd000083E2bc01sc01i85"
    ATTRS{numa_node}=="-1"
    ATTRS{enable}=="1"
    ATTRS{broken_parity_status}=="0"
    ATTRS{msi_bus}==""

device 0x7f90ec5a5200 has devpath '/devices/pci0000:00'
udevadm[29910]: device 0x7f90ec5a5200 has devpath '/devices/pci0000:00'
  looking at parent device '/devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""

Discorso simile vale per la partizione 1 del disco /dev/sda:

[root@linuxbox ~]# udevadm info -a -n /dev/sda1

il cui output sarà simile a:

custom logging function 0x7ff9331c9030 registered
udevadm[30106]: custom logging function 0x7ff9331c9030 registered
selinux=1
udevadm[30106]: selinux=1
calling: info
udevadm[30106]: calling: info
device 0x7ff9331ed460 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0/block/sda/sda1'
udevadm[30106]: device 0x7ff9331ed460 has devpath '/devices/pci0000:00/0000:00:0b.0/host0/target0:0:0/0:0:0:0/block/sda/sda1'

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:0b.0/host0/target0:0:0/0:0:0:0/block/sda/sda1':
    KERNEL=="sda1"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{partition}=="1"
    ATTR{start}=="2048"
    ATTR{size}=="1024000"
    ATTR{alignment_offset}=="0"
    ATTR{discard_alignment}=="0"
    ATTR{stat}=="    2379      166   368458    10840       34       49      178     1663        0    11039    12484"
    ATTR{inflight}=="       0        0"

In particolare, utilizzeremo le informazioni riportate come attributi (ATTR) per identificare nel modo più preciso possibile il device/partizione su cui applicare le nostre regole.

Detto ciò, procediamo con la stesura del contenuto relativo al file 10-local.rules, che dovrà essere simile al seguente:

KERNEL=="sd?1", SUBSYSTEM=="block", ATTR{size}=="3915639", NAME="sdd1"
KERNEL=="sd*", SUBSYSTEM=="block", ATTR{size}=="3915776", ATTR{capability}=="53", NAME="sdd"
KERNEL=="sdb", SUBSYSTEM=="block", ATTR{size}=="976773168", ATTR{capability}=="52", NAME="sda"
KERNEL=="sdb1", SUBSYSTEM=="block", ATTR{size}=="1024000", NAME="sda1"
KERNEL=="sdb2", SUBSYSTEM=="block", ATTR{size}=="975747072", NAME="sda2"
KERNEL=="sdc", SUBSYSTEM=="block", ATTR{size}=="1953525168", ATTR{capability}=="52", NAME="sdb"
KERNEL=="sdc1", SUBSYSTEM=="block", ATTR{size}=="1953520002", NAME="sdb1"

La prima direttiva fa in modo che la partizione della memoria flash (con dimensione pari a 3915639 byte) venga rinominata in sdd1. La seconda direttiva, invece, agisce direttamente sul device, rinominandolo in sdd. Da notare che tutti i campi che contengono le condizioni da matchare per l’identificazione del dispositivo/partizione si avvalgono dell’operatore ==, mentre quelle che agiscono su di essi contengono l’operatore di assegnazione, ovvero =. Inoltre, nell’ambito delle suddette direttive, si fa uso dei caratteri speciali ? e *, con il primo che identifica un solo carattere alfanumerico, e * che identifica qualsiasi occorrenza di caratteri alfanumerici (anche nel caso in cui esse siano pari a 0).

Le rimanenti direttive, stilate sulla falsariga della prima, fanno sì che i dischi rigidi vengano rinominati rispettivamente in /dev/sda e /dev/sdb. Ovviamente tale operazione è da intendersi solo ed esclusivamente nel caso in cui, durante la fase di boot della macchina, la memoria flash sia già collegata ad una porta USB della stessa.

Non ci rimane che testare “in place” (e quindi senza reboot) le suddette regole lanciando il comando:

[root@linuxbox ~]# udevadm test /sys/block/sdX

per i device e:

[root@linuxbox ~]# udevadm test /sys/block/sdX/sdXY

per le parizioni, seguito da un:

[root@linuxbox ~]# ls -ilah /dev

per appurare che i dispositivi siano stati effettivamente mappati secondo le nostre necessità.

Per ora è tutto. A presto.