NAME
move_pages - 프로세스의 개별 페이지들을 다른 노드로 옮기기
SYNOPSIS
#include <numaif.h>
long move_pages(int pid, unsigned long count, void **pages,
const int *nodes, int *status, int flags);
-lnuma로 링크.
주의: 이 시스템 호출에 대한 glibc 래퍼가 없다. NOTES 참고.
DESCRIPTION
move_pages()는 프로세스 pid의 지정한 pages를 nodes로 지정한 메모리 노드들로 옮긴다. 이동 결과가 status에 반영된다. flags는 이동할 페이지들에 대한 제약을 나타낸다.
pid는 이동할 페이지들이 있는 프로세스의 ID이다. pid가 0이면 move_pages()는 호출 프로세스의 페이지를 옮긴다.
다른 프로세스의 페이지를 옮기려면 다음 특권이 필요하다.
-
4.12까지의 커널: 호출자에게 특권(
CAP_SYS_NICE)이 있거나 호출 프로세스의 실제 내지 실효 사용자 ID가 대상 프로세스의 실제 내지 saved-set 사용자 ID와 일치해야 한다. -
이전 규칙 하에서는 커널에서 선정한 여러 가상 주소들을 호출자가 알아낼 수 있어서 호출자와 같은 UID가 소유하는 프로세스의 주소 공간 배치 난수화가 무력화 될 수 있었고, 그래서 리눅스 4.13부터 규칙이 바뀌었다. 리눅스 4.13부터는 대상 프로세스에 대한 ptrace 접근 모드
PTRACE_MODE_READ_REALCREDS검사로 허가 여부를 결정한다. ptrace(2) 참고.
count는 옮길 페이지 개수이다. 세 배열 pages, nodes, status의 크기를 규정한다.
pages는 옮겨야 할 페이지들에 대한 포인터들의 배열이다. 이 포인터들은 페이지 경계에 맞춰 정렬돼 있어야 한다. pid로 지정한 프로세스에게 보이는 주소로 지정한다.
nodes는 각 페이지에 대해 원하는 위치를 지정한 정수들의 배열이다. 배열의 각 항목은 노드 번호이다. nodes가 NULL일 수도 있는데, 그 경우 move_pages()는 페이지를 옮기지 않고 대신 각 페이지가 현재 자리한 노드를 status 배열로 반환한다. 옮겨야 할 페이지들을 알아내기 위해 각 페이지의 상태를 얻어야 할 수 있다.
status는 정수들의 배열이며 각 페이지의 상태를 반환한다. move_pages()가 오류를 반환하지 않은 경우에만 배열이 유효한 값들을 담고 있다. 배열의 값을 실제 numa 노드를 나타낼 수 없는 값이나 유효한 상태 배열 오류 값으로 미리 초기화해 두면 이동한 페이지들을 알아내는 데 도움이 될 수 있다.
flags는 옮길 페이지의 종류를 지정한다. MPOL_MF_MOVE는 프로세스에서 배타적으로 사용 중인 페이지들만 옮기라는 뜻이다. MPOL_MF_MOVE_ALL은 여러 프로세스들끼리 공유하는 페이지들도 옮길 수 있다는 뜻이다. MPOL_MF_MOVE_ALL을 쓰려면 프로세스가 특권(CAP_SYS_NICE)을 가지고 있어야 한다.
status 배열의 페이지 상태
status 배열의 각 항목으로 다음 값들을 반환할 수 있다.
0..MAX_NUMNODES- 페이지가 자리한 노드를 나타낸다.
-EACCES- 페이지를 여러 프로세스가 맵 하고 있어서
MPOL_MF_MOVE_ALL을 지정해야만 옮길 수 있다. -EBUSY- 페이지가 현재 사용 중이어서 옮길 수 없다. 나중에 다시 시도하라. 페이지로 I/O를 하는 중이거나 다른 커널 서브시스템에서 페이지에 대한 참조를 잡고 있는 경우이다.
-EFAULT- 제로 페이지이거나 프로세스가 맵 하지 않은 메모리 영역이다.
-EIO- 페이지를 내려 쓸 수 없다. 페이지가 변경됐는데 변경된 페이지를 옮길 수 있게 해 주는 이전 함수를 파일 시스템에서 제공하지 않기 때문에 페이지를 옮기기 위해선 아래로 기록해야 한다.
-EINVAL- 변경된 페이지를 이동할 수 없다. 파일 시스템에서 이전 함수를 제공하지 않으며 페이지를 내려 쓸 수 없다.
-ENOENT- 페이지가 존재하지 않는다.
-ENOMEM- 대상 노드에서 메모리를 할당할 수 없다.
RETURN VALUE
성공 시 move_pages()는 0을 반환한다. 오류 시 -1을 반환하며 오류를 나타내도록 errno를 설정한다. 양수 값을 반환하는 경우 그 값은 이동 안 된 페이지 개수이다.
ERRORS
- 양수 값
- 중대하지 않은 원인으로 인한 것인 경우 이동 안 된 페이지들의 개수.
E2BIG- 옮길 페이지가 너무 많다. 리눅스 2.6.29부터는 커널에서 이 오류를 내놓지 않는다.
EACCES- 한 대상 노드를 현재 cpuset에서 허용하지 않는다.
EFAULT- 매개변수 배열에 접근할 수 없다.
EINVALMPOL_MF_MOVE및MPOL_MF_MOVE_ALL외의 플래그를 지정했거나 커널 스레드의 페이지를 이동하려는 시도가 이뤄졌다.ENODEV- 한 대상 노드가 온라인이 아니다.
EPERM- 호출자가 충분한 특권(
CAP_SYS_NICE) 없이MPOL_MF_MOVE_ALL을 지정했다. 또는 호출자가 다른 사용자에게 속한 프로세스의 페이지를 옮기려고 시도했는데 그렇게 하기 위한 특권(CAP_SYS_NICE)을 가지고 있지 않았다. ESRCH- 프로세스가 존재하지 않는다.
VERSIONS
리눅스 버전 2.6.18에서 move_pages()가 처음 등장했다.
CONFORMING TO
이 시스템 호출은 리눅스 전용이다.
NOTES
glibc에서 이 시스템 호출의 래퍼를 제공하지 않는다. 라이브러리 지원에 대한 정보는 numa(7)를 보라.
get_mempolicy(2)를 MPOL_F_MEMS_ALLOWED 플래그로 사용하면 현재 cpuset에서 허용하는 노드들의 집합을 얻을 수 있다. 참고로 그 정보는 수동 내지 자동으로 이뤄지는 cpuset 재구성으로 인해 언제든 바뀔 수 있다.
이 함수를 사용하면 페이지들의 위치(노드)가 지정 주소(mbind(2)) 및/또는 지정 프로세스(set_mempolicy(2))에 대해 설정한 메모리 정책과 어긋나게 될 수도 있다. 다시 말해 메모리 정책이 move_pages()에서 쓰는 목적지 노드를 제약하지 않는다.
<numaif.h> 헤더는 glibc에 포함되어 있지 않으며 libnuma-devel 내지 그와 비슷한 패키지를 설치해야 한다.
SEE ALSO
get_mempolicy(2), mbind(2), set_mempolicy(2), numa(3), numa_maps(5), cpuset(7), numa(7), migratepages(8), numastat(8)
2021-03-22