Questo è l'output di ls -li
comando sul filesystem 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
e 1208
sono i numeri di inode della directory e del file. Tuttavia, il filesystem VFAT non ha il concetto di inode.
In che modo Linux assegna i numeri di inode ai file su un filesystem che non ha la nozione di inode?
Risposta accettata:
tl;dr:per filesystem virtuali, volatili o indipendenti dall'inode, i numeri di inode vengono generalmente generati da un contatore a 32 bit a incremento monotono quando viene creato l'inode. Il resto dell'inode (es. permessi) viene compilato dai dati equivalenti nel filesystem sottostante, o viene sostituito con valori impostati al momento del montaggio (es. {uid,gid}=
) se tale concetto non esiste.
Per rispondere alla domanda nel titolo (cioè astrattamente, come Linux alloca i numeri di inode per un filesystem che non ha il concetto di inode), dipende dal filesystem. Per alcuni filesystem virtuali o inode, il numero di inode viene estratto al momento dell'istanza da get_next_ino
piscina. Questo ha una serie di problemi, però:
get_next_ino()
utilizza numeri di inode a 32 bit anche su un kernel a 64 bit, a causa della gestione legacy per userland a 32 bit senza_FILE_OFFSET_BITS=64
;get_next_ino()
è solo un contatore a incremento globale utilizzato da più filesystem, quindi il rischio di overflow è ulteriormente aumentato.
Problemi come questo sono uno dei motivi per cui ho spostato tmpfs lontano da get_next_ino-backed inodes l'anno scorso.
Per questo motivo, tmpfs in particolare è un'eccezione dalla maggior parte dei formati di filesystem volatili o "inodeless". Prese, pipe, rampe e simili usano ancora get_next_ino
pool a partire dal 5.11.
Per quanto riguarda la tua domanda specifica sui filesystem FAT:fs/fat/inode.c
è dove vengono assegnati i numeri di inode per i vilesystem FAT. Se guardiamo lì dentro, vediamo fat_build_inode
(fonte):
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;
}
Ciò che in pratica dice è questo:
- Prendete il blocco per la creazione dell'inode FAT per questo superblocco.
- Verifica se l'inode esiste già in questa posizione nel superblocco. In tal caso, sblocca e restituisci quell'inode.
- Altrimenti, crea un nuovo inode.
- Ottieni il numero di inode da
iunique(sb, MSDOS_ROOT_INO)
(ne parleremo più in un secondo). - Riempi il resto dell'inode dalle strutture dati FAT equivalenti.
inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
è dove è impostato il numero di inode qui. iunique
(source) è una funzione fs-agnostic che fornisce numeri di inode univoci per un dato superblocco. Lo fa utilizzando una tabella hash basata su superblock + inode, con un contatore che aumenta in modo monotono:
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;
}
Sotto questo aspetto, è abbastanza simile al già citato get_next_ino
:solo per superblocco invece di essere globale (come per tubi, prese o simili) e con una protezione rudimentale basata su tabelle hash contro le collisioni. Eredita persino get_next_ino
Il comportamento di utilizzo dei numeri di inode a 32 bit come metodo per cercare di evitare EOVERFLOW su applicazioni legacy, quindi è probabile che ci saranno più filesystem che necessitano di correzioni di inode a 64 bit (come il mio già citato inode64
implementazione per tmpfs) in futuro.
Quindi per riassumere:
- La maggior parte dei filesystem virtuali o inode utilizzano un contatore ad incremento monotono per il numero di inode.
- Quel contatore non è stabile nemmeno per i filesystem inodeless su disco*. Può cambiare senza altre modifiche al filesystem al momento del rimontaggio.
- La maggior parte dei filesystem in questo stato (tranne tmpfs con
inode64
) utilizzano ancora contatori a 32 bit, quindi con un uso intenso è del tutto possibile che il contatore possa traboccare e potresti ritrovarti con inode duplicati.
* ...sebbene, per essere onesti, per contratto questo è vero anche per i filesystem che fanno avere un concetto di inode quando i_generation
cambia — è solo meno probabile che accada in pratica poiché spesso il numero di inode è correlato alla sua posizione fisica o simili.