전체 흐름
vfs_caches_init_early()와 vfs_caches_init()는 start_kernel(): early 호출과 start_kernel(): 정식 호출에서 분리되어 호출된다. 후자는 dentry·inode뿐 아니라 file, mount, block/character-device 기반까지 준비한다. pagecache_init(): 뒤따름은 별도 후속 호출이므로 여기서 page cache 전체가 준비된다고 읽지 않는다.
호출 순서는 start_kernel() 기준이다. 특정 파일 객체의 생성·공개 순서를 뜻하지 않는다.
| 호출 지점 | 고정 원문 | 범위 |
|---|---|---|
| early VFS | start_kernel(): early 호출 → vfs_caches_init_early | lookup-head와 hashdist 조건부 hash 준비 |
| 정식 VFS | start_kernel(): 정식 호출 → vfs_caches_init | names slab 후 하위 초기화 함수를 차례로 호출 |
| 별도 page cache | pagecache_init(): 뒤따름 | VFS cache 함수 본문 바깥 |
소스 코드 위치
먼저 확인할 Linux v6.6 소스 파일
Linux v6.6: fs/dcache.c
Linux v6.6: fs/inode.c
Linux v6.6: fs/file_table.c
Linux v6.6: fs/namespace.c
설명: fs/dcache.c의 두 진입 함수와 init/main.c 호출 지점, 각 하위 함수 구현을 대조해 초기화 책임을 구분한다.
GitHub 원본:
대표 코드
void __init vfs_caches_init
/* SLAB cache for __getname() consumers */
struct kmem_cache *names_cachep __read_mostly;
EXPORT_SYMBOL(names_cachep);
void __init vfs_caches_init_early(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(in_lookup_hashtable); i++)
INIT_HLIST_BL_HEAD(&in_lookup_hashtable[i]);
dcache_init_early();
inode_init_early();
}
void __init vfs_caches_init(void)
{
names_cachep = kmem_cache_create_usercopy("names_cache", PATH_MAX, 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC, 0, PATH_MAX, NULL);
dcache_init();
inode_init();
files_init();
files_maxfiles_init();
mnt_init();
bdev_cache_init();
chrdev_init();
}확인 사항: in-lookup head, early 호출과 정식 호출 순서를 함께 보인다. names cache는 SLAB_PANIC이다.
dcache_init
dhash_entries = simple_strtoul(str, &str, 0);
return 1;
}
__setup("dhash_entries=", set_dhash_entries);
static void __init dcache_init_early(void)
{
/* If hashes are distributed across NUMA nodes, defer
* hash allocation until vmalloc space is available.
*/
if (hashdist)
return;
dentry_hashtable =
alloc_large_system_hash("Dentry cache",
sizeof(struct hlist_bl_head),
dhash_entries,
13,
HASH_EARLY | HASH_ZERO,
&d_hash_shift,
NULL,
0,
0);
d_hash_shift = 32 - d_hash_shift;
}
static void __init dcache_init(void)
{
/*
* A constructor could be added for stable state like the lists,
* but it is probably not worth it because of the cache nature
* of the dcache.
*/
dentry_cache = KMEM_CACHE_USERCOPY(dentry,
SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD|SLAB_ACCOUNT,
d_iname);
/* Hash may have been set up in dcache_init_early */
if (!hashdist)
return;
dentry_hashtable =
alloc_large_system_hash("Dentry cache",
sizeof(struct hlist_bl_head),
dhash_entries,
13,
HASH_ZERO,
&d_hash_shift,
NULL,
0,
0);
d_hash_shift = 32 - d_hash_shift;
}확인 사항: early/정식 dentry hash의 hashdist 분기를 끝까지 포함한다. runtime_const_init() 호출 없음
함수별 분석
early 함수는 in-lookup hash head를 초기화한 뒤 dentry·inode early 함수를 부른다. dcache_init_early/inode_init_early는 hashdist가 참이면 hash 할당을 미룬다. 정식 함수의 dcache_init/inode_init는 slab을 만들고 미뤄진 경우에만 hash를 할당한다.
runtime_const_init() 호출 없음
fs/dcache.c의 호출열이다. 세부 준비·실패 처리는 하위 함수가 담당한다.
| 함수 | 실제 준비·변경 | 고정 원문 |
|---|---|---|
| dcache / inode | dentry slab의 usercopy 필드는 d_iname; inode slab; hashdist에 따라 early 또는 정식 시점에 hash 할당 | dcache_init · inode_init |
| file | filp_cachep 한 종류와 nr_files counter; 파일 수 상한도 별도 계산 | files_init · files_maxfiles_init |
| mount | mount/mountpoint hash, kernfs/sysfs, rootfs와 initial mount tree | mnt_init |
| device | bdev pseudo-fs 등록·mount; chrdev kobj_map | bdev_cache_init · chrdev_init |
구조체와 필드
여기서 만드는 것은 특정 dentry·inode·file 객체가 아니라 그것을 위한 slab, hash, 계수와 namespace 기반이다. vfs_caches_init()의 직접 설정과 하위 함수가 준비하는 기반을 구분한다.
호출 관계의 중심
허브에서 뻗는 초기화 책임을 나타낸다. dentry → inode → file 객체를 여기서 차례로 만든다는 뜻이 아니다.
| 자료구조 | 설정 함수 | 해석 |
|---|---|---|
in_lookup_hashtable
|
vfs_caches_init_early | head 초기화; 일반 dentry hash와 구별 |
dentry_hashtable
|
dcache_init_early / dcache_init | hashdist에 따라 early 또는 정식 |
names_cachep
|
vfs_caches_init | __read_mostly; name buffer slab |
filp_cachep
|
files_init | filp slab + nr_files per-CPU counter |
mount_hashtable / mountpoint_hashtable
|
mnt_init | rootfs/tree 구성도 같은 함수 안 |
실행 단계와 상태 변화
초기화 함수는 void이며 여기서 통합 오류 반환값이나 공통 unwind label을 제공하지 않는다. 실패 처리는 하위 함수마다 다르다. 준비 완료는 일반적인 모든 filesystem이 mount됐다는 뜻이 아니다.
| 경계 | 정상 완료 시 | 실패·주의 |
|---|---|---|
| early hash | in-lookup head; hashdist=0이면 dentry/inode hash | hashdist≠0이면 아직 hash를 만들지 않은 것이 정상 |
| 정식 slab/hash | names, dentry, inode, file slab·hash·파일 수 상한 | SLAB_PANIC slab 실패는 정상 반환·unwind로 이어지지 않음 |
| mount | mount hash, kernfs/sysfs, rootfs/tree | mount hash 실패는 panic; sysfs_init·fs_kobj 오류는 경고 후 진행 |
| bdev/chrdev | bdev pseudo-fs mount 뒤 cdev lookup map | bdev 등록·kern_mount 오류는 panic |
| 후속 | start_kernel의 pagecache_init() | VFS 초기화 본문 밖 |
불변 조건과 실패 사례
hashdist가 참이면 early hash 함수는 의도적으로 반환한다. 정식 함수에서 slab을 만든 뒤 hash를 할당한다.
slab·hash 준비를 특정 dentry·inode·file 객체 생성이나 pathname lookup 완료로 해석하지 않는다.
mnt_init()은 mount hash뿐 아니라 kernfs, sysfs, rootfs와 initial mount tree까지 진행한다.
공통 goto 복구가 없다. SLAB_PANIC, mount hash panic, sysfs 경고, bdev panic을 각각 읽는다.
계측과 검증
부팅 초기화의 호출 순서는 고정 소스에서 확인하고, 부팅한 시스템에서는 읽기 전용 출력으로 결과 기반을 관찰한다. 사후 slab 수치만으로 어느 init 함수가 언제 실행됐는지는 단정할 수 없다.
| 읽기 전용 관찰 | 확인 가능한 내용 | 한계 |
|---|---|---|
cat /proc/slabinfo
|
dentry, inode_cache, filp, mnt_cache, bdev_cache 등 이름 | 사용·할당 수는 부팅 이후 변함; 호출 순서 증거 아님 |
cat /proc/sys/fs/file-max
|
files_stat.max_files 관련 상한 | 런타임에 바뀔 수 있어 초기값과 다를 수 있음 |
cat /proc/self/mountinfo
|
현재 namespace의 mount 결과 | 초기 mount tree 생성 시각을 보여주지 않음 |
| 고정 원문 대조 | fs/dcache.c · start_kernel(): 정식 호출 | hashdist·panic·warning은 함수별 분기 확인 |
cat /proc/slabinfo
cat /proc/sys/fs/file-max
cat /proc/self/mountinfo
추가 확인 사항
- 대상 빌드의
hashdist값에 따라 dentry·inode hash는 어느 함수에서 할당되는가? - 진단 대상이 slab, hash, mount tree, bdev pseudo-fs 중 어느 단계까지 도달했는가?
- sysfs 경고와 bdev mount panic을 구분했는가?
- page cache 문제는
pagecache_init()이후의 경로인가?