NTFS ボリューム上で新規ファイルが作成できない現象について

こんにちは。Windows テクノロジー サポートの新川です。

Windows Server 2003 上でシステム リソースは全く枯渇していないのにSTATUS_INSUFFICIENT_RESOURCES (0xc000009a) を示す以下などのエラーが発生してファイルの新規作成やコピーができないというお問い合わせをいただく事があります。

 

・必要な記憶域をサーバーで確保できません

・リソースが不足しているため要求されたサービスを完了できません

 

上記エラーは $Secure の肥大化が原因である場合があります。今回は $Secure の肥大化によって発生する本事象について、NTFS の仕組みからじっくりとお話しします。

STATUS_INSUFFICIENT_RESOURCESエラーと NTFS の関係

Windows Vista より前の OS では、NTFS の特定領域 (ATTRIBUTE_LIST) をメモリのバッファ上に確保しようとした際に、バッファが確保できないと STATUS_INSUFFICIENT_RESOURCES エラーが返されます。これは、バッファが確保できない状況からリソース不足と考えて返しているのですが、実際にリソースが枯渇して十分なバッファを用意できない場合と、ATTRIBUTE_LIST の上限値 (256 KB) を超える処理が発生した場合に、先に行う ATTRIBUTE_LIST のバッファ確保の処理で、用意できる最大サイズのバッファでも足りないためにエラーが返される場合があります。

 

当然、これは十分なバッファを確保できない事が問題ではなく、ATTRIBUTE_LIST の上限値を超えた処理が行われた事が問題であり、Windows Vista 以降では、後者を区別できるよう別のエラー (STATUS_FILE_SYSTEM_LIMITATION) が返されるように動作が変更されています。以下の KB にもその内容や、処理のタイミングによっては他のエラーが返される可能性および、今回のお話にも大きく関連する ATTRIBUTE_LIST について書かれていますので、先にご案内させていただきます。

 

Article ID: 967351

A heavily fragmented file in an NTFS volume may not grow beyond a certain size

https://support.microsoft.com/kb/967351/en-us

 

Article ID: 957180

Problem: Extending a File may fail with “Disk Full” Error even though Volume has Free Space

https://support.microsoft.com/kb/957180/

 

もし、上記 KB をご覧いただいて、内容を一通りご理解いただけるのであれば、下記 NTFS の仕組みに関する部分は飛ばしていただき、$Secure に関する部分から御覧下さい。

 

 

ATTRIBUTE_LIST について

まずは今回の原因をお話する前に、ATTRIBUTE_LIST とは何であるかについてから説明します。

以下に、NTFS の拡張処理についてわかりやすい図が含まれているブログがありますので、別のウィンドウで開くなど、一緒にご覧いただきながらお読み下さい。

 

The Four Stages of NTFS File Growth

https://blogs.technet.com/askcore/archive/2009/10/16/the-four-stages-of-ntfs-file-growth.aspx

 

NTFS のファイル管理について非常に簡単に説明すると、NTFS ではボリューム上に存在する全てのファイルやフォルダは、MFT へ File Record として登録されています。ただし、File Record は サイズの上限が 1KB と決まっていますので、ファイルのメタデータも含めたサイズが 1KB 程度以下でないと MFT 内の File Record には収まりきりません。

 

データ部分などの収まりきらない領域を NTFS では ラン (拡張) と呼ばれる別のクラスタへ配置します。MFT 内の File Record には、このランがどこにあるかを見つけるための、VCN (Virtual Cluster Number) と LCN (Logical Cluster Number) のマッピング情報が格納されます。VCN とは、ファイルに先頭からクラスごとに順番を割り振ったものであり、LCN はボリューム全体のクラスタシーケンス番号を示します。わかりやすく言うと、ファイルのパーツがボリューム上のどこに保存されているかを示すマッピング情報です。これが、上記ブログの Stage two – Nonresident Dataの状態となります。

 

マッピング情報は具体的に [先頭 VCNの番号、先頭 LCN の番号、長さ (クラスタ数)] となりますが、ボリュームにフラグメントが発生している場合や、圧縮属性およびスパース属性を持ったファイル (圧縮属性およびスパース属性を持ったファイルの場合、マッピング情報は最大で 16 VCN ごとに行うという制約があります)は、マッピングのエントリが増える事となります。

 

このマッピング情報も File Record に登録されていますので、1KB 以下 (実際には 700Bytes 程度以下) である必要があります。ただし、マッピング情報は1 エントリにおよそ 40 Bytes 程度が必要となりますので (VCN や LCN の桁数等で大きく変わります)、状況によっては溢れてしまいます。

 

ここで、更にマッピング情報だけを保持するために、マッピング情報を登録するための File Record (Child File Record) を設け、MFT 内の File Record には Child File Record を管理するための ATTRIBUTE_LIST というリストを持ちます。これが上記ブログ内の  Stage three – Nonresident Attribute となります。

 

なお、この ATTRIBUTE_LIST は、上限値が 256KB となります。

となると、ATTRIBUTE_LIST は MFT 内の File Record に収まりきらない事になりますので、これもランを用いられて MFT の File Record 外に配置され、MFT 内の File Record に ATTRIBUTE_LIST のマッピング情報が格納されている状態が、上記ブログ内の Stage four – Nonresident Attribute List  となります。

 

 

ATTRIBUTE_LIST が上限値の 256 KB を超える状況

上記で NTFS は1つのファイルを大きく 2 段階の拡張 (ランの利用、ATTRIBUTE_LIST の利用) していると説明しました。

マッピング情報は LCN や VCN の桁数等によって大きく変わるのですが、上記にも記載したとおり、私の経験としてはおよそ 1 エントリあたり 40 Byte 程度消費します。ATTRIBUTE_LIST 内のエントリも大体同じ程度です。

 

という事は、256 KB の ATTRIBUTE_LIST と、1 KB の Child File Record (実際にはメタデータ等を含みますので、データとして利用可能なのは 700 Bytes 程度) をかけたマッピング情報が登録できるという事になり、およそですが 1 ファイル当たり最大で以下のエントリを持てるという事になります。(なお、Child File Record のフラグメント等を全く考慮していない計算式です)

 

256 KB / 40 Bytes * 700 Bytes / 40 = 114,688

 

マッピング情報だけでこれだけの数を持てるという事なので、ATTRIBUTE_LIST が枯渇する状況というのは通常は非常に考えにくいですが、前項でも少し触れた通り圧縮ファイルやスパース属性をもったファイルは 16 VCN ごとでエントリを区切る必要があるため、数百 GB 程度で上限値に達する事があり、フラグメントが発生している環境だと更に小さいファイルサイズでも発生するという内容が上記 KB 967351 や KB 957180 に記載されている内容となります。

 

 

NTFS では、セキュリティ記述子が残り続ける

ATTRIBUTE_LIST  に関する仕組みをご理解いただいたところで、ここで少し別の話に変わります。

 

Windows Server 2000 以降、NTFS はセキュリティ情報を $Secure と呼ばれる中央メタデータ ファイルを用意し、ボリューム上の全てのセキュリティ記述子をここに格納する形となっています。各ファイルには、$STANDARD_INFORMATION の中にセキュリティ ID のみが格納されており、ディスク消費の効率化が行われています。

 

ただ、一度作成されたセキュリティ記述子は、ボリューム上に存在するファイルやディレクトリが参照していない場合でも、削除されません。これは、Windows Server 2003 の NTFS を設計した時点では不要な ACL の割り当てが大量に行われる事はないと考えていたためです。

 

ここが、”NTFS ボリューム上で新規ファイルを作成できない” という問題に至る場合があります。

 

 

$Secure が肥大化し、新しいセキュリティ記述子が作成できなくなる

近年セキュリティに関して非常に厳しくなり、ACL が非常に細かく割り当てられ、セキュリティ記述子が大量に使用される場面が度々あります。

$Secure は MFT 内の NTFS メタデータ ファイルの1つですが、これも File Record の1つであるため 1KB の制約は受け、セキュリティ記述子 (実際にはセキュリティ記述子だけではなく、$SDH や $SII なども含まれます) が 収まりきらない場合ランが使用され、それでも収まりきらない場合は ATTRIBUTE_LIST が用いられます。

 

セキュリティ記述子は1つのデータあたりの情報はそれ程大きくないため、この ATTRIBUTE_LIST までもがいっぱいになる場面は稀ですが、ACL のパターンごとに生成され、更に全く削除が行われない動作となっているため、アクセスするユーザーが多く、セキュリティ設定が細かいファイルサーバーなどでは、$Secure の ATTRIBUTE_LIST が枯渇する場合があります。

 

そういう状況で、新たなセキュリティ記述子が必要となるような新規ファイルの作成を行う処理を行った場合、文頭にあげたような一見リソース不足を示すエラーが記録され、ファイルが作成されない現象が発生してしまいます。

 

 

$Secure が肥大化したかどうかを確認する方法

$Secure の肥大化に該当しているかどうかは、問題が発生しているボリューム上で $Secure の Child File Record がいくつ程度であるかを確認する必要があります。 

ATTRIBUTE_LIST (256KB) 内で 1 エントリに 40 Bytes 程度消費しますため、256KB / 40 Bytes ≒ 6554 程度の Child File Record で$Secure の ATTRIBUTE_LIST が枯渇する事が予想されます。nfi.exe の結果を $Secure (File Record 名が $Secure) で Grep し、File Record 数が 6000 を超えているのであれば、この問題が発生する可能性が高いと思われます。

 

 

対処方法

この問題に対応すべく、以下の KB 919241 にて chkdsk にて既に参照されていないセキュリティ記述子を削除する機能が追加されました。

 

Article ID: 919241

An update is available that lets the Chkdsk.exe tool compact the NTFS security descriptor stream in Windows Server 2003 Service Pack 2

https://support.microsoft.com/kb/919241/en-us

 

上記修正プログラムを適用し、chkdsk /f を行う事で不要なセキュリティ記述子が削除されます。

 

ただし、一般的に $Secure の ATTRIBUTE_LIST を使い切る環境は、大量の File Record が存在している事が予想されます。

過去お問い合わせいただいたお客様では、ディスク容量が 1TB 程度であっても、1 週間かかっても chkdsk が終わらなかったというお話を伺っています。

chkdsk 以外に不要なセキュリティ記述子を削除する方法としては、現在ボリューム上に存在しているデータをバックアップし、現在のボリュームをフォーマットした上でリストアする事で、必要なセキュリティ記述子のみが追加されます。chkdsk と比較して、大きく時間を短縮する事が可能かと思いますので、万が一この問題が発生した場合にはご検討ください。

 

なお、Windows7 / Windows Server 2008 R2 では、MFT 内の NTFS メタデータについても、デフラグが実施できるようになっています。

 

What's New in NTFS

https://technet.microsoft.com/en-au/library/ff383236(WS.10).aspx

*********************************************

Support for file system metadata defragmenting

Prior to Windows 7 and Windows Server 2008 R2, certain file system metadata associated with user data files (for example, reparse point or Encrypting File System (EFS) data) could not be defragmented. Enhancements to the defragment engine enable certain file system metadata to be defragmented. This change helps improve the performance of files with many reparse points and resident files. It can also help enable Volume Shrink to reclaim more space than was previously possible.

*********************************************

$Secure のデータは少しずつ登録される事が多く、非常にフラグメントが発生しやすい環境です。$Secure のフラグメントが解消される事で、登録できるセキュリティ記述子の数が増える事が期待できます。Windows7 / Windows Server 2008 R2 以降の環境で発生した場合には、まずはデフラグの実施をご検討ください。※ 現在、Windows 7 / Windows Server 2008 R2 環境でデフラグを実施したところ、反対に $Secure の File Record 数が増えてしまったという報告を受けています。詳細が確認出来次第この記事をアップデートいたしますので、それまで $Secure の ATTRIBUTE_LIST を減らす事を目的としたデフラグの実施はお待ちください。

また、設計段階であれば、同じ ACL を1つのボリュームにまとめるなど、各ボリュームのセキュリティ設定を減らせるように構成し、ACL はパターン数を減らせるよう可能な限りユーザー グループをご利用ください。