これは、ls -li
の出力です。 VFATファイルシステムのコマンド。
% ls -li
合計 736
1207 drwxr-xr-x 3 root root 16384 3月 10 10:42 efi
1208 -rwxr-xr-x 1 root root 721720 3月 22 14:15 kernel.bin
1207
および1208
ディレクトリとファイルのiノード番号です。ただし、VFATファイルシステムにはiノードの概念がありません。
Linuxは、iノードの概念がないファイルシステム上のファイルにiノード番号をどのように割り当てますか?
承認された回答:
tl; dr:仮想、揮発性、またはiノードに依存しないファイルシステムの場合、iノード番号は通常、iノードの作成時に単調に増加する32ビットカウンターから生成されます。 iノードの残りの部分(パーミッションなど)は、基盤となるファイルシステムの同等のデータから構築されるか、マウント時に設定された値({uid,gid}=
など)に置き換えられます。 )そのような概念が存在しない場合。
タイトルの質問(つまり、Linuxがiノードの概念を持たないファイルシステムにiノード番号を割り当てる方法)に答えるには、ファイルシステムによって異なります。一部の仮想ファイルシステムまたはiノードレスファイルシステムの場合、iノード番号はインスタンス化時にget_next_ino
から取得されます。 プール。ただし、これにはいくつかの問題があります。
-
get_next_ino()
_FILE_OFFSET_BITS=64
のない32ビットユーザーランドのレガシー処理により、64ビットカーネルでも32ビットiノード番号を使用します; -
get_next_ino()
は、複数のファイルシステムで使用されるグローバルにインクリメントするカウンターであるため、オーバーフローのリスクはさらに高まります。
このような問題は、昨年tmpfsをget_next_inoでバックアップされたiノードから移動した理由の1つです。
このため、特にtmpfsは、ほとんどの揮発性または「inodeless」ファイルシステム形式の例外です。ソケット、パイプ、ramfsなどは引き続きget_next_ino
を使用します 5.11現在のプール。
FATファイルシステムに関する具体的な質問:fs/fat/inode.c
ここで、iノード番号がFATvilesystemsに割り当てられます。そこを見ると、fat_build_inode
が表示されます。 (出典):
struct inode *fat_build_inode(struct super_block *sb,
struct msdos_dir_entry *de, loff_t i_pos)
{
struct inode *inode;
int err;
fat_lock_build_inode(MSDOS_SB(sb));
inode = fat_iget(sb, i_pos);
if (inode)
goto out;
inode = new_inode(sb);
if (!inode) {
inode = ERR_PTR(-ENOMEM);
goto out;
}
inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
inode_set_iversion(inode, 1);
err = fat_fill_inode(inode, de);
if (err) {
iput(inode);
inode = ERR_PTR(err);
goto out;
}
fat_attach(inode, i_pos);
insert_inode_hash(inode);
out:
fat_unlock_build_inode(MSDOS_SB(sb));
return inode;
}
これが基本的に言うことはこれです:
- このスーパーブロックのFATiノード作成ロックを取得します。
- iノードがスーパーブロックのこの位置にすでに存在するかどうかを確認します。その場合は、ロックを解除してそのiノードを返します。
- それ以外の場合は、新しいiノードを作成します。
-
iunique(sb, MSDOS_ROOT_INO)
からiノード番号を取得します (これについてはすぐに詳しく説明します)。 - 同等のFATデータ構造から残りのiノードを入力します。
inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
ここでiノード番号が設定されます。 iunique
(ソース)は、特定のスーパーブロックに一意のiノード番号を提供するfsに依存しない関数です。これは、スーパーブロック+ iノードベースのハッシュテーブルを使用して、単調に増加するカウンターで行います。
ino_t iunique(struct super_block *sb, ino_t max_reserved)
{
static DEFINE_SPINLOCK(iunique_lock);
static unsigned int counter;
ino_t res;
rcu_read_lock();
spin_lock(&iunique_lock);
do {
if (counter <= max_reserved)
counter = max_reserved + 1;
res = counter++;
} while (!test_inode_iunique(sb, res)); /* nb: this checks the hash table */
spin_unlock(&iunique_lock);
rcu_read_unlock();
return res;
}
その点では、前述のget_next_ino
と非常によく似ています。 :グローバルではなく(パイプやソケットなどのように)、スーパーブロックごとに、衝突に対する基本的なハッシュテーブルベースの保護を使用します。 get_next_ino
も継承します の動作は、レガシーアプリケーションでEOVERFLOWを回避する方法として、32ビットのiノード番号を使用しているため、64ビットのiノードの修正が必要なファイルシステムが増える可能性があります(前述のinode64
など)。 将来的にはtmpfsの実装)。
要約すると:
- ほとんどの仮想ファイルシステムまたはiノードレスファイルシステムは、iノード番号に単調にインクリメントするカウンターを使用します。
- このカウンターは、ディスク上のinodelessファイルシステム*でも安定していません。再マウント時にファイルシステムに他の変更を加えることなく変更される可能性があります。
- この状態のほとんどのファイルシステム(
inode64
のtmpfsを除く) )はまだ32ビットカウンタを使用しているため、頻繁に使用すると、カウンタがオーバーフローして、iノードが重複する可能性があります。
*…ただし、公平を期すために、契約により、これはするファイルシステムにも当てはまります。 i_generation
の場合、iノードの概念があります 変更— iノード番号はその物理的な位置などに関連していることが多いため、実際には発生する可能性は低くなります。