LVM2 on DRBD が一筋縄でいかなかった
DRBD のディスク上に LVM を構築しようとしたらちとはまりました。うーん困った,とおもってググったら,解決してる先達がいらっしゃいました→DRBD-8.0.X + LVM2 - end_of_scriptの日記。
元記事では生ディスク /dev/sda3 の上に DRBD を構築して(さらにその上に LVM を構築して)いらっしゃいますが,わたしは LVM 上の LV たる lv_mirror の上に DRBD を構築した(さらにその上に LVM を構築)という点が違います。が,問題となったポイントは同じです。step by step で何がおきて,どう解決したかを書いておきます。
問題発生
まずは現状の PV の状況とか。
# pvdisplay -C PV VG Fmt Attr PSize PFree /dev/sdb1 vg_mirror lvm2 a- 931.51G 419.39G
おおもとの LVM の PV は /dev/sdb1 上に構築してあります。これを vg_mirror という VG に属させて,そこから lv_mirror という LV を切り出してあります。
この lv_mirror をターゲットディスクとして DRBD を構築しました(手順は省略します)。仮想デバイスノードは /dev/drbd1 としました。
で,その /dev/drbd1 をあたらしい PV にしてみました。
# pvcreate /dev/drbd1 Physical volume "/dev/drbd1" successfully created
一見無事作成されたようです。しかし,ほんとにきちんとできたかな?と pvdisplay してみると,
# pvdisplay -C PV VG Fmt Attr PSize PFree /dev/sdb1 vg_mirror lvm2 a- 931.51G 419.39G /dev/vg_mirror/lv_mirror lvm2 -- 512.00G 512.00G
PV のブロックデバイス名が /dev/drbd1 ではなく LV(/dev/vg_mirror/lv_mirror)になってしまってます。
それでも無視して vgcreate しようとすると
# vgcreate -v vg_store /dev/drbd1 No physical volume label read from /dev/drbd1 /dev/drbd1 not identified as an existing physical volume Unable to add physical volume '/dev/drbd1' to volume group 'vg_store'.
/dev/drbd1 は PV じゃないでしょ,と怒られてしまいました。
原因
LVM2 は「あるタイミングで」指定されたディレクトリ((デフォルトだと /dev 以下の全ディレクトリです。))下のデバイスノードを全走査してブロックデバイスをさがし,実際にブロックデバイスにアクセスしてみて LVM としてのシグニチャ(や設定内容)があるかどうかを見ています。そして LVM 対象の PV をキャッシュに格納し,のちのちその情報を使います。
pvscan を verbosity をあげて実行すると,全走査の様子をみることができます。
# pvscan -vv
Setting global/locking_type to 1
File-based locking selected.
Setting global/locking_dir to /var/lock/lvm
Locking /var/lock/lvm/P_global WB
Wiping cache of LVM-capable devices
Wiping internal VG cache
Walking through all physical volumes
/dev/ramdisk: size is 32768 sectors
/dev/ramdisk: size is 32768 sectors
/dev/ramdisk: No label detected
...... snip snip snip ......
/dev/drbd1: size is 1073741824 sectors
/dev/drbd1: size is 1073741824 sectors
/dev/drbd1: lvm2 label detected
...... snip snip snip ......
/dev/vg_mirror/lv_mirror: size is 1073741824 sectors
/dev/vg_mirror/lv_mirror: size is 1073741824 sectors
/dev/vg_mirror/lv_mirror: lvm2 label detected
Duplicate PV JmrO...snip...gB2W on /dev/drbd1 - using dm /dev/vg_mirror/lv_mirror
...... snip snip snip ......
PV /dev/sdb1 VG vg_mirror lvm2 [931.51 GB / 419.39 GB free]
PV /dev/vg_mirror/lv_mirror lvm2 [512.00 GB]
Total: 2 [1.40 TB] / in use: 1 [931.51 GB] / in no VG: 1 [512.00 GB]
Unlocking /var/lock/lvm/P_globalはじめ /dev/drbd1 を LVM2 の PV として検出しています。そのあと,/dev/vg_mirror/lv_mirror も走査して PV だと検出されました。しかし,さきほどの /dev/drbd1 の PV のシグニチャ(UUID)と同じなので(Duplicate PV ... のようにいわれている),/dev/drbd1 のかわりに /dev/vg_mirror/lv_mirror のほうを使うよ,となってしまっています((ここで /dev/drbd1 より /dev/vg_mirror/lv_mirror が優先される理由はわかりません。あとからみつかったものが優先されるのかもしれません。そもそもこちらがあとから見つかった理由もわかりませんけど。))。
で最終的に「これが PV だよキャッシュ」には /dev/sdb1 と /dev/vg_mirror/lv_mirror のみ格納されました(/dev/drbd1 は対象になっていない)。なので /dev/drbd1 を VG に追加しようとしても「これが PV だよキャッシュ」に含まれない……すなわち PV とはみなされず,うまくいかない,というわけです。
対処
LVM2 が走査対象とするブロックデバイスを制限してやればよい,つまり見てほしくないブロックデバイスは見ないように設定してやればよいです。
具体的には /etc/lvm/lvm.conf 設定ファイルの filter 設定子を指定します。
デフォルトで
# By default we accept every block device:
filter = [ "a/.*/" ]のようになっているかと思いますので,
# By default we accept every block device:
#filter = [ "a/.*/" ]
filter = [ "r|^/dev/vg_|", "r|^/dev/mapper/|" ]のように変更します((元記事だと filter 行が複数になっているように見えますが,filter 行は一行のみ有効になります。複数指定するとどうなるんだっけな……先頭行か最終行のみ有効になったかと思います。))。
書式は,推察がつくと思いますが,先頭に a がついている正規表現にマッチするものは「走査対象デバイス」となり,先頭が r になっている正規表現にマッチするものが「非走査デバイス」になります((元記事では /dev/sda3 のように raw disk を対象外として指定していますが,わたしの環境では LV 上に DRBD を構築したので /dev/vg_mirror/* を対象外にすればよいことになります。念のために /dev/mapper/* も除外していますが,デフォルトで対象にならないようです。))。
ここで念を入れて
filter = [ "a/.*/", "r|^/dev/vg_|", "r|^/dev/mapper/|" ]
のように書きたくなりますが,このように書くとうまくいきません。
# Be careful if there there are symbolic links or multiple filesystem
# entries for the same device as each name is checked separately against
# the list of patterns. The effect is that if any name matches any 'a'
# pattern, the device is accepted; otherwise if any name matches any 'r'
# pattern it is rejected; otherwise it is accepted.
aパターンにマッチするものは無条件で走査対象rパターンにマッチするものは無条件で非走査- いずれにもマッチしなければ走査対象
のようになっているので,"a/.*/" で全デバイスが対象になってしまうんですね。対象に含めたあと除外,のようなアルゴリズムではないので注意が必要です(凝った条件で除外したい場合,がんばって正規表現をあみだす必要があります)。
うまくいった?
さきほど「あるタイミングで」LVM デバイス情報キャッシュを(再)構築する,と書きました。「あるタイミング」とは具体的にいうと pv/vg/lvscan や pv/vg/lvcreate したときのことです((実際 pvscan の出力例でも「Wiping cache of LVM-capable devices」のようにいわれてますよね。))。ですので,設定ファイルを書き換えたあと再起動する必要はありません。さきほどと同じように pvscan -vv してみましょう。
# pvscan -vv
Setting global/locking_type to 1
File-based locking selected.
Setting global/locking_dir to /var/lock/lvm
Locking /var/lock/lvm/P_global WB
Wiping cache of LVM-capable devices
Wiping internal VG cache
Walking through all physical volumes
/dev/ramdisk: size is 32768 sectors
/dev/ramdisk: size is 32768 sectors
/dev/ramdisk: No label detected
...... snip snip snip ......
/dev/drbd1: lvm2 label detected
/dev/drbd1: lvm2 label detected
...... snip snip snip ......
PV /dev/sdb1 VG vg_mirror lvm2 [931.51 GB / 419.39 GB free]
PV /dev/drbd1 lvm2 [512.00 GB]
Total: 2 [1.40 TB] / in use: 1 [931.51 GB] / in no VG: 1 [512.00 GB]
Unlocking /var/lock/lvm/P_global先ほどと異なり,そもそも /dev/vg_mirror/lv_mirror が走査対象に含まれませんでした。なので無事 /dev/drbd1 を PV として認識させることができました。
pvdisplay で見てみても,
# pvdisplay -C PV VG Fmt Attr PSize PFree /dev/drbd1 lvm2 -- 512.00G 512.00G /dev/sdb1 vg_mirror lvm2 a- 931.51G 419.39G
のようにうまくいっていることがわかります。
ここまでくれば vgcreate が成功するのは自明でしょう。
# vgcreate vg_store /dev/drbd1 Volume group "vg_store" successfully created
# vgdisplay -C VG #PV #LV #SN Attr VSize VFree vg_mirror 1 2 0 wz--n- 931.51G 419.39G vg_store 1 0 0 wz--n- 512.00G 512.00G