小さくなって欲しいときもあります

仮想化を使っていると仮想ディスクを大きくする話は良く見るのですが Windows でディスクを小さくする話をあんまり見なかったのでちょっと試してみました。といっても近頃の Windows ならばパーティションを小さくすることくらい簡単です。

「コンピュータの管理」から「ディスクの管理」を探しだせば右クリックで縮小ができます。http://www.atmarkit.co.jp/fwin2k/win2ktips/941diskshrink/diskshrink.html おっと、こんなページもありました。

で、問題は EC2 の場合なんかです。EBS ボリュームは今のところ後からサイズ変更ができません。サイズを変更しようと思うとスナップショットを撮ってそこからボリュームを作り直したりする必要があります。更にスナップショットからより大きなボリュームは作れるのですが、元のボリュームよりも小さなボリュームは作れません。どーしよう。小さなボリューム作って dd で突っ込んでみましょう。

注意

下記手順は適当な思いつきでその後の長期運用など試していないので新しく作ったボリュームを利用していて何の問題も無いという保証はできません。このままにしろ改善するにしろ自己責任でね!

作業環境を準備する

先ずは作業用のインスタンスが欲しいので Amazon Linux の最新版を起動してみます。今だと amzn-ami-pv-2013.03.0.x86_64-ebs ってのが最新です。ログインしたら /etc/yum.repos.d/epel.repo の enabled=0 を

$ sudo vi /etc/yum.repos.d/epel.repo

でも何でもいいので 1 にします。これで epel の利用準備が完了です。epel から ntfsprogs をインストールします。

$ sudo yum install ntfsprogs

ntfsresize が使えるようになりました。

小さくなって欲しいボリュームを用意する

次に Windows インスタンスを立てて stop します。Amazon Linux を立てる前に立てておいた方がいい、かな? パスワードが取得できる前に stop していいのかどうかとか良く分かっていません。でも変なことはしない方が良いに違いありません。stop したら /dev/sda1 のボリュームをデタッチして作業用 Amazon Linux にアタッチします。とその前に、本番環境だったらここでスナップショット取得ですね。

$ sudo fdisk -l -u /dev/sdf

ディスク /dev/sdf: 32.2 GB, 32212254720 バイト
ヘッド 255, セクタ 63, シリンダ 3916, 合計 62914560 セクタ
Units = セクタ数 of 1 * 512 = 512 バイト
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O size (minimum/optimal): 512 bytes / 512 bytes
ディスク識別子: 0xb3009496

デバイス ブート      始点        終点     ブロック   Id  システム
/dev/sdf1   *        2048      718847      358400    7  HPFS/NTFS
パーティション 1 は、シリンダ境界で終わっていません。
/dev/sdf2          718848    62912511    31096832    7  HPFS/NTFS

「境界で終わっていません」と何だか怖い言葉が出てきていますがきっと何かの間違いでしょう。sdf1 は起動用か何かで sdf2 にシステムが入っているものと思われます。今回のターゲットは sdf2 です。

ntfsresize でごにょごにょする

ntfsresize は空打ちすると丁寧な help が出てくる親切なコマンドなので一度叩いておきましょう。で、情報を取得してみます。

$ sudo ntfsresize -i /dev/sdf2
ntfsresize v2011.4.12 (libntfs-3g)
Device name        : /dev/sdf2
NTFS volume version: 3.1
Cluster size       : 4096 bytes
Current volume size: 31843152384 bytes (31844 MB)
Current device size: 31843155968 bytes (31844 MB)
Checking filesystem consistency ...
100.00 percent completed
Accounting clusters ...
Space in use       : 24170 MB (75.9%)
Collecting resizing constraints ...
You might resize at 24169693184 bytes or 24170 MB (freeing 7674 MB).
Please make a test run using both the -n and -s options before real resizing!

7674 MB 小さくできると教えてくれました。ありがとう! では早速。

$ sudo ntfsresize -s 24170M -P /dev/sdf2
ntfsresize v2011.4.12 (libntfs-3g)
Device name        : /dev/sdf2
NTFS volume version: 3.1
Cluster size       : 4096 bytes
Current volume size: 31843152384 bytes (31844 MB)
Current device size: 31843155968 bytes (31844 MB)
New volume size    : 24169992704 bytes (24170 MB)
Checking filesystem consistency ...
Accounting clusters ...
Space in use       : 24170 MB (75.9%)
Collecting resizing constraints ...
Needed relocations : 112369 (461 MB)
WARNING: Every sanity check passed and only the dangerous operations left.
Make sure that important data has been backed up! Power outage or computer
crash may result major data loss!
Are you sure you want to proceed (y/[n])? y
Schedule chkdsk for NTFS consistency check at Windows boot time ...
Resetting $LogFile ... (this might take a while)
Relocating needed data ...
Updating $BadClust file ...
Updating $Bitmap file ...
Updating Boot record ...
Syncing device ...
Successfully resized NTFS on device '/dev/sdf2'.
You can go on to shrink the device for example with Linux fdisk.
IMPORTANT: When recreating the partition, make sure that you
  1)  create it at the same disk sector (use sector as the unit!)
  2)  create it with the same partition type (usually 7, HPFS/NTFS)
  3)  do not make it smaller than the new NTFS filesystem size
  4)  set the bootable flag for the partition if it existed before
Otherwise you won't be able to access NTFS or can't boot from the disk!
If you make a mistake and don't have a partition table backup then you
can recover the partition table by TestDisk or Parted's rescue mode.

ファイルを移動して縮小してくれました。移動が入るのでちょっと時間が掛かるかも。環境次第ですね。

fdisk で partition を小さくする

残念ながら ntfsresize は partition size までは小さくしてくれませんでした。仕方がないので fdisk で partition を切り直してあげましょう。大きさは ntfsresize で -s で指定したのと同じにしてあげます。切り直すとシステムタイプとやらが Linux に戻ってしまうので NTFS に戻すのを忘れずに。

$ sudo fdisk /dev/sdf

警告: DOS互換モードは廃止予定です。このモード (コマンド 'c') を止めることを
      強く推奨します。 and change display units to
         sectors (command 'u').

コマンド (m でヘルプ): c
DOS互換フラグは設定されていません

コマンド (m でヘルプ): u
セクタ数 の表示/項目ユニットを変更します

コマンド (m でヘルプ): p

ディスク /dev/sdf: 32.2 GB, 32212254720 バイト
ヘッド 255, セクタ 63, シリンダ 3916, 合計 62914560 セクタ
Units = セクタ数 of 1 * 512 = 512 バイト
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O size (minimum/optimal): 512 bytes / 512 bytes
ディスク識別子: 0xb3009496

デバイス ブート      始点        終点     ブロック   Id  システム
/dev/sdf1   *        2048      718847      358400    7  HPFS/NTFS
/dev/sdf2          718848    62912511    31096832    7  HPFS/NTFS

コマンド (m でヘルプ): d
パーティション番号 (1-4): 2

コマンド (m でヘルプ): n
コマンドアクション
   e   拡張
   p   基本パーティション (1-4)
p
パーティション番号 (1-4): 2
最初 セクタ (718848-62914559, 初期値 718848): 
初期値 718848 を使います
Last セクタ, +セクタ数 or +size{K,M,G} (718848-62914559, 初期値 62914559): +24170M

コマンド (m でヘルプ): t
パーティション番号 (1-4): 2
16進数コード (L コマンドでコードリスト表示): 7
領域のシステムタイプを 2 から 7 (HPFS/NTFS) に変更しました

コマンド (m でヘルプ): p

ディスク /dev/sdf: 32.2 GB, 32212254720 バイト
ヘッド 255, セクタ 63, シリンダ 3916, 合計 62914560 セクタ
Units = セクタ数 of 1 * 512 = 512 バイト
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O size (minimum/optimal): 512 bytes / 512 bytes
ディスク識別子: 0xb3009496

デバイス ブート      始点        終点     ブロック   Id  システム
/dev/sdf1   *        2048      718847      358400    7  HPFS/NTFS
/dev/sdf2          718848    50219007    24750080    7  HPFS/NTFS

コマンド (m でヘルプ): w
パーティションテーブルは変更されました!

ioctl() を呼び出してパーティションテーブルを再読込みします。
ディスクを同期しています。

さて、これで若しかするとぶっ壊れてしまったかもしれませんし上手くいってるかもしれません。試しに mount してみましょうか。

$ sudo mount /dev/sdf2 /mnt
$ ls /mnt
$Recycle.Bin  Documents and Settings  Program Files        ProgramData                Users    bootmgr
BOOTNXT       PerfLogs                Program Files (x86)  System Volume Information  Windows  pagefile.sys
$ df
Filesystem           1K-ブロック    使用   使用可 使用% マウント位置
/dev/xvda1             8256952   1015968   7157128  13% /
tmpfs                   848352         0    848352   0% /dev/shm
/dev/xvdf2            23603508  23602984       524 100% /mnt

大変、使用% が 100% だわ!!! このままだと起動しない気がしてきました。やり過ぎたか。。。

dd で新規ボリュームに流し込みましょう

7GB くらい小さくできたので、というかそもそも GB 単位で小さくすれば良かったですね。ともかく、余裕を見て 24GB の EBS ボリュームを作って /dev/sdg にアタッチします。そして、同じ感じでパーティションを切ってあげましょう。

$ sudo fdisk /dev/sdg
デバイスは正常な DOS 領域テーブルも、Sun, SGI や OSF ディスクラベルも
含んでいません
新たに DOS ディスクラベルをディスク識別子 0x7e1c6893 で作成します。
あなたが書き込みを決定するまで、変更はメモリ内だけに残します。
その後はもちろん以前の内容は修復不可能になります。
警告: 領域テーブル 4 の不正なフラグ 0x0000 は w(書き込み)によって
正常になります

警告: DOS互換モードは廃止予定です。このモード (コマンド 'c') を止めることを
      強く推奨します。 and change display units to
         sectors (command 'u').

コマンド (m でヘルプ): c
DOS互換フラグは設定されていません

コマンド (m でヘルプ): u
セクタ数 の表示/項目ユニットを変更します

コマンド (m でヘルプ): n
コマンドアクション
   e   拡張
   p   基本パーティション (1-4)
p
パーティション番号 (1-4): 1
最初 セクタ (2048-50331647, 初期値 2048): 
初期値 2048 を使います
Last セクタ, +セクタ数 or +size{K,M,G} (2048-50331647, 初期値 50331647): 718847

コマンド (m でヘルプ): n
コマンドアクション
   e   拡張
   p   基本パーティション (1-4)
p
パーティション番号 (1-4): 2
最初 セクタ (718848-50331647, 初期値 718848): 718848
Last セクタ, +セクタ数 or +size{K,M,G} (718848-50331647, 初期値 50331647): 50219007

コマンド (m でヘルプ): t
パーティション番号 (1-4): 1
16進数コード (L コマンドでコードリスト表示): 7
領域のシステムタイプを 1 から 7 (HPFS/NTFS) に変更しました

コマンド (m でヘルプ): t
パーティション番号 (1-4): 2
16進数コード (L コマンドでコードリスト表示): 7
領域のシステムタイプを 2 から 7 (HPFS/NTFS) に変更しました

コマンド (m でヘルプ): a
パーティション番号 (1-4): 1

コマンド (m でヘルプ): p

ディスク /dev/sdg: 25.8 GB, 25769803776 バイト
ヘッド 255, セクタ 63, シリンダ 3133, 合計 50331648 セクタ
Units = セクタ数 of 1 * 512 = 512 バイト
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O size (minimum/optimal): 512 bytes / 512 bytes
ディスク識別子: 0x7e1c6893

デバイス ブート      始点        終点     ブロック   Id  システム
/dev/sdg1   *        2048      718847      358400    7  HPFS/NTFS
/dev/sdg2          718848    50219007    24750080    7  HPFS/NTFS

コマンド (m でヘルプ): w
パーティションテーブルは変更されました!

ioctl() を呼び出してパーティションテーブルを再読込みします。
ディスクを同期しています。

で、器ができたので dd で流し込みます。

$ sudo dd if=/dev/sdf of=/dev/sdg bs=512 count=1
1+0 records in
1+0 records out
512 bytes (512 B) copied, 0.0217699 s, 23.5 kB/s
$ sudo dd if=/dev/sdf1 of=/dev/sdg1 bs=1M
350+0 records in
350+0 records out
367001600 bytes (367 MB) copied, 23.7274 s, 15.5 MB/s
$ sudo dd if=/dev/sdf2 of=/dev/sdg2 bs=1M
24170+0 records in
24170+0 records out
25344081920 bytes (25 GB) copied, 992.344 s, 25.5 MB/s

Windows 再び

では 24GB の方のボリュームを元の Windows インスタンスの /dev/sda1 にアタッチしてインスタンスを start してみます。

おぉ、起動してしまいました。しまった、パスワードをまだ取得していない。取得してログオンします。

おぉぉ、容量が足りないせいかデスクトップの構築に失敗してしまった!!

53MB 残っていました。

で、53MB 広げてディスクのチェックを調べてみたらエラーがありました....。修復の為に再起動だ!

無事再起動し接続したらデスクトップを再度構築してくれました。ふぅ。今度はディスクチェックも通って安心。

反省点

多分、縮小までは Windows で実行した方が簡単ですね。ntfsresize + fdisk は数値の正確な計算などがなぁ、と思いました。というか、多分色々なところで無駄が出ています。真面目にやるならちゃんと計算しましょう。多分この辺りはちゃんとググるともっと正しい方法を載せてる人も居そう。あと、小さくし過ぎると危険。