Linux 커 널 모듈 자동 로드 메커니즘
ID, SubVendor ID 의 장치 가 서 비 스 를 제공 합 니 다.PCI 장 치 를 예 로 들 면 pcidevice_id 의 데이터 구조 로 이 기능 을 실현 합 니 다.예 를 들 어 RTL 8139 의 Pcidevice_id 정의:
static struct pci_device_id rtl8139_pci_tbl[] = {
{0x10ec, 0x8139, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
{0x10ec, 0x8138, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8139 },
......
}
MODULE_DEVICE_TABLE (pci, rtl8139_pci_tbl);
위의 정보 에 따 르 면 베 르 돈 ID 가 0x10EC 이 고 Device ID 가 0x 8139 이 며 0x 8138 인 PCI 장치 (SubVendor ID 와 SubDeviceID 가 PCI ANY ID 로 제한 되 지 않 음 을 표시 함) 는 모두 이 드라이버 (8139 too) 를 사용 할 수 있다.
alias pci:v000010ECd00008138sv*sd*bc*sc*i* 8139too
alias pci:v000010ECd00008139sv*sd*bc*sc*i* 8139too
......
v 뒤의 000010 EC 는 벤 더 ID 가 10EC 이 고 d 뒤의 00008138 은 Device ID 가 8139 이 며 sv 는 sd 와 SubVendor ID 와 SubDevice ID 이 며 뒤의 별 번 호 는 임 의 일치 임 을 나타 낸다.
또한 / lib / modules / uname - r / modules. dep 파일 에 이 모듈 간 의존 관 계 를 저장 합 니 다. 그 내용 은 다음 과 같 습 니 다.
( 。)
8139too.ko:mii.ko
options, 이 안의 각종 버스 는 Y 나 N 만 선택 할 수 있 고 M.) 을 선택 할 수 없 으 며 모든 장치 에 장치 대상 을 만 들 수 있 습 니 다.모든 버스 대상 은 kset 대상 이 있 습 니 다. 모든 장치 대상 은 하나의 kobject 대상 을 포함 하고 kobject 는 kset 대상 에 연결 되 어 있 습 니 다. 이렇게 버스 와 버스 사이 에 버스 와 장치 장치 간 에 하나의 트 리 구조 로 구성 되 어 있 습 니 다.버스 드라이버 가 스 캔 된 장치 에 장치 대상 을 만 들 때 kobject 대상 을 초기 화하 고 장치 트 리 에 연결 하 며 kobject 를 호출 합 니 다.uevent () 는 이 (새 장 치 를 추가 하 는) 이벤트 와 관련 정보 (장치 의 VendorID, DeviceID 등 정보 포함) 를 netlink 를 통 해 사용자 상태 로 보 냅 니 다.사용자 상태의 udevd 에서 이 사건 을 감지 하면 이 정보 에 따라 / lib / modules / uname - r / modules. alias 파일 을 열 수 있 습 니 다.
alias pci:v000010ECd00008138sv*sd*bc*sc*i* 8139too
새로 스 캔 한 장치 구동 모듈 이 8139 too 라 는 것 을 알 게 되 었 습 니 다.그래서 modprobe 는 8139 too 라 는 모듈 을 불 러 올 줄 알 았 습 니 다. 또한 modprobe 는 modules. dep 파일 에 따 르 면 8139 too 는 mii. ko 에 의존 하고 mii. ko 가 불 러 오지 않 으 면 modprobe 는 먼저 mii. ko 를 불 러 오고 이어서 8139 too. ko 를 불 러 옵 니 다.
테스트
셸 에서 실행:
# ps aux | grep udevd
root 25063 ...... /sbin/udevd --daemon
udevd 의 프로 세 스 ID 25063 을 받 았 습 니 다. 이 프로 세 스 를 끝 냅 니 다.
# kill -9 25063
그리고 udevd 를 추적 하여 셸 에서 실행 합 니 다:
# strace -f /sbin/udevd --daemon
이때, 우 리 는 udevd 의 출력 을 다음 과 같이 보 았 다.
......
close(8) = 0
munmap(0xb7f8c000, 4096) = 0
select(7, [3 4 5 6], NULL, NULL, NULL
우 리 는 udevd 가 여기에서 select () 함수 에 막 혀 있 는 것 을 발견 했다.
select 함수 원형 은 다음 과 같 습 니 다.
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
:nfds , 7( 6 ?)。
:readfds , 3,4,5,6.
:writefds , NULL。
:exceptfds , NULL。
:timeout , NULL。
select 함수 의 역할 은 readfds 의 모든 파일 에 데 이 터 를 읽 을 수 있 거나 witefds 의 모든 파일 을 기록 할 수 있 거나 exceptfds 의 모든 파일 에 이상 이 있 을 때 되 돌아 오 는 것 입 니 다.그렇지 않 으 면 현재 프로 세 스 를 막 습 니 다. 항소 조건 이 만족 하거나 차단 시간 이 timeout 에서 지정 한 시간 을 초과 하여 현재 프로 세 스 가 깨 어 나 select 로 돌아 갑 니 다.
그래서 여기 서 udevd 는 3, 4, 5, 6 이 몇 개의 파일 을 읽 을 수 있 는 데이터 가 있어 야 깨 어 납 니 다.현재 셸 에서 실행:
# ps aux | grep udevd
root 27615 ...... strace -o /tmp/udevd.debug -f /sbin/udevd --daemon
root 27617 ...... /sbin/udevd --daemon
udevd 의 프로 세 스 id 는 27617 입 니 다. 이제 select 가 기다 리 는 몇 개의 파일 을 보 겠 습 니 다.
# cd /proc/27615/fd
# ls -l
udevd , , /dev/null.
0 -> /dev/null
1 -> /dev/null
2 -> /dev/null
udevd 。
3 -> /inotify
4 -> socket:[331468]
5 -> socket:[331469]
6 -> pipe:[331470]
7 -> pipe:[331470]
실행 중 8139 의 네트워크 카드 를 삽입 하 는 것 이 불편 하기 때문에 지금 우 리 는 U 디스크 로 시험 을 하고 있 습 니 다. U 디스크 를 삽입 하면 strace 의 출력 을 볼 수 있 습 니 다. 출력 에서 udevd 가 select 에서 돌아 온 후에 modprobe 로드 드라이브 모듈 을 호출 하고 sys 를 호출 하 는 것 을 볼 수 있 습 니 다.mknod, dev 디 렉 터 리 에 해당 하 는 노드 를 만 들 었 습 니 다.
execve("/sbin/modprobe", ["/sbin/modprobe", "-Q", "usb:v05ACp1301d0100dc00dsc00dp00"...]
......
mknod("/dev/sdb", S_IFBLK|0660, makedev(8, 16)) = 0
......
여기 modprobe 의 인자 "usb: v05AC..." 는 modules. alias 의 한 모듈 에 대응 합 니 다.
udevmonitor 를 통 해 커 널 이 netlink 를 통 해 udevd 에 보 낸 메 시 지 를 볼 수 있 고 셸 에서 실 행 됩 니 다.
# udevmonitor --env
그리고 USB 를 삽입 하면 관련 udevd 에 보 내 는 메 시 지 를 볼 수 있 습 니 다.
= = 커 널 처리 과정 = =:
여기 서 PCI 버스 를 예 로 들 어 이 과정 에서 커 널 이 어떻게 처리 되 는 지 살 펴 보 자.PCI 버스 드라이버 가 새로운 장 치 를 검색 할 때 장치 대상 을 만 들 고 Pci 를 호출 합 니 다.bus_add_device () 함수, 이 함 수 는 최종 적 으로 kobject 를 호출 합 니 다.uevent () 는 netlink 를 통 해 사용자 상태의 udevd 에 메 시 지 를 보 냅 니 다.
int pci_bus_add_device(struct pci_dev *dev)
{
int retval;
retval = device_add(&dev->dev);
......
return 0;
}
device_add () 코드 는 다음 과 같 습 니 다.
int device_add(struct device *dev)
{
struct device *parent = NULL;
dev = get_device(dev);
......
error = bus_add_device(dev);
if (error)
goto BusError;
kobject_uevent(&dev->kobj, KOBJ_ADD);
......
}
device_add () 관련 데이터 구 조 를 준비 한 후 kobject 를 호출 합 니 다.uevent (), 이 메 시 지 를 사용자 공간 에 보 내 는 udevd.
int kobject_uevent(struct kobject *kobj, enum kobject_action action)
{
return kobject_uevent_env(kobj, action, NULL);
}
int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp_ext[])
{
struct kobj_uevent_env *env;
const char *action_string = kobject_actions[action];
const char *devpath = NULL;
const char *subsystem;
struct kobject *top_kobj;
struct kset *kset;
struct kset_uevent_ops *uevent_ops;
u64 seq;
int i = 0;
int retval = 0;
......
/* default keys */
retval = add_uevent_var(env, "ACTION=%s", action_string);
if (retval)
goto exit;
retval = add_uevent_var(env, "DEVPATH=%s", devpath);
if (retval)
goto exit;
retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem);
if (retval)
goto exit;
/* keys passed in from the caller */
if (envp_ext) {
for (i = 0; envp_ext[i]; i++) {
retval = add_uevent_var(env, envp_ext[i]);
if (retval)
goto exit;
}
}
......
/* netlink , udevd select() , 。 */
#if defined(CONFIG_NET)
/* send netlink message */
if (uevent_sock) {
struct sk_buff *skb;
size_t len;
/* allocate message with the maximum possible size */
len = strlen(action_string) + strlen(devpath) + 2;
skb = alloc_skb(len + env->buflen, GFP_KERNEL);
if (skb) {
char *scratch;
/* add header */
scratch = skb_put(skb, len);
sprintf(scratch, "%s@%s", action_string, devpath);
/* copy keys to our continuous event payload buffer */
for (i = 0; i < env->envp_idx; i++) {
len = strlen(env->envp[i]) + 1;
scratch = skb_put(skb, len);
strcpy(scratch, env->envp[i]);
}
NETLINK_CB(skb).dst_group = 1;
netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
}
}
#endif
......
return retval;
}
:
현재 우 리 는 / dev 디 렉 터 리 아래 의 장치 파일 이 udevd 가 만 든 것 을 알 고 있 습 니 다. 그러나 커 널 시작 과정 에서 mount 루트 디 렉 터 리 가 필요 합 니 다. 보통 우리 의 루트 디 렉 터 리 는 하 드 디스크 에 있 습 니 다. 예 를 들 어 / dev / sda 1 이지 만 하 드 디스크 에 대응 하 는 드라이버 가 불 러 오기 전에 / dev / sda 1 은 존재 하지 않 습 니 다. / dev / sda 1 이 없 으 면...루트 디 렉 터 리 를 mount / dev / sda 1 / 로 마 운 트 할 수 없습니다.다른 한편, udevd 는 실행 가능 한 파일 입 니 다. 하 드 디스크 드라이버 가 불 러 오지 않 았 을 때 루트 디 렉 터 리 가 존재 하지 않 으 면 udevd 는 실행 할 수 없습니다.udevd 가 실행 되 지 않 으 면 디스크 드라이버 를 자동 으로 불 러 오지 않 고 / dev / sda 1 을 자동 으로 만 들 수 없습니다.이거 자물쇠 아니 야?그럼 리 눅 스 는 어떻게 시 작 했 어 요?
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.