連載
» 2004年03月30日 00時00分 公開

Linuxファイルシステム技術解説(6):JFSのファイル管理とジャーナリングの実装 (2/3)

[菅谷みどり, 木村浩章, 杵渕雄樹,@IT]

JFSのジャーナリングと障害回復

 JFSのジャーナリングは、ext3およびReiserFSと同様にメタ・データを保存する。

JFSのジャーナリング処理

 JFSを通したディスク操作は、「ファイル生成」「リンク」「ディレクトリ作成」「データ削除」など、複数のトランザクションに分割して処理される。これらの操作は、ディスクとログの同期も含めてジャーナルログに記録される。

 ジャーナルログはまずメモリに記録され、JFSのフラッシュデーモンによってディスクへ書き込まれる。JFSのディスク復旧は、ジャーナルログを読み込んでディスク操作を再生(redo)することで行われる(redo操作はjfs.fsckコマンドに含まれている)。redoは、実際に行われた操作を時系列に沿って再実行する。ジャーナルログには、実際に行われたディスクとジャーナルログの同期情報も記録されるため、障害復旧時は同期後のログデータのみを再生することで無駄な処理が発生しないようになっている。

 ジャーナルログはファイルシステムの作成時(mkfs.jfs)に、一緒に作成される。デフォルトでは、ファイルシステムの総和の0.4%、最大サイズは32Mbytesとなっている。

ジャーナルログを基にした復旧作業

 障害が発生すると、JFSはジャーナルログを参照しながら最終コミット以降の復旧を試みる。具体的には、以下の順番で処理が行われる。

  1. スーパーブロックチェック
    ジャーナルログを開いて最初にスーパーブロックを読み込み、バージョン情報や状態フィールド、マジックナンバーなどのチェックを行う。このとき、状態(state)が「LOGREDONE」(すでにジャーナルログの再生が終了している)になっている場合は、単にスーパーブロックの更新を行って終了する。それ以外の場合は以下の作業を続行する。

  2. ジャーナルログレコードの再生開始ポイントの検出
    ジャーナルログの最後尾を探し出し、トランザクションの処理内容を調査する。

    ディスクと同期を行う同期点(sync point)は、ジャーナルログレコードに「SYNCPT」と記録される。ジャーナルログにSYNCPTが記録されていれば、その時点でディスクと同期したことが分かる。

    ジャーナリングシステムの障害回復という観点からいえば、このSYNCPTより前の情報はディスクとログの同期が保証されるため、復旧操作は必要ない。実際に復旧が必要なのは、まだディスクと同期が行われていないSYNCPT以降の操作である。故に、JFSはこのSYNCPT以降のトランザクションの操作を調査するために、ジャーナルログレコードの処理手順を再生(replay)する。

  3. ジャーナルログレコードの再生
    ジャーナルログレコードの再生開始ポイントを検出したら、時系列に沿って処理を再生する。

  4. トランザクションのチェック
    ジャーナルログを再生した後、各トランザクション処理が時系列的に矛盾のないことをチェックし、バッファをディスクにフラッシュする。

  5. 終了処理
    iノードの割り当てマップおよびスーパーブロックを更新する。

jfs_dumpによるジャーナルログの参照

 JFSが行うジャーナリングのロギングは、jfs_logdumpコマンドで取得したジャーナルログのダンプメッセージで確認できる。

 以下の例は、/dev/hda3をJFSのパーティションとしたときのジャーナルログの処理内容を示している。

# jfs_logdump /dev/hda3
jfs_logdump version 1.1.3、 05-Sep-2003
Device Name: /dev/hda3
JFS_LOGDUMP: The current JFS log has been dumped into ./jfslog.dmp

 jfs_logdumpによって生成されたjfslog.dmpは、以下のようになる。

JOURNAL SUPERBLOCK:
------------------------------------------------------
   magic number: x 87654321
   version     : x 1
   serial      : x 9
   size        : t 7168 pages (4096 bytes/page)
   bsize       : t 4096 bytes/block
   l2bsize     : t 12
   flag        : x 10200900
   state       : x 1
   end         : x 1a1c7b0
======================================================
**WARNING** jfs_logdump and log file /dev/hda3 state is LOGREDONE
======================================================
logrec d 0   Logaddr= x 1bfff78   Nextaddr= x 1bfff54   Backchain
 = x  1bfff54
LOG_COMMIT     (type = d 32768)     logtid = d 5781
        data length = d 0
---------------------------------------------------------------------
logrec d 1   Logaddr= x 1bfff54  Nextaddr= x 1bffeac  Backchain
 = x 0
LOG_REDOPAGE   (type = d 2048)     logtid = d 5781
        data length = d 132    fileset = d 1    inode = d 16 (x 10)
        type = d 1 REDOPAGE:INODE
        l2linesize = d 7    pxd length = d 1   phys offset = x 12035e  
(d 1180510)
   0x8083f20  3FF33E40 10000000 70000400 504D0100    ?.>@....p...PM..
   0x8083f30  04000000 5C031200 ACA82400 00000000    ....\.....$.....
   0x8083f40  4B020000 00000000 01000000 00000000    K...............
(中略)
---------------------------------------------------------------------
logrec d 2   Logaddr= x 1bffeac   Nextaddr= x 1bffe88   Backchain
 = x
 1bffe88
LOG_COMMIT     (type = d 32768)     logtid = d 5780
        data length = d 0
(以下略)

 ジャーナルログには、

  • LOG_COMMIT
  • LOG_MOUNT
  • LOG_SYNCPT
  • LOG_REDOPAGE
  • LOG_NOREDOPAGE
  • LOG_NREDOINOEXT
  • LOG_UPDATEMP

という7種類の情報が記録される。特に、LOG_REDOPAGEレコードにはiノードの確保/解放など、iノードマップを更新するためのメタ・データ情報が含まれている。ジャーナルログの中で、ディスク操作を再生するための最も重要な部分といえる。

 また、上記のジャーナルログでも確認できるように、LOG_COMMITとLOG_REDOPAGEは対になっている。さらに、「logtid」(赤字部分)は、1組ごとに等しいIDが割り振られていることが分かる。つまり、LOG_COMMITとLOG_REDOPAGEが1つのアトミックトランザクションとして処理されているということである。

 LOG_SYNCPT(同期地点)を以下に赤字で示す。このLOG_SYNCPTは、トランザクションID(logtid = d 4603)が等しい2つの操作LOG_COMMITとLOG_REDOPAGEの間で実行されている。つまり、アトミックトランザクションの間に同期が行われている。

logrec d 2550   Logaddr= x 1b9c9a8   Nextaddr= x 1b9c984   Backchain
 = x  1b9c984
LOG_COMMIT     (type = d 32768)     logtid = d 4603
        data length = d 0
----------------------------------------------------------------------
logrec d 2551   Logaddr= x 1b9c984   Nextaddr= x 1b9c960   Backchain
 = x 0
****************************************************************
LOG_SYNCPT     (type = d 16384)     logtid = d 0
        data length = d 0
        sync = x 1b82f78
****************************************************************

----------------------------------------------------------------------
logrec d 2552   Logaddr= x 1b9c960   Nextaddr= x 1b9c8b8   Backchain
 = x 0
LOG_REDOPAGE   (type = d 2048)     logtid = d 4603
        data length = d 132    fileset = d 1    inode = d 16 (x 10)
        type = d 1 REDOPAGE:INODE
        l2linesize = d 7    pxd length = d 1   phys offset = x 174990
  (d 1526160)
    0x8083f20  3FF33E40 10000000 43D70500 60180100     ?.>@....C...`...
    0x8083f30  04000000 90491700 B2030000 00000000     .....I..........
    0x8083f40  01000000 00000000 01000000 00000000     ................

 LOG_SYNCPT以前のデータの整合性は保証されるため、ジャーナリング処理では「logrec d 2552」のLOG_REDOPAGEは再生せず、LOG_COMMIT以降を再生する。ここまでの様子を図5に示す。

図5 トランザクションと障害発生 図5 トランザクションと障害発生

 時系列にコミットが行われ、それがジャーナルログに記録されているシステムにおいて、時刻Tに何らかの障害が発生した場合を考えてみよう。JFSは、記録していたジャーナルログを再生する。再生の手順としては、ジャーナルログを読み込んで、最後にSYNCPTした時点までさかのぼる。

図6 ログの再生 図6 ログの再生

 図6は、トランザクション2の途中でSYNCPTが取られているケースである。トランザクション1は、ログに記録したトランザクション操作とディスクに記録されている操作が同期しているため、データの整合性が保証される。しかし、トランザクション2はSYNCPTが完了していないため、操作およびデータの整合性が保証されない。トランザクション2以降も同様である。この場合、JFSはコミットされたトランザクションを再生(redo)あるいはコミットされていないトランザクションをロールバック(undo)するなどして、メタ・データの復旧を試みる。

 これらの操作はfsck_jfsに実装されており、起動時なども同様の手順でジャーナリング処理が行われる。

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。