3. Char Drivers

Download Report

Transcript 3. Char Drivers

Chapter 3. Char Drivers
 scull 설계
 주 번호 및 부 번호 (Major and Minor numbers)
 파일 오퍼레이션 (File Operations)
 scull의 open과 release 메쏘드
 scull의 메모리 사용
 레이스 조건 (Race Conditions), 세마포
 read 및 write 메쏘드
 디바이스 파일 시스템
 scull 코드의 실행 예
순천향대학교 정보기술공학부
이상정
1
scull 설계
순천향대학교 정보기술공학부
이상정
2
LINUX Device Drivers
scull 코드 소개 (1)
 scull (simple character utility for loading localities)
• scull은 메모리 영역을 디바이스처럼 사용하는 char 드라이버
 다양한 형태의 scull 구현
• scull0 ~ scull3
• 메모리 영역으로 구성된 4개의 디바이스
• 광역(global)이고 지속적(persistent)
• 디바이스가 여러 번 오픈되는 경우 디바이스 내의 각 데이터는 오픈한 모
든 파일 디스크립터(file descriptor) 간에 공유된다는 점에서 광역
• 디바이스가 종결(close)되고 다시 오픈되어도 데이터가 손실되지 않고
유지된다는 점에서 지속적
• 기존의 셀 명령 cp, cat 및 셀 I/O 재방향(redirection) 등을 사용하여 액
세스하고 테스트
순천향대학교 정보기술공학부
이상정
3
Ch.3 Char Drivers
LINUX Device Drivers
scull 코드 소개 (2)
• scullpipe0 ~ scullpipe3
•
•
•
•
•
파이프(pipe)처럼 동작하는 4개의 FIFO(first-in-first-out) 디바이스
한 프로세스가 쓰기한 것을 다른 프로세스가 읽음
만약 여러 프로세스들이 같은 디바이스 읽기를 시도하면 서로 경쟁
scullpipe는 블록킹(blocking), 비블록킹(non-blocking) 읽기와 쓰기 동
작예
scullsingle, scullpriv, sculluid, scullwuid
•
•
•
•
scull과는 달리 오픈 시에 몇 가지 제약이 부가
scullsingle은 한번에 한 프로세스만 드라이버 사용
scullpriv는 디바이스가 가상 콘솔(또는 X 터미널 세션)에 국한(private)
sculluid와 scullwuid는 한번에 한 사용자만이 오픈
– sculluid는 다른 사용자가 디바이스를 잠그면(locking) “Device Busy” 에러
를 리턴
– scullwuid는 블록킹 오픈을 구현
 이 장에서는 scull0 ~ scull3 만을 소개
 나머지 디바이스들은 5장에서 소개
순천향대학교 정보기술공학부
이상정
4
Ch.3 Char Drivers
주 번호 및 부 번호
(Major and Minor numbers)
순천향대학교 정보기술공학부
이상정
5
LINUX Device Drivers
디바이스 파일(노드) (1)
 디바이스들은 파일 시스템 트리 상에서 특수 파일 또는 디바이스 파일 또는 단순
히 노드라 불리는 이름을 통하여 접근
$ ls –l /dev
crw-rw-rwcrw------crw------crw-rw-rwcrw-rw-rwcrw------crw------crw-rw-rw-
1
1
1
1
1
1
1
1
root
root
rubini
root
root
root
root
root
root
1, 3
root
10, 1
tty
4, 1
dialout 4, 64
dialout 4, 65
sys
7, 1
sys
7, 129
root
1, 5
Feb 23 1999
Feb 23 1999
Aug 16 22:22
Jun 30 11:19
Aug 16 00:00
Feb 23 1999
Feb 23 1999
Feb 23 1999
null
psaux
tty1
ttyS0
ttyS1
vcs1
vcsa1
zero
 위에서 날짜 전에 표시된 숫자는 디바이스의 주(major), 부(minor) 번호
• 주 번호는 디바이스와 관련된 드라이버를 표시, 디바이스 유형
• 부 번호는 주 번호에 의해 기술된 드라이버에서만 사용, 디바이스 단위
• 드라이버 여러 개의 디바이스를 제어하는 경우 이들을 구분하기 위해 부 번호가 사용
순천향대학교 정보기술공학부
이상정
6
Ch.3 Char Drivers
LINUX Device Drivers
디바이스 파일(노드) (2)
순천향대학교 정보기술공학부
이상정
7
Ch.3 Char Drivers
LINUX Device Drivers
주 번호 할당 (1)
 새로운 드라이버를 추가하는 것은 주 번호 할당을 의미
 <linux/fs.h>에 정의된 다음 함수가 드라이버(모듈) 초기화
시 주 번호를 할당
int register_chrdev(unsigned int major, const char *name,
struct file_operations *fops);
• 할당 성공 시 0 또는 양수를, 실패 시 음수를 리턴
• major는 할당하고자 하는 주 번호
• name은 /proc/devices 에 표시되는 디바이스의 이름
• fops는 드라이버의 엔트리 포인트를 실행하는데 사용되는 함수의 포
인터 배열의 포인터
 주 번호는 char 드라이버의 정적배열의 인덱스로 사용
• 8비트로 표현되며 2.0에서는 128개, 2.2와 2.4에서는 256개(0~255)
까지 할당
• 부 번호 역시 8비트로 표현
순천향대학교 정보기술공학부
이상정
8
Ch.3 Char Drivers
LINUX Device Drivers
주 번호 할당 (2)
 드라이버가 커널 테이블에 등록되면 등록된 주 번호와 관련
하여 연산이 수행
• 주 번호와 관련된 문자 디바이스 파일 상에 연산이 수행될 때마다 커
널은 file_operations 구조체로부터 해당 함수를 찾아서 실행
 파일 시스템에서 디바이스 노드를 생성하기 위해서는
mknod 명령을 사용
• 이는 관리자 권한으로 수행되며 다음과 같이 3개의 인수를 기술
mknod /dev/scull0 c 254 0
• 주 번호 254, 부 번호 0, scull0의 이름을 갖는 char 디바이스 파일을 생
성
• 제거 시에는 rm /dev/scull0 명령을 사용
순천향대학교 정보기술공학부
이상정
9
Ch.3 Char Drivers
LINUX Device Drivers
단말기 드라이버 초기화 예, tty_init()
순천향대학교 정보기술공학부
이상정
10
Ch.3 Char Drivers
LINUX Device Drivers
chrdevs[] 테이블 구조
순천향대학교 정보기술공학부
이상정
11
Ch.3 Char Drivers
LINUX Device Drivers
주 번호의 동적 할당
 주 번호는 register_chardev 함수의 인수 major를 0으로 세
팅하여 동적으로 할당
• 함수는 가용한 번호를 리턴
• 동적 할당 시 미리 디바이스 노드를 생성할 수 없는 것이 단점
$ cat /proc/devices
Character devices:
1 mem
2 pty
3 ttyp
4 ttyS
6 lp
7 vcs
10 misc
13 input
……
Block devices:
2 fd
8 sd
11 sr
.....
순천향대학교 정보기술공학부
이상정
12
Ch.3 Char Drivers
LINUX Device Drivers
노드 생성
 할당된 주 번호는 awk 등을 사용하여 찾아서 노드를 생성하는 스크립트
를 작성
• 다음은 4개의 디바이스를 생성하는 scull_load 스크립트의 일부
#!/bin/sh
module="scull"
device="scull"
mode="664"
# invoke insmod with all arguments we were passed
# and use a pathname, as newer modutils don’t look in . by default
/sbin/insmod -f ./$module.o $* || exit 1
# remove stale nodes
rm -f /dev/${device}[0-3]
major=‘awk "\\$2==\"$module\" {print \\$1}" /proc/devices‘
mknod /dev/${device}0 c $major 0
mknod /dev/${device}1 c $major 1
mknod /dev/${device}2 c $major 2
mknod /dev/${device}3 c $major 3
# give appropriate group/permissions, and change the group.
# Not all distributions have staff; some have "wheel" instead.
group="staff"
grep ’^staff:’ /etc/group > /dev/null || group="wheel"
chgrp $group /dev/${device}[0-3]
chmod $mode /dev/${device}[0-3]
순천향대학교 정보기술공학부
이상정
13
Ch.3 Char Drivers
LINUX Device Drivers
scull 주 번호 할당
 scull 코드에서는 scull.h 에서 SCULL_MAJOR를 초기화
• 이 값이 0이면 동적으로 아니면 지정된 주 번호로 할당
result = register_chrdev(scull_major, "scull", &scull_fops);
if (result < 0) {
printk(KERN_WARNING "scull: can’t get major %d\n", scull_major);
return result;
}
if (scull_major == 0) scull_major = result; /* dynamic */
 시스템에서 드라이버 제거
• 모듈이 시스템에서 제거될 때 다음 함수를 모듈의 해제 함수에서 호
출하여 해제
int unregister_chrdev(unsigned int major, const char *name);
순천향대학교 정보기술공학부
이상정
14
Ch.3 Char Drivers
LINUX Device Drivers
부 번호(minor number)
 주 번호와 부 번호는 이 후에 소개될 inode 구조체의 i_rdev
필드에 저장
• 드라이버 함수들은 첫번째 인수로 struct inode의 포인터를 받는데
inode->i_rdev 로부터 디바이스의 번호를 추출
• 리눅스 커널은 kdev_t 형으로 디바이스 번호 표현
• kdev_t는 <linux/kdev_t.h>에 정의되었고 <linux/fs.h>가 이를 포함
 다음의 매크로와 함수가 kdev_t 상에서 연산을 수행
• MAJOR(kdev_t dev);
kdev_t 구조체에서 주 번호를 추출
• MINOR(kdev_t dev);
부 번호를 추출
• kdev_t_to__nr(kdev_t dev);
kdev_t 형을 숫자(dev_t)로 변환
• to_kdev_t(int dev);
숫자를 kdev_t로 변환
순천향대학교 정보기술공학부
이상정
15
Ch.3 Char Drivers
파일 오퍼레이션 (File Operations)
순천향대학교 정보기술공학부
이상정
16
LINUX Device Drivers
파일 오퍼레이션 구조체
 디바이스는 내부적으로 파일 구조체로 표현
 커널은 file_operation 구조체를 사용하여 드라이버의 함수
(메쏘드)에 접근
•
•
•
•
이 구조체는 <linux/fs.h>에 함수(메쏘드)의 포인터 배열로 정의
각 메쏘드는 응용 프로그램의 시스템 콜의 엔트리 포인트
구조체의 각 필드는 드라이버의 특정 기능을 구현한 함수의 포인터
이들 필드는 태그화된 초기화(tagged initialization)을 통하여 이름이
기술되어 초기화
• 태그화된 초기화는 표준 C는 아니고 GNU 컴파일러에서 확장
순천향대학교 정보기술공학부
이상정
17
Ch.3 Char Drivers
LINUX Device Drivers
메쏘드 (1)
 다음은 struct file_operations 의 각 필드에서 표현되는 함수(메쏘드)의
포인터
• 성공인 경우에 0, 함수가 실패한 경우에는 음수를 리턴
• loff_t (*llseek) (struct file *, loff_t, int);
llseek 함수는 파일의 현재 읽기/쓰기 위치를 변경하여 새로운 위치를 리턴
loff_t 는 “long offset”을 의미하며 적어도 64 비트로 표현
• ssize_t (*read) (struct file *, char *, size_t, loff_t *);
디바이스로부터 데이터를 읽음.
실패 시 –EINVAL, 성공하면 읽어들인 바이트 수를 리턴
• ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
디바이스로 데이터 쓰기를 수행.
실패 시 –EINVAL, 성공하면 데이터 쓰기의 바이트 수를 리턴
• int (*readdir) (struct file *, void *, filldir_t);
디바이스 파일인 경우 이 필드는 NULL이 됨.
파일 시스템에서 디렉토리를 읽기 위해 사용
• unsigned int (*poll) (struct file *, struct poll_table_struct *);
디바이스 상태를 조사하는 함수로 디바이스가 읽기 가능, 쓰기 가능 또는 특
수한 상태에 있는지를 조사.
디바이스의 상태를 기술하는 비트 마스크를 리턴
순천향대학교 정보기술공학부
이상정
18
Ch.3 Char Drivers
LINUX Device Drivers
메쏘드 (2)
• int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
디바이스 관련 특정 명령을 이슈(예를들어 플로피 디스크 포맷 등과 같이 읽
기, 쓰기가 아닌 명령들).
실패 시 –ENOTTY, 성공 시 양수를 리턴
• int (*mmap) (struct file *, struct vm_area_struct *);
디바이스 메모리를 프로세스의 주소 공간으로 매핑.
실패 시 –ENODEV를 리턴
• int (*open) (struct inode *, struct file *);
디바이스 파일 상에 수행되는 첫번째 연산으로 디바이스 오픈
• int (*flush) (struct file *);
프로세스가 디바이스의 파일 디스크립터를 종결(close)할 때 호출.
현재는 네트워크 파일 시스템(NFS)에서만 사용
• int (*release) (struct inode *, struct file *);
파일 구조체가 해제될 때 호출된다.
• int (*fsync) (struct inode *, struct dentry *, int);
현재 보류된 데이터를 배출(flush)하고자 할 때 사용
순천향대학교 정보기술공학부
이상정
19
Ch.3 Char Drivers
LINUX Device Drivers
메쏘드 (3)
• int (*lock) (struct file *, int, struct file_lock *);
파일의 잠금 시 사용되는데 디바이스 드라이버에서는 거의 구현되지 않음
• ssize_t (*readv) (struct file *, const struct iovec *, unsigned long,
loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long,
loff_t *);
분산된 여러 메모리 영역들에 대해 한 번의 읽기/쓰기를 수행
• struct module *owner;
이 필드는 이 file_operation 구조체를 소유하는 모듈의 포인터. 커널이 모듈
의 사용횟수를 관리하기 위해 사용
순천향대학교 정보기술공학부
이상정
20
Ch.3 Char Drivers
LINUX Device Drivers
메쏘드 초기화
 메쏘드들은 태그화된 초기화가 되어 선언
 scull 디바이스 드라이버는 위의 메쏘드 중 주요 함수만 구현하고 다음과
같이 file_operations을 선언
struct file_operations scull_fops = {
llseek: scull_llseek,
read: scull_read,
write: scull_write,
ioctl: scull_ioctl,
open: scull_open,
release: scull_release,
};
 owner 필드는 다음과 같이 초기화
• 2.4 커널인 경우
owner: THIS_MODULE,
• 또는 이전 버전과 호환을 위해 다음과 같이 SET_MODULE_OWNER 매크로
를 사용
SET_MODULE_OWNER(&scull_fops);
순천향대학교 정보기술공학부
이상정
21
Ch.3 Char Drivers
LINUX Device Drivers
파일 구조체 (File Structure)
 struct file 구조체
• <linux/fs.h>에서 정의된 디바이스 드라이버에서 두번째로 중요한 자
료구조
• C 사용자 프로그램의 FILE 자료구조와는 별개의 것
• file 구조체는 open file을 표현
• open file은 struct inode 로 표현되는 디스크 파일을 다룸
• open file은 커널 상에서 open 메쏘드(함수)로 생성되어 해당 open
file 상에서 동작하는 함수로 전달되고 close로 해제
• 커널 소스에서 struct file의 포인터를 flip(“file pointer”)로 표시
순천향대학교 정보기술공학부
이상정
22
Ch.3 Char Drivers
LINUX Device Drivers
struct file의 주요 필드 (1)
 mode_t f_mode;
• 파일의 모드는 파일이 읽기 가능 또는 쓰기 가능인지를 비트
FMODE_READ, FMODE_WRITE로 표현
 loff_t f_pos;
• 현재 읽기와 쓰기의 위치를 표시
• loff_t는 64비트 값이다(gcc 용어로는 long long)
 unsigned int f_flags;
• 비블록킹(nonblocking) 여부 등을 체크하는 파일 플래그로써
O_RDONLY, O_NONBLOCK, O_SYNC 등으로 표시
• 모든 플래그는 <linux/fcntl.h>에서 정의
 struct file_operations *f_op;
• 파일과 관련된 오퍼레이션들의 포인터
• 커널은 open 구현의 결과로 이 포인터를 지정
• 같은 주 번호를 갖는 드라이버의 open 시 flip->f_op 는 오픈되는 부
번호에 따라 지정
순천향대학교 정보기술공학부
이상정
23
Ch.3 Char Drivers
LINUX Device Drivers
struct file의 주요 필드 (2)
 void *private_data;
• 드라이버는 자유롭게 이 필드를 사용하여 데이터를 할당하여 시스템
콜 간에 상태 정보 등을 저장하는 공간을 확보
• file 구조체가 커널에 의해 해제되기 전에 이 포인터가 가리키는 메모
리 영역을 해제해야 함
 struct dentry *f_dentry;
• 파일과 관련된 디렉토리 엔트리(dentry)의 포인터
• 드라이버가 flip->f_dentry->d_inode 로 inode 구조체에 접근하기
위해 사용
순천향대학교 정보기술공학부
이상정
24
Ch.3 Char Drivers
scull의 open과 release 메쏘드
순천향대학교 정보기술공학부
이상정
25
LINUX Device Drivers
open 메쏘드
 드라이버는 open 메쏘드를 사용하여 다음과 같은 초기화를 수행
• 사용횟수(usage count)를 증가
• 디바이스 준비여부(device-not-ready), 하드웨어 문제 등과 같은 디바이스
관련 에러를 체크
• 처음 오픈된 경우 디바이스를 초기화
• 부 번호를 인지하고 필요하면 f_op 포인터를 갱신
• 특정 자료구조를 위해 메모리를 할당하고 flip->private_data 에 저장
 scull 에서는 오픈되는 디바이스의 부 번호에 따라 구분
• 먼저 어느 디바이스가 사용되는지를 inode->i_rdev 를 사용하여 구별
• scull은 부 번호의 상위 4비트는 디바이스의 타입, 하위 4비트는 하나 이상의
디바이스를 지원하는 타입에서 개별 디바이스를 구분
• 예를들어 scull0와 scullpipe0는 상위 4비트가 다르고, scull0와 scull1은 하위 4비
트가 다름
• scull.h에 다음과 같이 두 개의 매크로가 정의된다.
#define TYPE(dev) (MINOR(dev) >> 4) /* high nibble */
#define NUM(dev) (MINOR(dev) & 0xf) /* low nibble */
순천향대학교 정보기술공학부
이상정
26
Ch.3 Char Drivers
LINUX Device Drivers
파일 오퍼레이션 구조체 정의
 부 번호의 각 디바이스 타입에 따라 open 시에 flip->f_op
지정
struct file_operations *scull_fop_array[]={
&scull_fops,
/* type 0 */
&scull_priv_fops, /* type 1 */
&scull_pipe_fops, /* type 2 */
&scull_sngl_fops, /* type 3 */
&scull_user_fops, /* type 4 */
&scull_wusr_fops /* type 5 */
};
#define SCULL_MAX_TYPE 5
/* In scull_open, the fop_array is used according to TYPE(dev) */
int type = TYPE(inode->i_rdev);
if (type > SCULL_MAX_TYPE) return -ENODEV;
filp->f_op = scull_fop_array[type];
순천향대학교 정보기술공학부
이상정
27
Ch.3 Char Drivers
LINUX Device Drivers
scull_open() 함수
 커널은 주 번호에 따라 open을 호출
• 부 번호의 디바이스 타입에 따라 flip->f_op에 해당 파일 오퍼레이션
지정
• 각 디바이스 타입에 관련된 open 메쏘드를 실행하기 위해
flip->f_op->open을 호출
 다음은 scull_open() 함수의 코드 내용
• Scull_Dev 자료구조는 드라이버의 메모리 영역을 표시
• scull_nr_devs는 가용한 디바이스의 수
• scull_devices[]는 Scull_Dev에 대한 배열의 포인터
• down_interruptible과 up은 나중에 설명
• 디바이스가 쓰기로 오픈된 경우 크기를 0으로 세팅
• 일반 파일의 새로운 오픈 시 크기가 0이되는 것과 같음
• 읽기를 위해 오픈되는 경우 어떤 동작도 수행되지 않음
순천향대학교 정보기술공학부
이상정
28
Ch.3 Char Drivers
LINUX Device Drivers
scull_open() 코드 (1)
/* In scull_open, the fop_array is used according to TYPE(dev) */
int scull_open(struct inode *inode, struct file *filp)
{
Scull_Dev *dev; /* device information */
int num = NUM(inode->i_rdev);
int type = TYPE(inode->i_rdev);
/*
* If private data is not valid, we are not using devfs
* so use the type (from minor nr.) to select a new f_op
*/
if (!filp->private_data && type) {
if (type > SCULL_MAX_TYPE) return -ENODEV;
filp->f_op = scull_fop_array[type];
return filp->f_op->open(inode, filp); /* dispatch to specific open */
}
/* type 0, check the device number (unless private_data valid) */
dev = (Scull_Dev *)filp->private_data;
순천향대학교 정보기술공학부
이상정
29
Ch.3 Char Drivers
LINUX Device Drivers
scull_open() 코드 (2)
if (!dev) {
if (num >= scull_nr_devs) return -ENODEV;
dev = &scull_devices[num];
filp->private_data = dev; /* for other methods */
}
MOD_INC_USE_COUNT; /* Before we maybe sleep */
/* now trim to 0 the length of the device if open was write-only */
if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
if (down_interruptible(&dev->sem)) {
MOD_DEC_USE_COUNT;
return -ERESTARTSYS;
}
scull_trim(dev); /* ignore errors */
up(&dev->sem);
}
return 0;
/* success */
}
순천향대학교 정보기술공학부
이상정
30
Ch.3 Char Drivers
LINUX Device Drivers
release 메쏘드
 release 메쏘드는 다음 기능을 수행
• open 시 flip->private_data 에 할당된 메모리를 해제
• 마지막 release인 경우 디바이스를 종료(shut down)
• 모듈의 사용횟수를 감소
 close 시스템 콜은 file 구조체의 카운터가 0인 경우경우에만
release 메쏘드를 실행
 scull 코드는 종료할 하드웨어가 없기 때문에 간단
int scull_release(struct inode *inode, struct file *filp)
{
MOD_DEC_USE_COUNT;
return 0;
}
순천향대학교 정보기술공학부
이상정
31
Ch.3 Char Drivers
scull의 메모리 사용
순천향대학교 정보기술공학부
이상정
32
LINUX Device Drivers
scull 디바이스
 Scull_Dev 구조체의 링크 리스트(linked list)로 구성
• 각 구조체는 1000개의 4000 바이트 메모리 영역들로 구성되어 최대
4M 바이트의 크기
• 각 메모리 영역을 퀀텀(quantum), 이들을 가리키는 1000개의 배열
을 퀀텀 세트(quantum set)라 함
 scull에서 한 바이트 쓰기
• 퀀텀은 4K
• 퀀텀 세트는 4K 또는 8K로(주소가 32비트 또는 64비트 여부에 따라
포인터의 크기가 달라짐)
• 총 8K 또는 12K 바이트의 메모리를 소모
 퀀텀과 퀀텀의 크기는 scull.h 에서 정의
• SCULL_QUANTUM, SCULL_QSET 값으로 정의
• 모듈 로드 시 scull_quantum과 scull_qset 값 지정
순천향대학교 정보기술공학부
이상정
33
Ch.3 Char Drivers
LINUX Device Drivers
순천향대학교 정보기술공학부
이상정
34
Ch.3 Char Drivers
LINUX Device Drivers
Scull_Dev 구조체
typedef struct Scull_Dev {
void **data;
struct Scull_Dev *next;
int quantum;
int qset;
unsigned long size;
devfs_handle_t handle;
unsigned int access_key;
struct semaphore sem;
} Scull_Dev;
순천향대학교 정보기술공학부
이상정
/* next listitem */
/* the current quantum size */
/* the current array size */
/* data size */
/* only used if devfs is there */
/* used by sculluid and scullpriv */
/* mutual exclusion semaphore
*/
35
Ch.3 Char Drivers
LINUX Device Drivers
Scull_Dev 사용 예, scull_trim (1)
 scull_trim은 쓰기로 오픈시 scull_open에 의해 호출
• 전체 데이터 영역을 해제
• 링크 리스트를 통해 퀀텀과 퀀텀 세트를 해제
int scull_trim(Scull_Dev *dev)
{
Scull_Dev *next, *dptr;
int qset = dev->qset; /* "dev" is not-null */
int i;
for (dptr = dev; dptr; dptr = next) { /* all the list items */
if (dptr->data) {
for (i = 0; i < qset; i++)
if (dptr->data[i])
kfree(dptr->data[i]);
kfree(dptr->data);
dptr->data=NULL;
}
순천향대학교 정보기술공학부
이상정
36
Ch.3 Char Drivers
LINUX Device Drivers
Scull_Dev 사용 예, scull_trim (2)
next=dptr->next;
if (dptr != dev) kfree(dptr); /* all of them but the first */
}
dev->size = 0;
dev->quantum = scull_quantum;
dev->qset = scull_qset;
dev->next = NULL;
return 0;
}
순천향대학교 정보기술공학부
이상정
37
Ch.3 Char Drivers
레이스 조건 (Race Conditions), 세마포
순천향대학교 정보기술공학부
이상정
38
LINUX Device Drivers
레이스 조건
 두 개의 프로세스 A,B가 동시에 scull 디바이스에 쓰기 위해
오픈하여 같은 퀀텀에 할당하는 경우 문제가 발생
• 즉 A가 할당한 포인터를 B가 덮어쓰기(overwrite)할 수가 있음
• 이를 레이스 조건(race condition)이라 함
 일반적으로 단일 프로세서 리눅스 시스템에서는 현재 수행되
는 커널 코드가 다른 프로세스에 의해 선점되지 않기 때문에
이와 같은 문제가 발생하지 않음
• SMP 시스템에서는 프로세스 A,B가 동시에 다른 프로세서에서 실행
되어 간섭을 일으킬 수 있음
• 레이스 조건을 해결하는 리눅스 커널에 대한 자세한 내용은 9장에서
기술
순천향대학교 정보기술공학부
이상정
39
Ch.3 Char Drivers
LINUX Device Drivers
세마포(semaphore) (1)
 세마포(semaphore)
• 자원들에의 접근을 제어하는 일반적인 메커니즘으로 상호배제(mutual
exclusion)를 위해 사용
• 세마포에 의해 서로 상호배제되는 프로세스들은 동시에 같은 코드를 실행하
거니 같은 데이터에 접근할 수 없음
• 이와 같이 상호배제 되는 세마포를 뮤텍스(mutex)라 한다.
 리눅스의 세마포 구현
•
•
•
•
struct semaphore로 선언되며 <asm/semaphore.h>에서 정의
scull 에서 세마포는 Scull_Dev 구조체의 필드로 기술
세마포는 사용되기 전에 sema_init 함수로 초기화
상호배제 응용에서 세마포는 1로 초기화하여 사용
 다음은 scull 코드의 scull_init_module 함수(main.c)의 일부 예
for (i=0; i < scull_nr_devs; i++) {
scull_devices[i].quantum = scull_quantum;
scull_devices[i].qset = scull_qset;
sema_init(&scull_devices[i].sem, 1);
}
순천향대학교 정보기술공학부
이상정
40
Ch.3 Char Drivers
LINUX Device Drivers
세마포(semaphore) (2)
 세마포에 의해 상호배제되는 코드를 진입하는 프로세스는 이미 다른 프
로세스가 사용 중인지를 체크해야 함
 리눅스에서 세마포를 획득하는 함수인 down 이나 down_interruptible
(운영체제 교재에서 P) 함수를 사용하여 체크
• 이들 함수는 세마포가 0보다 크면 세마포를 감소시키고 리턴하여 코드로 진
입
• 만약 세마포가 0이면 이 함수는 수면(sleep)에 들어가고, 세마포를 해제하여
이 함수를 깨울 가능성이 있는 다른 프로세스 처리 후에 다시 시도
• down_interruptible 함수는 시그널에 의한 인터럽트를 수용하는 반면 down
은 프로세스에 시그널의 전달을 허용하지 않음
• 시그널을 허용하지 않으면 프로세스를 강제로 소멸시킬 수 없는 경우나 예상
치 못한 동작을 초래하므로 보통 시그널을 허용하는 down_interruptible 함수
를 사용
• down_interruptible 함수에서는 함수에 인터럽트가 발생하였는지를 체크해야
함
• 프로세스가 인터럽트되면 이들 함수는 0이 아닌 값을 리턴하고 세마포는 획
득하지 못함
순천향대학교 정보기술공학부
이상정
41
Ch.3 Char Drivers
LINUX Device Drivers
세마포(semaphore) (3)
• 다음은 인터럽트 여부를 체크하는 루틴으로 인터럽트되면
-ERESTARTSYS를 반환
if (down_interruptible(&sem))
return -ERESTARTSYS;
 세마포는 획득 후에 해제
• 리눅스에서는 up 함수(운영체제 교재에서 V)
• 이 함수는 세마포를 증가시키고 세마포를 위해 기다리고 있는 프로세스들을
깨움
up (&sem);
 세마포를 획득하기 위해 down_interruptible 를 사용하는 코드는 세마포
를 획득하려는 다른 함수를 호출하지 말아야 함
• 그렇지 않으면 데드록(deadlock) 유발
• 이미 세마포를 획득하여 세마포가 0이되고 해제되지 않은 상태에서 다시 세
마포 획득을 시도하면 수면에 들어가 해제하는 up에 도달하지 못함
순천향대학교 정보기술공학부
이상정
42
Ch.3 Char Drivers
LINUX Device Drivers
세마포(semaphore) (4)
 scull에서는 메모리 접근을 보호하기 위해 디바이스 당 세마
포(per-device semaphore)를 사용
• Scull_Dev의 data 필드를 접근하고자 하는 코드는 먼저 세마포를 획
득해야 함
• 디바이스 메쏘드를 구현하는 함수만이 세마포를 획득하여 데드록을
피함
• 이외 내부 루틴들은 앞의 scull_trim 의 예와 같이 이미 세마포를 획득
한 것으로 가정
• 이상과 같은 방식으로 Scull_Dev 구조체는 레이스 조건으로부터 보
호
순천향대학교 정보기술공학부
이상정
43
Ch.3 Char Drivers
read 및 write 메쏘드
순천향대학교 정보기술공학부
이상정
44
LINUX Device Drivers
read, write 메쏘드 프로토타입
 ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp);
ssize_t write(struct file *filp, const char *buff, size_t count,
loff_t *offp);
•
•
•
•
•
flip는 파일 포인터
count는 전송되는 데이터의 크기
buff는 송수신되는 사용자 버퍼
offp는 사용자가 액세스하는 파일의 위치를 표시
“signed size type”을 리턴
 이들 메쏘드는 커널 주소공간과 사용자 주소공간 간에 데이터를 송수신
• 사용자 주소공간은 스와핑(swapped out)이 된다는 점에서 커널 주소공간과
차이
• 따라서 단순 포인터나 memcpy를 통해 송수신할 수는 없음
• 커널이 사용자 영역 포인터를 액세스할 때 해당 페이지가 메모리에 없는 경
우 페이지 폴트가 발생
• CPU가 커널 공간을 실행하고 있을 때에도 페이지 폴트를 다루는 기법이 필요
• 이장과 5장의 “Using the fault ioctl Argument”에서 소개
순천향대학교 정보기술공학부
이상정
45
Ch.3 Char Drivers
LINUX Device Drivers
사용자 공간과 커널 공간과의 데이터 전송
 리눅스에서는 사용자 공간과 커널 공간과의 전송은
<asm/uaccess.h>에 정의된 특수 함수들에 의해 수행
• unsigned long copy_to_user(void *to, const void *from, unsigned
long count);
• unsigned long copy_from_user(void *to, const void *from,
unsigned long count);
 이들 함수는 일반 memcpy 함수와 유사하지만 커널 코드에
서 사용자 영역을 액세스하는데 주의가 필요
• 사용자 페이지가 메모리에 없는 경우 페이지 폴트 핸들러는 프로세스
를 수면상태(sleep)로 전환하고 페이지를 스왑공간에서 가져 옴
• 수면 시 스케쥴러 호출하여 다른 프로세스 실행하므로 병행성
(concurrency) 문제 발생
• 따라서 드라이버에서 사용자 공간을 액세스하는 함수는 재진입 가능
(reentrant)하고 다른 드라이버 함수들과 동시에 실행(concurrently
execute)할 수 있어야 함
• 이와 같은 동시 접근의 제어를 위해 세마포를 사용
순천향대학교 정보기술공학부
이상정
46
Ch.3 Char Drivers
LINUX Device Drivers
copy_to_user, copy_from_user
 이 두 함수는 각 공간 사이의 데이터 복사 뿐만 아니라 사용
자 공간의 포인터가 유효한지도 체크
• 복사 중 유효하지 않은 주소를 만나 경우 유효한 부분까지만 복사되
고 복사된 메모리의 양을 리턴
• 만약 사용자 공간의 유효성 여부의 체크가 필요 없으면
__copy_to_user와 __copy_from_user를 사용
 read 메쏘드는 디바이스에서 사용자 공간으로 데이터를 복
사(copy_to_user 사용)
 write 메쏘드는 사용자 공간에서 디바이스로 데이터를 복사
(copy_from_user 사용).
 데이터 복사 후 파일 위치 *offp 는 갱신
• 대부분의 경우 이는 flip->f_pos 의 포인터
• pread와 pwrite 시스템 콜에서는 다른 포인터가 사용
• 이들 시스템 콜은 한번에 lssek과 read 또는 write를 수행한다.
순천향대학교 정보기술공학부
이상정
47
Ch.3 Char Drivers
LINUX Device Drivers
read 메쏘드 인수의 사용
순천향대학교 정보기술공학부
이상정
48
Ch.3 Char Drivers
LINUX Device Drivers
read 메쏘드
 read 메쏘드 리턴 값 의미
• 리턴 값이 count 인수와 같으면 요청된 바이트의 수를 성공적 전송
• 리턴 값이 양수이고 count 보다 작으면 데이터의 부분만이 전송되었
음을 의미
• 대개의 경우 응용 프로그램은 read를 다시 시도
• 만약 fread 함수로 호출하였다면 라이브러리 함수는 요청된 전송이 완료
될 때까지 이 시스템 콜을 재 이슈
• 0을 리턴하면 파일의 끝에 도달하였음을 의미
• 음수인 경우 에러가 발생했음을 나타내고 <linux/error.h>에 기술된
에러 내용에 해당하는 값을 리턴
• 현재 데이터가 없고 이 후에 데이터가 입력되는 경우 read 시스템 콜
은 불로킹
• 블로킹은 5장의 “Blocking I/O”에서 다루어 짐
순천향대학교 정보기술공학부
이상정
49
Ch.3 Char Drivers
LINUX Device Drivers
scull_read 함수
 Scull의 scull_read 함수
• 한 번에 지정된 모든 데이터를 읽기 위해 루프를 사용하지 않고 부분
읽기를 사용하여 한번에 데이터 퀀텀 한 개 씩 읽음
• 응용 프로그램이 더 많은 데이터를 원하면 루프를 사용하여 다시 호
출
• 코드 분석
• *f_pos는 이전까지 읽은 데이터의 바이트 수
• count는 현재 읽어야 할 바이트 수
• *f_pos로부터 Scull_Dev 구조체의 한 노드, 퀀텀 세트 및 퀀텀의 위치를
계산
–
–
–
–
itemsize는 Scull_Dev 구조체의 한 노드가 저장하는 총 바이트 수(4M)
item은 현재 읽어야 할 Scull_Dev 노드를 가리킴
rest는 현재 item아 가리키는 노드에서의 바이트 수(위치)
item 노드 중 s_pos는 퀀텀 세트의 위치, q_pos는 퀀텀에서의 위치를 가리
킴
순천향대학교 정보기술공학부
이상정
50
Ch.3 Char Drivers
LINUX Device Drivers
scull_read 코드 (1)
ssize_t scull_read(struct file *filp, char *buf, size_t count, loff_t *f_pos)
{
Scull_Dev *dev = filp->private_data; /* the first listitem */
Scull_Dev *dptr;
int quantum = dev->quantum;
int qset = dev->qset;
int itemsize = quantum * qset; /* how many bytes in the listitem */
int item, s_pos, q_pos, rest;
ssize_t ret = 0;
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
if (*f_pos >= dev->size)
goto out;
순천향대학교 정보기술공학부
이상정
51
Ch.3 Char Drivers
LINUX Device Drivers
scull_read 코드 (2)
if (*f_pos + count > dev->size)
count = dev->size - *f_pos;
/* find listitem, qset index, and offset in the quantum */
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum; q_pos = rest % quantum;
/* follow the list up to the right position (defined elsewhere) */
dptr = scull_follow(dev, item);
if (!dptr->data)
goto out; /* don't fill holes */
if (!dptr->data[s_pos])
goto out;
순천향대학교 정보기술공학부
이상정
52
Ch.3 Char Drivers
LINUX Device Drivers
scull_read 코드 (3)
/* read only up to the end of this quantum */
if (count > quantum - q_pos)
count = quantum - q_pos;
if (copy_to_user(buf, dptr->data[s_pos]+q_pos, count)) {
ret = -EFAULT;
goto out;
}
*f_pos += count;
ret = count;
out:
up(&dev->sem);
return ret;
}
순천향대학교 정보기술공학부
이상정
53
Ch.3 Char Drivers
LINUX Device Drivers
write 메쏘드
 write 메쏘드 리턴 값 의미
• 리턴 값이 count 인수와 같으면 요청된 바이트의 수 만큼 성공적 전
송
• 리턴 값이 양수이고 count 보다 작으면 데이터의 일부만이 전송되었
음을 의미
• 대개의 경우 응용 프로그램은 write를 다시 시도
• 0을 리턴하면 아직 어느 것도 전송되지 않았음을 의미하며 에러는 아
님
• 이는 블로킹 쓰기이며 5장의 “Blocking I/O”에서 기술
• 음수인 경우 에러가 발생했음을 나타내고 <linux/error.h>에 기술된
에러 내용에 해당하는 값을 리턴
 Scull 코드 scull_write 에서는 read와 마찬가지로 한번에 데
이터 퀀텀 한 개씩 쓰기를 수행
순천향대학교 정보기술공학부
이상정
54
Ch.3 Char Drivers
LINUX Device Drivers
scull_write 코드 (1)
ssize_t scull_write(struct file *filp, const char *buf, size_t count,
loff_t *f_pos)
{
Scull_Dev *dev = filp->private_data;
Scull_Dev *dptr;
int quantum = dev->quantum;
int qset = dev->qset;
int itemsize = quantum * qset;
int item, s_pos, q_pos, rest;
ssize_t ret = -ENOMEM; /* value used in "goto out" statements */
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
순천향대학교 정보기술공학부
이상정
55
Ch.3 Char Drivers
LINUX Device Drivers
scull_write 코드 (2)
/* find listitem, qset index and offset in the quantum */
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum; q_pos = rest % quantum;
/* follow the list up to the right position */
dptr = scull_follow(dev, item);
if (!dptr->data) {
dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
if (!dptr->data)
goto out;
memset(dptr->data, 0, qset * sizeof(char *));
}
if (!dptr->data[s_pos]) {
dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
if (!dptr->data[s_pos])
goto out;
}
순천향대학교 정보기술공학부
이상정
56
Ch.3 Char Drivers
LINUX Device Drivers
scull_write 코드 (3)
/* write only up to the end of this quantum */
if (count > quantum - q_pos)
count = quantum - q_pos;
if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {
ret = -EFAULT;
goto out;
}
*f_pos += count;
ret = count;
/* update the size */
if (dev->size < *f_pos)
dev-> size = *f_pos;
out:
up(&dev->sem);
return ret;
}
순천향대학교 정보기술공학부
이상정
57
Ch.3 Char Drivers
디바이스 파일 시스템
(Device Filesystem)
순천향대학교 정보기술공학부
이상정
58
LINUX Device Drivers
디바이스 파일시스템, defs
 2.3.46 이후 리눅스 커널에서 디바이스 파일 시스템 defs 제공
 defs의 주요 특징
• /dev 에서의 디바이스 파일(노드) 는 디바이스 초기화 시에 생성되고 디바이
스 제거 시 제거
• 디바이스 드라이버가 디바이스 이름, 소유 및 허용 등을 명시할 수 있고 사용
자 영역 프로그램은 소유 및 허용을 변경
• 파일 이름의 변경은 허용되지 않음
• 디바이스 드라이버의 주 번호를 할당할 필요가 없고 부 번호(minor number)
를 관리할 필요가 없음
• 드라이버 자신의 디바이스 파일을 자동으로 관리하므로 모듈이 로드되거나
제거될 때 디바이스 특수 파일을 생성하는 스크립트를 실행할 필요가 없음
 scull 에서는 defs 특징을 활용
• 컴파일 시 커널 구성 정보 CONFIG_DEVFS_FS 로 defs의 정의 여부를 구분
• 이 책에서는 scull 코드를 제외하고는 defs 사용하지 않음
순천향대학교 정보기술공학부
이상정
59
Ch.3 Char Drivers
LINUX Device Drivers
defs 함수 (1)
#include <linux/devfs_fs_kernel.h>
devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name,
void *info);
devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,
unsigned int flags, unsigned int major, unsigned int minor,
umode_t mode, void *ops, void *info);
void devfs_unregister (devfs_handle_t de);
 dir
• 새로운 특수 파일이 놓일 디렉토리를 기술
• NULL 이면 /dev 디렉토리를 의미
• 고유의 디렉토리를 만들려면 defs_mk_dir 함수를 사용
 name
• 디바이스의 이름으로 서브디렉토리를 명시하기 위해 ‘/’가 포함될 수 있음
 flags
• defs 플래그의 비트 마스크
• 대개의 경우 DEVFS_FL_DEFAULT 를 사용
• 주 번호, 부 번호를 자동으로 할당하려면 DEVFS_FL_AUTO_DEVNUM 을 사용
• 나머지 플래그는 다음에 소개
순천향대학교 정보기술공학부
이상정
60
Ch.3 Char Drivers
LINUX Device Drivers
defs 함수 (2)
 major, minor
• 디바이스의 주 번호, 부 번호
• DEVFS_FL_AUTO_DEVNUM 가 기술되면 사용되지 않음
 mode
• 디바이스의 액세스 모드
 ops
• 디바이스에 대한 파일 오퍼레이션 구조체의 포인터

info
• flip->private_data 의 디폴트 값
• 파일 시스템은 디바이스가 오픈될 때 이 값으로 포인터를 초기화
• defs_mk_dir의 info 포인터는 defs에서 사용되지 않으며 “client data” 포인
터 역할을 함
 de
• 이전 defs_register 의 호출로 구해진 defs 엔트리이다.
순천향대학교 정보기술공학부
이상정
61
Ch.3 Char Drivers
LINUX Device Drivers
defs 플래그 (1)
 defs 플래그들은 <linux/devfs_fs_kernel.h>에 기술
• DEVFS_FL_NONE, DEVFS_FL_DEFAULT
• 전자는 단순히 0으로 정의되고 코드의 읽기를 용이하기 위해 제공
• 후자는 현재는 DEVFS_FL_NONE 로 정의되었으나 나중에 코드 호환을
위해 이를 사용하는 것이 바람직
• DEVFS_FL_AUTO_OWNER
• 마지막에 특수 파일을 오픈한 uid/gid 가 디바이스의 소유하도록 함
• 마지막에 오픈한 프로세스가 없으면 누구나 read/write가 가능
• DEVFS_FL_SHOW_UNREG, DEVFS_FL_HIDE
• 전자는 등록 해제(unregister)할 때 /dev에서 디바이스 파일을 제거하지
말도록 지시
• 후자는 /dev에 디바이스 파일을 보이지 않도록 지시
• DEVFS_FL_AUTO_DEVNUM
• 디바이스 번호를 자동으로 할당
• 디바이스 이름과 관련되어 할당된 번호는 디바이스가 등록 해제되어도
유지
• 따라서 시스템 셧다운 이전에 다시 로드되면 같은 번호를 부여
순천향대학교 정보기술공학부
이상정
62
Ch.3 Char Drivers
LINUX Device Drivers
defs 플래그 (2)
• DEVFS_FL_NO_PERSISTENCE
• 디바이스를 제거할 떄 디바이스에 관련된 속성(액세스 모드, 소유권, 주/
부 번호) 등을 저장하지 않고 버림
 다음은 플래그에 관한 정보를 확득하고 변경하는 함수
int devfs_get_flags (devfs_handle_t de, unsigned int *flags);
int devfs_set_flags (devfs_handle_t de, unsigned int flags);
순천향대학교 정보기술공학부
이상정
63
Ch.3 Char Drivers
LINUX Device Drivers
defs 사용 예 (1)
 scull 코드에 defs 기능을 추가한 코드 예
• scull에서 defs를 사용하는 경우 scull_load 스크립트를 실행하지 않
고 바로 insmod 를 실행
• scull 관련 특수파일들은 /dev/scull 디렉토리에 생성
• scull_init(main.c) 함수에서 다음과 같이 디바이스를 생성
#ifdef CONFIG_DEVFS_FS
/* If we have devfs, create /dev/scull to put files in there */
scull_devfs_dir = devfs_mk_dir(NULL, "scull", NULL);
if (!scull_devfs_dir) return -EBUSY; /* problem */
#else /* no devfs, do it the "classic" way */
………….
result = register_chrdev(scull_major, "scull", &scull_fops);
…………
#endif /* CONFIG_DEVFS_FS */
……….
순천향대학교 정보기술공학부
이상정
64
Ch.3 Char Drivers
LINUX Device Drivers
defs 사용 예 – scull_init (2)
for (i=0; i < scull_nr_devs; i++) {
scull_devices[i].quantum = scull_quantum;
scull_devices[i].qset = scull_qset;
sema_init(&scull_devices[i].sem, 1);
#ifdef CONFIG_DEVFS_FS
sprintf(devname, "%i", i);
devfs_register(scull_devfs_dir, devname,
DEVFS_FL_AUTO_DEVNUM,
0, 0, S_IFCHR | S_IRUGO | S_IWUGO,
&scull_fops,
scull_devices+i);
#endif
}
순천향대학교 정보기술공학부
이상정
65
Ch.3 Char Drivers
LINUX Device Drivers
defs 사용 예 – scull_cleanup (3)
 scull_cleanup 함수
if (scull_devices) {
for (i=0; i<scull_nr_devs; i++) {
scull_trim(scull_devices+i);
/* the following line is only used for devfs */
devfs_unregister(scull_devices[i].handle);
}
kfree(scull_devices);
}
………
/* once again, only for devfs */
devfs_unregister(scull_devfs_dir);
순천향대학교 정보기술공학부
이상정
66
Ch.3 Char Drivers
LINUX Device Drivers
defs 사용 예 (4)
 scull 모듈을 로드하면 defs를 실행하고, ls -l /dev/scull 의
실행 결과는 다음과 같다.
crw-rw-rwcrw-rw-rwcrw-rw-rwcrw-rw-rwcrw-rw-rwcrw-rw-rwcrw-rw-rwcrw-rw-rwcrw-rw-rwcrw-rw-rwcrw-rw-rwcrw-rw-rw순천향대학교 정보기술공학부
1
1
1
1
1
1
1
1
1
1
1
1
root
root
root
root
root
root
root
root
root
root
root
root
이상정
root
root
root
root
root
root
root
root
root
root
root
root
144,
144,
144,
144,
144,
144,
144,
144,
144,
144,
144,
144,
67
1 Jan 1 1970 0
2 Jan 1 1970 1
3 Jan 1 1970 2
4 Jan 1 1970 3
5 Jan 1 1970 pipe0
6 Jan 1 1970 pipe1
7 Jan 1 1970 pipe2
8 Jan 1 1970 pipe3
12 Jan 1 1970 priv
9 Jan 1 1970 single
10 Jan 1 1970 user
11 Jan 1 1970 wuser
Ch.3 Char Drivers
scull 코드의 실행 예
순천향대학교 정보기술공학부
이상정
68
LINUX Device Drivers
컴파일 및 로드
# cd source/scull
# make
# sh scull_load
# ls –l /dev/scull*
lrwxrwxrwx
1 root
rw-rw-r-1 root
crw-rw-r-- 1 root
crw-rw-r-- 1 root
crw-rw-r-- 1 root
lrwxrwxrwx
1 root
crw-rw-r-- 1 root
crw-rw-r-- 1 root
crw-rw-r-- 1 root
crw-rw-r-- 1 root
crw-rw-r-- 1 root
crw-rw-r-- 1 root
crw-rw-r-- 1 root
crw-rw-r-- 1 root
순천향대학교 정보기술공학부
root
wheel
wheel
wheel
wheel
root
wheel
wheel
wheel
wheel
wheel
wheel
wheel
wheel
이상정
254,
254,
254,
254,
254,
254,
254,
254,
254,
254,
254,
254,
6 11월 20 23:08 /dev/scull -> scull0
0 11월 20 23:08 /dev/scull0
1 11월 20 23:08 /dev/scull1
2 11월 20 23:08 /dev/scull2
3 11월 20 23:08 /dev/scull3
10 11월 20 23:08 /dev/scullpipe -> scullpipe0
32 11월 20 23:08 /dev/scullpipe0
33 11월 20 23:08 /dev/scullpipe1
34 11월 20 23:08 /dev/scullpipe2
35 11월 20 23:08 /dev/scullpipe3
16 11월 20 23:08 /dev/scullpriv
48 11월 20 23:08 /dev/scullsingle
64 11월 20 23:08 /dev/sculluid
80 11월 20 23:08 /dev/scullwuid
69
Ch.3 Char Drivers
LINUX Device Drivers
디바이스 파일 이용
# free
total
used
Mem: 126060
117076
-/+ buffers/cache: 24752
Swap: 353420
30380
free
shared
8984
0
101308
323040
buffers
51980
cached
40344
free
shared
8500
0
100828
323040
buffers
51988
cached
40340
# ls –l /dev > /dev/scull0
# cat /dev/scull0
……………
……………
# free
total
used
Mem: 126060
117560
-/+ buffers/cache: 25232
Swap: 353420
30380
# /sbin/rmmod scull
순천향대학교 정보기술공학부
이상정
70
Ch.3 Char Drivers
LINUX Device Drivers
사용자 프로그램의 시스템 콜 이용 (1)
# cat myWrite.c
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
char buffer[1024] = "!!! Test writing to scull device ???";
int main(int argc, char *argv[])
{
int fd, n;
fd = open("/dev/scull1", O_WRONLY, 0);
if ((n=write(fd, buffer, strlen(buffer))) < strlen(buffer))
printf("!! only %d bytes write\n", n);
else
printf("!! writing success to /dev/scull1\n");
return 0;
}
순천향대학교 정보기술공학부
이상정
71
Ch.3 Char Drivers
LINUX Device Drivers
사용자 프로그램의 시스템 콜 이용 (2)
# cc myWrite.c -o myWrite
# ./myWrite
!! writing success to /dev/scull1
# cat /dev/scull1
!!! Test writing to scull device ???
#
순천향대학교 정보기술공학부
이상정
72
Ch.3 Char Drivers
LINUX Device Drivers
과제
 코드 분석
• 3장의 내용에 해당하는 코드 분석
• source/scull Makefile scull_load scull_unload scull.h main.c
 실행 및 결과분석
• 강의에서 제시된 예와 차별화
순천향대학교 정보기술공학부
이상정
73
Ch.3 Char Drivers