2014年4月7日月曜日

パーティションテーブルのオンライン編集

Linux動作中に、mountなどで利用しているディスクのパーティションテーブルを変更するときにエラーになったりならなかったりするはなし。
 
パーティションテーブルの書き換え自体はいきなりブロックデバイスに書くのでいつでもできます。しかしカーネルが保持しているパーティション情報の更新は失敗するケースがあります。パーティション情報の更新はデバイスにたいするioctlでおこない、対応する手法によって失敗する条件が変わります。

ioctl BLKRRPART でパーティションを読み直しさせると、既に利用しているデバイスの場合はEBUSYで失敗します。

つかうがわ
util-linux-ng-2.17.2/fdisk/fdisk.c

                printf(_("Calling ioctl() to re-read partition table.\n"));
                i = ioctl(fd, BLKRRPART);

つかわれるがわ
linux-2.6.32-71.el6.x86_64/fs/partitions/check.c

int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
{
        struct disk_part_iter piter;
        struct hd_struct *part;
        struct parsed_partitions *state;
        int p, highest, res;

        if (bdev->bd_part_count)
                return -EBUSY;
ioctl BLKPG でパーティションを明示して追加させると、既に利用しているパーティションと競合する場合はEBUSYで失敗します

つかうがわ
util-linux-ng-2.17.2/partx/partx.c
                                pt.pno = lower+j;
                                pt.start = 512 * (long long) slices[j].start;
                                pt.length = 512 * (long long) slices[j].size;
                                pt.devname[0] = 0;
                                pt.volname[0] = 0;
                                a.op = BLKPG_ADD_PARTITION;
                                a.flags = 0;
                                a.datalen = sizeof(pt);
                                a.data = &pt;
                                if (ioctl(fd, BLKPG, &a) == -1) {
                                    perror("BLKPG");

つかわれるがわ
linux-2.6.32-431.el6.x86_64/block/ioctl.c
                        /* overlap? */
                        disk_part_iter_init(&piter, disk,
                                            DISK_PITER_INCL_EMPTY);
                        while ((part = disk_part_iter_next(&piter))) {
                                if (!(start + length <= part->start_sect ||
                                      start >= part->start_sect + part->nr_sects)) {
                                        disk_part_iter_exit(&piter);
                                        mutex_unlock(&bdev->bd_mutex);
                                        return -EBUSY;
                                }
                        }

再起動せずにパーティションを追加してそのパーティションをブロックデバイスとして見せたいシチュエーションでは、BLKPGを使うpartxなどでカーネルにパーティション追加の通知をすると既存のパーティションと重なっていなければ利用可能です。

さらに異常なシチュエーションで、既存のパーティションと重なっているような場合であっても、devicemapperで適当なマッピングをパーティション情報から作ってくれる kpartx を利用すればなんとでもなったりします……。

2014年3月17日月曜日

linux virtual consoleのリサイズ

linuxのvirtual consoleをリサイズする方法を調べたのでメモ

いくつか手法があるのでおすすめ順に。

1. fbset コマンドを利用してリサイズ
    - 実行しながらダイナミックに変更できるフレームバッファの表示サイズを変更する
    - RHEL6から入っていない。Fedoraには存在している
    - 要perl

2. カーネルのコマンドラインでvideo=オプションを指定する
    - video=800x600 のようにモードを指定する
    - カーネルの中に含まれているモードのDBを利用するので好き勝手なサイズにはできない
    - video=オプションのサポートはデバイスドライバ毎におこなわれているので互換性の問題がある。ただし現在主流のものはOK

3. drm_kms_helperモジュールのedid_firmwareオプションで(通常はディスプレイが提供する)EDID情報を提供する
    - drm_kms_helper.edid_firmware=edid/1024x768.bin
    - モジュールのオプションなのでカーネルのコマンドラインだけでなくmodprobe.confでも指定できる

4. カーネルのコマンドラインでnomodesetオプションを指定する
    - 80x24のコンソールだけでよければこれでok.
    - vga= オプションでサイズ指定もある程度可能
    - 基本的にデバッグ用のオプションなので推奨されません(RHELだとサポート対象外)

5. virtual consoleをつかわない
    - 仮想化環境であれば、シリアルコンソールを設定してvirtual consoleを使わないオプションはそれなりにリーズナブル

変更:
1. nomodesetはデバッグ用でサポートされない話を追記
2. drm_kms_helperモジュールを教えてもらったので追記

2014年2月10日月曜日

gnome3でuim-skkをつかうメモ

# yum install uim-skk uim-gtk3 uim-gtk2 uim-qt uim-qt3

$ gsettings set org.gnome.settings-daemon.plugins.keyboard active false

ログアウト→ログイン

$ im-chooser
UIMを選択

uim-toolbarを自動起動するため、~/.config/autostart/uim-toolbar.desktop に、以下を書く
[Desktop Entry]
Encoding=UTF-8
Type=Application
Name=uim-toolbar
Exec=uim-toolbar-gtk3
StartupNotify=false
Terminal=false
Hidden=false

追記: 設定した日現在、uim-toolbar-systray-gtk3をgnome3で実行しても表示ができません。(既知の問題のようです) ~/.config/imsettings/xinputrcスクリプトはuim-toolbar-systray-gtk3起動してくれているのですが見えないので上記ファイルでuim-toolbar-gtk3を起動しています。

2013年12月16日月曜日

最近のCPUでは乱数生成がはやい話

Ivy Bridge以降のCPUではCPU内に乱数生成器が含まれています。それに対応した最近のrngdをつかうとそれなりに乱数生成が速くてしあわせになれます。

linuxでは乱数を取得するために /dev/random と /dev/urandom の2種類のデバイスがあります。それぞれの説明は man 4 random にみっちり書いてありますが、かいつまんで言うと:
  • random: カーネルがあつめてきたノイズを元に品質の高い疑似乱数を生成します。ノイズが不足するとblockします。
  • urandom: カーネルがあつめてきたノイズを元にそこそこの品質の疑似乱数を生成します。品質はそこそこですがblockしないので速いです。
ためしにcat /dev/random とかすると1kとか4kくらい乱数が出力されて止まってしまう。これでは割と足りないので選択肢が2種類。1) 品質をあきらめてurandomを使う、2) 乱数生成器をつけてrngd経由で書き込みとエントロピーの追加をおこなう。乱数生成器は一部のチップセットに内蔵されたりしてたんですが、 専用ハードウェアもあったりします。

いいかげんな乱数でよければurandomなのですが、sshのキーをつくるとかsslちゃんとやろうとか証明書発行しようとかしたいときは/dev/randomをつかいたい、でも周辺装置とかチップセットの制約とかめんどいなー。 という事情がありました。

そこでIvy Bridge世代ではrdrand命令を追加して、CPUのチップ内で乱数生成をして専用命令で読みだせるようにしました。このテクノロジー自体もかなりおもしろいです。IEEE Spectrumの記事がおすすめ。


実際つかってみましょう。rngdの最近のバージョンでは、rdrand命令に対応しています。最近のfedoraであればデフォルトでrngdが動いていますが、有効でなければ systemctl start rngd.service とか叩いて有効にします。

ddで1バイトずつ乱数読みだしをおこないます。乱数生成器がない環境とかrngd止まってるとかだとこれがblockしてずーーっと待つことになるので注意。
$ dd if=/dev/random of=/dev/null bs=1 count=1000000 
1000000+0 records in
1000000+0 records out
1000000 bytes (1.0 MB) copied, 4.32184 s, 231 kB/s
 比較対象としてurandomでも同じことをしてみましょう。
$ dd if=/dev/urandom of=/dev/null bs=1 count=1000000
1000000+0 records in
1000000+0 records out
1000000 bytes (1.0 MB) copied, 1.3472 s, 742 kB/s
urandomのほうがまだ速いですけど1/3くらいの速度はでますね。これくらい出てくれるなら乱数つかい放題といってもいいんじゃないかしら。


2013-12-16追記
Debianではrng-toolsが独自forkなためrdrand対応がまだ入っていないらしい。rng-toolsのアップデートについてのケースがfileされている。一方UbuntuにはDebianはforkだから独自に新版入れてくれというケースが。Debianの動き悪いのはわかるけどUbuntuだけ対応するってなんだかなあ。

2013年12月15日日曜日

/proc/cpuinfoを目で読むのがつらい

最近のコンピュータだとCPUのコア数やスレッド数が多いので/proc/cpuinfoを直接読むよりまとめて出力してくれるlscpuやhwlocをつかったほうがよい。

最近コア数とか多いですね。デスクトップでもCore i7だと8スレッドとかありますしサーバだと4ソケット40コア80スレッドとかあります。

CPUがどういう構成なのか知りたい時は /proc/cpuinfo  や /sys/devices/system/cpu/* を読むことが多いですが表示が冗長なのでつらいです。そこで適当にまとめて表示してくれるコマンドが便利です。


lscpuはCPUのキャッシュ構成とか、ソケット-コア-スレッドの個数の関係がわかります。実機で数回実行するとわかりますがCPU MHzのところは実際の周波数にあわせてちょいちょい変わるのでアテになりません。
出力はこんなかんじ:
$ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                8
On-line CPU(s) list:   0-7
Thread(s) per core:    2
Core(s) per socket:    4
Socket(s):             1
NUMA node(s):          1
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 58
Stepping:              9
CPU MHz:               1802.000
BogoMIPS:              6784.54
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              8192K
NUMA node0 CPU(s):     0-7
hwlocは本来はNUMA環境などをうまく使うために適切なtaskset等を生成したりするためのツールセットなのですが、今回は表示してくれるところだけ見ます。グラフィカルなのが好きな人はいいんじゃないですかね。
  $ hwloc-ls -p

以下はしばらく前にとった4ソケットマシンでのhwloc-lsの出力。「でかい!」ってことしかわからない気もします。。

2013年12月10日火曜日

広告消した

なんとなくつけていた広告、自分はadblockを使っていていつもみていないんですが人のブラウザで自分のblogを見たらかなり鬱陶しかったので消しました :)

2013年12月7日土曜日

SSDの寿命をext4ファイルシステムの統計情報から推定する

SSDを選定する場合には書き込み量の推定が重要です。 

NAND Flashの各ブロックに書き換え回数の上限があるSSDでは書き込み総量に制限が存在します。
NAND Flash自体の書き換え回数上限は実装にどのような技術が使われているかにもよりますが数千回から10万回程度。HDDやRAMDISKではこの回数上限は事実上存在しません。

そのためSSDではファームウェアで各ブロックが均等に書き換えられるように工夫したり、外部に見せるより多い容量のNAND Flashを用意してブロックあたりの書き換え回数を減らしたり、不良ブロック発生時にもただちに影響がないようにしています。

このため、コンシューマ向けでは記載がないものもありますが、エンタープライズ向けSSDでは必ず総書き込み上限について記載があります。

適当にぐぐったIntelのSSD仕様の例: http://ark.intel.com/ja/products/75682/Intel-SSD-DC-S3500-Series-300GB-2_5in-SATA-6Gbs-20nm-MLC

耐久性評価 (書き込み上限数) 170 TBW 
この例では170TB書きこみできます。
170TB / 300GB =  566.66... なので、566回程度ディスク全体を書き換えられる。。 といわれてもまったくピンときませんよね。

たとえば想定される利用期間に対してトータル+安全係数で200TBくらい書きそうな場合にはこの製品よりグレードの高いものを選ぶべきです。しかしHDDでは書き込み回数に上限がなかったこともあり、これからSSDを使おうという場合に、書き込み容量総計についてはノウハウが無いまたは少ないケースが多いです。書き込み量がどのくらいかは完全にワークロード次第でかわり、負荷が高めのDBや、仮想マシンの作成・削除を頻繁に繰り返すような環境では非常に大きくなりえます。


ext4では2009年に導入されたパッチでファイルシステムへの書き込み総量を記録する機能をもつようになりました。この情報はdumpe2fsで確認できます。以下はHDDの例ですが、出力中の Lifetime writes:というフィールドがそれにあたります。
# dumpe2fs -h /dev/mapper/backup-backup
dumpe2fs 1.42.8 (20-Jun-2013)
Filesystem volume name:  
Last mounted on:          /var/spool/backup
Filesystem UUID:          fc89edc2-fab9-4d35-9761-f0fd60f6c171
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags:         signed_directory_hash
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              122101760
Block count:              488377344
Reserved block count:     24418867
Free blocks:              196290282
Free inodes:              121615201
First block:              0
Block size:               4096
Fragment size:            4096
Reserved GDT blocks:      907
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         8192
Inode blocks per group:   512
Flex block group size:    16
Filesystem created:       Sun Nov 28 10:04:04 2010
Last mount time:          Mon Nov  4 09:50:05 2013
Last write time:          Mon Nov  4 09:50:05 2013
Mount count:              94
Maximum mount count:      34
Last checked:             Sun Nov 28 10:04:04 2010
Check interval:           15552000 (6 months)
Next check after:         Fri May 27 10:04:04 2011
Lifetime writes:          5899 GB
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11

(以下略)

3年で5899GBほど書いています。月あたりの書き込み量を概算すると
6000GBの書き込み / 36ヶ月 = 166GBW/月
となり、ディスクの寿命を5年とすると
166GBW/月 * 60ヶ月 = 9960GBW
となります。書き込みの使われかたがおおよそ安定していると想定すると、10TBWほど。さきほどのintelのSSDを使えば余裕ですね。