うまいぼうぶろぐ

linuxとhttpdとperlのメモ

drbd 0.7でmeta-diskをinternalに設定する際の注意 - /dev/drbd0へのmkfsを忘れないこと

ref: http://www.linux-ha.org/DRBD/FAQ#head-ac2d92db0450b941fe9d9873ce13613f49897f55

/dev/drbd0へmkfsしないといけないのはdrbd 8系でも同じなんだけど、8系だと手順をすっ飛ばすと途中でdrbd構築途中でエラーが出る(はず)。それに対して、0.7だとスルーされるので。ということでスーパーチョンボをしてしまったので反省エントリ。

kernelが吐いたエラー

ずーっと前に作ったdrbd 0.7で作ったサーバで、/dev/drbd0でマウントしてたディレクトリに書き込みしてたら、突然こんなログが出てreadonlyになった。

kernel: attempt to access beyond end of device
kernel: drbd0: rw=0, want=16515080, limit=16509440
kernel: EXT3-fs error (device drbd0): read_block_bitmap: Canno t read block bitmap - block_group = 63, block_bitmap = 2064384
kernel: Aborting journal on device drbd0.
kernel: EXT3-fs error (device drbd0) in ext3_ordered_writepage: IO failure
kernel: ext3_abort called.
kernel: EXT3-fs error (device drbd0): ext3_journal_start_sb: Detected aborted journal
kernel: Remounting filesystem read-only

umount/mountでとりあえず書き込み可能な状態になったけど

# tune2fs -l /dev/drbd0 | grep state
Filesystem state:         clean with errors

となって、ext3もおかしくなっている。

DRBDのFAQを読むと

If you did mkfs /real/device, then later mount through DRBD, the file system either recognized size mismatch in superblock vs. tual block device size on the spot and refuse to mount (xfs does this, iirc).
the file system mounts alright, because it skips the check for block device size (ext3, at least certain version of it, apareny do this; it is ok for a file system to assume that its superblock contains valid data) and then thinks it could use the now n available space which is occupied by IMD.
(中略)
When the file system will start using that area is nearly impossible to pretict. So it may appear to work fine for month, and tn suddenly break again and again.

まさにこれずら。

DRBDの基本

  1. 特定のパーティション(/dev/sdb1とか)を/dev/drbd0とかに割り当てる
  2. そのパーティションにdrbdのメタデータを(今回はinternalに)作成
  3. 作成した/dev/drbd0を使いたいファイルシステムでフォーマット(mkfs.ext3とかで)

このとき、うっかり3番の手順をすっ飛ばして利用してたのでエラーが出た。internalでメタデータを作成すると、パーティションの後ろにdrbd用メタデータが作成されるから。なのに、/dev/sdb1をext3でフォーマットした状態(OSインストール直後だったので)で、そのまま使ってたから。

DRBDのメタデータ

ガイドを読むかぎり、メタデータは外部パーティションに設定することを推奨してる?特にメタデータを別ディスクにすると、ディスクシークの関係で書き込み性能があがるようんたらかんたらっていう。

internalだと特別な設定が不要なので管理は楽かな。

メタデータのサイズ

v0.7系では128M固定。v8系では以下の関係。

ブロックデバイスのサイズ DRBDメタデータのサイズ
1GB 2 MB
100GB 5 MB
1TB 33 MB
4TB 128 MB

間違えた経緯

もう忘れてもうたけど、たぶんこんな感じ。

  • OSインストール時にとりあえず/dev/sdb1をext3パーティション作成
  • DRBD インストール
  • DRBD メタデータ作成 # drbdadm adjust drbd0 (drbdsetup)でmeta-dataをinternalに作成
  • ### 本当はここでmkfs.ext3 /dev/drbd0が必要 !!
  • mkfsを忘れて、/dev/drbd0をext3としてマウント (/mntとかに)
    • OSインストール時にext3で作成してたからか、特にエラーも出ずマウント出来る
  • /mnt をディスクぎりぎりまで使ったときにメタデータに干渉して冒頭のエラー

というみじめなな結果に。

DRBD v8の場合

drbd 8.3.6でテストしてみた。↑のdrbd7と同じような手順でやってみたけど、メタデータの作成のとこでエラーがでるので、普通にやってたらどこかで間違いに気づくかな。

  • OSインストール時にとりあえず/dev/sdb1をext3パーティション作成
  • DRBD インストール
  • DRBD メタデータ作成 # /etc/drbd.conf書いて、drbdadm create-md drbd0を実行

すると、こんなエラーが。

# drbdadm createmd drbd0
md_offset 246718464
al_offset 246685696
bm_offset 246677504

Found ext3 filesystem
	      240940 kB data area apparently used
	      240896 kB left usable by current configuration

Device size would be truncated, which
would corrupt data and result in
'access beyond end of device' errors.
You need to either
   * use external meta data (recommended)
   * shrink that filesystem first
   * zero out the device (destroy the filesystem)
Operation refused.

Command 'drbdmeta 0 v08 /dev/sdb1 internal create-md' terminated with exit code 40
drbdadm create-md drbd0: exited with code 40
  • "(destroy the filesystem)"とあるので、/dev/sdb1の先頭を0で埋めて壊して、メタデータ作成
# dd if=/dev/zero of=/dev/sdb1 bs=1M count=1
# drbdadm create-md drbd0
  • ddによって/dev/sdb1はファイルシステムを破壊されたから、/dev/drbd0をext3でマウントしようとしてもできない
    • なのでmkfsして、mount
# mkfs.ext3 /dev/drbd0
# mount -t ext3 /dev/drbd0 /mnt

と、こうなるのでdrbd 0.7でmkfsし忘れた、みたいな状況はたぶん起きない。

おまけ

わざと間違って/dev/sdb1にmkfsしてみた。

# /etc/init.d/drbd stop
# mkfs.ext3 /dev/sdb1
# /etc/init.d/drbd start
Starting DRBD resources: [ d(drbd0) 0: Failure: (119) No valid meta-data signature found.

==> Use 'drbdadm create-md res' to initialize meta-data area. <==

[drbd0] cmd /sbin/drbdsetup 0 disk /dev/sdb1 /dev/sdb1 internal --set-defaults --create-device --on-io-error=pass_on  failed - ntinuing!

その後、drbdを起動しようとするけど、メタデータが壊れている(dev/sdb1にmkfsしたから当然)のでエラーで起動できない。


おまけ2: drbdデバイスにmkfs.ext3 してるか調べる方法

drbd 0.7はメタデータサイズが128M固定なので、これを利用して調べれる。比較するのは

  • /proc/partitions
  • tune2fs -l /dev/drbd0

の値。

OSインストール直後を想定して/dev/sdb1をext3でフォーマットして、sdb1にメタデータ作成。最後にmkfs.ext3 /dev/drbd0をするかしないかで値を比較。240Mぐらいのパーティションで試してみた。

/proc/partitionsの値
# egrep 'blocks|sdb1|drbd0' /proc/partitions
major minor  #blocks  name
 202    18     240975 sdb1
 147     0     109900 drbd0
# python
>>> (240975 -  109900) / 1024
128

メタデータを作成した時点でdrbd0で使用できるblockサイズが128M減っている。(drbd0にmkfsしてるかどうかは関係ない)

tune2fs -l

sdb1、drbd0どっちでもいいのでtune2fs -lして、blockサイズ計算する。(DRBDのFAQに載っている計算)

Block count * Block size / 1024

  • 正しく mkfs.ext3 /dev/drbd0をした場合
# tune2fs -l /dev/drbd0 | 
    awk '/^Block.size:  / { bs=$NF } 
         /^Block.count: / { bc=$NF } 
         END { print bc * bs / 1024 }'
109900

/proc/partitionsのdrbd0のとこと値が一致する

  • うっかり mkfs.ext3 /dev/drbd0を忘れた場合
# tune2fs -l /dev/drbd0 | 
    awk '/^Block.size:  / { bs=$NF } 
         /^Block.count: / { bc=$NF } 
         END { print bc * bs / 1024 }'
240975

/proc/partitionsのsdb1のとこと値が一致する。つまりメタデータ分が除外されてファイルシステムのサイズが認識されているので、このまま使い出すといつか冒頭のエラーになる。実際、この状態でパーティションをフルに使うと

# mount /dev/drbd0 /mnt
# dd if=/dev/zero of=/mnt/hoge bs=1M count=1000
dd: writing `hoge': Read-only file system
102+0 records in
101+0 records out
106532864 bytes (107 MB) copied, 1.23778 seconds, 86.1 MB/s
#  df -h | egrep 'Size|drbd'
Filesystem            Size  Used Avail Use% Mounted on
/dev/drbd0            228M  109M  109M  50% /data

となってdfで見たら128M(メタデータのサイズ)ほど容量は空いてるけど、readonlyになってext3がおかしくなる。