KVM上の仮想マシンのディスクサイズの増やし方(LVM)

最近はコンテナ主流ですが、まだまだホスト型の仮想マシンも利用します。(主に検証用)
適当に作った仮想マシンを再利用とかしていると、ディスク容量が足りなくなることがよくあるので、増やし方をメモしておきます。

まずは仮想マシンの作り方

virt-install --connect=qemu:///system -n Fedora30 -r 4096 --disk path=/var/lib/libvirt/qemu/fedora30.img,size=32,format=qcow2 --vcpus=4 --os-type linux --network network=default --nographics --extra-args=--extra-args='ks=file:/fedora-ks.cfg console=tty0 console=ttyS0,115200n8' --location /data/Resource/Fedora-Server-dvd-x86_64-30-1.2.iso

こんな感じでテキストインストールです。 普通にやると、 /dev/mapper/fedora-rootが/にマウントされており、この/を拡張可能となります。

ディスク/パーティションサイズの増やし方

  1. 仮想マシンのシャットダウン(省略)
  2. QEMUイメージの拡張
  3. 仮想マシン起動(省略)
  4. パーティションサイズ拡張
  5. LVM物理ボリューム拡張
  6. LVM論理ボリューム拡張

の流れです

QEMUイメージの拡張
# qemu-img info /var/lib/libvirt/qemu/fedora30.img
image: /var/lib/libvirt/qemu/fedora30.img
file format: qcow2
virtual size: 64G (68719476736 bytes)
disk size: 29G
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: true
# file /var/lib/libvirt/qemu/fedora30.img
/var/lib/libvirt/qemu/fedora30.img: QEMU QCOW Image (v3), 68719476736 bytes

拡張

# qemu-img resize /var/lib/libvirt/qemu/fedora30.img +5G
Image resized.
# qemu-img info /var/lib/libvirt/qemu/fedora30.img
image: /var/lib/libvirt/qemu/fedora30.img
file format: qcow2
virtual size: 69G (74088185856 bytes)
disk size: 29G
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: true

これで、ディスクの拡張ができました。この増やした分のサイズを仮想マシンに適用していきます。

パーティションサイズ拡張

まずはディスクのパーティションの拡張です。

# parted /dev/sda
(parted) p
モデル: ATA QEMU HARDDISK (scsi)
ディスク /dev/sda: 74.1GB
セクタサイズ (論理/物理): 512B/512B
パーティションテーブル: msdos
ディスクフラグ:

番号  開始    終了    サイズ  タイプ   ファイルシステム  フラグ
 1    1049kB  1075MB  1074MB  primary  ext4              boot
 2    1075MB  68.0GB  66.9GB  primary                    lvm
(parted) resizepart 2 100%
(parted) p
番号  開始    終了    サイズ  タイプ   ファイルシステム  フラグ
 1    1049kB  1075MB  1074MB  primary  ext4              boot
 2    1075MB  74.1GB  73.0GB  primary                    lvm
LVM物理ボリューム拡張

パーティションが拡張されたので、その上のLVM物理ボリュームの拡張です

# pvdisplay
  --- Physical volume ---
  PV Name               /dev/sda2
  VG Name               fedora
  PV Size               <62.33 GiB / not usable 3.85 MiB
  Allocatable           yes (but full)
  PE Size               4.00 MiB
  Total PE              15955
  Free PE               0
  Allocated PE          15955
  PV UUID               Yq9YcH-V4rM-QHFf-5gyR-tUh8-0PmE-y4Vwt3

# pvs
  PV         VG     Fmt  Attr PSize  PFree
  /dev/sda2  fedora lvm2 a--  62.32g    0
# pvresize /dev/sda2
  Physical volume "/dev/sda2" changed
  1 physical volume(s) resized or updated / 0 physical volume(s) not resized
# pvs
  PV         VG     Fmt  Attr PSize   PFree
  /dev/sda2  fedora lvm2 a--  <68.00g 5.67g
# pvsisplay
  --- Physical volume ---
  PV Name               /dev/sda2
  VG Name               fedora
  PV Size               <68.00 GiB / not usable 2.00 MiB
  Allocatable           yes
  PE Size               4.00 MiB
  Total PE              17407
  Free PE               1452
  Allocated PE          15955
  PV UUID               Yq9YcH-V4rM-QHFf-5gyR-tUh8-0PmE-y4Vwt3

Freeのところを増やすことができました。

LVM論理ボリューム拡張

拡張した物理ボリューム上の論理ボリュームの拡張です。今回はrootしか切ってないので全部利用します

# lvdisplay
  --- Logical volume ---
  LV Path                /dev/fedora/swap
  LV Name                swap
  VG Name                fedora
  LV UUID                CrBKUg-42Pr-l3PM-g0w8-atOG-CgvK-WPI7r6
  LV Write Access        read/write
  LV Creation host, time localhost, 2019-06-03 15:55:13 +0900
  LV Status              available
  # open                 2
  LV Size                3.20 GiB
  Current LE             820
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:1

  --- Logical volume ---
  LV Path                /dev/fedora/root
  LV Name                root
  VG Name                fedora
  LV UUID                QBQwNS-q36Z-Rg2Y-9kTh-uwRA-2Nfn-llxArG
  LV Write Access        read/write
  LV Creation host, time localhost, 2019-06-03 15:55:13 +0900
  LV Status              available
  # open                 1
  LV Size                59.12 GiB
  Current LE             15135
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:0
# lvextend -l +100%FREE /dev/sda2fedrora/root
 Size of logical volume fedora/root changed from 59.12 GiB (15135 extents) to 64.79 GiB (16587extents).
 Logical volume fedora/root successfully resized.
# lvdisplay
  --- Logical volume ---
  LV Path                /dev/fedora/swap
  LV Name                swap
  VG Name                fedora
  LV UUID                CrBKUg-42Pr-l3PM-g0w8-atOG-CgvK-WPI7r6
  LV Write Access        read/write
  LV Creation host, time localhost, 2019-06-03 15:55:13 +0900
  LV Status              available
  # open                 2
  LV Size                3.20 GiB
  Current LE             820
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:1

  --- Logical volume ---
  LV Path                /dev/fedora/root
  LV Name                root
  VG Name                fedora
  LV UUID                QBQwNS-q36Z-Rg2Y-9kTh-uwRA-2Nfn-llxArG
  LV Write Access        read/write
  LV Creation host, time localhost, 2019-06-03 15:55:13 +0900
  LV Status              available
  # open                 1
  LV Size                64.79 GiB
  Current LE             16587
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:0

論理ボリュームも拡張できました。ただこの状態でdfでチェックしても増えていません。 ファイルシステムも拡張してあげる必要があります。 今回はxfsのため、以下のコマンドです

# xfs_growfs /
meta-data=/dev/mapper/fedora-root isize=512    agcount=16, agsize=983040 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=0
data     =                       bsize=4096   blocks=15498240, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
data blocks changed from 15498240 to 16985088
# df -h
ファイルシス            サイズ  使用  残り 使用% マウント位置
/dev/mapper/fedora-root    65G   28G   38G   42% /

これで無事に拡張できたのではないかと思います。正直結構面倒ではありますが、kernelとか大きいビルドをするときは、割とディスク容量が足りなくなることがあるので、メモっておくと使う機会は割りとあります。

kgdbによるkernelデバッグ(2)

前回に引き続いてkgdbによるLinux kerenlのデバッグです。
実際にアタッチするのと、kernel moduleのシンボルの解決について記します。

アタッチ

remoteからのアタッチになるので、gdb実行側で、kernelのシンボル情報を読み込ませる必要があります。
vmlinuxファイルに入っているので、前回展開したものをgdbに読み込ませます。
その後、シリアル接続の情報を設定します。

# gdb vmlinux
(gdb) set remotebaud 115200

targetとなる端末では、アタッチするためにkerenlを一旦止める必要があります。目当ての動作中のデバッグをするには、breakpointを貼って、breakpointで止まったところを見る必要があります。
止めるには以下のコマンドを実行するか、ブートオプションのkgdbwaitを使います。

# echo g > /proc/sysrq-trigger

この状態で、gdb

(gdb) target remote /dev/ttyS0

というようにシリアルからアタッチ出来ると思います。あとはいつものgdbです。continueコマンドでkernel実行を継続すれば、止めてたshellも復帰します。

kernel moduleのデバッグ

この状態だと、kernel coreのシンボル解決は出来ますが、moduleについては情報がないため、デバッグ出来ない状態です。
moduleのアドレス情報は起動ごとに異なるので、まずはターゲット上で目当てのmodule情報を収集します。
moduleの各セクションのアドレス情報は、/sys/modue//sections/以下にあります。ここから各セクションの情報を取得します。
取得したアドレス情報はgdbに登録します。gdbのヘルプを見ると、

(gdb) help add-symbol-file Load symbols from FILE, assuming FILE has been dynamically loaded. Usage: add-symbol-file FILE [-readnow | -readnever] [-o OFF] [ADDR] [-s SECT-NAME SECT-ADDR]... ADDR is the starting address of the file's text. Each '-s' argument provides a section name and address, and should be specified if the data and bss segments are not contiguous with the text. SECT-NAME is a section name to be loaded at SECT-ADDR. OFF is an optional offset which is added to the default load addresses of all sections for which no other address was specified.

とあるので、textのアドレスとそれ以外のアドレスを入れる感じですね。 これを手で入れるのは面倒なので、スクリプトを作成します。

(print-section.sh ターゲットに配置)

#!/bin/sh

cd /sys/module/$1/sections/
if [ $? -ne 0 ]; then
    echo "cannot found module"
    exit 1
fi

addr=`cat .text`
echo -n "$addr"

for A in .*
do
    if [ "$A" = "." ]; then continue; fi
    if [ "$A" = ".." ]; then continue; fi
    if [ "$A" = ".text" ]; then continue; fi
    addr=`cat $A`
    echo -n " -s $A $addr"
done
echo

(kgdb-attach.sh リモートに配置)

#/bin/bash

gdbinit=".gdbinit"

dirdriver="lib/modules/4.16.7_D1+/kernel/drivers/"
vmlinux="boot/vmlinux-4.16.75_D1+"

declare -A modules
modules=(
    ["mod1"]="${dirdriver}/.../mod1.ko"
    ["mod2"]="${dirdriver}/.../mod2.ko"
)



echo "" > ${gdbinit}
echo "file $vmlinux" >> ${gdbinit}
echo "set remotebaud 115200" >> ${gdbinit}

for m in ${!modules[@]}; do
    section="`ssh root@192.168.100.1 bash ./print-section.sh ${m}`"
    echo "add-symbol-file ${modules[$m]} $section" >> ${gdbinit}
done

gdb
echo "" > ${gdbinit}

kgdb-attach.shの配列にデバッグしたい、もしくは関連するモジュールを入れて実行すると、アドレス情報を取ってきてgdbを実行します。
gdbの自動設定はgdbinitを使用しています。生成される.gdbinitの場所次第で警告が出ると思いますが、これを解消するには、homeディレクトリに、

# vi ~/.gdbinit
add-auto-load-safe-path /.../.gdbinit

というようにすれば大丈夫だと思います。
これでkerenl moduleに対してもデバッグできるようになりました。
kernelの開発だけでなく、kerenlの動きの理解や、ユーザランドのアプリの検証などにも使えると思うので気軽にkernelにアタッチしてみましょう!
最近はシリアルポートがない端末も増えてきてるので、ethernet経由でのデバッグもやってみようと思います。

kgdbによるkernelデバッグ

久しぶりにkerenlデバッグをする機会があったのでまとめておきます。 環境は以下

  • 物理PC(x86)
  • kernel 4.16.7(OSはRedhat系)
  • 接続はシリアル接続(デバッグ対象を端末A, 接続端末をB)

kernelをデバッグするときは、kernelを一旦止める必要があるため、基本的には外部からアタッチする形になります。
使うツールはgdbです。
qemuなどの仮想環境上で動いている場合は、qemu上のgdbserverが使えるのか、その限りではないです(?)
仮想環境上で試せる場合は先にそちらで試したほうがいいですね。 やり方はkernel Documentに書いてあります。(Documentation/dev-tools/gdb-kernel-debugging.rst)

kernel config

まずは、デバッグ対象のkerenlのconfigで、kgdbによるデバッグができるよう設定を行います。 Documentation/dev-tools/kgdb.rstやネットで書いてある通りです。

# make menuconfig
(kgdbの有効化 & シリアルコンソールからのデバッグ有効化)
Kernel hacking  --->
  [*] Kernel debugging
  [*] KGDB: kernel debugger  --->
    <*>   KGDB: use kgdb over the serial console
(kernelのデバッグシンボルを残す)
  Compile-time checks and compiler options  --->
    [*] Compile the kernel with debug info
    [ ]   Reduce debugging information
    [*]   Provide GDB scripts for kernel debugging   <= 必須ではないが、仮想環境上でのデバッグやkernelのビルド環境上でデバッグする場合は

その他のconfig

上記以外に以下のconfigを設定しますが、正直やり方があっているかわかりません。今の所問題はないようです。

CONFIG_FRAME_POINTER

ファイルにフレーム情報を保存するコードを埋め込むなどするので、スタックトレースなどが正確になる(らしい)ので、これを有効化します。
いろんなところで、

-> Kernel hacking
  -> Compile-time checks and compiler options

の中に設定項目があると書いてありますが見えません。menuconfigで"/"を押し、探してみると、UNWINDER_FRAME_POINTERに依存されているので、

-> Kernel hacking
  (X) Frame pointer unwinder

とします。これにより

CONFIG_FRAME_POINTER=y
CONFIG_UNWINDER_FRAME_POINTER=y

となります。

CONFIG_STRICT_KERNEL_RWX

これはkernelのメモリ空間をroとし、セキュリティを高める設定ですが、これが有効だと、breakpointの設定ができなくなります。 breakpoint自体は貼れるけど、動かすと多分こんな感じになる。

(gdb) c
Cannot inser breakpont 1.
Error accessing memory address 0xffff...: 不明なエラーです-1.

ただ、x86の場合、強制的に有効化されています。私は無理やり有効化しています。

# vim arch/x86/Kconfig
- select ARCH_HAS_STRICT_KERNEL_RWX
- select ARCH_HAS_STRICT_MODULE_RWX
+ #select ARCH_HAS_STRICT_KERNEL_RWX
+ #select ARCH_HAS_STRICT_MODULE_RWX

# make prepare
# make menuconfig

こうすると、.configから設定が消えると思います。

nokaslr

configとは異なりますが、この設定も無効化する必要があります。KASLRとは仮想メモリアドレスをランダム化し、セキュリティを高める仕組みですが、これが有効だとデバッグシンボルを入れてもgdbが関数などのアドレスを見つけられません。
そのためこれを無効化するんですが、これはkernelのブートオプションで無効化できます。(configでも無効化できると思いますがやったことはありません)
kernelのブートオプションにnokaslrを入れるだけです。設定方法は、kgdbの設定と一緒に紹介します。

Build

私はRPMでのパッケージ管理を崩したくない(デバッグ,開発時もリリースと手順を変えないことで、影響を減らしたい)のと、対象PCが貧弱なので、ビルドマシンでRPM化しています。

# make rpm-pkg

このとき、Makefile

VERSION = 4
PATCHLEVEL = 16
SUBLEVEL = 7
EXTRAVERSION =

RPMの名前が決まるので、EXTRAVERSIONにデバッグ番号などをつけています。 出来たRPMは端末Aにインストールします。develパッケージはこの用途では入れる必要はないと思いますが、別途systemtapなど端末A自体でデバッグを行う場合は必要になると思います。
別途端末Bでもvmlinuxが必要なため、RPMを展開します。vmlinuxもbzip2で圧縮されているので展開しておきます。

端末B
# rpm2cpio kernel.rpm | cpio -id
# bunzip2 boot/vmlinuz-xxx

kgdb設定

端末Aでkgdbの接続設定を行います。その前にちゃんとシリアルコンソールで接続できるか確認しておいたほうがいいでしょう。


シリアルコンソール接続方法

端末Aでシリアル接続を有効かします。systemdを利用している場合です。

# systemctl start serial-getty@ttyS0.service
# vi /etc/securetty
+ ttyS0

これで、端末Bからminicomなどで接続すると、端末Aにログインできるはずです。私はこのやり方が簡単なので使っていますが、systemdが起動しないとログインできないので、OS起動時から入りたい場合はgrubに設定することになります。


接続できることがわかったら、kgdbの設定を行います。kernelのブートオプションに設定します。基本的には2つです。

kgdboc=[kms][[,]kbd][[,]serial_device][,baud]
kgdbwait

kgdbocは接続情報、kgdbwaitはOSブート時に、kgdb接続を待ち受けるかです。kgdbwaitが有効だとkernelはできるだけ早くkgdbの待受に入ります。boot時のデバッグや、breakpointを貼ってから起動する場合などに使います。
以下は設定例です。KASLRの無効化設定も入れています。

# vi /etc/default/grub
GRUB_CMDLINE_LINUX="rhgb nokaslr kgdboc=ttyS0,115200 kgdbwait"
# grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg

これでOSを再起動したら、remoteのgdbでkernelにアタッチできるようになりました。
接続方法は次の記事に回します。

flatpak(1)

Flatpakを少し触ってみました。

Flatpak—the future of application distribution

どのディストリビューションでも同じ動きをし、flatpak環境下で動作させることで、sandbox的な制御も 可能となるようです。 アプリケーションはgithubのような、flathubというリポジトリがあり、主要なアプリケーションは簡単に インストールすることができます。

libreofficeや、VLCといった大きいアプリケーションほど、どの環境でも動作するというのは 助かるので、GUIアプリケーションの導入元としてはありだと思いました。 ただ、アプリケーションのバージョンアップがちゃんと追従するのかは確認ですかね。

sandboxとして、アプリケーションの制限をどのように行っているかは、次の記事にします。

ニューラルネットワーク自作入門メモ

ニューラルネットワーク自作入門

最近AIや機械学習が自分の周りでも聞かれるようになってきたので、基本だけ抑えておこうと思い読んでみました。 読んでみてなんとなくニューラルネットワークがわかった気になれるいい本だったと思います。

文字認識もいいんですが、画像認識はどうなのかと思い、 CIFAR-10 and CIFAR-100 datasets で方式はそのままで試してみました。 データの読み取り方法は、サンプルにもありますが、

def unpickle(self, file):
    import _pickle
    fo = open(file, 'rb')
    dict = _pickle.load(fo, encoding='latin1')
    fo.close()
    return dict

こんな感じで、dict型で取得できます。この中に、dataとlabelsがあり、dataは32323(RGB)の値が入っているようなので、まずはこの1次元配列をそのまま入力層として利用してみました。 本のサンプルから変更しているところはこんな感じ

    epochs = 5

    for e in range(1, epochs):
        data_dict = n.unpickle('cifar-10-batches-py/data_batch_' + str(e))
        # go through all records in the training data set
        for record in range(len(data_dict['labels'])):
            # split the record by the ',' commas
            #all_values = record.split(',')
            # scale and shift the inputs
            inputs = (numpy.asfarray(data_dict['data'][record]) / 255.0 * 0.99) + 0.01
            # create the target output values (all 0.01, except the desired label which is 0.99)
            targets = numpy.zeros(output_nodes) + 0.01
            # all_values[0] is the target label for this record
            targets[int(data_dict['labels'][record])] = 0.99
            n.train(inputs, targets)
            pass
        pass
    for record in range(len(test_dict['labels'])):
    # split the record by the ',' commas
    #all_values = record.split(',')
    # correct answer is first value
    correct_label = int(test_dict['labels'][record])
    # scale and shift the inputs
    inputs = (numpy.asfarray(test_dict['data'][record]) / 255.0 * 0.99) + 0.01
    # query the network
    outputs = n.query(inputs)
    #print(outputs)
    # the index of the highest value corresponds to the label
    label = numpy.argmax(outputs)
    # append correct or incorrect to list
    if (label == correct_label):
    # network's answer matches correct answer, add 1 to scorecard
    scorecard.append(1)
    print (label, " == ", correct_label)
    else:
    # network's answer doesn't match correct answer, add 0 to scorecard
    scorecard.append(0)
    print (label, " != ", correct_label)
    pass

    pass

これでやってみると、正解率はだいたい20%ほど。 こんなもんかという感じですが、色をまとめて入れるのはどうかという気もするのでもう少し工夫したり、CNNをやってみてもいいかも。 なかなか楽しいですが、これを自分のサービスに入れ込もうとするにはいろいろやってみて応用を効かせられるようにならないといけないですね。