6장 : 장치접근
Last updated
Last updated
프로세스 대신해서 커널이 장치에 접근합니다. 구체적으로는 다음과 같은 인터페이스를 사용합니다.
디바이스 파일이라는 특수한 파일을 조작합니다.
블록 장치에 구축한 파일 시스템을 조작합니다.
파일 시스템은 7장을 참조합니다.
네트워크 인터페이스 카드(NIC)
는 속도 등의 문제로 디바이스 파일을 사용하는 대신에
소켓 구조를 사용합니다.
여기서 중요한 것은 Block Device
는 시스템 버퍼 캐시를 사용하고, Character Device
는 사용하지 않는다는 점입니다.
프로그램이 파일 입출력을 사용하는 것은 단순하게 느껴지지만 내부적으로는 복잡한 과정이 이루어지는 것을 볼 수 있습니다.
바탕 지식
major number : 디바이스를 처리하기 위한 Device Driver 식별 번호, 최대 255
minor number : Device Driver가 처리하는 특정 Device를 식별하기 위한 번호
디바이스 파일은 장치와 커널의 연결점입니다.
예를 들어 /dev/sda
, /dev/sdb
는 각각 다른 저장 장치(또는 파티션)에 해당합니다.
TCP 소켓이나 UDP 소켓을 사용해서 다른 기기와 프로세스 통신할 때 사용
프로세스는 이 디바이스 파일을 일반 파일처럼 조작해서 장치를 다룹니다.
리눅스는 프로세스가 디바이스 파일을 조작하면 커널 내부의
디바이스 드라이버 device driver
라고 부르는 소프트웨어가 사용자 대신에 장치에 접근합니다.
사용자는 read()
, write()
등의 시스템 콜을 호출해 디바이스 파일을 읽고 씁니다.
일반 파일과 똑같은 방식으로 디바이스 파일 조작
커널 내부에서는 디바이스 드라이버가 이 요청을 해석하고 실제 장치를 조작합니다.
특수한 조작은 ioctl()
시스템 콜로 수행합니다.
ioctl()
이란?I/O control의 약자로, 장치(디바이스)에 대해 입출력 외의 특수한 조작을 수행할 수 있도록 해주는 시스템 콜이에요.
read()
→ 읽기write()
→ 쓰기ioctl()
→ 그 외 특수한 기능들 제어 (장치 설정, 동작 제어 등)
- "하드 디스크의 온도를 알고 싶다"
- "카메라 장치의 해상도를 바꾸고 싶다"
- "터미널에서 에코 모드를 끄고 싶다"
CD-ROM 장치는 읽고 쓰는 것도 중요하지만, “열기/닫기” 같은 특수 기능도 있어야 하잖아요?
이럴 때 ioctl()
로 “CD-ROM 트레이 열기” 명령을 보냅니다!
터미널 창에서 입력 방식(에코 모드, 키 입력 버퍼 설정 등)을 변경하고 싶을 때도
ioctl()
을 사용해 제어할 수 있어요.
read()
나 write()
로 안 될까요?read()
는 데이터를 읽는 것
write()
는 데이터를 쓰는 것
하지만 장치는 읽고 쓰기만 하는 게 아니라, 동작 제어나 상태 변경 같은 작업도 필요하거든요.
→ ioctl()
은 장치별로 정의된 명령어(명령 코드)를 통해
특수한 조작을 가능하게 해줍니다.
ioctl()
은 장치와 대화하는 비밀 통로예요! 단순히 읽고 쓰는 걸 넘어, 특수한 명령이나 설정을 조정할 때 사용됩니다.
디바이스 파일은 단순한 파일이 아닌, 다음과 같은 고유 정보를 가집니다:
종류
캐릭터 장치(Character Device) 또는 블록 장치(Block Device)
메이저 번호
어떤 드라이버를 사용할지 결정하는 번호
마이너 번호
드라이버 내부에서 어떤 장치인지 구별하는 번호
예를 들어 /dev/sda1
, /dev/sda2
는 같은 저장장치(sda
)의 서로 다른 파티션입니다.
예시
키보드, 마우스, 터미널
하드디스크, SSD, USB
특징
1바이트씩 연속적으로 접근
블록 단위(보통 512B, 4KB)로 접근
전송 방식
스트리밍
랜덤 접근 가능
대부분의 디바이스 파일은 보안상의 이유로 루트만 접근 가능합니다.
예: /dev/mem
(물리 메모리 전체에 접근)은 일반 사용자에겐 매우 위험하므로 제한됨.
출력 예시:
b
로 시작: 블록 장치
c
로 시작: 캐릭터 장치
8, 0
등은 메이저 번호와 마이너 번호
"디바이스 파일은 하드웨어를 추상화한 문, 커널 드라이버는 그 문의 비밀번호다."
캐릭터 장치는 연속적인 데이터 흐름을 처리하는 장치로, 대표적인 예는 다음과 같습니다:
단말 (예: 터미널)
키보드
마우스
이 장치들은 읽기(read)와 쓰기(write)는 가능하지만, seek(탐색) 기능은 지원하지 않아요. 즉, 파일처럼 임의 위치로 이동해서 데이터를 읽는 기능은 없다는 뜻입니다.
단말 장치는 디바이스 파일 /dev/pts/X
에 매핑되어 있고, 해당 파일을 통해 장치를 직접 조작할 수 있습니다.
✅ 1. 현재 단말 확인
여기서 pts/9
는 현재 터미널이 사용하는 단말 장치입니다.
/dev/ 아래에 있 는 pts/9 파일이 단말에 대응하는 디바이스 파일
✅ 2. 현재 단말에 문자열 쓰기
→ 해당 단말에 hello
문자열이 출력됩니다.
디바이스 파일에 write() 시스템 콜을 호출
echo hello 명령어를 실행했을 때와 동일한 결과인데 이유가 뭘까요?
echo 명령어는 표준 출력에 hello를 쓰고, 리눅스에서 표준 출력은 단말과 연결되어 있기 때문입니다.
✅ 3. 다른 단말에도 쓰기 가능
“한 터미널에서 다른 터미널 화면에 글씨를 강제로 출력해보기” 실험이에요.
📌 먼저 기본 개념부터 정리
터미널(단말)
우리가 bash 명령어를 입력하는 창
/dev/pts/N
각 터미널에 연결된 디바이스 파일 경로
echo hello > /dev/pts/10
"10번 터미널에 ‘hello’ 라고 써줘" 라는 명령
🧪 실험 과정 요약
첫 번째 터미널: 내가 명령어를 입력할 곳
두 번째 터미널: 메시지를 받아볼 곳 (아무것도 안 해도 됨)
이걸 보면,
첫 번째 터미널은 /dev/pts/9
두 번째 터미널은 /dev/pts/10
이란 뜻이에요.
echo hello
: "hello"를 출력해라!
> /dev/pts/10
: 그 출력을 10번 터미널 화면에 보내라!
이건 내가 입력한 게 아니고,
첫 번째 터미널에서 강제로 출력한 hello가 내 터미널에 나타난 것이에요!
🎯 핵심 이해 포인트
리눅스에서는 터미널 하나하나가 다 파일처럼 존재해요 (/dev/pts/번호
)
그래서 다른 터미널에다가도 write()
하듯 출력할 수 있어요
echo hello > /dev/pts/10
은 10번 터미널에 hello를 강제로 써주는 것이에요.
💬 추가 설명이 필요한 경우
sudo
가 필요한 이유는? → 다른 사용자 터미널은 루트만 접근 가능해서!
pts/10
같은 경로는 어떻게 생기냐면 → pseudo terminal slave
라 불리는 가상 터미널 장치에요.
캐릭터 장치
탐색 불가 / 스트림 기반 데이터 처리
단말 장치 예시
/dev/pts/9
, /dev/pts/10
등
시스템 콜
read()
, write()
를 통해 조작
리눅스에서는 '모든 것은 파일'이라는 철학 하에, 장치도 파일처럼 다룰 수 있어요
리눅스나 유닉스 계열 시스템에서 모든 입출력은 "파일"처럼 다룰 수 있어요.
stdin
(표준 입력, 키보드) → 파일 번호 0
stdout
(표준 출력, 화면) → 파일 번호 1
stderr
(표준 에러, 에러 메시지 출력용) → 파일 번호 2
즉, 터미널에서 echo hello
를 입력하면,
💡 "hello"라는 문자열을 표준 출력(stdout)에 쓰는 것이에요.
지금 내가 명령어를 입력하고 있는 터미널이 바로 단말 장치(device)
예요.
리눅스는 이 터미널을 /dev/pts/9
같은 디바이스 파일로 만들어놔요.
즉, 표준 출력은 이 디바이스 파일에 연결돼 있는 상태인 거예요.
이 명령은 실제로는 다음과 같이 동작하는 거예요:
echo
프로그램이 실행된다.
내부적으로 "hello\n"
문자열을 stdout(표준 출력)으로 보낸다.
리눅스는 이 stdout을 /dev/pts/9 같은 단말 디바이스 파일에 연결해두었다.
결과적으로 이 문자열은 내가 보고 있는 터미널 화면에 출력된다!
➡ 이 명령은 echo hello
를 다른 터미널에 출력하라는 의미예요.
왜냐하면 /dev/pts/10
은 다른 단말(터미널)을 나타내니까요!
echo hello
는 사실stdout
에 "hello"를 출력하는 것이고, 이stdout
은 리눅스에서 내 터미널 디바이스 파일(/dev/pts/9)에 연결되어 있기 때문에, 화면에 보이게 되는 거예요!
블록 단위로 읽고 쓰기가 가능하고, 탐색도 가능한 장치
대표 장치: 하드디스크, SSD 등 저장 장치
보통은 파일 시스템을 통해 접근하지만, 실습에서는 파일 시스템 없이 직접 조작도 가능
비어 있는 파티션 /dev/sdc7
을 사용한다고 가정
비어 있는 파티션이 없다면 나중에 설명하는 루프
장치 컬럼
을 참조해서 루프 장치를 사용
비어 있는 파티션이 없다는 말은?
실습이나 테스트를 위해 직접 블록 장치(/dev/sdc7
같은)에 접근하려면,
다른 데이터가 없는 빈 파티션이 필요해요.
그런데 대부분의 시스템은 이미 모든 디스크 공간이 OS나 사용자 데이터로 꽉 차 있어요.
⚠️ 이럴 때 잘못된 파티션을 실습에 사용하면 데이터가 날아가는 대참사가 발생할 수 있습니다
루프 장치란?
"진짜 디스크가 없어도 마치 디스크인 것처럼" 사용할 수 있게 해주는 가상 장치예요.
하나의 일반 파일(img 파일)을 준비한 다음,
그걸 /dev/loop0
, /dev/loop1
같은 루프 디바이스 파일에 연결하면
마치 진짜 /dev/sdc1
처럼 동작합니다.
"비어 있는 진짜 디스크 공간이 없다면, 루프 장치라는 가짜 디스크를 만들어 실습하라!"
ext4 파일 시스템을 생성:
마운트:
📦 마운트(Mount)란?
❓ 정의부터 간단하게!
마운트란 어떤 파일 시스템(디스크, USB, 루프 장치 등)을 리눅스 시스템의 디렉토리 트리에 연결하는 작업입니다.
💬 쉽게 말해서?
"어디에 붙일지 정해서, 사용할 수 있게 만드는 일"
예: USB를 컴퓨터에 꽂고 `/mnt/usb`에서 쓸 수 있도록 만드는 것
🏡 비유로 이해해볼게요!
🧳 여행 가방 = 디스크
🪑 여행 가방을 펼쳐 놓을 책상 = 디렉토리(/mnt)
여행 가방(USB, 외장하드 등)을 들고 왔다고 해서 당장 쓸 수는 없죠.
책상 위에 가방을 펼쳐야(good 위치에 마운트해야) 안에 든 옷이나 물건을 꺼낼 수 있어요.
즉, 마운트란:
📁 디스크(파일 시스템)를 📂 리눅스의 특정 디렉토리 경로에 "연결"하는 것!
1) mount /dev/sdc7 /mnt
💡 "디바이스 파일
/dev/sdc7
에 있는 파일 시스템을/mnt
디렉토리에 연결해줘!"
/dev/sdc7
: 디스크나 파티션(예: 외장하드, USB 등)의 블록 디바이스 파일
/mnt
: 리눅스에서 임시로 디스크를 붙이는 디렉토리
📌 이걸 마운트하면:
/mnt
아래에서 /dev/sdc7
의 내용을 일반 디렉토리처럼 접근할 수 있어요.
예: /mnt/testfile
은 실제 /dev/sdc7
에 저장되는 것!
2) echo "hello world" > /mnt/testfile
💡 "
/mnt/testfile
이라는 새 파일을 만들고, 그 안에 'hello world' 문자열을 써!"
이때 /mnt
는 위에서 마운트한 /dev/sdc7
이기 때문에,
결과적으로는 /dev/sdc7
디스크에 "hello world"라는 내용을 가진 파일이 생깁니다!
3) umount /mnt
💡 "이제 디스크 사용 끝났으니
/mnt
에서 연결 해제할게!"
umount
는 "unmount"의 줄임말.
연결을 해제하면 /mnt
는 다시 빈 디렉토리가 되고,
/dev/sdc7
은 더 이상 접근할 수 없게 됩니다.
📝 요약 흐름 정리
1
mount
디바이스를 디렉토리에 붙임
2
echo >
붙인 디스크에 파일 생성 및 쓰기
3
umount
디바이스와 디렉토리 연결 해제
🧠 실전 응용 팁
실수로 umount
안 하고 디스크 뽑으면? → 데이터 손상 가능 😱
꼭 umount
로 안전하게 연결 해제하고 빼야 해요!
출력 예:
이건 /mnt/testfile
에 쓴 "hello world"가 실제 블록 장치 /dev/sdc7
안의 803d000 위치에 저장되었음을 보여줍니다.
출력 결과에서 /dev/sdc7에는
lost+found 디렉터리 및 testfile 파일명
파일 내부에 있는 hello world 문자열
정보가 들어 있습니다.
각각의 문자열이 두 번 출력된 건 ext4의 저널링 기능 때문인데 저널링은 데이터를 쓰기 전에 저널 영역이라고 부르는 장소에 함께 기록합니다
🧙♂️ 파일 시스템을 거치지 않고 직접 디바이스 파일을 조작했어요!
데이터를 디스크에 기록하기 전에, “이 작업을 할 거야!”라는 계획을 따로 미리 적어두는 것입니다.
이 메모장을 “저널(Journal)”이라고 부릅니다. 마치 일기장이죠! 어떤 일이 일어날지 적어놓고, 나중에 진짜로 실행하는 방식이에요.
이 명령어를 실행하면:
먼저 ext4 파일 시스템은
"나는 testfile이라는 파일에 'hello world'를 쓸 거야!"
라는 내용을 저널 영역에 먼저 기록합니다.
그 다음에야 실제 데이터 블록에 진짜로 저장을 시작해요.
바로, 데이터 손상 방지 때문입니다!
저장 중 갑자기 정전이 되거나, 디스크가 중간에 제거되면…
파일의 일부만 저장되거나, 파일 시스템이 손상될 수 있어요.
특히 디렉토리 구조나 메타데이터가 꼬이면 부팅조차 안 될 수도 있어요!
시스템이 재부팅되면 저널을 보고
"아, 이 작업은 끝나지 않았구나"
를 감지해서
중단된 작업을 롤백하거나 다시 실행해서 일관성을 복구할 수 있어요.
👉 저널링 덕분에 ext4는 갑작스런 장애가 있어도 파일 시스템을 안전하게 유지할 수 있어요.
앞서 strings -tx /dev/sdc7
명령어를 썼을 때
이렇게 두 번 나왔던 이유는:
하나는 실제 데이터 블록
하나는 저널 영역에 미리 써둔 로그
이라는 의미예요!
저널링은 파일 시스템의 "일기장"! 데이터를 쓰기 전에 먼저 기록해서, 문제가 생겨도 복구할 수 있게 해줍니다.
파일을 디바이스처럼 사용할 수 있게 해주는 기능 하드웨어 파티션이 없는 경우에 실험 용도로 딱!
출력 예:
블록 장치
하드디스크, SSD 등. 블록 단위로 탐색 가능
디바이스 파일
/dev/sda
, /dev/sdc7
등. 커널이 장치를 매핑한 가상 경로
루프 장치
일반 파일을 블록 장치처럼 다루는 기능
strings -tx
바이너리 파일 내 문자열 검색 (파일 오프셋과 함께)
dd
블록 단위 복사 도구. 디바이스 조작 가능
블록 장치는 일반 파일보다 더 직접적이고 강력한 방식으로 저장소를 다룹니다. 루프 장치는 실험과 테스트 환경에서 매우 유용한 가상 장치입니다.
디바이스 드라이버는 커널이 장치를 제어하기 위해 사용하는 소프트웨어입니다.
"프로세스 → 디바이스 파일을 통해 → 드라이버 → 장치"
라는 식으로 연결되며, 사용자(프로세스)는 장치의 복잡한 동작을 몰라도 일반 파일처럼 다룰 수 있게 됩니다.
장치에는 레지스터(register) 라는 내부 설정/데이터 영역이 있고, 이것을 통해 장치를 조작합니다. 예를 들어 저장 장치에 데이터를 읽어오려면 다음과 같은 순서로 진행됩니다:
장치를 직접 조작하려면 각 장치에 내장된 레지스터 영역을 읽고 써야 합니다.
구체적인 레지스 터 종류와 조작법 같은 정보는 각 장치 사양에 따라 달라집니다.
1️⃣
프로세스가 디바이스 파일을 통해 read() 호출
2️⃣
CPU가 커널 모드로 전환됨
3️⃣
디바이스 드라이버가 레지스터에 "읽기 작업" 요청 (주소/크기/명령 입력)
4️⃣
장치가 요청을 받아서 처리
5️⃣
완료되면 장치가 레지스터 플래그로 알려줌
6️⃣
CPU가 사용자 모드로 돌아오고, 결과를 프로세스에게 전달
장치의 레지스터를 메모리처럼 접근하는 방식
x86_64 아키텍처는 리눅스 커널이 자신의 가상 주소 공간에 물리 메모리를 모두 매핑합니다.
커널의 가상 주소 공간 범위
가 0~1000바이트라고 하면, 예를 들어 [그림 06-03]처럼 가상 주
소 공간의 0~500에 물리 메모리
를 매핑합니다.
MMIO를 사용하면 레지스터 접근이 마치 메모리에 쓰는 것처럼 됩니다. 예를 들어 아래와 같이 커널 메모리 공간에 장치 0, 1, 2의 레지스터가 매핑됩니다:
이 주소 범위에 값을 쓰거나 읽는 걸로 장치를 조작하는 것이죠!
메모리 100 ~ 200 영역에, 저장장치의 300 ~ 400 주소 데이터를 읽어오자!
0
메모리로 데이터를 저장할 시작 주소
10
저장장치 내부에서 읽을 시작 주소
20
읽을 데이터 크기
30
요청 명령 (0: read, 1: write)
40
처리 완료 플래그 (0: 진행 중, 1: 완료)
레지스터 설정:
0x500 = 100 (메모리 주소)
0x510 = 300 (저장장치 주소)
0x520 = 100 (읽을 크기)
0x530 = 0 (읽기 명령 실행)
저장장치가 작업 시작 → 0x540 = 0 (처리 중)
작업 완료 후 → 0x540 = 1
디바이스 드라이버가 완료 확인
폴링(Polling)
계속 레지스터를 읽어서 완료 여부를 확인
인터럽트(Interrupt)
장치가 직접 CPU에 알려주는 방식 (효율적)
디바이스 드라이버
커널이 장치와 통신할 때 사용하는 프로그램
MMIO
장치 레지스터를 메모리에 매핑해서 접근하는 방식
레지스터
장치에 명령을 내리거나 상태를 확인하는 용도
폴링/인터럽트
장치 처리 완료 여부를 확인하는 방법
좋아요! 주신 내용을 기반으로 폴링(Polling) 방식이 무엇인지, 왜 비효율적인지, 그리고 이를 개선하기 위한 방법까지 차근차근 설명드릴게요 😊
“끝났어?”를 계속 묻는 방식
디바이스 드라이버가 장치에게 계속 “끝났나요?” 하고 물어보는 방식입니다.
프로세스가 장치에게 어떤 작업(예: 저장, 출력 등)을 요청합니다.
이 요청은 커널을 통해 디바이스 드라이버로 전달됩니다.
드라이버는 장치의 "처리 완료 레지스터" 값을 계속 읽어서, 작업이 끝났는지 감시합니다.
이런 동작은 마치 이런 상황과 같습니다:
👤 “답장 왔나?” 📱 (앱 열어봄) “아직...” 👤 “답장 왔나?” 📱 (앱 열어봄) “아직...”
이런 식으로 계속 확인하는 거예요!
CPU는 레지스터 값을 확인하는 동안 다른 일을 못 합니다.
예를 들어 프로세스 p0
이 장치에 요청을 하고 기다리는 동안,
프로세스 p1
이 아무 일도 하지 못하고 같이 기다리게 되는 일이 벌어집니다.
CPU는 초당 수십억 개 명령을 실행할 수 있는데, 몇 밀리초를 기다리느라 놀고 있다면 너무 아깝겠죠?
⏰ 일정 시간마다만 장치에 “끝났니?”라고 물어보는 것.
이 방법은 CPU 낭비를 줄여주지만, 여전히 고민거리가 있어요:
이렇게 정교하게 만들어도 폴링은 디바이스 드라이버가 복잡해진다는 단점이 있습니다.
예를 들어 [그림 06-08]에서 장치에 처리를 요청하고 완료할 때까지 pl이 동작한다면, P1에서 하는 처리 중간 중간에 레지스터 값을 읽는 코드를 삽입해야 합니다. 또한
간격이 너무 길면: 처리 완료 통지가 늦어짐
간격이 너무 짧으면: CPU 낭비는 여전
장치가 아직 처리를 끝내지 않았는데, 계속 CPU가 ‘확인만’ 반복하는 구조.
CPU가 다른 일도 하면서, 중간중간 확인
그래도 "얼마나 자주?"라는 간격 조절이 난이도 높음
폴링(Polling)
디바이스 상태를 드라이버가 직접 주기적으로 확인
장점
구조가 단순하다
단점
CPU 낭비 심함, 응답 지연 가능
개선 방법
주기적 폴링 (하지만 간격 조절이 어려움)
🧠 그래서 등장한 해결책이 바로 “인터럽트(Interrupt)” 방식입니다. → 장치가 “끝났어!” 하고 알려주는 방식이랍니다
먼저 폴링을 떠올려 봅시다. 이 방식은 마치 친구한테 문자를 보내놓고, 계속 휴대폰을 켜서 “답장 왔나?”를 확인하는 것과 비슷합니다. CPU가 계속 디바이스 상태를 확인하는 것이죠.
하지만 단점이 큽니다:
답장이 올 때까지 CPU가 다른 일을 못함
확인하는 시간 동안 자원 낭비 심함
예) p0이 장치 요청을 하고, 처리 끝날 때까지 p1조차 못 돌리는 구조
인터럽트(interrupt)는 장치가 “나 다 끝냈어!” 하고 먼저 CPU를 부르는 방식입니다.
디바이스 드라이버가 장치에 요청을 보냅니다.
CPU는 요청을 보낸 뒤 다른 일(예: p1 실행)을 합니다.
장치가 처리를 끝내면 인터럽트 신호를 CPU에 보냅니다.
CPU는 그 신호를 받아서 미리 등록된 **인터럽트 핸들러(interrupt handler)**를 실행합니다.
드라이버는 이 핸들러를 통해 결과를 확인합니다.
폴링: 앱 열어보며 계속 “답 왔나?” 확인
인터럽트: 답 오면 앱이 알림을 보내줌
여기서 중요한 부분
장치 처리가 완료할 때까지 CPU는 다른 프로세스를 실행할 수 있습니다. 예제에서는 pl이 동작합니다.
장치 처리 완료를 즉시 확인 가능합니다. 예제에서는 처리 완료 후 곧바로 p0이 동작할 수 있습니다.
장치에서 처리가 이뤄지는 동안 동작하는 프로세스(여기서는 pl)는 장치에서 무슨 일이 일어나고 있는지 신경 쓸 필요가 없습니다.
CPU 자원 낭비 없음
기다리는 동안 다른 일 가능
즉시 반응 가능
장치가 바로 알려주니 지연 적음
프로세스 독립성 보장
장치 처리와 무관한 프로세스는 영향 없음
📌 요즘 대부분의 하드웨어 I/O는 인터럽트 기반입니다.
/proc/interrupts
파일이란?리눅스에서는 현재까지 발생한 인터럽트 개수를 확인할 수 있는 파일이 있어요.
바로 /proc/interrupts
입니다.
이 파일을 보면 다음과 같은 형식의 데이터가 나옵니다:
첫 번째 필드
인터럽트 번호 또는 구분자 (0
, 1
, LOC
, 등)
두 번째~여러 번째 필드
각 논리 CPU에서 발생한 인터럽트 횟수
마지막 필드
해당 인터럽트가 어떤 장치 또는 기능에 대응되는지 (예: timer
, keyboard
, Local timer
)
예시에서 LOC:
은 Local Timer Interrupt를 의미합니다.
이 명령어는 매초마다 /proc/interrupts
에서 타이머 인터럽트 수를 확인하는 거예요.
출력은 이렇게 나와요:
→ 매초 인터럽트 횟수가 늘어나는 것을 확인할 수 있어요!
타이머 인터럽트는 운영체제가 정기적으로 시간을 체크하거나 작업을 스케줄링하기 위해 발생시키는 신호입니다.
예전에는 1초에 1000번씩 모든 CPU에서 발생했지만,
지금은 필요할 때만 발생하도록 최적화되어 있습니다!
💡 성능 향상
CPU가 너무 자주 모드 전환(커널 ↔ 사용자)을 하지 않게 됨
🔋 전력 절감
대기 상태의 CPU에 쓸데없는 깨움을 줄일 수 있음
즉, 스마트하게 시간을 관리해서 자원을 아끼는 방식으로 진화한 것이죠.
/proc/interrupts
인터럽트 발생 횟수를 확인하는 파일
LOC:
Local timer interrupt를 나타냄
타이머 인터럽트
CPU에게 "정해진 시간 됐어!"를 알리는 신호
변화
과거: 매초 1000회 → 현재: 필요할 때만
장치 속도가 너무 빠르거나
처리 빈도가 너무 높아서
인터럽트 오버헤드(호출 자체의 시간)가 더 손해일 때
이럴 땐 폴링으로 전환하는 디바이스 드라이버도 있습니다.
리눅스는 디바이스 레지스터를 직접 매핑해서, 사용자 공간(예: Python)에서도 디바이스 드라이버를 만들 수 있게 해줘요.
이걸 UIO (Userspace I/O) 라고 합니다.
인터럽트 없이도 장치에 빠르게 접근 가능
커널 모드 전환을 피하니 속도 향상
고속 처리 필요할 때 사용
대표 예: DPDK, SPDK 같은 고속 네트워크/스토리지 프레임워크
폴링
CPU가 직접 장치 상태를 계속 확인
문자 확인 계속 눌러보는 친구
인터럽트
장치가 먼저 "끝났어!" 알려줌
채팅 앱 알림
UIO
사용자 공간에서 디바이스 접근
파이썬으로 드라이버 만들기 가능
리눅스에서는 저장 장치가 연결될 때, 자동으로 디바이스 파일 이름(/dev/sda, /dev/sdb 등)이 정해집니다.
하지만 이 이름은 '고정된 것'이 아니며, 매번 부팅할 때마다 달라질 수 있어요!
새 장치 추가
A → B 순서였는데, 중간에 C가 추가되면 이름이 밀릴 수 있음
장치 연결 순서 변경
하드웨어 연결 순서 바뀌면 인식 순서도 바뀜
고장 발생
예: A가 고장 → B가 /dev/sda
가 되어버림
⚠️ 실수로
/dev/sdc
에 파일 시스템을 만들려 했는데, 장치 순서 바뀌어서/dev/sdb
를 지우는 상황도 발생할 수 있습니다.
이런 문제를 막기 위해 리눅스는 udev라는 프로그램을 통해, **"바뀌지 않는 이름"**을 자동으로 만들어줍니다!
/dev/disk/by-path/
장치의 물리적 연결 경로 기반 이름
/dev/disk/by-uuid/
파일 시스템의 UUID(고유 ID) 기반 이름
/dev/disk/by-label/
사용자가 설정한 레이블 기반 이름
→ /dev/sda
와 /dev/disk/by-path/...
는 같은 장치를 가리키고 있지만,
by-path는 다음 부팅에도 바뀌지 않음!
/etc/fstab
에 적용하는 예시시스템 부팅 시 자동으로 디스크를 마운트할 때는, 장치명 대신 UUID를 쓰는 게 안정적입니다.
이렇게 하면
/dev/sda
든/dev/sdb
든 UUID로 정확한 디스크를 구분하니, 실수로 잘못 마운트하거나 포맷하는 일을 방지할 수 있어요!
디바이스 파일명은 부팅할 때마다 바뀔 수 있음
ex. /dev/sda
↔ /dev/sdb
원인
인식 순서, 연결 순서, 고장 등
해결책
udev가 만든 영구 장치명 사용 (UUID, by-path 등)
실수 방지
/etc/fstab
에 UUID로 마운트 설정하면 안전!
장치 이름은 믿지 말고, UUID를 믿자!
출처 :