Come mappare gli identificatori ataX.0 nei messaggi di errore kern.log su dispositivi / dev / sdY effettivi?


11

Prendi in considerazione il seguente kern.logframmento:

 ata4.00: failed command: WRITE FPDMA QUEUED
 ata4.00: cmd 61/00:78:40:1e:6c/04:00:f0:00:00/40 tag 15 ncq 524288 out
        res 41/04:00:00:00:00/04:00:00:00:00/00 Emask 0x1 (device error)
 ata4.00: status: { DRDY ERR }
 ata4.00: error: { ABRT }
 ata4: hard resetting link
 ata4: nv: skipping hardreset on occupied port
 ata4: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
 ata4.00: configured for UDMA/133
 ata4: EH complete

Come posso identificare quale disco rigido il kernel intende effettivamente quando parla ata4.00?

Come posso trovare il /dev/sdYnome del dispositivo corrispondente ?

Risposte:


10

Puoi trovare il corrispondente dispositivo / dev / sdY attraversando l' /sysalbero:

$ find /sys/devices | grep '/ata[0-9]\+/.*/block/s[^/]\+$' \
    | sed 's@^.\+/\(ata[0-9]\+\)/.\+/block/\(.\+\)$@\1 => /dev/\2@'

Con un /systraversal più efficiente (cfr. Lsata.sh ):

$ echo /sys/class/ata_port/ata*/../../host*/target*/*/block/s* | tr ' ' '\n' \
    | awk -F/ '{printf("%s => /dev/%s\n", $5, $NF)}'

Esempio di output da un sistema a 2 dischi:

ata1 => /dev/sda
ata2 => /dev/sdb

Quindi, per identificare in modo affidabile l'hardware effettivo è necessario mappare / dev / sdY al numero di serie, ad esempio:

$ ls /dev/disk/by-id -l | grep 'ata.*sd[a-zA-Z]$'

lssci

L' lssciutilità può anche essere utilizzata per derivare il mapping:

$ lsscsi | sed 's@^\[\([^:]\+\).\+\(/dev/.\+\)$@\1,\2@' \
    | awk -F, '{ printf("ata%d => %s\n", $1+1, $2) }'

Si noti che l'enumerazione lsscsi pertinente inizia da 0 mentre l'enumerazione ata inizia da 0.

syslog

Se nient'altro funziona, si può guardare il syslog / journal per ricavare la mappatura.

I /dev/sdYdispositivi vengono creati nello stesso ordine in cui sono elencati gli identificativi ataX kern.logmentre si ignorano i dispositivi non disco (ATAPI) e i collegamenti non connessi.

Pertanto, il comando seguente visualizza il mapping:

$ grep '^May 28 2'  /var/log/kern.log.0  | \
   grep 'ata[0-9]\+.[0-9][0-9]: ATA-' | \
   sed 's/^.*\] ata//' | \
   sort -n | sed 's/:.*//' | \
   awk ' { a="ata" $1; printf("%10s is /dev/sd%c\n", a, 96+NR); }'
ata1.00 is /dev/sda
ata3.00 is /dev/sdb
ata5.00 is /dev/sdc
ata7.00 is /dev/sdd
ata8.00 is /dev/sde
ata10.00 is /dev/sdf

(Notare che ata4 non viene visualizzato perché i messaggi di registro sopra riportati provengono da un altro sistema.)

Sto usando /var/log/kern.log.0e non /var/log/kern.logperché i messaggi di avvio sono già ruotati. Grep per May 28 2perché questo è stato l'ultimo tempo di avvio e voglio ignorare i messaggi precedenti.

Per verificare la mappatura è possibile effettuare alcuni controlli guardando l'output di:

$ grep '^May 28 2'  /var/log/kern.log.0  | \
grep 'ata[0-9]\+.[0-9][0-9]: ATA-'
May 28 20:43:26 hn kernel: [    1.260488] ata1.00: ATA-7: SAMSUNG SV0802N, max UDMA/100
May 28 20:43:26 hn kernel: [    1.676400] ata5.00: ATA-5: ST380021A, 3.19, max UDMA/10
[..]

E puoi confrontare questo output con hdparmoutput, ad esempio:

$ hdparm -i /dev/sda

/dev/sda:

Model=SAMSUNG SV0802N [..]

(usando il kernel 2.6.32-31)


È semplicemente fantastico, grazie mille per questa eccellente risposta ...
stuartc

@stuarte, prego - btw, cks ha scritto un articolo su tutti i diversi schemi di denominazione dei dispositivi SATA sugli attuali sistemi Linux . Per quanto riguarda gli identificatori di ataX, scrive: "Questi nomi non appaiono affatto nel sysfs per quanto posso vedere"
maxschlepzig

1
Hmm. Il mio problema con l'operazione di verifica di questo è che in genere ho 8+ dischi dello stesso modello esatto, quindi i controlli del produttore non sono così preziosi.
drescherjm,

1
@drescherjm, ho aggiornato la mia risposta. Il nuovo metodo dovrebbe essere solido e quindi eliminare qualsiasi necessità di un controllo del fornitore.
maxschlepzig

Ho quello che penso sia uno script sysfs migliorato; in particolare gestisce numeri ata a doppia cifra (/ ata [0-9] / non corrisponde a ata10) e trova anche dispositivi sata non chiamati sd * (es. sr0): per un in / sys / class / ata_port / ata * ; do printf '% s \ t% s \ n' "$ (basename" $ ​​a ")" "$ (trova" $ a / device / "-iname 'block' -exec ls {} \;)"; fatto
Jason

2

Ecco la mia versione, modificata dall'alto. Dato che non conosco la data esatta in cui è stato avviato il sistema (per testarlo è stato 27 giorni fa), e non so quale kern.log contenga i dati di cui ho bisogno (alcuni potrebbero essere gzippedsul mio sistema), uso uptimee dateper calcolare una data di avvio approssimativa del sistema (al giorno, comunque), quindi usare zgrepper cercare tutti i file kern.log disponibili.

Ho anche modificato leggermente la seconda grepistruzione, poiché ora mostrerà anche un'unità CD / DVD ATAPI e unità ATA- *.

Potrebbe comunque utilizzare il perfezionamento (ovvero se il tempo di attività del sistema è superiore a un anno), ma per ora dovrebbe funzionare correttamente.

#!/bin/bash

uptime=$(uptime | awk -F' '  '{ print $3" "$4 }' | sed s/,//)
date=$(date -d "$uptime ago" | awk '{print $2" "$3 }')
zgrep "$date"  /var/log/kern.log*  | \
grep 'ata[0-9]\+.[0-9][0-9]: ATA'  | \
sed 's/^.*\] ata//' | \
sort -n | sed 's/:.*//' | \
awk ' { a="ata" $1; printf("%10s is /dev/sd%c\n", a, 96+NR); }'

1

Ho appena avuto lo stesso problema e ho trovato un'altra soluzione che potrebbe piacere.

Lo strumento lsscsi elenca i dispositivi (o host) SCSI e il loro attributo.

Con lsscsi si ottengono il nome ata e il nome del dispositivo.

Somiglia a questo:

$ lsscsi --long
[0:0:1:0]    cd/dvd  MATSHITA DVD-ROM UJDA780  1.50  /dev/sr0
  state=running queue_depth=1 scsi_level=6 type=5 device_blocked=0 timeout=30
[2:0:0:0]    disk    ATA      WDC WD3000FYYZ-0 01.0  /dev/sda
  state=running queue_depth=1 scsi_level=6 type=0 device_blocked=0 timeout=30
[3:0:0:0]    disk    ATA      WDC WD1002FBYS-0 03.0  /dev/sdb
  state=running queue_depth=1 scsi_level=6 type=0 device_blocked=0 timeout=30
[4:0:0:0]    disk    ATA      WDC WD1002FBYS-0 03.0  /dev/sdc
  state=running queue_depth=1 scsi_level=6 type=0 device_blocked=0 timeout=30
[5:0:0:0]    disk    ATA      WDC WD1002FBYS-0 03.0  /dev/sdd
  state=running queue_depth=1 scsi_level=6 type=0 device_blocked=0 timeout=30
[6:0:0:0]    disk    ATA      WDC WD3000FYYZ-0 01.0  /dev/sde
  state=running queue_depth=1 scsi_level=6 type=0 device_blocked=0 timeout=30
[7:0:0:0]    disk    ATA      WDC WD1002FBYS-0 03.0  /dev/sdf
  state=running queue_depth=1 scsi_level=6 type=0 device_blocked=0 timeout=30

Su Ubuntu è possibile installare lsscsi semplicemente con

$ sudo apt-get install lsscsi

2
hm, e in che modo la ataXmappa con quale parte lsscsidell'output?
maxschlepzig,

1
@maxschlepzig Il primo numero in: quads è lo stesso di ataX con un'importante distinzione; l'output di lsscsi è indicizzato 0 e ataZ è 1 indicizzato; quindi [2: 0: 0: 0] sarebbe ata3 che è / dev / sda nell'output pubblicato da longsleep
Jason

@Jason, ok, ecco una lsscsi | sed 's@^\[\([^:]\+\).\+\(/dev/.\+\)$@\1,\2@' | awk -F, '{ printf("ata%d => %s\n", $1+1, $2) }'
riga

@Jason, vedi anche la mia risposta aggiornata per un'alternativa che accede direttamente /sys/devicessenza lsscsi.
maxschlepzig,

0

Nessuna delle risposte di cui sopra ha funzionato per me e l'approccio lsscsi ha effettivamente prodotto la risposta sbagliata, a causa delle discrepanze tra i numeri del bus SCSI e i numeri ATA. Su un sistema a 21 dischi, ho avuto molti rapporti syslog su problemi con ATA18 (violazioni di HSM). Quale disco ha causato questi errori? Alcuni erano unità USB, il che rendeva le cose molto più confuse. Avevo bisogno di una contabilità di come ogni singola unità SCSI è collegata al sistema e ho scritto lo script seguente che fornisce elenchi tabulari per tutti i dischi SCSI (/ dev / s [dr]?) Indipendentemente dal fatto che ATA o USB.

Quindi, con tutte le unità disco completamente contabilizzate, sono stato sorpreso di vedere che i miei errori ATA non avevano nulla a che fare con nessuna delle mie unità disco. Avevo fatto la domanda sbagliata e penso che altri potrebbero facilmente cadere nella stessa trappola, motivo per cui lo menziono qui. Ho quindi utilizzato un secondo approccio che ha identificato l'hardware che stava generando i messaggi di violazione HSM, dettagliato anche nella documentazione che appare nello script seguente.

#!/bin/bash

## This script lists the ata and usb bus numbers, as well as the
## overall "host" numbers, of each scsi disk.  The same information
## appears formatted four ways, redundantly, for ease of lookup by (1)
## device lettername, (2) ata bus, (3) usb bus, or (4) overall "host"
## number.

#######################################################

## Q: What if you're looking for an ATA bus number, e.g. ata18, that
##    isn't listed by this script?

## (1) Well, it's probably not a SCSI disk, at least not one that's
##     operating.

## (2) Somewhere in /sys you can find a mapping from the ATA bus
##     number to some overall host number, such as host17.  For example,
##     if you're looking for ata18, you can use a find command...

##     find /sys -type l -exec bash -c 'link=`readlink "$0"`; if [[ "$link" =~ /ata18/ ]] ; then echo $link ; fi' {} \;

##     ...which, after some delay, might yield output something like this:

##    ../../devices/pci0000:00/0000:00:02.0/0000:02:00.0/ata18/ata_port/ata18
##    ../../devices/pci0000:00/0000:00:02.0/0000:02:00.0/ata18/host17/target17:0:0/17:0:0:0/scsi_generic/sg5
##    ../../devices/pci0000:00/0000:00:02.0/0000:02:00.0/ata18/link18/dev18.0/ata_device/dev18.0
##    ../../devices/pci0000:00/0000:00:02.0/0000:02:00.0/ata18/host17/scsi_host/host17
##    ../../devices/pci0000:00/0000:00:02.0/0000:02:00.0/ata18/link18/ata_link/link18
##    ../../devices/pci0000:00/0000:00:02.0/0000:02:00.0/ata18/host17/target17:0:0/17:0:0:0/bsg/17:0:0:0
##    ../../devices/pci0000:00/0000:00:02.0/0000:02:00.0/ata18/host17/target17:0:0/17:0:0:0/scsi_device/17:0:0:0
##    ../../devices/pci0000:00/0000:00:02.0/0000:02:00.0/ata18/host17/target17:0:0/17:0:0:0/scsi_generic/sg5
##    ../../devices/pci0000:00/0000:00:02.0/0000:02:00.0/ata18/host17/target17:0:0/17:0:0:0/bsg/17:0:0:0
##    ../../../devices/pci0000:00/0000:00:02.0/0000:02:00.0/ata18/host17/target17:0:0/17:0:0:0
##    ../../../devices/pci0000:00/0000:00:02.0/0000:02:00.0/ata18/host17
##    ../../../devices/pci0000:00/0000:00:02.0/0000:02:00.0/ata18/host17/target17:0:0

##     Then you might notice the "/host17/" or "scsi_device/17:0:0:0"
##     in the above output lines, and look in the output of...

##     lshw

##     .. for "scsi17" or "17:0" or such, and discover, somewhere in it ...

##     ...
##        *-scsi:5
##           physical id: 8
##           logical name: scsi17
##           capabilities: emulated
##         *-processor UNCLAIMED
##              description: SCSI Processor
##              product: 91xx Config
##              vendor: Marvell
##              physical id: 0.0.0
##              bus info: scsi@17:0.0.0
##              version: 1.01
##              capabilities: removable
##              configuration: ansiversion=5
##     ...

## ...thus learning that ata18 corresponds to an unclaimed device (but
## not actually a disk).  Q.E.D.

## P.S. the lsscsi command yields the following, which might lead
## one to think that the problem was being caused by a CD-ROM drive
## (SCSI18:0) rather than emanating from the Marvell (SCSI17:0):

## [17:0:0:0]   process Marvell  91xx Config      1.01  -        
## [18:0:0:0]   cd/dvd  HL-DT-ST DVDRAM GH22NS90  HN00  /dev/sr0 

## ... but ATA != SCSI, and 17 != 18.  The CD/DVD drive was ATA19, 
## actually.  You can still use lsscsi, but
## bear in mind that what you're seeing in the left column
## is *not* ATA numbers but rather SCSI bus numbers, and the two
## are not to be confused.
#######################################################

blockDevsDir=/sys/dev/block

declare -A scsiDevLetters
declare -A hostNumbers
declare -A ataNumbers
declare -A usbNumbers

scsiDevLetterRE='/s(d[a-z]|r[0-9])$'
hostNumberRE='/host([0-9]+)/'
ataNumberRE='/ata([0-9]+)/'
usbNumberRE='/usb([0-9]+)/'

cd "$blockDevsDir"
for busid in `ls -1` ; do
    linkval=`readlink "$busid" `
    if [[ "$linkval" =~ $scsiDevLetterRE ]] ; then
        scsiDevLetter="${BASH_REMATCH[1]}"
        if [[ "$linkval" =~ $hostNumberRE ]] ; then
            hostNumber="${BASH_REMATCH[1]}"
            if [[ "$linkval" =~ $ataNumberRE ]] ; then
                ataNumber="${BASH_REMATCH[1]}"
                scsiDevLetters[$scsiDevLetter]=`printf 'ata%-2.2s  host%-2.2s' "${ataNumber}" "${hostNumber}"`
                hostNumbers[${hostNumber}]=`printf '/dev/sd%s  ata%-2.2s' "${scsiDevLetter}" "${ataNumber}"`
                ataNumbers[${ataNumber}]=`printf '/dev/sd%s  host%-2.2s' "${scsiDevLetter}" "${hostNumber}"`
            elif [[ "$linkval" =~ $usbNumberRE ]] ; then
                usbNumber="${BASH_REMATCH[1]}"
                scsiDevLetters[$scsiDevLetter]=`printf 'usb%-2.2s  host%-2.2s' "${usbNumber}" "${hostNumber}"`
                hostNumbers[${hostNumber}]=`printf '/dev/sd%s  usb%-2.2s' "${scsiDevLetter}" "${usbNumber}"`

                existingUsbValue="${usbNumbers[${usbNumber}]}"
                addedUsbValue=`printf '/dev/sd%s  host%-2.2s' "${scsiDevLetter}" "${hostNumber}"`
                if [ -n "$existingUsbValue" ] ; then
                    usbNumbers[${usbNumber}]="$existingUsbValue | $addedUsbValue"
                else
                    usbNumbers[${usbNumber}]="$addedUsbValue"
        fi
            else
        echo "Neither ata nor usb: /dev/sd${scsiDevLetter} (host${hostNumber}) !"
            fi
        else
        echo "No host number for /dev/sd${scsiDevLetter}"
        fi
    fi
done    

echo '/dev/sd?'
echo '--------'
for scsiDevLetter in `echo "${!scsiDevLetters[*]}" | tr ' ' '\n' | sort` ; do
    echo "/dev/sd${scsiDevLetter}    ${scsiDevLetters[$scsiDevLetter]}"
done
echo
echo 'ataNN'
echo '-----'
for ataNumber in `echo "${!ataNumbers[*]}" | tr ' ' '\n' | sort -n` ; do
    printf 'ata%-2.2s    %s\n' "$ataNumber" "${ataNumbers[$ataNumber]}"
done
echo
echo 'usbNN'
echo '-----'
for usbNumber in `echo "${!usbNumbers[*]}" | tr ' ' '\n' | sort -n` ; do
    printf 'usb%-2.2s    %s\n' "$usbNumber" "${usbNumbers[$usbNumber]}"
done
echo
echo 'hostNN'
echo '------'
for hostNumber in `echo "${!hostNumbers[*]}" | tr ' ' '\n' | sort -n` ; do
    printf 'host%-2.2s    %s\n' "$hostNumber" "${hostNumbers[$hostNumber]}"
done
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.