こだわりのWindowsパーティション設定(GPT限定)

注意

何をやっているのか分からない方は手を出さないでください。 (極めて特殊なケースを除き、こんな設定の必要はありません。)

はじめに

  • Windowsのインストーラの実行中にShift+F10を押すとコマンドプロンプトが開きます。 そこでパーティションの設定について、いろいろと頑張れます。
  • WindowsインストーラやdiskpartのMB単位での指定ですが、実際は1MiB(220バイト)単位の指定です。
  • 調べた限りでですが、Windowsのインストーラは作成したパーティションに対してボリュームネームを設定しません。 ボリュームネームについて悩む必要は恐らくありません。
  • こだわりのある方には常識だと思いますが、GPTではディスクの先頭だけでなく、末尾の33セクタも使われるので、パーティションの設定ではその点も考慮する必要があります。
  • PiKVMのような、別のPCからコピペ入力ができるキーボードがあると作業が全然楽になります。特に回復パーティションのGUIDã‚„attributesの手入力は大変かつ危険です。 その手のハードが使えなければ、危険を承知で頑張って手入力するか、diskpartスクリプトをあらかじめUSBメモリに保存しておき、そちらを使うことになります。

パーティションの順序

未使用のハードディスクにWindowsをインストールすると、(1) ESP、(2) MSR、(3) Cドライブ、(4) 回復パーティション、の順でパーティションが作成されますが、それと同じ順序が良いと思います。

別案として、ESPやMSRをディスクの後ろの方に持ってくる方法も考えられるものの、標準的なインストールとは違うパーティションの順序にするのは操作ミスに繋がる等、危ない感じがします。

ディスクの初期化(既存パーティションの全削除)

実際に初期化が必要かどうかは各自の判断にお任せするとして、diskpartでの手順は以下の通りです。 cleanコマンドでは確認なしに既存のパーティションテーブルが削除されるので覚悟してください。

list disk       # ディスクの一覧が表示されるので、インストール先のディスクの番号を探す
select disk X   # Xにはインストール先のディスクの番号を指定する
clean
convert gpt

最近はインストールにUSBメモリを使うこともあって、インストール先のディスクの番号が0以外のことも珍しくありません。0を仮定した既存のdiskpartスクリプトをそのまま使えないことが増えました。

なお、以下に示すdiskpartでは、上記と同様のselect diskコマンドにより対象となるディスクが選択されているものとします。 ちなみに、diskpartのcreate partitionコマンドは作成したパーティションを選択するので、作業でselect paritionは不要なことが多いです。

ESPの作成

大抵のPC環境では100MiBになりますが、先頭が1MiBの位置で気持ちよくありません。 1MiBではなく4MiBでアラインしたくないですか?

続くMSRパーティションのサイズが16MiBであることを考えると、先頭4MiB、サイズ108MiBでどうでしょう。 ただし、開始位置やサイズを変えるためにはdiskpartによる手作業が必要になります。

create partition efi offset=4096 size=108
format quick fs=fat32

本当に100MiBも必要なのかは気になりますが、後でサイズを変えるのは面倒なので、素直に100MiB以上で作る方が無難そうです。

別案として、EPSはデフォルトの100MiBのまま、Cドライブの先頭位置はMSRのサイズで調整する方法も思い浮かびます。 ただ、ESPはいざというときのファイル置き場としても使えるので(FAT32なので)、ESPのサイズで調整する方が良いと思います。

MSRパーティションの作成

続くMSRパーティションは通常16MiBです。 Cドライブをdiskpartで作るためにはその前に来るMSRも予め作っておく必要があります。 MSRパーティションのフォーマットは不要です。

create partition msr size=16

Cドライブ

アライン等を考慮しつつ、お好きなサイズで。 もちろん、後述する回復パーティションに必要な領域は残す必要があります。

また、Cドライブ用のパーティションですが、Windowsインストールの直前に一旦削除して、それによりできた未使用領域を指定してWindowsをインストールする方が良いかもしれません。 その場合、diskpartでパーティションを作成する際のフォーマットは不要です。

create partition primary size=XXXX

ちなみにこだわりのない場合は、Cドライブのパーティションを一旦最大サイズで作成し、その後で回復パーティションのサイズ分だけシュリンクする手順が一般的なようです。

(参考)
create partition primary
shrink minimum=500

しかしこの方法ですと、回復パーティションのアラインが思い通りになりません。

回復パーティションの作成

Windowsのインストーラが作成する回復パーティションのサイズはバージョン依存のようです。 回復パーティションに必要なサイズは年々増えているので、後のことも考え、ここでは1024MiBにします。 マイクロソフトのドキュメントでは最低300MBで、Windows回復環境ツールには追加の空き領域として最低100MB(ただし推奨は250MB)が必要とされていますが、Windows 11 Pro (24H2)を実際にクリーンインストールしたところ、回復パーティションのサイズは685MiBになったので、1024MiBというのはそれなりに妥当なサイズだと思います。 実際、検索すると1GiB派は結構いらっしゃるようです。 そもそもCドライブの直後に配置するので、こちらは後でサイズを変えられなくもないです。

create partition primary id=de94bba4-06d1-4d40-a16a-bfd50179d6ac size=1024
format quick fs=ntfs
gpt attributes=0x8000000000000001

このidとattributesの入力が一連の作業における最大のハードルだと思います。

参考

(Obsolete) ASUS ROG STRIX X670E-AのオンボードNIC(I225-V B3)をLinuxで使うためにASPM(Active-State Power Management)を無効にする

注意: ASUS ROG STRIX X670E-AのBIOSバージョン2007では、ASPM設定が有効のままでもオンボードのI225-Vが問題なく動作するようです。

BIOSバージョン1905では以下の問題が生じていました。


そもそも評判の良くないIntel I225-Vですが(「I225-V 不具合」で検索しましょう)、現在もASUSマザーボード上のI225-VをLinuxでしばらく使っていると、ネットワークインタフェースが突然消えてしまいます。

https://www.reddit.com/r/buildapc/comments/xypn1m/network_card_intel_ethernet_controller_i225v_igc/ によると、Intel的にはパワーマネジメントに関連したASUSの実装が原因で、 カーネルのパラメータにpcie_port_pm=off pcie_aspm.policy=performanceを追加して、PCIeのパワーマネジメント機能を無効にすると良いようです。

しかし、この設定ではPCIeデバイス全てに影響してしまうので、もう少し穏やかな方法を考えます。

動作についてはASUS ROG STRIX X670E-Aで確認しました。 ちなみに、手元のマザーボードのI225-VのステッピングはB3でした。 同世代のASUSマザーボードでも同様の対応が可能ではないかと思います。

方法

オンボードI225-VへのPCIeリンクでのみASPMを無効にするため、

echo 0 > /sys/class/net/eno1/device/link/l1_aspm

を実行します。なお、上記のeno1はネットワークインタフェースの名前で、Linuxディストリビューションやマザーボードによって異なる名前になる可能性があります。

この設定を行って以降、ネットワークインタフェースは消えなくなりました。

解説等

ASPM (Active-State Power Management)とは

PCIeリンクの消費電力を削減する枠組みです。 通常の通信時はL0というステートになり、これに加えてL0sとL1という電力消費を削減したステートが定義されます。

L0sでは通信は止めるものの、極めて短時間でL0に復帰できます(しなければならない)。 一方L1ではPCIe送受信用のPLLも止める代わりにL0への復帰までに時間がかかる(かけられる)ようになっています。 また、後の拡張でL1については従来のL1(=L1.0)に加えて、さらに電力を削減したL1.1、L1.2というサブステートが追加されました。

I225-VのASPM対応状況

lspci -vvで調べるとオンボードのI225-Vは

...
            LnkCap: Port #1, Speed 5GT/s, Width x1, ASPM L1, Exit Latency L1 <4us
                    ClockPM- Surprise- LLActRep- BwNot- ASPMOptComp+
...
    Capabilities: [1e0 v1] L1 PM Substates
            L1SubCap: PCI-PM_L1.2- PCI-PM_L1.1+ ASPM_L1.2- ASPM_L1.1+ L1_PM_Substates+
            L1SubCtl1: PCI-PM_L1.2- PCI-PM_L1.1- ASPM_L1.2- ASPM_L1.1-
            L1SubCtl2:
...

のようになっており、L1とL1.1に対応しています。 L0sには対応していません。

ちなみに、L1への遷移方法にはPCI-PM L1とASPM L1の2つの方法があり、それぞれ上流側、下流側で使われます。 またL1.1やL1.2への遷移可否はPCI-PMとAPSMのそれぞれで決められます。

なお、Linuxのカーネルパラメータ等でASPM関連の設定をしない場合は、基本的にBIOSでの設定がそのまま引き継がれます。 デフォルト設定のままですとオンボードI225-VでL1.1は使われないようです。

一方、カーネルパラメータとしてpcie_aspm.policy=performanceを追加すると、ASPMのデフォルトが「無効」になります。

I225-VのASPM有効/無効の確認と変更

カーネルパラメータなしでLinuxを起動すると、lscpi -vvの結果は

...
            LnkCtl: ASPM L1 Enabled; RCB 64 bytes, Disabled- CommClk+
                    ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
...

となり、ASPM L1が有効になっていることが分かります。その状態で、

echo 0 > /sys/class/net/eno1/device/link/l1_aspm

を実行すると、結果は

...
            LnkCtl: ASPM Disabled; RCB 64 bytes, Disabled- CommClk+
                    ExtSynch- ClockPM- AutWidDis- BWInt- AutBWInt-
...

となり、ASPMの無効化を確認できます。

I225-V自体の電源状態

ASPMとは別に、PCI/PCIeデバイスの電力制御(PCI-PM)としてD0~D3の4つの状態があります。

lspci -vvの結果では

...
    Capabilities: [40] Power Management version 3
            Flags: PMEClk- DSI+ D1- D2- AuxCurrent=0mA PME(D0+,D1-,D2-,D3hot+,D3cold+)
            Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=1 PME-
...

となっていて、I225-VではD0とD3のみサポートしています。 仮にD3がWake-on-Lan (WoL)用の状態だとすると、I225-Vを普通に使っている間はD0固定となって、PCIeの電源管理の影響はなさそうです。つまり、カーネルパラメータのpcie_port_pm=offは不要そうです。

ASPM無効化を自動で設定する方法

Debianですと/etc/network/interfacesのpre-upに上記コマンドを書けば終わりです。 一方、最近のUbuntuはifupdownではなくnetplanをデフォルトで用いており、設定にnetworkd-dispatcherが必要です。
https://netplan.io/faq#example-for-an-ifupdown-legacy-hook-for-post-up%2Fpost-down-states

余談

当初、ASPM L1.1の問題かと思いましたが、実際に調べてみると、そもそもL1.1は有効になっていませんでした。

Pure SSHなGit LFSを使う

以前のGit LFSは常にHTTPでサーバに接続していました。 しかし、git-lfsの最近のバージョンはSSH接続もサポートしています。
また、リモートのGitレポジトリとは違う場所にSSHで接続するGit LFSのサーバを作ることもできます。

やりたいこと

  • リモートのGitレポジトリとは別のSSHでアクセスできるマシンをGit LFSのサーバにしてデータを置きたい。
    • 例えば、100MB超のファイルを含むGitレポジトリをGitHubで管理したいが、GitHubのGit LFSが使えない場合。
      • 注: GitHubへは100MB超のファイルがあるとpushできません。またGit LFSの無料枠は1GBです。

条件等

  • LinuxなSSHサーバが既にある。とにかくSSH接続だけで済ませたい。
    • 逆に言うと、SSH接続が前提なので、パブリックなレポジトリではセキュリティ的に大変かもしれません。
  • Git LFSのロック機能には興味が無い
    • 今回、Git LFSのロック機能は全く検証していません。

Git LFSサーバ側の設定

既にSSHのサーバは設定されているものとします。

Git LFSをSSH経由で使う場合、サーバ側にgit-lfs-transferという実行ファイルが必要です。 今回は、Git LFSクライアント側の開発時にリファレンス実装として用いられたscutiger-lfsを使います。 Rustで実装されています。

ちなみに、2023年12月現在、Git LFSの実装リストによると、git-lfs-transferの実装は他に2つあります。

git-lfs-transfer のビルドとインストール

以下はDebian 12 (bookworm)を想定した手順となります。 もし、将来git-lfs-transfer実装のどれかがDebianパッケージ化されれば、それをインストールするだけで良いはずです。

まず、ScutigerのREADMEによると、ビルドにはRust 1.63以降、Cargo、Gnu Make、gitが必要です。 加えて、zlib、libpcre2、libgit2のダイナミックリンクが推奨されているので、それらの開発用パッケージもインストールします。

sudo apt update
sudo apt install rustc cargo make git zlib1g-dev libpcre2-dev libgit2-dev

次に、Scutigerのソースをダウンロードしてビルドします。 そしてビルドされたgit-lfs-transferを/usr/local/binにインストールします。
(ここでは/usr/local/binにパスが通っているものとします。)

git clone https://github.com/bk2204/scutiger
cd scutiger
make
sudo cp target/release/git-lfs-transfer /usr/local/bin/

Git LFS用のディレクトリを作成

Git LFSのデータ格納用のディレクトリとして、空のGitレポジトリを作成してください。 ここではそのパスを/home/gituser/git/testrepo.gitとします。

git init --bare --shared /home/gituser/git/testrepo.git

このようにbareレポジトリを作成した場合、実際のGit LFSのデータは/home/gituser/git/testrepo.git/lfs/に格納されます。
(注: SSH越しにGitを用いる場合はGitレポジトリをgroup writableにすることが多いため、例でも--sharedを指定しています。)

あるいは、bareレポジトリにしなくてもかまいません。 Git LFSのデータを格納するbareではないGitレポジトリが/home/gituser/git/testrepoの時、Git LFSのデータは /home/gituser/git/testrepo/.git/lfs/に格納されます。

scutiger-lfsのgit-lfs-transferはGitレポジトリの中にしかGit LFSのディレクトリを配置できないようなので今回は空のGitレポジトリを作っていますが、この辺はgit-lfs-transferの実装によっても異なると思います。

サーバ側の設定はこれで終わりです。

クライアント側の設定

ローカルのGitレポジトリの設定 (Gitレポジトリとは別の場所にGit LFSサーバを置きたい場合)

ここでは、Git LFSサーバのホスト名がssh.example.comであるとします。

Git LFSのエンドポイントをssh.example.comに向けるために、ローカルのGitレポジトリのトップディレクトリで

git config -f .lfsconfig lfs.url ssh://ssh.example.com/home/gituser/git/testrepo.git

を実行します。また、もしポート番号が(22ではなく)12345であれば

git config -f .lfsconfig lfs.url ssh://ssh.example.com:12345/home/gituser/git/testrepo.git

となります。

その他は通常のGit LFSと同じ使い方になります。まずは

git lfs install

を実行してください。 ただし、以下の補足にて述べるように、追加で

git config lfs.ssh.automultiplex false

を実行する必要があるかもしれません。

補足

  • ローカル側が正しく設定されていれば、git lfs envの実行結果に

    Endpoint=https://ssh.example.com/home/gituser/git/testrepo.git (auth=none)
      [email protected]:/home/gituser/git/testrepo.git
    

    という行があるはずです。 なお、SSHのポート番号を指定した場合、その値がここでは表示されないものの、内部で呼ばれる実際のsshコマンドでは-pオプションでポート番号が指定されます。

  • 繰り返しになりますが、今回用いたgit-lfs-transfer実装の都合により/home/gituser/git/testrepo.gitという空のGitレポジトリを作成しているだけで、それをGitレポジトリとしては使わない想定です。
    とはいえ、もちろんGitレポジトリとして普通に使うこともできます。 さらに、.lfsconfig がなければ、Git LFSのエンドポイントはリモートのGitレポジトリと同じ場所になります。 つまり、リモートのGitレポジトリにSSHでアクセスさせる構成なら、そのリモートのマシンにgit-lfs-transferを追加でインストールするだけでGit LFSが使えます。
    (というか、今回のようにリモートのGitレポジトリとGit LFSサーバを別のホストにする方が特殊だと思います。)

  • OpenSSHを使っている場合、複数のSSH通信を1つのコネクションにまとめることができます(マルチプレキシング)。 デフォルトではその機能が有効になっていますが、クライアントとサーバが同じホストにある場合にgit pushが途中で止まってしまったりと、環境によっては正しく動作しないことがあります。 その場合は

    git config lfs.ssh.automultiplex false
    

    を実行して、マルチプレキシングを無効にしてください。

  • (SSH接続に限った話ではありませんが) .gitattributesのコミットは忘れやすいので気をつけましょう。