NAME

ioprio_get, ioprio_set - I/O 스케줄링 클래스 및 우선순위 얻기/설정하기

SYNOPSIS

int ioprio_get(int which, int who);
int ioprio_set(int which, int who, int ioprio);

주의: 이 시스템 호출에 대한 glibc 래퍼가 없다. NOTES 참고.

DESCRIPTION

ioprio_get()ioprio_set() 시스템 호출은 한 개 또는 여러 스레드의 I/O 스케줄링 클래스와 우선순위를 얻고 설정한다.

whichwho 인자는 시스템 호출의 동작 대상이 되는 스레드(들)을 나타낸다. which 인자는 who를 해석하는 방식을 결정하며 다음 값들 중 하나이다.

IOPRIO_WHO_PROCESS
who가 프로세스 ID나 스레드 ID이며 단일 프로세스 내지 스레드를 나타낸다. who가 0이면 호출 스레드가 대상이다.
IOPRIO_WHO_PGRP
who가 프로세스 그룹 ID이며 프로세스 그룹의 구성원 모두를 나타낸다. who가 0이면 호출자가 구성원인 프로세스 그룹이 대상이다.
IOPRIO_WHO_USER
who가 사용자 ID이며 실제 UID가 일치하는 프로세스 모두를 나타낸다.

ioprio_get() 호출 시에 whichIOPRIO_WHO_PGRP이나 IOPRIO_WHO_USER이고 who에 여러 프로세스가 걸리는 경우에는 걸리는 프로세스 전체에서 가장 높은 우선순위를 반환하게 된다. 어떤 우선순위가 더 높다는 것은 더 높은 우선순위 클래스에 속하거나 (IOPRIO_CLASS_RT가 가장 높은 우선순위 클래스이고 IOPRIO_CLASS_IDLE이 가장 낮음) 아니면 같은 우선순위 클래스에 속하면서 우선순위 단계가 더 높은 것이다 (낮은 우선순위 수가 높은 우선순위 단계를 뜻함).

ioprio_set()에 주는 ioprio 인자는 대상 프로세스(들)에 부여할 스케줄링 클래스와 우선순위 모두를 나타내는 비트 마스크이다. 다음 매크로를 사용해 ioprio 값을 합치거나 분해한다.

IOPRIO_PRIO_VALUE(class, data)
이 매크로는 스케줄링 클래스(class)와 우선순위(data)를 받아서 두 값을 합친 ioprio 값을 만들어 매크로 결과로 반환한다.
IOPRIO_PRIO_CLASS(mask)
이 매크로는 mask(ioprio 값)를 받아서 I/O 클래스 요소를 반환한다. 즉 IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE 중 하나를 반환한다.
IOPRIO_PRIO_DATA(mask)
이 매크로는 mask(ioprio 값)를 받아서 우선순위(data) 요소를 반환한다.

스케줄링 클래스와 우선순위에 대한 추가 정보와 ioprio를 0으로 지정했을 때의 의미에 대해선 NOTES 절을 참고하라.

읽기와 동기적인 (O_DIRECT, O_SYNC) 쓰기에서 I/O 우선순위를 지원한다. 비동기 쓰기에는 I/O 우선순위를 지원하지 않는데, 메모리를 변경하는 프로그램의 맥락 밖에서 개시되므로 프로그램별 우선순위가 적용되지 않기 때문이다.

RETURN VALUE

성공 시 ioprio_get()whichwho로 지정한 기준에 맞는 프로세스들 중 가장 높은 I/O 우선순위를 가진 프로세스의 ioprio 값을 반환한다. 오류 시 -1을 반환하며 오류를 나타내도록 errno를 설정한다.

성공 시 ioprio_set()은 0을 반환한다. 오류 시 -1을 반환하며 오류를 나타내도록 errno를 설정한다.

ERRORS

EINVAL
whichioprio에 유효하지 않은 값. ioprio에 사용 가능한 스케줄러 클래스와 우선순위는 NOTES 절 참고.
EPERM
호출 프로세스에게 지정한 프로세스(들)에게 그 ioprio를 부여할 특권이 없다. ioprio_set()에 필요한 특권에 대한 자세한 내용은 NOTES 절 참고.
ESRCH
whichwho의 지정 내용에 일치하는 프로세스를 찾을 수 없다.

VERSIONS

리눅스 커널 2.6.13부터 이 시스템 호출들이 사용 가능하다.

CONFORMING TO

이 시스템 호출들은 리눅스 전용이다.

NOTES

glibc에서 이 시스템 호출의 래퍼를 제공하지 않는다. syscall(2)을 이용해 호출해야 한다.

둘 이상의 프로세스 내지 스레드가 I/O 문맥을 공유할 수 있다. clone(2)CLONE_IO 플래그를 써서 호출한 경우가 그렇다. 하지만 기본적으로는 프로세스의 스레드들이 같은 I/O 문맥을 공유하지 않는다. 따라서 프로세스의 모든 스레드의 I/O 우선순위를 바꾸고 싶다면 스레드 각각에 ioprio_set()을 호출해야 할 수도 있다. 그때 필요한 스레드 ID는 gettid(2)clone(2)이 반환한 값이다.

I/O 우선순위를 지원하는 I/O 스케줄러를 사용할 때에만 이 시스템 호출들에 효력이 있다. 커널 2.6.17 현재 그런 유일한 스케줄러는 Completely Fair Queuing (CFQ) I/O 스케줄러이다.

스레드에 어떤 I/O 스케줄러도 설정하지 않았으면 기본적으로 I/O 우선순위가 CPU 나이스 값(setpriority(2))을 따른다. 리눅스 커널 버전 2.6.24 전에서는 ioprio_set()으로 I/O 우선순위를 한번 설정하고 나면 I/O 스케줄링 동작을 기본으로 되돌릴 방법이 없었다. 리눅스 2.6.24부터는 ioprio를 0으로 지정해서 기본 I/O 스케줄링 동작으로 되돌릴 수 있다.

I/O 스케줄러 선택

I/O 스케줄러는 특수 파일 /sys/block/<device>/queue/scheduler를 통해 장치별로 선택한다.

/sys 파일 시스템을 통해 현재 I/O 스케줄러를 볼 수 있다. 예를 들어 다음 명령은 현재 커널에 적재된 모든 스케줄러들의 목록을 보여 준다.

$ cat /sys/block/sda/queue/scheduler
noop anticipatory deadline [cfq]

꺽쇠괄호가 쳐진 게 그 장치(여기선 sda)에 실제 사용 중인 스케줄러이다. 다른 스케줄러를 선택하려면 이 파일에 새 스케줄러의 이름을 기록하면 된다. 예를 들어 다음 명령은 sda 장치의 스케줄러를 cfq로 설정한다.

$ su
Password:
# echo cfq > /sys/block/sda/queue/scheduler

Completely Fair Queuing (CFQ) I/O 스케줄러

(CFQ Time Sliced라고도 하는) 버전 3부터 CFQ에서는 CPU 스케줄링과 비슷한 I/O 나이스 단계를 구현한다. 그 나이스 단계들을 세 가지 스케줄링 클래스로 묶으며, 각 클래스마다 한 개 이상의 우선순위 단계가 있다.

IOPRIO_CLASS_RT (1)
실시간 I/O 클래스이다. 이 스케줄링 클래스에는 다른 어떤 클래스보다 높은 우선순위를 준다. 즉 이 클래스의 프로세스들에 매번 최우선 디스크 접근권을 준다. 따라서 이 I/O 클래스는 조심해서 사용할 필요가 있다. I/O가 실시간인 프로세스 하나가 전체 시스템을 굶게 만들 수 있기 때문이다. 실시간 클래스 내에는 8단계의 클래스 데이터(우선순위)가 있어서 이 프로세스가 각 서비스마다 정확히 얼마나 오래 디스크를 필요로 하는지 결정한다. 가장 높은 실시간 우선순위 단계는 0이고 가장 낮은 단계는 7이다. 향후에는 원하는 데이터 속도를 전달해서 더 직접적으로 성능과 연결되도록 바뀔 수도 있다.
IOPRIO_CLASS_BE (2)
최선 스케줄링 클래스이다. 특별히 I/O 우선순위를 설정하지 않은 프로세스들의 기본값이다. 클래스 데이터(우선순위)는 프로세스가 얼마나 많은 I/O 대역폭을 얻게 될지 결정한다. 최선 우선순위 단계들은 CPU 나이스 값과 유사하다. (getpriority(2) 참고.) 우선순위 단계는 최선 스케줄링 클래스 내의 다른 프로세스들에 대한 상대적 우선도를 결정한다. 우선순위 단계의 범위는 0(최고)에서 7(최저)까지이다.
IOPRIO_CLASS_IDLE (3)
유휴 스케줄링 클래스이다. 이 단계에서 동작하는 프로세스는 디스크를 필요로 하는 다른 프로세스가 없을 때에만 I/O 시간을 얻는다. 유휴 클래스에는 클래스 데이터가 없다. 프로세스에 이 우선순위 클래스를 부여할 때는 주의할 필요가 있는데, 더 높은 우선도의 프로세스들이 계속해서 디스크에 접근하면 그 프로세스가 굶주리게 될 수 있기 때문이다.

CFQ I/O 스케줄러에 대한 추가 내용과 예시 프로그램은 커널 소스 파일 Documentation/block/ioprio.txt를 참고하라.

I/O 우선순위 설정에 필요한 권한

두 가지 기준에 따라 프로세스 우선순위 변경이 허가되거나 거부된다.

프로세스 소유권
비특권 프로세스는 호출 프로세스의 실제 UID나 실효 UID와 일치하는 실제 UID를 가진 프로세스에 대해서만 I/O 우선순위를 설정할 수 있다. CAP_SYS_NICE 역능을 가진 프로세스는 모든 프로세스의 우선순위를 바꿀 수 있다.
원하는 우선순위
아주 높은 우선순위(IOPRIO_CLASS_RT)를 설정하려면 CAP_SYS_ADMIN 역능이 필요하다. 커널 버전 2.6.24까지는 아주 낮은 우선순위(IOPRIO_CLASS_IDLE)를 설정하는 데도 CAP_SYS_ADMIN이 필요했지만 리눅스 2.6.25부터는 필요하지 않다.

ioprio_set() 호출 시 두 규칙 모두를 따라야 하며, 그렇지 않으면 호출이 EPERM 오류로 실패하게 된다.

BUGS

이 페이지에서 기술하는 함수 원형과 매크로를 정의하는 적절한 헤더 파일을 glibc에서 아직 제공하지 않는다. linux/ioprio.h에서 적절한 정의들을 찾을 수 있다.

SEE ALSO

ionice(1), getpriority(2), open(2), capabilities(7), cgroups(7)

리눅스 커널 소스 트리의 Documentation/block/ioprio.txt


2019-03-06