orm@doc-tcpip.org

Erstellt: August 2007 - Letzte Modifikation: März 2008

[ Main | Local ]


Praxis rund um den VGDA


Der VGDA

Gemeinhin wird unter der Bezeichnis "VGDA" alles zusammengefaßt, was an Informationen vom LVM auf eine Platte gelegt wird, wenn diese in eine VG aufgenommen wird. Das sind aber mehrere Teile, die nicht unbedingt redundant auf der Platte liegen. So gibt es den LVM Record (LVM_REC) pro Platte nur einmal im Block 7. Die anderen Teile (VGSA und VGDA) sind an zwei Stellen vorhanden. Dabei kommt es darauf an, was für eine Art von VG gebaut worden ist.

Die genauen Informationen zur Lage finden sich im LVM_REC. Das Format ist im Header File /usr/include/lvmrec.h festgelegt. Dieser Block wird auf die Platte geschrieben, wenn sie in eine VG aufgenommen wird.

Auslesen und Modifizieren der Daten

Zum informativem auslesen gibt es unter AIX ein Kommando: /usr/sbin/readvgda. Der Aufruf geht gegen das hdisk-Device:

# /usr/sbin/readvgda /dev/hdisk0 | more
Mit dem Kommando kann man auch für einzelne LV Maps erstellen. Dieses Kommando liest immer den ersten VGDA aus. Sollte man Probleme mit dem Quorum haben, dann müßte man den zweiten VGDA von Hand bearbeiten, wie unten gezeigt.

Das Problem ist jetzt, das AIX sehr konservativ ist, was das Schreiben der Information auf den Platten angeht. Mit regulären Kommandos ist eigentlich nur ein Abgleich von der Platte in die ODM möglich (synclvodm). Die VGDAs lassen sich im Prinzip nur durch das Anlegen eines Dummy-LV tatsächlich auf die Platten schreiben, was nur bei kleineren Problemen hilft.

Will man Teile der Information modifizieren (weil sie durch irgendwelche Wunder dritter Ordnung verstrubbelt worden sind), dann muß man mit dem dd-Kommando die relevanten Teile von der Platte ziehen, in einem Hex-Editor ändern und per dd wieder zurücklegen.

Dieses Vorgehen wird dann nötig, wenn nicht die gesamte Information auf allen Platten inkonsistent ist (da hilft das Dummy-LV mit implizitem Neuschreiben des VGDA aller Platten), sondern eine Platte aus der Reihe fällt.

Auslesen mit dem dd-Kommando

Welche Blocks man ausliest, ergibt sich aus der Ausgabe des readvgda Kommandos bzw. aus dem LVM_REC. Nützlich ist da das Redbook "LVM A-Z", da sind die Blöcke beschrieben.

Auslesen des Blocks 7, in dem der LVM_REC steht:

dd if=/dev/hdisk4 of=/tmp/hdisk4.blk7 count=1 skip=7 

Die binäre Datei läßt sich mit dem od-Kommando 
in Hex darstellen:

root@dumpy:/root # od -x /tmp/hdisk4.blk7
0000000  5f4c 564d 00c6 a02f 0000 4c00 0000 0115
0000020  dccc aefd 0000 466a 0000 21ea 0000 0180
0000040  0000 2500 07ff 6a7f 0000 0100 0001 001c
0000060  0000 0100 0000 0080 0000 2400 001e 0000
0000100  0000 0000 0000 0000 0000 0000 0000 0000
*
0001000

od -x gibt hexadezimale 2-Byte Einheiten. Vorne werden
die Zeilen in Oktal gezählt. Die Bytes sind also so
nummeriert:
ByteNr.  0 1  2 3  4 5  6 7  8    10   12   14
                               9    11   13   15
0000000  5f4c 564d 00c6 a02f 0000 4c00 0000 0115
0000020  Und 20 oktal == 16 dezimal 
0001000  1000 oktal == 512 dezimal, also 1 Block

In /usr/include/lvmrec.h findet sich das Layout für den 
LVM Record. Zur Verwirrung werden hier die Bytes 
wieder in Hex gezählt, und zwar vom Offset der 
nutzbaren Platte (E00 == 3540 Byte, 3548/512 = 7,
also sind wir im Block 7).

Das ist der LVM_REC für eine "Standard-VG":
/* Old LVM record layout
00000E00   LVM___ID VGID__W1 VGID__W2 VGID__W3
00000E10   VGID__W4 AREA_LEN VGDA_LEN VGDAPSN0
00000E20   VGDAPSN1 RELOCPSN RELOCLEN PVnmPPsh
00000E30   VGSA_LEN VGSAPSN0 VGSAPSN1 VERnTYPE
00000E40   LTG_SIZE RESERVED RESERVED RESERVED
00000E50   RESERVED RESERVED RESERVED RESERVED
...
00000FF0   RESERVED RESERVED RESERVED RESERVED
*/

Eine neue, scalable VG hat so einen LVM_REC:

/* LVM record layout
00000E00 LVM___ID VGID__W1 VGID__W2 VGID__W3
00000E10 VGID__W4 PPSA_LEN PVM__LEN MWCDBLEN
00000E20 VGI__LEN PVI__LEN LVCBILEN LVEA_LEN
00000E30 PPEA_LEN RESA_LEN PV___NUM VERnPPSZ
00000E40 PPSAPSN0 PPSAPSN0 PPSAPSN1 PPSAPSN1
00000E50 PVM_PSN0 PVM_PSN0 PVM_PSN1 PVM_PSN1
00000E60 MWC_PSN0 MWC_PSN0 MWC_PSN1 MWC_PSN1
00000E70 VGI_PSN0 VGI_PSN0 VGI_PSN1 VGI_PSN1
00000E80 PVI_PSN0 PVI_PSN0 PVI_PSN1 PVI_PSN1
00000E90 LVCBPSN0 LVCBPSN0 LVCBPSN1 LVCBPSN1
00000EA0 LVEAPSN0 LVEAPSN0 LVEAPSN1 LVEAPSN1
00000EB0 PPEAPSN0 PPEAPSN0 PPEAPSN1 PPEAPSN1
00000EC0 VGSAPSN0 VGSAPSN0 VGSAPSN1 VGSAPSN1
00000ED0 VGDAPSN0 VGDAPSN0 VGDAPSN1 VGDAPSN1
00000EE0 VGSA_LEN VGDA_LEN LTG_SIZE BBR__LEN
00000EF0 BBR_PSN0 BBR_PSN0 RESERVED RESERVED
...
00000FF0 RESERVED RESERVED RESERVED RESERVED
*/ 

Die einzelnen Felder sind jeweils in Wörtern, also
2 Byte. So ergibt sich:

LVM_ID == 5f4c 564d
Das ist immer so, es ist "_LVM" in ASCII.

Die VGID sind 4 Wörter:
VGID == 00c6 a02f 0000 4c00 0000 0115 dccc aefd

Das deckt sich jetzt alles ganz wunderbar mit 
der Ausgabe des LVM_REC aus readvgda (man kann
also ganz sorgenlos dieses Kommando benutzen):

lvmid:       1598838349 (5f4c564d)         => LVM___ID 
vgid:     00c6a02f00004c0000000115dcccaefd => VGID__W1 - W4
lvmarea_len: 18026                         => AREA_LEN
vgda_len:    8682                          => VGDA_LEN
vgda_psn[0]: 384                           => VGDAPSN0
vgda_psn[1]: 9472                          => VGDAPSN1
reloc_psn:   134179455                     => RELOCPSN
pv_num:      1                             => PVnmPPsh 
pp_size:     28                            => PVnmPPsh
vgsa_len:    256                           => VGSA_LEN
vgsa_psn[0]: 128                           => VGSAPSN0
vgsa_psn[1]: 9216                          => VGSAPSN1
version:     30                            => VERnTYPE
vg_type:     0                             => VERnTYPE
ltg_shift:   0(128K)                       => LTG_SIZE

Auf diese Weise findet man jetzt auch die Lage von
VGDA und VGSA - wo es losgeht, zeigen diese
Einträge, jeweils für 1. und 2. Kopie. Das ist
der Block, wo VGDA und VGSA beginnen:

vgda_psn[0]: 384
vgda_psn[1]: 9472

vgsa_psn[0]: 128
vgsa_psn[1]: 9216

Dann muß man nur noch herausfinden, wieviel man 
auslesen muß. Das sind folgende Werte in Byte:
vgda_len:    8682
vgsa_len:    256

Die Werte teilt man durch 512 (ein Block, und man
muß auf volle Blöcke aufrunden). Das ist der
Count für das dd-Kommando.

Will man also die beiden VGDAs der Platte:

dd if=/dev/hdisk4 of=/tmp/hdisk4.vgda1 count=17 skip=384
dd if=/dev/hdisk4 of=/tmp/hdisk4.vgda2 count=17 skip=9472

Sinngemäß dasselbe für den VGSA, wobei der nur einen halben
Block lang ist.

dd if=/dev/hdisk4 of=/tmp/hdisk4.vgsa1 count=1 skip=128
dd if=/dev/hdisk4 of=/tmp/hdisk4.vgsa2 count=1 skip=9216

root@dumpy:/tmp # od -x hdisk4.vgsa1
0000000  479f 60f4 20ba c8bc 0000 0000 0000 0000
0000020  0000 0000 0000 0000 0000 0000 0000 0000
*
0001000

Das ist der Zeitstempel in dezimalen Sekunden seit Epoch, 
dann das Feld mit den Stale-Flags pro PP.
 
Wenn man nun hoffentlich einen Fehler identifiziert hat, 
kann man den entsprechenden Teil von LVM_REC, VGSA oder
VGDA mit einem Hex-Editor editieren (z.B. khex im KDE).

Das Ergebniss mutig mit dem dd-Kommando zurückschreiben
und freuen...

Ein Beispiel-VGDA zerpflückt

*****************************************
LVMREC at block 7 
*****************************************
lvmid:       1598838349 (5f4c564d)
vgid:     00c6a02f00004c0000000115dcccaefd
lvmarea_len: 18026
vgda_len:    8682
vgda_psn[0]: 384
vgda_psn[1]: 9472
reloc_psn:   134179455
pv_num:      1
pp_size:     28
vgsa_len:    256
vgsa_psn[0]: 128
vgsa_psn[1]: 9216
version:     30
vg_type:     0
ltg_shift:   0(128K)
Das ist der LVM_REC, den gibt es, wie schon gesagt, nur einmal auf jeder Platte. Die lvmid ist immer gleich, die VGID die der VG - die muß in allen LVM_RECs und VGDAs aller Platten gleich sein. Wichtig sind die Größen und Offsets des VGSA und des VGDA: Länge vgsa_len, Offset für 1. VGSA vgsa_psn[0], Offset für 2. VGSA vgsa_psn[1]. Analog für den VGDA. Eine genaue Beschreibung der Felder gibt es in /usr/include/lvmrec.h.
*=============== 1ST VGDA-VGSA: /dev/hdisk4 ===============*

*****************************************
VGSA at block 128
*****************************************
*****************************************
vgsa beg: timestamp 1196161260 (474bf8ec), 620686730 (24feed8a)
vgsa beg: timestamp Tue Nov 27 12:01:00 MEZ:2007
vgsa.pv_missing:        0
vgsa.stalepp[0]:       0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
vgsa.stalepp[1]:       0 fe 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
vgsa.stalepp[2]:       0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
vgsa.stalepp[3]:       0 fe 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
vgsa.factor:    1
vgsa.pad2:      0 0 0
lv_dirty_bit:
 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0|
vgsa end: timestamp 1196161260 (474bf8ec), 620686730 (24feed8a)
vgsa end: timestamp Tue Nov 27 12:01:00 MEZ:2007
Das ist jetzt der VGSA. Er beginnt mit dem Zeitstempel, dann folgt ein Flag, das gesetzt wird, wenn ein PV in der VG fehlt. Dann folgen die Felder mit den Flags für Stale PPs. Der VGSA Faktor ist die Folge, wenn man eine VG mit dem "t-Faktor" anlegt und so das Feld für die Flags vergrößert. Dann ein Feld, indem Dirty-Flags für nicht synchronisierte LV gesetzt werden können. Zum Schluß nochmal ein Zeitstempel.
*****************************************
VGDA at block 384
*****************************************
*****************************************
vgh.vg_id:    00c6a02f00004c0000000115dcccaefd
vgh.numlvs:      2
vgh.maxlvs:      512
vgh.pp_size:     28
vgh.numpvs:      4
vgh.total_vgdas: 4
vgh.bigda_size:  8682
vgh.vgtype:      1
vgh.quorum:      0
vgh.auto_varyon: 0
vgh.check_sum:   0
vgh.snapshotvg:  0
vgh.snapshot_copy: 0
vgh.primary_vgid: 00000000000000000000000000000000
vgh.seconadary_vgid: 00000000000000000000000000000000
vgda hdr: timestamp 1196161665 (474bfa81), 357995727 (155694cf)
vgda hdr: timestamp Tue Nov 27 12:07:45 MEZ:2007
Die Daten der VG: VGID, PP Size, Typ der VG, Anzahl der PV, die die VG bilden, Anzahl der LV. Beim Typ der VG sind folgende Werte möglich: 0 = OldVG, 1 = BigVG, 2 = Scalable VG.
**********  Logical Volume: maestrofta1lv  ***********
lv_entries.lvname:              0
lv_entries.maxsize:             512
lv_entries.lv_state:            1
lv_entries.mirror:              2
lv_entries.mirror_policy:       2
lv_entries.num_lps:             4
lv_entries.permissions:         1
lv_entries.bb_relocation:       1
lv_entries.write_veryfy:        2
lv_entries.mirwrt_consist:      1
lv_entries.stripe_exp:          0
lv_entries.striping_width:      0
lv_entries.lv_avoid:            0
lv_entries.child_minor_num:     0
lv_entries.dev_uid:             0
lv_entries.dev_gid:             0
lv_entries.dev_perm:            432
lv_entries.lvcb.type:           jfs2
lv_entries.lvcb.created_time:   Fri Oct 26 16:52:54 2007
lv_entries.lvcb.modified_time:  Fri Oct 26 16:53:06 2007
lv_entries.lvcb.relocatable:    y
lv_entries.lvcb.interpolicy:    m
lv_entries.lvcb.intrapolicy:    m
lv_entries.lvcb.strict:         s
lv_entries.lvcb.upperbound:     2
lv_entries.lvcb.label:          /applications/maestro1
lv_entries.lvcb.fs:             vfs=jfs2:log=INLINE:type=db1:account=false
**********  Logical Volume: tivoli_lcf_a_lv  ***********
lv_entries.lvname:              1
lv_entries.maxsize:             512
lv_entries.lv_state:            1
lv_entries.mirror:              2
lv_entries.mirror_policy:       2
lv_entries.num_lps:             1
lv_entries.permissions:         1
lv_entries.bb_relocation:       1
lv_entries.write_veryfy:        2
lv_entries.mirwrt_consist:      1
lv_entries.stripe_exp:          0
lv_entries.striping_width:      0
lv_entries.lv_avoid:            0
lv_entries.child_minor_num:     0
lv_entries.dev_uid:             0
lv_entries.dev_gid:             0
lv_entries.dev_perm:            432
lv_entries.lvcb.type:           jfs2
lv_entries.lvcb.created_time:   Fri Oct 26 16:52:58 2007
lv_entries.lvcb.modified_time:  Fri Oct 26 16:53:13 2007
lv_entries.lvcb.relocatable:    y
lv_entries.lvcb.interpolicy:    m
lv_entries.lvcb.intrapolicy:    m
lv_entries.lvcb.strict:         s
lv_entries.lvcb.upperbound:     2
lv_entries.lvcb.label:          /opt/Tivoli/lcf_A
lv_entries.lvcb.fs:             vfs=jfs2:log=INLINE:type=db1:account=false
Für jedes der zwei vorhanden LV folgt ein Control-Block mit den wichtigen Daten zum LV.
**********  Physical Volume: 1  ***********
pvh.pv_num:      1
pvh.pv_id:       00c6a02fdccca6a4
pvh.pp_count:    255
pvh.pv_state:    1
pvh.pvnum_vgdas: 1
pvh.psn_part1:   18176
*  pv_num:pp_num:pp_state   lv_name:lp_num:pp_copy_val:pv_fst_mir:part_fst_mir:pv_snd_mir:part_snd_mir
*  pv1:  2:1   maestrofta1lv:3:1:2:2:0:0
*  pv1:  3:1   maestrofta1lv:4:1:2:3:0:0
Jetzt kommt pro PV ein Datensatz: Logische Nummer des PV, PVID, Anzahl PP, Status des PV. Die Nummern dazu findet man in /usr/include/lvm.h ( 0 = not defined, 1 = aktive, 2 = PV missing, 4 = PV removed, 16 = PV stale etc.). Dann folgt die PP-Map der LV, die auf dieser Platten Daten haben.
**********  Physical Volume: 2  ***********
pvh.pv_num:      2
pvh.pv_id:       00c6a02fdccca8fc
pvh.pp_count:    255
pvh.pv_state:    1
pvh.pvnum_vgdas: 1
pvh.psn_part1:   18176
*  pv_num:pp_num:pp_state   lv_name:lp_num:pp_copy_val:pv_fst_mir:part_fst_mir:pv_snd_mir:part_snd_mir
*  pv2:  2:1   maestrofta1lv:3:2:1:2:0:0
*  pv2:  3:1   maestrofta1lv:4:2:1:3:0:0
**********  Physical Volume: 3  ***********
pvh.pv_num:      3
pvh.pv_id:       00c6a02fdcccab41
pvh.pp_count:    255
pvh.pv_state:    1
pvh.pvnum_vgdas: 1
pvh.psn_part1:   18176
*  pv_num:pp_num:pp_state   lv_name:lp_num:pp_copy_val:pv_fst_mir:part_fst_mir:pv_snd_mir:part_snd_mir
*  pv3:  2:1   maestrofta1lv:1:1:4:2:0:0
*  pv3:  3:1   maestrofta1lv:2:1:4:3:0:0
*  pv3:  4:1   tivoli_lcf_a_lv:1:1:4:4:0:0
**********  Physical Volume: 4  ***********
pvh.pv_num:      4
pvh.pv_id:       00c6a02fdcccae29
pvh.pp_count:    255
pvh.pv_state:    1
pvh.pvnum_vgdas: 1
pvh.psn_part1:   18176
*  pv_num:pp_num:pp_state   lv_name:lp_num:pp_copy_val:pv_fst_mir:part_fst_mir:pv_snd_mir:part_snd_mir
*  pv4:  2:1   maestrofta1lv:1:2:3:2:0:0
*  pv4:  3:1   maestrofta1lv:2:2:3:3:0:0
*  pv4:  4:1   tivoli_lcf_a_lv:1:2:3:4:0:0
*****************************************
vgt.concurrency:        32
vgda trl: timestamp 1196161665 (474bfa81), 357995727 (155694cf)
vgda trl: timestamp Tue Nov 27 12:07:45 MEZ:2007
Am Ende noch ein Zeitstempel.


[ Main | Local ]

[ Allgemein | UNIX | AIX | TCP-IP | TCP | ROUTING | DNS | NTP | NFS | FreeBSD | Linux | SMTP | Tracing | GPS ]

Copyright 2001-2014 by Orm Hager - Es gilt die GPL
Feedback bitte an: Orm Hager (orm@doc-tcpip.org )