전체 흐름
driver_init()은 init/main.c의 do_basic_setup()에서 L1326에 직접 호출되고 일반 do_initcalls()보다 앞선다. drivers/base/init.c에 적힌 순서로 device model의 기반을 만든다. 특정 driver 등록·match·probe는 이후 단계다.
devtmpfs, device kobject, bus, class, firmware/hypervisor 기반과 후속 platform 등의 core 진입점을 순서대로 부른다.
driver_init()은 void다. devices_init()의 int 반환값은 이 호출자에게서 사용되지 않는다.
실선은 고정 init.c의 호출 순서와 이후 단계의 경계를 뜻한다. probe 완료 표시가 아니다.
소스 코드 위치
먼저 확인할 Linux v6.6 소스 파일
Linux v6.6: drivers/base/init.c
Linux v6.6: drivers/base/core.c
Linux v6.6: drivers/base/bus.c
Linux v6.6: drivers/base/dd.c
설명: 이 글의 대표 함수는 init.c의 driver_init()과 core.c의 devices_init()이다. bus 등록과 driver matching/probe는 별도 파일·후속 단계로 읽는다.
대표 코드
void __init driver_init
void __init driver_init(void)
{
/* These are the core pieces */
bdi_init(&noop_backing_dev_info);
devtmpfs_init();
devices_init();
buses_init();
classes_init();
firmware_init();
hypervisor_init();
/* These are also core pieces, but must come after the
* core core pieces.
*/
of_core_init();
platform_bus_init();
auxiliary_bus_init();
cpu_dev_init();
memory_dev_init();
node_dev_init();
container_dev_init();
}
확인 사항: driver_init()은 void이고 devices_init()의 반환값을 사용하지 않는다. 호출 순서는 core 기반의 순서이며 probe 완료가 아니다.
devices_init
int __init devices_init(void)
{
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
if (!devices_kset)
return -ENOMEM;
dev_kobj = kobject_create_and_add("dev", NULL);
if (!dev_kobj)
goto dev_kobj_err;
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
if (!sysfs_dev_block_kobj)
goto block_kobj_err;
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
if (!sysfs_dev_char_kobj)
goto char_kobj_err;
return 0;
char_kobj_err:
kobject_put(sysfs_dev_block_kobj);
block_kobj_err:
kobject_put(dev_kobj);
dev_kobj_err:
kset_unregister(devices_kset);
return -ENOMEM;
}
devices_init()은 driver_init()의 직접 호출이다. devices_kset과 dev/block/char sysfs 기반을 만들고, 실패 시 이미 만든 것만 역순 정리해 -ENOMEM을 돌려주지만 상위 호출은 그 값을 읽지 않는다.
함수별 분석
devices_init()은 driver_init()이 직접 호출한다. 내부에서 devices_kset, dev_kobj, block/char kobject를 순서대로 만들며, workqueue 할당 단계 없이 끝난다. 이 함수는 bus/class 객체나 개별 driver의 private data를 만들지 않는다.
각 단계가 실패하면 그때까지 만든 대상만 반대 순서로 해제한다. 함수 내부의 오류 처리와 driver_init()의 반환값 무시를 구분한다.
| 실제 함수 | 변경하는 상태 | 별도로 남는 질문 |
|---|---|---|
driver_init() | 하위 core init 함수를 순서대로 호출 | 각 void/int 호출의 반환 정책은 서로 다름 |
devices_init() | kset/kobject 기반 | 성공 0 / 실패 -ENOMEM; 호출자는 반환값을 읽지 않음 |
| 이후 driver 등록 | bus에 driver를 추가하고 matching 진입 가능 | 이 코드 조각만으로 특정 probe의 실행·완료를 단정할 수 없음 |
객체와 sysfs 경로
devices_kset은 /sys/devices의 기반이다. dev_kobj는 별도 /sys/dev root이고 block/char kobject는 그 자식이다. device_link_wq와 wq_err는 이 버전에 없다.
bus_type과 class는 각각 뒤의 buses_init(), classes_init()에서 다룬다.
| 객체 | 생성 코드 | 관찰 가능한 위치 |
|---|---|---|
devices_kset | kset_create_and_add("devices", …) | /sys/devices |
dev_kobj | kobject_create_and_add("dev", NULL) | /sys/dev |
| block / char kobject | parent = dev_kobj | /sys/dev/block, /sys/dev/char |
실행 단계와 상태 변화
devices_init()의 성공·실패는 함수 내부에서는 구분된다. 하지만 driver_init()은 반환값을 검사하지 않고 다음 buses_init()으로 진행한다. 그러므로 뒤 함수가 호출되었다는 사실을 앞의 모든 객체 생성 성공으로 읽지 않는다.
초기화 실패가 무조건 특정 probe의 실패나 자동 복구로 이어진다고 단정하지 않는다.
| 지점 | 성공 | 실패 | 다음 단계 |
|---|---|---|---|
devices_kset | devices root 생성 | 즉시 -ENOMEM | dev_kobj |
dev_kobj | dev root 생성 | devices_kset unregister | block |
| block kobject | block child 생성 | dev put → kset unregister | char |
| char kobject | char child 생성 | block → dev → kset 정리 | return 0 |
불변 조건과 실패 사례
char는 block과 dev root가 만들어진 뒤 생성한다. v6.6에는 faux_bus_init()가 없고 CPU→memory→node 순서다.
devices_init()의 label은 현재까지 만든 객체만 정리한다. device_link_wq와 wq_err는 이 버전에 없다.
driver_init()은 devices_init()의 -ENOMEM을 전파하지 않는다. 뒤의 기반이 정상이라는 결론을 여기서 내릴 수 없다.
sysfs 기반의 존재는 특정 device에 driver가 붙었거나 하드웨어 초기화가 끝났다는 증거가 아니다.
계측과 검증
이 경로에는 전용 driver_init tracepoint가 없다. initcall_debug도 do_initcalls()의 개별 initcall에 대한 것이므로, 그 앞의 직접 호출인 driver_init() 자체가 완료됐다는 기록으로 읽지 않는다. 다음은 공유 tracefs 설정을 바꾸지 않는 관찰이다.
| 읽기 전용 관찰 | 알 수 있는 것 | 한계 |
|---|---|---|
ls -ld /sys/devices /sys/dev /sys/dev/block /sys/dev/char | 현재 sysfs root와 자식 존재 | 부팅 당시 어느 내부 호출이 성공했는지 단독 증명 불가 |
ls /sys/bus | 이후 등록된 bus 목록 | 특정 device probe 완료와 다름 |
dmesg | grep -i "probe\|device" | 장치별 후속 메시지 | 로그 설정과 driver 구현에 좌우 |
cat /sys/kernel/debug/devices_deferred (파일이 있을 때) | 현재 deferred probe 대상 | driver_init() 완료 기록이 아님 |
ls -ld /sys/devices /sys/dev /sys/dev/block /sys/dev/char
ls /sys/bus
if [ -r /sys/kernel/debug/devices_deferred ]; then cat /sys/kernel/debug/devices_deferred; fi추가 확인 사항
devices_init()가 -ENOMEM을 반환한 뒤driver_init()은 왜 그 값을 전파하지 않는가?- v6.6의 마지막 char kobject 실패는 어떤 순서로 되돌리는가?
/sys/devices가 보이는 것과 특정 driver의 probe 완료를 어떤 로그·소스로 구분할 수 있는가?- 두 버전의 뒤쪽 core 호출 순서 차이가 특정 platform 초기화 의존성에 영향을 주는가?