資料を整理していたら懐かしの資料が出てきた。今ではVSAMに加えストライピングなどの拡張データセットやPDSEも登場しそれらの利用も普及し、従来からのPSやPDSだけではないので簡単に救えるわけではないけれど、せっかくなので備忘録代わりに残そうと思う。
(※この記事にはz/OS DFSMSdfpのDASDボリューム管理の知識を必要とする内容を含みます)
消してしまったデータセットの復活を試みる
考え方の基本は「データセットを消しても、単にVTOCから外れているだけで元のトラック上にはデータは残っている」ということ。消したデータセットが使っていたトラックが、新しく作成した別のデータセットに割り当てられない限りデータは残っているはず、ということに基づく。削除してしまったデータセットが、ボリューム内のどのアドレスにあったかを突き止められるなら、同じ位置に同じ形でデータセットを被せてそこから読み出すことを試みる。
ただし、消してしまったデータセットがワーク・ボリュームなどのいろんなジョブから頻繁に一時的データセットなどが作られるボリュームにあった場合、消してしまったデータセットのトラック・データは、後から作られたデータセットで上書きされている可能性が高いので復活は望み薄。また、バックアップがあるならそこから戻すに超したことはない。バックアップが古すぎて役に立たないとか、バックアップ後の更新を再反映させる手間が多すぎるとか、何とかできないのかと思ったなら試す価値はある。
なお、作業中は対象のDASDボリュームへの新規データセットの作成を禁止すること。既存のデータセットの読み込みはかまわないが書き出しはやめた方がよい。もしエクステントが拡張されると、消したデータセットのトラックが再使用される可能性がある。
復活方法①
PSデータセットであれば、ABSTRアロケーションでボリューム内の元の位置にスペースを割り当てれば、IEBGENERで読み出すことができる。PDSでも同様だが、元のデータセットが複数エクステントに分かれているとかなり面倒である。簡単ではあるが、PSもしくは単一エクステントのPDSにだけ適用できる方法。
※SMS管理データセットや拡張順次データセットは、この方法では復活できません。
- 消してしまったPSデータセットをABSTRアロケーションで再割り振りする
- IEBGENERで元のレコードを読み出す
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//ALLOC EXEC PGM=IEFBR14 //D1 DD DISP=(,KEEP),DSN=WORK.SALVAGE1, // UNIT=SYSDA,VOL=SER=volume,SPACE=(ABSTR,(00100,02325)), // DCB=(DSORG=PS,RECFM=FB,LRECL=???,BLKSIZE=?????) // //ALLOC EXEC PGM=IEFBR14 //D1 DD DISP=(,KEEP),DSN=WORK.SALVAGE1.EXT01, // UNIT=SYSDA,VOL=SER=volume,SPACE=(ABSTR,(00100,02325)), // DCB=(DSORG=PS,RECFM=FB,LRECL=???,BLKSIZE=?????) //D2 DD DISP=(,KEEP),DSN=WORK.SALVAGE1.EXT02, // UNIT=SYSDA,VOL=SER=volume,SPACE=(ABSTR,(00050,09630)), // DCB=(DSORG=PS,RECFM=FB,LRECL=???,BLKSIZE=?????) //D3 DD DISP=(,KEEP),DSN=WORK.SALVAGE1.EXT03, // UNIT=SYSDA,VOL=SER=volume,SPACE=(ABSTR,(00050,14786)), // DCB=(DSORG=PS,RECFM=FB,LRECL=???,BLKSIZE=?????) // |
ABSTR指定のSPACEパラメーターで、元のトラック位置に仮のデータセットを割り振る。DCBパラメーターは消してしまっ
たデータセットと同じものを指定する。複数エクステントで構成されていた場合は、エクステント毎に仮データセットを割り振る。
z/OS V1R11以降では、非SMS管理のPSデータセットであってもスペース割り振り時に、無条件にEOFレコードが書き込まれるようになった。これを防止するにはDSORG=PSではなく、DSORG=DA(もしくはDSORG=PO)を指定する。なお、DAの場合はSDBが計算されないので、BLKSIZEは必ず明示しなければならない。
1 2 3 4 5 |
//ALLOC EXEC PGM=IEFBR14 //D1 DD DISP=(,KEEP),DSN=WORK.SALVAGE1, // UNIT=SYSDA,VOL=SER=volume,SPACE=(ABSTR,(00100,02325)), // DCB=(DSORG=DA,RECFM=FB,LRECL=???,BLKSIZE=?????) // |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
//IEBGENER EXEC PGM=IEBGENER //SYSPRINT DD SYSOUT=* //SYSUT1 DD DISP=SHR,DSN=WORK.SALVAGE1, // UNIT=SYSDA,VOL=SER=volume //SYSUT2 DD DISP=(,CATLG),DSN=元のデータセット名, // UNIT=SYSDA,SPACE=(TRK,(100,50)) //SYSIN DD DUMMY // //IEBGENER EXEC PGM=IEBGENER //SYSPRINT DD SYSOUT=* //SYSUT1 DD DISP=SHR,DSN=WORK.SALVAGE1.EXT01, // UNIT=SYSDA,VOL=SER=volume // DD DISP=SHR,DSN=WORK.SALVAGE1.EXT02, // UNIT=SYSDA,VOL=SER=volume // DD DISP=SHR,DSN=WORK.SALVAGE1.EXT03, // UNIT=SYSDA,VOL=SER=volume //SYSUT2 DD DISP=(,CATLG),DSN=元のデータセット名, // UNIT=SYSDA,SPACE=(TRK,(100,50)) //SYSIN DD DUMMY // |
SYSUT1に仮のデータセットを、SYSUT2に復活させたいデータセット名を新規に割り振ってIEBGENERを実行する。PSデータセットの場合、消してから復元作業までの間に、別のデータセットが割り振られたり、スペースの2次拡張などで元のトラックが上書きされていなければ、これで復元できる。マルチ・エクステントの場合は、エクステント毎の仮データセットをエクステント順に連結させればよい。
なお、仮のデータセットのVTOC DSCB1レコードは、本来あるべき状態になっていないのでISPFではレコード内容を表示できないが、GENERでなら読み出すことができる。
z/OS V1R11以降において、DSORG=DAやPOを指定したABSTRアロケーションした場合は、GENER実行時にSYSUT1 DDステートメントにDCB=(DSORG=PS)を指定すれば、PSデータセットと見なされてコピーできる。
1 2 3 4 5 6 7 8 |
//IEBGENER EXEC PGM=IEBGENER //SYSPRINT DD SYSOUT=* //SYSUT1 DD DISP=SHR,DSN=&SYSUID..SALVAGE1, // UNIT=SYSDA,VOL=SER=volume,DCB=(DSORG=PS) //SYSUT2 DD DISP=(,CATLG),DSN=&SYSUID..SALVAGED.PS1, // UNIT=SYSDA,SPACE=(CYL,(1,1)) //SYSIN DD DUMMY // |
単一エクステントのPDSデータセットは、PSに準じた方法で復活できる。
- 消してしまったPDSデータセットをABSTRアロケーションで再割り振りする
- IEBCOPYで元のメンバーを読み出す
1 2 3 4 5 |
//ALLOC EXEC PGM=IEFBR14 //D1 DD DISP=(,KEEP),DSN=WORK.SALVAGE2, // UNIT=SYSDA,VOL=SER=volume,SPACE=(ABSTR,(00100,02325)), // DCB=(DSORG=PO,RECFM=FB,LRECL=???,BLKSIZE=?????) // |
PDSの場合、ABSTR指定のSPACEパラメーターで元のトラック位置に仮のデータセットを割り振ることは同じだが、絶対にディレクトリー・ブロック数を指定してはならない。DIR数が指定されると、ABSTR割り振りしたスペースの先頭に空のディレクトリー部が作られてしまい、元のデータセットのディレクトリー部は上書きされてしまう。メンバー部は残っているが、ディレクトリーが消えているので、どのメンバーがどこに書かれていたかがわからなくなり復活できない。
1 2 3 4 5 6 7 8 9 |
//IEBCOPY EXEC PGM=IEBCOPY //SYSPRINT DD SYSOUT=* //SYSUT1 DD DISP=SHR,DSN=&SYSUID..SALVAGE2, // UNIT=SYSDA,VOL=SER=volume //SYSUT2 DD DISP=(,CATLG),DSN=元のデータセット名, // UNIT=SYSDA,SPACE=(CYL,(10,5,50)), // DCB=(DSORG=PO,RECFM=FB,LRECL=???,BLKSIZE=?????) //SYSIN DD DUMMY // |
SYSUT1に仮のデータセットを、SYSUT2に復活させたいデータセット名を新規に割り振ってIEBCOPYを実行する。単一エクステントのPDSデータセットも、消してから復元作業までの間に、別のデータセットが割り振られたり、スペースの2次拡張などで元のトラックが上書きされていなければ、これで復元できる。PDSの場合は、ISPFブラウザーで仮データセットのメンバー・リストやメンバー内容を表示させることもできる。
なお、仮のデータセットのVTOC DSCB1レコードは、本来あるべき状態になっていないのでIEBCOPYはディレクトリー部が無いのでは?と警告しCC=8で終了するが、I/Oエラーが起きない限り全メンバーが読み出されコピーされる。
復活方法②
仮のデータセットをABSTRアロケーションするのではなく、VTOCにZAPすることで一時的に復活させる方法もある。昔、誤ってソースやロード・モジュールのライブラリーを消してしまった時に使った。その時は、担当してたPPが持っていたオンラインのDASDパッチツールを使ったが、IMASPZAPでも同様のことができる。
以降に説明する手順は、PSやPDSデータセットについてのもので、エクステントが複数(それも4個以上)にまたがるようなものや、SMS管理の拡張データセットなどをVTOC ZAPで復元するには十分なDFSMSのスキルが必要になる。しかし、上手くできればプログラムなどを作ることなく復活できる可能性がある。
- 同じVOL内で身代わりにするデータセットのDSCBを選択してそのアドレスを求める
- 身代わりになるデータセットのバックアップを取る
- 身代わりになるデータセットのDSCB内のエクステント記述部分を、消してしまったデータセットの元のエクステント・アドレスに書き換える
- 復活したデータセットを別ボリュームにコピーする
- 身代わりデータセットのDSCBを元に戻す
求めるのはデータセットではなくDSCBのアドレス。IEHLIST LISTVTOC/FORMATかDUMPで得られる。
※可能な限り、消してしまったデータセットと同じ形式で、容量やエクステント数が近いものがよい。まったく違うデータセットだと、DSCBの変更量が増えて大変。同じ形式のPSがあるならそれがよい。
拡張フォーマット・データセットでなければSPACE=(TRK,0)で同じ形式のデータセットをアロケートしてもよい。VTOCにDSCB1は追加されるが、どのトラックも割り当てられないので、元のデータセットのトラックには影響しない。
複数のエクステントがあるなら、それに応じて書き換え部分を増やす。なお、元のデータセットが3個を超えるエクステントを持っていた場合、追加のDSCB3を作る必要がある。したがって、身代わりデータセットも4個以上のエクステントを持ち、DSCB3がチェインされているものを選ぶ必要がある。エクステント数が多かったり、ストライピングでいくつものボリュームにまたがっているデータセットの強制復活にチャレンジするには、DFSMSが拡張フォーマットのデータセットやストライピングをどう管理しているか十分に理解してからでないと危険。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//VTOCZAP EXEC PGM=IMASPZAP //SYSPRINT DD SYSOUT=* //SYSLIB DD DISP=OLD,DSN=FORMAT4.DSCB, // UNIT=SYSDA,VOL=SER=volume,DCB=KEYLEN=44 //SYSIN DD * * * UPDATE VTOC DSCB1 TO RESTORE SCRATCHED DATASET * CCHHR 0000000104 VER 006B 000200000002000E REP 006B 000300000003000E ABSDUMP 0000000104 0000000104 // |
これがエクステント・アドレスを付け替えるSPZAPのサンプル。DSCB1はCCHHR=0000-0001-04にある。
身代わりデータセットのエクステント0002-0000~0002-000Eの15トラック分を、消してしまったデータセットのエクステント0003-0000~0003-000Eに付け替える。
単一エクステントで構成された簡単な例で、エクステント・アドレスとDSN以外は、身代わりデータセットと消してしまったデータセットでは同じ場合の例。
DSCBのフィールドとオフセットについてはIECSDSL1マクロで確認できる。または、マニュアル「DFSMSdfp拡張サービス」参照。SPZAP実行時は、コンソールにコンファーム・リプライが上がるので注意。
1 2 3 4 5 6 7 |
//IEBGENER EXEC PGM=IEBGENER(またはICEGENER) //SYSPRINT DD SYSOUT=* //SYSUT1 DD DISP=SHR,DSN=身代わりのデータセット名 //SYSUT2 DD DISP=(,CATLG),DSN=消してしまったデータセットに対応した任意のDSN, // UNIT=SYSDA,VOL=SER=WRKVOL,SPACE=(CYL,(1,1)) SPACE量は必要に応じて指定 //SYSIN DD DUMMY // |
実行後ISPFなどで内容を確認する。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//VTOCZAP EXEC PGM=IMASPZAP //SYSPRINT DD SYSOUT=* //SYSLIB DD DISP=OLD,DSN=FORMAT4.DSCB, // UNIT=SYSDA,VOL=SER=volume,DCB=KEYLEN=44 //SYSIN DD * * * RESTORE ORIGIN DSCB1 * CCHHR 0000000104 VER 006B 000300000003000E REP 006B 000200000002000E ABSDUMP 0000000104 0000000104 // |
これはとても重要な作業。IEBGENERが上手くいって復活できるとそれで安心して終わりにしてしまいがち。ZAPで変更したDSCB1は最終的に元に戻さないと身代わりにしたデータセットにアクセスできなくなるし、ボリューム内の空きスペース管理にも不整合が生じてしまう。
複数エクステントのPDSデータセットのVTOC ZAPによる復活手順
複数エクステントのPDSは、3エクステントまでならABSTRアロケーションとVTOC ZAPを組み合わせて比較的容易に復活させることができる。
- 消してしまったPDSデータセットをABSTRアロケーションで再割り振りする
- 先頭エクステント用の仮データセットのDSCB内のエクステント記述部分を、消してしまったデータセットの元のエクステント・アドレスに書き換える
- IEBCOPYで元のメンバーを読み出す
- 先頭エクステント用の仮データセットのDSCBを元に戻す
1 2 3 4 5 6 7 8 9 10 11 |
//ALLOC EXEC PGM=IEFBR14 //D1 DD DISP=(,KEEP),DSN=&SYSUID..SALVAG4A, // UNIT=SYSDA,VOL=SER=volume,SPACE=(ABSTR,(00010,02390)), // DCB=(DSORG=PO,RECFM=FB,LRECL=???,BLKSIZE=?????) //D2 DD DISP=(,KEEP),DSN=&SYSUID..SALVAG4B, // UNIT=SYSDA,VOL=SER=volume,SPACE=(ABSTR,(00010,02400)), // DCB=(DSORG=PS,RECFM=FB,LRECL=???,BLKSIZE=?????) //D3 DD DISP=(,KEEP),DSN=&SYSUID..SALVAG4C, // UNIT=SYSDA,VOL=SER=volume,SPACE=(ABSTR,(00010,02410)), // DCB=(DSORG=PS,RECFM=FB,LRECL=???,BLKSIZE=?????) // |
複数エクステントのPDSも、複数エクステントのPS同様にエクステント毎に仮データセットを割り振る。ただし、DCBのDSORGにPOを指定するのは先頭エクステント用の仮データセットだけである。また、絶対にディレクトリー・ブロック数を指定してはならない点は、単一エクステントのPDSを復活する際と同じである。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//VTOCZAP EXEC PGM=IMASPZAP //SYSPRINT DD SYSOUT=* //SYSLIB DD DISP=OLD,DSN=FORMAT4.DSCB, // UNIT=SYSDA,VOL=SER=volume,DCB=KEYLEN=44 //SYSIN DD * * * UPDATE VTOC DSCB1 TO RESTORE SCRATCHED DATASET * CCHHR 0000000121 VER 003B 01 REP 003B 03 VER 0073 00000000000000000000 REP 0073 010100A0000000A00009 VER 007D 00000000000000000000 REP 007D 010200A0000A00A10004 ABSDUMP 0000000121 0000000121 // |
オフセットx3Bがエクステント数、オフセットx73が第2エクステント、オフセットx7Dが第3エクステントの場所である。上記のサンプルは、3エクステントで構成されたPDSのもの。2エクステントであれば、オフセットx3Bを02にしてオフセットx73の部分を書き換えればよい。
PDSデータセットがDASDボリューム内でどのように管理されているかの仕組みがわかっていれば、4エクステント以上を持つPDSデータセットでも復活はできる。その場合は、別にDSCB3を作り(適当な空きDSCBを潰す)そのDSCB3をDSCB1にチェインさせるなどの追加作業が必要で、また、その間は同じボリューム内で別の新規データセットの作成やエクステント拡張などがなされないような注意も必要。
1 2 3 4 5 6 7 8 9 |
//IEBCOPY EXEC PGM=IEBCOPY //SYSPRINT DD SYSOUT=* //SYSUT1 DD DISP=SHR,DSN=&SYSUID..SALVAG4A, // UNIT=SYSDA,VOL=SER=volume //SYSUT2 DD DISP=(,CATLG),DSN=元のデータセット名, // UNIT=SYSDA,SPACE=(CYL,(10,5,50)), // DCB=(DSORG=PO,RECFM=FB,LRECL=???,BLKSIZE=?????) //SYSIN DD DUMMY // |
単一エクステントのPDS同様にIEBCOPYでコピーすることで復元できる。仮のデータセットのVTOC DSCB1レコードは、本来あるべき状態になっていないのでIEBCOPYがCC=8で終了する点は単一エクステントの復活時と同じだが、I/Oエラーが起きない限り全メンバーをコピーできる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//VTOCZAP EXEC PGM=IMASPZAP //SYSPRINT DD SYSOUT=* //SYSLIB DD DISP=OLD,DSN=FORMAT4.DSCB, // UNIT=SYSDA,VOL=SER=volume,DCB=KEYLEN=44 //SYSIN DD * * * RESTORE ORIGIN DSCB1 * CCHHR 0000000121 VER 003B 03 REP 003B 01 VER 0073 010100A0000000A00009 REP 0073 00000000000000000000 VER 007D 010200A0000A00A10004 REP 007D 00000000000000000000 ABSDUMP 0000000121 0000000121 // |
ある意味、これが一番重要な作業。IEBCOPYが上手くいって復活できるとそれで安心して終わりにしてしまいがち。ZAPで変更したDSCB1は最終的に元に戻さないといけない。忘れるとボリューム内の空きスペース管理に不整合が生じてしまう。
ABSTRアロケーションにせよ、VTOC ZAPにせよ、消してしまったデータセットがボリューム内のどこに置かれていたかがポイント。それがわからないとどうにもならない。定期的にIEHLISTなどによってVTOCリストなどを取得していればよいが、そうでない場合は、ボリューム内の空きスペース位置を調べてそこのトラック内容などからあたりを付けることになる。それはそれで面倒な作業であるが、バックアップからリストアーできなければやるしかない。
いずれにしても、ABSTRアロケーションとユーティリティーの組み合わせだけの復活方法①でなければ、DASDボリュームのVTOC構造やスペース管理についての知識を必要とするので自信がなければやらないこと。いざとなったらこんな方法もある、ということ。