LVMでディスクを追加

LVM は公式ドキュメントがどこにあるのかわからない。

とりあえずこれを読んでみる。
http://tldp.org/HOWTO/LVM-HOWTO/commontask.html

  • pvcreate で /dev/xvdb を全部 PV とする。

HOWTO では推奨されてないが、Linux 以外からパーティションを認識できなくなる、という問題であって、今回の環境では Linux以外で管理するつもりがないので問題無しとする。

[root@ikura ~]# LANG=C date; pvcreate /dev/xvdb; LANG=C date
Wed Sep 16 21:50:31 JST 2009
  Physical volume "/dev/xvdb" successfully created
Wed Sep 16 21:50:31 JST 2009
[root@ikura ~]# 

オンラインでディスクの追加できるのか?
まあ、バックアップ取ってるし試してみるか。

[root@ikura ~]# vgscan --verbose
    Wiping cache of LVM-capable devices
    Wiping internal VG cache
  Reading all physical volumes.  This may take a while...
    Finding all volume groups
    Finding volume group "VolGroup00"
  Found volume group "VolGroup00" using metadata type lvm2
[root@ikura ~]#
[root@ikura ~]# vgextend VolGroup00 /dev/xvdb 
  Volume group "VolGroup00" successfully extended
[root@ikura ~]# 

うげ、成功した。意味わからん。
いや、PV - VG - LV という関係だから、 VG にディスクを追加するのは問題ないかも。

[root@ikura ~]# df -h 
Filesystem          サイズ  使用  残り 使用% マウント位置
/dev/mapper/VolGroup00-LogVol00
                      3.3G  2.6G  528M  84% /
/dev/xvda1             99M   43M   52M  45% /boot
tmpfs                 129M     0  129M   0% /dev/shm
[root@ikura ~]# 

df は変化無し。

VG にディスクを追加した。次に LV を拡張すればいいはず。
これはオンラインでできるのか?

いや、原点回帰。現在の状況を整理しよう。

[root@ikura ~]# pvscan 
  PV /dev/xvda2   VG VolGroup00   lvm2 [3.88 GB / 0    free]
  PV /dev/xvdb    VG VolGroup00   lvm2 [3.97 GB / 3.97 GB free]
  Total: 2 [7.84 GB] / in use: 2 [7.84 GB] / in no VG: 0 [0   ]
[root@ikura ~]# pvdisplay 
  --- Physical volume ---
  PV Name               /dev/xvda2
  VG Name               VolGroup00
  PV Size               3.90 GB / not usable 24.72 MB
  Allocatable           yes (but full)
  PE Size (KByte)       32768
  Total PE              124
  Free PE               0
  Allocated PE          124
  PV UUID               SVwvda-AetG-AJdi-qtz0-vnS9-sdh7-prptlk
   
  --- Physical volume ---
  PV Name               /dev/xvdb
  VG Name               VolGroup00
  PV Size               4.00 GB / not usable 32.00 MB
  Allocatable           yes 
  PE Size (KByte)       32768
  Total PE              127
  Free PE               127
  Allocated PE          0
  PV UUID               4013gs-R1mw-zlIM-OFdc-sTUC-Fz2g-IGXdr3
   
[root@ikura ~]# 

PV として /dev/xvdb を認識できている。
これは pvcreate /dev/xvdb で PV として追加できた、ということかもしれない。

[root@ikura ~]# vgscan 
  Reading all physical volumes.  This may take a while...
  Found volume group "VolGroup00" using metadata type lvm2
[root@ikura ~]# vgdisplay 
  --- Volume group ---
  VG Name               VolGroup00
  System ID             
  Format                lvm2
  Metadata Areas        2
  Metadata Sequence No  4
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                2
  Open LV               2
  Max PV                0
  Cur PV                2
  Act PV                2
  VG Size               7.84 GB
  PE Size               32.00 MB
  Total PE              251
  Alloc PE / Size       124 / 3.88 GB
  Free  PE / Size       127 / 3.97 GB
  VG UUID               jjBm64-Yd3Y-Ml2V-2RAt-4HoV-CzCT-2sVjLA
   
[root@ikura ~]# 

うーん、わからん。 vgdisplay の出力に 3.88, 3.97 という値が見るが、これは VG として追加されているからなのか?vgextend の結果、ここに追加されたのだろうか。

えい。

[root@ikura ~]# lvextend -L+3900M /dev/VolGroup00/LogVol00
  Rounding up size to full physical extent 3.81 GB
  Extending logical volume LogVol00 to 7.16 GB
  Logical volume LogVol00 successfully resized
[root@ikura ~]# 

あれ、追加できた。気持ち悪い。

[root@ikura ~]# df -h
Filesystem          サイズ  使用  残り 使用% マウント位置
/dev/mapper/VolGroup00-LogVol00
                      3.3G  2.6G  528M  84% /
/dev/xvda1             99M   43M   52M  45% /boot
tmpfs                 129M     0  129M   0% /dev/shm
[root@ikura ~]# 

df の出力は同じまま。
resize2fs でリサイズすればいいのかな。

次。single user mode で起動。
resize2fs を試みる。

だめだ。resize2fs をしたい / に resize2fs が入っているので、シングルユーザモードにしても無駄。
今は bootable なメディアが無いし、LVM で HDD を増強するのはめんどい。

bootable なメディアが手に入る迄本件保留とする。

DOM-U ikura にディスクイメージを追加。

  • ディスクイメージを作る。

特に意味はないが、既存のイメージファイルと合わせることにする。

[root@gohan ~]# ls -l /var/lib/xen/images/ikura.img 
  • rwxr-xr-x 1 root root 4294967297 Sep 16 20:59 /var/lib/xen/images/ikura.img
[root@gohan ~]# bc bc 1.06 Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. scale=8 4294967297 / 1024 / 1024 / 1024 4.00000000

ぴったり 4GB だ。これに 4GB を追加する。

[root@gohan ~]# df -h 
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
                       36G   15G   19G  44% /
/dev/sda1              99M   43M   52M  45% /boot
tmpfs                 1.8G     0  1.8G   0% /dev/shm
none                  1.8G  128K  1.8G   1% /var/lib/xenstored
[root@gohan ~]# 

空き容量は十分だ。
4GB のディスクイメージを作る。

[root@gohan ~]# dd if=/dev/zero bs=1024 count=`echo '4 * 1024 * 1024' | bc` > /var/lib/xen/images/ikura-2.img
4194304+0 records in
4194304+0 records out
4294967296 bytes (4.3 GB) copied, 222.965 seconds, 19.3 MB/s
[root@gohan ~]# ls -l /var/lib/xen/images/ikura*.img
  • rw-r--r-- 1 root root 4294967296 Sep 16 21:10 /var/lib/xen/images/ikura-2.img
  • rwxr-xr-x 1 root root 4294967297 Sep 16 20:59 /var/lib/xen/images/ikura.img
[root@gohan ~]#

あ!1byte ちがうwww
追記で帳尻合わせをする。

[root@gohan ~]# dd if=/dev/zero bs=1 count=1 >> /var/lib/xen/images/ikura-2.img
1+0 records in
1+0 records out
1 byte (1 B) copied, 6.7e-05 seconds, 14.9 kB/s
[root@gohan ~]# ls -l /var/lib/xen/images/ikura*.img
  • rw-r--r-- 1 root root 4294967297 Sep 16 21:12 /var/lib/xen/images/ikura-2.img
  • rwxr-xr-x 1 root root 4294967297 Sep 16 20:59 /var/lib/xen/images/ikura.img
[root@gohan ~]#
  • ikura にログインして shutdown する。
[root@gohan images]# xm list 
Name                                      ID Mem(MiB) VCPUs State   Time(s)
Domain-0                                   0     3464     1 r-----  13936.5
ikura                                      2      255     1 ------  27053.3
[root@gohan images]# 

うん。よし。

  • /etc/xen/ikura の編集

加えた変更は次だけ。

[root@gohan ~]# diff /etc/xen/ikura_2009-09-16 /etc/xen/ikura
11c11
< disk = [ "tap:aio:/var/lib/xen/images/ikura.img,xvda,w" ]
    • -
> disk = [ "tap:aio:/var/lib/xen/images/ikura.img,xvda,w", "tap:aio:/var/lib/xen/images/ikura-2.img,xvdb,w" ] [root@gohan ~]#
  • ikura のバックアップ

ikura 作業で事故がないようにバックアップを取得しておく。

[root@gohan ~]# LANG=C date; gzip < /var/lib/xen/images/ikura.img > /var/lib/xen/images/ikura.img_`date +%F`; LANG=C date
Wed Sep 16 21:19:03 JST 2009
Wed Sep 16 21:31:17 JST 2009
[root@gohan ~]# ls -l /var/lib/xen/images/ikura*
  • rw-r--r-- 1 root root 4294967297 Sep 16 21:12 /var/lib/xen/images/ikura-2.img
  • rwxr-xr-x 1 root root 4294967297 Sep 16 20:59 /var/lib/xen/images/ikura.img
  • rw-r--r-- 1 root root 1062451270 Sep 16 21:31 /var/lib/xen/images/ikura.img_2009-09-16
[root@gohan ~]#

手順が逆になったが、 ikura-2.img のパーミッションを ikura.img に合わせておこう。多分、合わせた方が良いものだと思う。

  • ikura 起動
[root@gohan ~]# xm create ikura
Using config file "/etc/xen/ikura".
Error: VM name 'ikura' already in use by domain 2
[root@gohan ~]# 

あれ。動かない。

フォーラム見ると同様の事例があり、DOM-0側サーバの再起動でことなきをえた、らしい。でもまだ諦めない。xend を再起動してみる。

[root@gohan ~]# service xend status
xend is running
[root@gohan ~]# service xend stop
Stopping xend:                                             [  OK  ]
[root@gohan ~]# service xend status
xend is stopped
[root@gohan ~]# service xend start
Starting xend:                                             [  OK  ]
[root@gohan ~]# service xend status
xend is running
[root@gohan ~]# xm create -c ikura

動いた!
認識してるだろうか。どうたしかめればいいか。

[root@ikura ~]$ dmesg | grep -2 xvdb
Registering block device major 202
 xvda: xvda1 xvda2
 xvdb: unknown partition table
device-mapper: uevent: version 1.0.3
device-mapper: ioctl: 4.11.5-ioctl (2007-12-12) initialised: dm-devel@redhat.com
[root@ikura ~]$

おっけーっぽい。

Xen ディスク追加方法を模索

/etc/xend/ikura に設定ファイルを見つけた。他人事のように言っているのは、しばらく触ってなくて手探りで探しているから。
ちなみに、ファイル名が ikura なのは disk full で困っている DOM-U のホスト名が ikura だからだ。
xen の設定はホスト名に合わせてある。なお、DOM-0 のホスト名は gohan だ。

disk
List of block devices to export to the domain e.g. disk = [ 'phy:hda1,sda1,r' ] exports physical device /dev/hda1 to the domain as /dev/sda1 with read-only access. Exporting a disk read-write which is currently mounted is dangerous - if you are certain you wish to do this, you can specify w! as the mode.

公式マニュアルを見ると設定ファイルに disk をリストして記載する。リストといってるんだから、複数指定できるだろう。
今の記載は次のようになっている。これを複数にしたい。

disk = [ "tap:aio:/var/lib/xen/images/ikura.img,xvda,w" ]

既存のイメージファイル自体を大きくする(ができるかどうかは別として)、あるいは、新たなイメージファイルを作ってリストに追加してあげればいいだろう。

イメージファイル自体を変更する方法として
http://www.vinacis.net/content/view/32/32/
http://www.kelvinism.com/howtos/resize-xen-image/
に記載があるとおり、 dd で作ったファイルを追記書き込みする方法があるらしいが、
今回は DOM-U の ikura に OS インストール済みだし、ディスクの容量を後から変更する行為自体が微妙そうなのと、 ikura は LVM を使っていることから software raid でディスク追加ができそう、とのことで新たなイメージファイルを追加することで話を進める。

LVM で raid 組んだこと無いから、面白そうだし。

http://tx.downloads.xensource.com/downloads/docs/user/#SECTION03210000000000000000

対策を考える

プライオリティが高いのは disk full の解決だ。

disk full になったマシンをどうするか。

  • サーバを捨てる。
  • 新しく別のマシンを用意して、プログラム/データを移行する。
  • Xen にディスク容量をなんとかして増やす。

いろいろデータが詰まってて、捨てるには持った無い。新しい Xen ゲストOSをするなりすれば、ディスク容量を簡単に大きい物を用意できる。でも、移行なんて考えたらめんどくさくてやってらんない。

ディスクの容量を増やしたい。
今の Xen のゲストOSのイメージファイルは /var/lib/xen/images にある。
このファイルをそのまま大きくすることができるか、あるいは、別のイメージを作って Xen のゲストOS にディスクを1コ追加するようなことができればいい。

サーバ disk full

Linux Xen の上で飼ってる VM の1個が disk full になった。
remedie, tiarra, mysql, cpan modules etc をインストールしてたらいつのまに小さな HDD を圧迫したのだ。
自宅のおもちゃサーバだからいいんだけどさ。

問題は2つ。

  • disk full を解決する必要があること。
  • disk full に気づかなかったこと。

こまったこまった。

ソートされた複数のCSVファイルを結合するスクリプト

問題

CSVファイルが複数存在する。各ファイルは異なる列データが保存されているが、どのファイルもCSV左端列でソートされている。これらを左端列でソートされた1つのCSVファイルにまとめたい。まとめるプログラムを作れ。

なお、CSVファイルは数万行を想定し、メモリ消費を考慮したプログラムを書くこと。

CSVデータ

data1.txt
#id,data11,data12
1,data111,data121
2,data112,data122
3,data113,data123
4,data114,data124
5,data115,data125
6,data116,data126
7,data117,data127
data2.txt
#id,data21,data22
0,data210,data220
1,data211,data221
4,data214,data224
5,data215,data225
6,data216,data226
7,data217,data227
8,data218,data228
9,data219,data229
data3.txt
#id,data31,data32
0,data310,data320
1,data311,data321
2,data312,data322
5,data315,data325
6,data316,data326
7,data317,data327
8,data318,data328
9,data319,data329
期待する出力例

※カンマだとわかりにくいので、タブ文字で出力してみた。

id	data11	data12	data21	data22	data31	data32
0			data210	data220	data310	data320
1	data111	data121	data211	data221	data311	data321
2	data112	data122			data312	data322
3	data113	data123				
4	data114	data124	data214	data224		
5	data115	data125	data215	data225	data315	data325
6	data116	data126	data216	data226	data316	data326
7	data117	data127	data217	data227	data317	data327
8			data218	data228	data318	data328
9			data219	data229	data319	data329

回答例

続きを読む

Linux のメモリ管理動作確認のために作成したCコード

メモリを消費するためのプログラム。好きな量のメモリをmalloc/freeで割当/解放するだけ。 watch -d cat /proc/meminfo と合わせて使うことを想定。本当は swap させるまでメモリを使いたいんだけど、このプログラムじゃダメかも。割り当てるだけじゃだめなの?なんで?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct list {
    unsigned char *buf;
    unsigned int buflen;
    struct list *next;
};

void print_help(void)
{
    puts("size_and_unit - allocate memory [b/k/m] (ex. 10m, 5k, 300b)");
    puts("list          - show memory size and index for freeing");
    puts("free index    - allocate memory [b/k/m]");
    puts("help          - print this message");
    puts("quit          - exit");
}

void chomp(char *p)
{
    while (*p != '\n' && *p != '\0')
        *p++;
    *p = '\0';
}

void print_list(struct list *p)
{
    int total = 0;
    int index = 0;

    while (p) {
        printf("index:%d, buflen:%d\n", index++, p->buflen);
        total += p->buflen;
        p = p->next;
    }
    printf("total:%d\n", total);
}

void print_alloc(struct list **head, int size)
{
    if (*head == NULL) {
        if ((*head = malloc(sizeof(struct list))) == NULL)
            perror("malloc");
        if (((*head)->buf = malloc(size)) == NULL)
            perror("malloc");
        (*head)->buflen = size;
        (*head)->next = NULL;
    } else {
        struct list *p = *head;

        while (p->next != NULL)
            p = p->next;

        if ((p->next = malloc(sizeof(struct list))) == NULL)
            perror("malloc");
        p = p->next;
        if ((p->buf = malloc(size)) == NULL)
            perror("malloc");
        p->buflen = size;
        p->next = NULL;
    }
    printf("alloc %d bytes\n", size);
}

void print_free(struct list **head, int pos)
{
    if (pos == 0) {
        struct list *next = (*head)->next;

        free((*head)->buf);
        free(*head);
        *head = next;
    } else {
        struct list *p = *head;
        int index = 0;

        while (p) {
            if (index + 1 == pos) {
                struct list *next = p->next->next;
                free(p->next->buf);
                free(p->next);
                p->next = next;
                break;
            }
            p = p->next;
        }
    }
    printf("free index#%d\n", pos);
}

int main(void)
{
    char line[1024];
    struct list *head = NULL;

    while (fgets(line, sizeof line, stdin)) {
        int size, unit, pos;

        chomp(line);

        if (!strcmp(line, "")) {
            ;
        } else if (!strcmp(line, "list")) {
            print_list(head);
        } else if (!strcmp(line, "help")) {
            print_help();
        } else if (sscanf(line, "free %d", &pos) == 1) {
            print_free(&head, pos);
        } else if (sscanf(line, "%d%c", &size, &unit) == 2) {
            char *units = "bkm", *p;
            if ((p = strchr(units, unit)) != NULL) {
                int n = ((char *)p - units);
                while (n-- > 0)
                    size *= 1024;
                printf("size=%d\n", size);
                print_alloc(&head, size);
            } else {
                printf("illeal unit given: %c", unit);
            }
        } else if (!strcmp(line, "quit")) {
            break;
        } else {
            printf("failed to parse: %s\n", line);
        }
    }
    return 0;
}
/* vim:set ts=4 sw=4 sts et nu ai: */