mbind

title: mbind(2)

text:
# mbind(2)

## ИМЯ
mbind - устанавливает политику на область памяти

## ОБЗОР

```
#include <numaif.h>
```

```
long mbind(void *addr, unsigned long len, int mode,
           const unsigned long *nodemask, unsigned long maxnode,
           unsigned flags);
```

```
Компонуется при указании параметра -lnuma.
```

## ОПИСАНИЕ
Вызов mbind() устанавливает политику памяти NUMA, состоящую из режима политики и нуля или более узлов, на область памяти, начинающуюся с addr и длиной len байт. Политикой памяти задаётся на каком узле будет выделяться память.

Если область памяти, заданная аргументами addr и len, включает «анонимную» область памяти — область памяти, созданную с помощью системного вызова mmap(2) с аргументом MAP_ANONYMOUS — или файл, отображённый в память с помощью вызова mmap(2) с флагом MAP_PRIVATE, то страницы будут выделены в соответствии с указанной политикой только когда приложение выполняет запись (сохранение) страницы. Для анонимных областей при первоначальном доступе на чтение будет использоваться общая страница ядра, содержащая только нули. Для отображённого файла с флагом MAP_PRIVATE, при первоначальном доступе на чтение будут выделены страницы в соответствии с политикой памяти нити, для которой происходит выделение страницы. Это может быть не та нить, которая вызвала mbind().

Указанная политика в заданной области памяти будет игнорироваться для всех отображений MAP_SHARED. Скорее всего, страницы будут выделены согласно политике памяти нити, для которой происходит выделение страницы. Но опять таки, это может быть не та нить, которая вызвала mbind().

Если заданная область памяти включает общую область памяти, созданную с помощью системного вызова shmget(2) и подключённую с помощью системного вызова shmat(2), то страницы, выделяемые для анонимной или общей области памяти, будут выделены согласно указанной политике, независимо от того, какой процесс подключил сегмент общей памяти, что вызвало выделение. Однако, если общая область памяти была создана с флагом SHM_HUGETLB, то огромные страницы будут выделяться согласно указанной политике, только если выделение страницы происходит из-за процесса, который вызвал mbind() для этой области.

По умолчанию, mbind() учитывается только при новых выделениях; если страницы внутри области уже были использованы до настройки политики, то политика не применяется. Такое поведение можно изменить с помощью флагов MPOL_MF_MOVE и MPOL_MF_MOVE_ALL, описанных далее.

В аргументе mode должно быть указано одно из следующих значений: MPOL_DEFAULT, MPOL_BIND, MPOL_INTERLEAVE, MPOL_PREFERRED или MPOL_LOCAL (описано далее). Для всех режимов политики, за исключением MPOL_DEFAULT, требуется, чтобы вызывающий указывал в аргументе nodemask узел или узлы, для которых применяется режим.

Аргумент mode также может содержать необязательный флаг режима. Поддерживаемые флаги режима:

MPOL_F_STATIC_NODES (начиная с Linux-2.6.26)

В аргументе nodemask указываются идентификаторы физических узлов. Linux не пересоставляет nodemask, если нить перемещается в другой контекст набора процессоров или когда изменяется набор узлов, который доступен нити согласно текущему контексту набора процессоров.

MPOL_F_RELATIVE_NODES (начиная с Linux-2.6.26)

В аргументе nodemask указываются идентификаторы узлов из набора идентификаторов узлов, разрешённых нити текущим контекстом набора процессоров.

В nodemask содержится битовая маска узлов, в которой содержится до maxnode бит. Размер битовой маски округляется до следующего кратного значения sizeof(unsigned long), но ядром будет использовано только до maxnode бит. Значением NULL в nodemask или значением maxnode равным 0 задаётся пустой набор узлов. Если значение maxnode равно 0, то аргумент nodemask игнорируется. Там, где требуется nodemask, его значение должно содержать, как минимум, один работающий узел, который разрешён нити текущим контекстом набора процессоров (если не указан флаг MPOL_F_STATIC_NODES) и у которого имеется память.

Аргумент mode должен включать одно из следующих значений:

MPOL_DEFAULT

Этот режим запрашивает удаление любой политики не по умолчанию и восстановление поведения по умолчанию. Если он применяется к области памяти посредством mbind(), то это означает использование политики памяти нити, которая могла быть установлена с помощью set_mempolicy(2). Если режим политики памяти нити также равен MPOL_DEFAULT, то будет задействована системная политика по умолчанию. При системной политике по умолчанию выделяются страницы на том узле ЦП, на котором было запрошено выделение. Для MPOL_DEFAULT в аргументах nodemask и maxnode должен быть указан пустой набор узлов.

MPOL_BIND

Этот режим задаёт жёсткую политику, при которой выделение памяти ограничено узлами, заданными в nodemask. Если в nodemask указано более одного узла, то выделение страниц начнётся с узла с достаточным объёмом свободной памяти, который наиболее близок к узлу, где запрошено выделение. Страницы не выделяются на узлах, не указанных в IR nodemask(до Linux 2.6.26 выделение страниц происходило начиная с узла с меньшим номером идентификатора, и продолжится до тех пор, пока на нём не кончится свободная память. Затем выделение продолжится на узле со следующим большим номером идентификатора, указанного в nodemask, и т.д. до тех пор, пока на всех заданных узлах не закончится свободная память).

MPOL_INTERLEAVE

Этот режим задаёт, что при выделении страниц нужно выполнять чередование узлов, которые указаны в nodemask. Это оптимизирует использование полосы пропускания, но не задержку, вовлекая при доступ к страницам и памяти множество узлов. Чтобы это дало эффект, область памяти должна быть достаточно большой, не менее 1 МБ или более, и характер доступа должен быть достаточно равномерным. Доступ к одной странице области будет по прежнему ограничен размером полосы пропускания одного узла.

MPOL_PREFERRED

В этом режиме устанавливается предпочтительный узел для выделения. Ядро сначала будет пытаться выделить страницы на этом узле и перейдёт на другие узлы, если на предпочтительном узле недостаточно свободной памяти. Если в nodemask задано более одного идентификатора узла, то в качестве предпочтительного будет выбран первый из маски. Если в аргументах nodemask и maxnode указан пустой набор, то память будет выделена на узле ЦП, на котором запросили выделение.

MPOL_LOCAL (начиная с Linux 3.8)

Этот режим устанавливает «локальное выделение»; памяти выделяется на узле с ЦП, на котором запросили выделение («локальный узел»). Аргументы nodemask и maxnode должны содержать пустой набор. Если на «локальном узле» не хватает свободной памяти, то ядро попытается выделить память на других узлах. Ядро выделит памяти на «локальном узле» сколько бы ни было на нём памяти. Если «локальный узел» не разрешён для нити текущим контекстом набора процессоров, то ядро попытается выделить память на других узлах. Ядро выделит памяти на «локальном узле» независимо от того, станет ли он разрешённым для нити текущим контекстом набора процессоров. В отличии от этого , MPOL_DEFAULT восстанавливает политику памяти нити (которая может быть задана с помощью set_mempolicy(2)); эта политика может быть другой, не «локальным выделением».

Если в flags указан MPOL_MF_STRICT и mode не равно MPOL_DEFAULT, то вызов завершается ошибкой EIO, если существующие страницы в области памяти не следуют политике.

Если в flags указан MPOL_MF_MOVE, то ядро будет пытаться переместить все существующие страницы в области памяти так, чтобы они следовали политике. Страницы, используемые совместно с другими процессами, перемещаться не будут. Если также указан MPOL_MF_STRICT, что вызов завершается ошибкой EIO, если страницы не могут быть перемещены.

Если в flags указан MPOL_MF_MOVE_ALL, то ядро будет пытаться переместить все существующие страницы в области памяти независимо от того, используются ли они другими процессами. Для использования данного флага вызывающая нить должна быть привилегированной (CAP_SYS_NICE). Если также указан MPOL_MF_STRICT, то вызов завершается ошибкой EIO, если некоторые страницы нельзя переместить.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении mbind() возвращается 0. При ошибке возвращается -1, а в errno содержится код ошибки.

## ОШИБКИ
EFAULT

Часть или вся область памяти, заданная в nodemask и maxnode, указывает за пределы доступного адресного пространства. Или в области памяти, задаваемой addr и len, есть неотображаемая дыра (hole).

EINVAL

В flags или mode указано неправильное значение; или addr + len меньше чем addr; или addr не кратен системному размеру страницы. Или mode равен MPOL_DEFAULT и в nodemask задан непустой набор; или mode равен MPOL_BIND или MPOL_INTERLEAVE и значение nodemask пусто. Или значение maxnode превышает устанавливаемое ядром ограничение. Или в nodemask задан один или более идентификаторов узлов, номер которого больше чем максимально поддерживаемый. Или в nodemask не задано ни одного идентификатора узла, включённого в данный момент и разрешённого нити текущим контекстом набора процессоров, или ни один из указанных узлов не содержит память. Или в аргументе mode указаны сразу MPOL_F_STATIC_NODES и MPOL_F_RELATIVE_NODES.

EIO

Был указан MPOL_MF_STRICT и существующая страница была уже на узле, что не следует политике; или был указан MPOL_MF_MOVE или MPOL_MF_MOVE_ALL и ядро не смогло переместить все существующие страницы области.

ENOMEM

Недостаточное количество памяти ядра.

EPERM

Аргумент flags содержит флаг MPOL_MF_MOVE_ALL и вызывающий не имеет мандата CAP_SYS_NICE.

## ВЕРСИИ
Системный вызов mbind() был добавлен в ядро Linux версии 2.6.7.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Данный вызов есть только в Linux.

## ЗАМЕЧАНИЯ
Информация о библиотеке доступна в numa(7).

Политика NUMA не поддерживается для области памяти отображения файла, который отображён с флагом MAP_SHARED.

Режим MPOL_DEFAULT может по разному влиять на mbind() и set_mempolicy(2). Когда указан MPOL_DEFAULT для set_mempolicy(2), политика памяти нити возвращается к политике по умолчанию или локальному выделению. Когда MPOL_DEFAULT указан для области памяти, используемой mbind(), все страницы, последовательно выделяемые для этой области, будут использовать политику памяти нити, которая задана с помощью set_mempolicy(2). Это эффективно удаляет явную политику из указанной области, «откатываясь» к возможной политике не по умолчанию. Для выбора явного «локального выделения» области памяти, укажите в mode значение MPOL_LOCAL или MPOL_PREFERRED с пустым набором узлов. Этот метод также сработает и в вызове set_mempolicy(2).

Поддержка политики для огромных страниц была добавлена в версию 2.6.16. Для эффективной работы политики чередования на огромных страничных отображениях, контролируемая память должна измеряться десятками мегабайт или больше.

Режим MPOL_MF_STRICT игнорируется для огромных страничных отображений.

Режимы MPOL_MF_MOVE и MPOL_MF_MOVE_ALL доступны только в Linux 2.6.16 и новее.

## СМОТРИТЕ ТАКЖЕ
get_mempolicy(2), getcpu(2), mmap(2), set_mempolicy(2), shmat(2), shmget(2), numa(3), cpuset(7), numa(7), numactl(8)


membarrier

package: man-pages-ru

title: membarrier(2)

summary: задаёт барьеры памяти в наборе нитей

text:
# membarrier(2)

## ИМЯ
membarrier - задаёт барьеры памяти в наборе нитей

## ОБЗОР
\#include <linux/membarrier.h>

int membarrier(int cmd, int flags);

## ОПИСАНИЕ
Системный вызов membarrier() помогает сократить накладные расходы инструкций барьера памяти, которые требуются при доступе к памяти в многоядерных системах. Однако данный системный вызов затратнее чем барьер памяти, поэтому чтобы использовать его эффективно недостаточно просто заменить им барьеры памяти, требуется понимание описанного далее.

При использовании барьеров памяти нужно принимать во внимание, что барьер памяти всегда должен или иметь противоположную сторону барьера, или что модель памяти архитектуры этого не требует.

При работе бывает, что одна сторона барьера (которую будем называть «быстрой стороной») применяется чаще чем другая (которую будем называть «медленной стороной»). Это основная цель использования membarrier(). Основная идея в замене этих барьеров: быстрые стороны барьеров — простыми барьерами компилятора:

```
asm volatile ("" : : : "memory")
```

а медленные стороны барьеров — вызовами membarrier().

Это добавит накладных расходов к медленной стороне и удалит расходы у быстрой стороны, что в результате повысит общую производительность в зависимости от того, как часто используются вызовы membarrier() у медленной стороны, из-за которой возникают издержки, и не перевесит ли это увеличение производительности быстрой стороны.

Аргумент cmd может принимать одно из следующих значений:

MEMBARRIER_CMD_QUERY (начиная с Linux 4.3)

Запросить набор поддерживаемых команд. Возвращаемое вызовом значение представляет собой битовую маску поддерживаемых команд. Сама команда MEMBARRIER_CMD_QUERY имеет значение 0 и не включается в эту маску. Данная команда поддерживается всегда (в ядрах с поддержкой membarrier()).

MEMBARRIER_CMD_GLOBAL (начиная с Linux 4.16)

Проверить, что все потоки всех процессов в системе прошли через состояние, где все доступы к памяти по адресам пространства пользователя соответствуют программному порядку между входом и возвратом из системного вызова membarrier(). Все потоки в системе являются целью этой команды.

MEMBARRIER_CMD_GLOBAL_EXPEDITED (начиная с Linux 4.16)

Установить барьер памяти во всех выполняющихся нитях всех процессов, которые были ранее зарегистрированы с помощью MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED.

После возврата из системного вызова вызвавшей нити гарантируется, что все выполняющиеся нити прошли через состояние, где все доступы к памяти по адресам пространства пользователя соответствуют программному порядку между входом и возвратом из системного вызова (не выполняющиеся нити уже в таком состоянии). Это гарантируется только для нитей процессов, которые были ранее зарегистрированы с помощью MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED.

Учтите, что регистрация о намерении получать барьеры допускается вызовом MEMBARRIER_CMD_GLOBAL_EXPEDITED только из процесса, который не использовал MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED.

«Курируемые» (expedited) команды выполняются быстрее чем не курируемые; они никогда не блокируются, но на них приходятся дополнительные издержки.

MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED (начиная с Linux 4.16)

Зарегистрировать намерение процесса получать барьеры памяти MEMBARRIER_CMD_GLOBAL_EXPEDITED.

MEMBARRIER_CMD_PRIVATE_EXPEDITED (начиная с Linux 4.14)

Применить барьер памяти на все выполняющиеся нити, принадлежащие тому же процессу, что и вызвавшая нить.

После возврата из системного вызова вызвавшей нити гарантируется, что все выполняющиеся, одноуровневые с ней нити прошли через состояние, где все доступы к памяти по адресам пространства пользователя соответствуют программному порядку между входом и возвратом из системного вызова (невыполняющиеся нити уже в таком состоянии). Это гарантируется только для нитей того же процесса, что и вызвавшая нить.

«Курируемые» (expedited) команды выполняются быстрее чем не курируемые; они никогда не блокируются, но на них приходятся дополнительные издержки.

Процессу нужно регистрировать своё намерение использовать частную курируемую команду до её использования.

MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED (начиная с Linux 4.14)

Зарегистрировать намерение процесса использовать MEMBARRIER_CMD_PRIVATE_EXPEDITED.

MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE (начиная с Linux 4.16)

В дополнении к гарантии упорядочивания памяти, описанной в MEMBARRIER_CMD_PRIVATE_EXPEDITED, после возврата из системного вызова вызвавшей нити гарантируется, что все выполняющиеся, одноуровневые с ней нити выполнили ядерную инструкцию сериализации (core serializing instruction). Это гарантируется только для нитей того же процесса, что и вызвавшая нить.

«Курируемые» (expedited) команды выполняются быстрее чем не курируемые; они никогда не блокируются, но на них приходятся дополнительные издержки.

Процессу нужно регистрировать своё намерение использовать частную курируемую ядерную команду синхронизации до её использования.

MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE (начиная с Linux 4.16)

Зарегистрировать намерение процесса использовать MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE.

MEMBARRIER_CMD_SHARED (начиная с Linux 4.3)

Псевдоним MEMBARRIER_CMD_GLOBAL, существует для обратной совместимости в заголовке.

В настоящее время аргумент flags не используется и должен равняться 0.

Все доступы к памяти, выполняемые в программном порядке из каждого целевого потока, гарантированно упорядочены в отношении membarrier().

Если использовать семантику barrier() для представления барьера компилятора, обеспечивающего доступа к памяти, выполняемого в программном порядке для пересечения барьера, и smp_mb() — для представления явных барьеров памяти, обеспечивающих полный упорядоченный доступ к памяти через барьер, то получится следующая упорядочивающая таблица для каждой пары barrier(), membarrier() и smp_mb(). Наличие порядка в паре показано знаком (O: упорядочено, X: не упорядочено):

barrier() smp_mb() membarrier()

barrier() X X O

smp_mb() X O O

membarrier() O O O

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении операции MEMBARRIER_CMD_QUERY возвращается битовая маска поддерживаемых команд, а операции MEMBARRIER_CMD_GLOBAL, MEMBARRIER_CMD_GLOBAL_EXPEDITED, MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, MEMBARRIER_CMD_PRIVATE_EXPEDITED, MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE и MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE возвращают ноль. При ошибке возвращается -1 и в errno устанавливается соответствующее значение.

Для данной команды, если флаг flags равен 0, то системный вызов всегда гарантирует возврат одного и того же значения до перезагрузки. Последующие вызовы с теми же аргументами всегда возвращают тот же результат. Поэтому, если flags равен 0, то обработка ошибок требуется только при первом вызове membarrier().

## ОШИБКИ
EINVAL

Неверное значение cmd, значение flags не равно нулю, отключена команда MEMBARRIER_CMD_GLOBAL, так как указан параметр ЦП nohz_full или команды MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE иMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE не реализованы для архитектуры.

ENOSYS

Системный вызов membarrier() не реализован в данном ядре.

EPERM

Текущий процесс не зарегистрирован до использования частных курируемых команд.

## ВЕРСИИ
Системный вызов membarrier() впервые появился в Linux версии 4.3.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Вызов membarrier() есть только в Linux.

## ЗАМЕЧАНИЯ
Инструкция барьера памяти является частью системы команд архитектуры со слабо упорядоченными моделями памяти. Она упорядочивает доступ к памяти до барьера и после барьера в соответствии совпадающими барьерами на других ядрах. Например, загрузка барьера (fence) может упорядочить загрузку до и после этого барьера в соответствии порядком хранилища, установленного барьерами хранилища.

Программный порядок — это порядок, в котором инструкции упорядочены в ассемблерном коде программы.

Вызов membarrier() может быть полезным для реализации библиотек чтения-копирования-обновления или сборщиков мусора.

## ПРИМЕР
Предполагая, что в многонитевой программе «fast_path()» выполняется очень часто, а «slow_path()» — редко, следующий код (x86) можно преобразовать используя membarrier():

```
#include <stdlib.h>
static volatile int a, b;
static void
fast_path(int *read_b)
{

    a = 1;

    asm volatile ("mfence" : : : "memory");

    *read_b = b;
}
static void
slow_path(int *read_a)
{

    b = 1;

    asm volatile ("mfence" : : : "memory");

    *read_a = a;
}
int
main(int argc, char **argv)
{

    int read_a, read_b;

    /*

     * В реальных приложениях вызовы fast_path() и slow_path()

     * были бы в разных нитях. Их вызов из main() сделан только

     * для укорачивания данного примера.

     */

    slow_path(&read_a);

    fast_path(&read_b);

    /*

     * read_b == 0 подразумевает read_a == 1 и

     * read_a == 0 подразумевает read_b == 1.

     */

    if (read_b == 0 && read_a == 0)

        abort();

    exit(EXIT_SUCCESS);
}
```

Этот же код, переписанный с использованием membarrier():

```
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/membarrier.h>
static volatile int a, b;
static int
membarrier(int cmd, int flags)
{

    return syscall(__NR_membarrier, cmd, flags);
}
static int
init_membarrier(void)
{

    int ret;

    /* Проверка поддержки в функции membarrier() */

    ret = membarrier(MEMBARRIER_CMD_QUERY, 0);

    if (ret < 0) {

        perror("membarrier");

        return -1;

    }

    if (!(ret & MEMBARRIER_CMD_GLOBAL)) {

        fprintf(stderr,

            "membarrier не поддерживает MEMBARRIER_CMD_GLOBAL\n");

        return -1;

    }

    return 0;
}
static void
fast_path(int *read_b)
{

    a = 1;

    asm volatile ("" : : : "memory");

    *read_b = b;
}
static void
slow_path(int *read_a)
{

    b = 1;

    membarrier(MEMBARRIER_CMD_GLOBAL, 0);

    *read_a = a;
}
int
main(int argc, char **argv)
{

    int read_a, read_b;

    if (init_membarrier())

        exit(EXIT_FAILURE);

    /*

     * В реальных приложениях вызовы fast_path() и slow_path()

     * были бы в разных нитях. Их вызов из main() сделан только

     * для укорачивания данного примера.

     */

    slow_path(&read_a);

    fast_path(&read_b);

    /*

     * read_b == 0 подразумевает read_a == 1 и

     * read_a == 0 подразумевает read_b == 1.

     */

    if (read_b == 0 && read_a == 0)

        abort();

    exit(EXIT_SUCCESS);
}
```

branch: sisyphus


title: memfd_create(2)

summary: создаёт анонимный файл

text:
# memfd_create(2)

## ИМЯ
memfd_create - создаёт анонимный файл

## ОБЗОР

```
#define _GNU_SOURCE         /* смотрите feature_test_macros(7) */
#include <sys/mman.h>
```

```
int memfd_create(const char *name, unsigned int flags);
```

## ОПИСАНИЕ
Вызов memfd_create() создаёт анонимный файл и возвращает ссылающийся на него файловый дескриптор. Анонимный файл ведёт себя как обычный файл и может быть изменён, обрезан, отображён в память и т.д. Однако в отличие от обычного файла он располагается в ОЗУ и не имеет энергонезависимого хранилища. Как только все ссылки на файл удаляются, он автоматически исчезает. Анонимные файлы располагаются в анонимной памяти. Поэтому у файлов, создаваемых memfd_create(), такая же семантика как и областей анонимной памяти, выделяемой с помощью mmap(2) с флагом MAP_ANONYMOUS.

Первоначально, размер файла равен 0. После этого вызова нужно задать размер файла с помощью ftruncate(2) (или заполнить файл с помощью write(2) или подобными).

Имя, указанное в name, используется в качестве имени файла и будет показываться как цель соответствующей символьной ссылки в каталоге. /proc/self/fd/. Отображаемое имя всегда начинается с memfd: и служит только для отладки. Имена не влияют на поведение файлового дескриптора и поэтому несколько файлов могут иметь одно имя без каких-либо последствий.

Для изменения поведения memfd_create() можно использовать следующие значения flags (через OR):

MFD_CLOEXEC

Устанавливает флаг close-on-exec (FD_CLOEXEC) для нового открытого файлового дескриптора. Смотрите описание флага O_CLOEXEC в open(2) для того, чтобы узнать как это может пригодиться.

MFD_ALLOW_SEALING

Разрешает операции опечатывания (sealing) файла. Описание операций F_ADD_SEALS и F_GET_SEALS смотрите в fcntl(2), а также в ЗАМЕЧАНИЯ ниже. Первоначально набор печатей пуст. Если этот флаг не установлен, то начальным набором печатей будет F_SEAL_SEAL, означающий запрещение установки печатей на файл.

MFD_HUGETLB (начиная с Linux 4.14)

В файловой системе hugetlbfs, использующей огромные страницы, будет создан анонимный файл. В файле исходного кода Linux Documentation/admin-guide/mm/hugetlbpage.rst дана подробная информация о hugetlbfs. Одновременное указание MFD_HUGETLB и MFD_ALLOW_SEALING в flags поддерживается начиная с Linux 4.16.

MFD_HUGE_2MB, MFD_HUGE_1GB, ...

Используется как дополнение к MFD_HUGETLB для выбора размера страницы hugetlb (соответственно, 2 МБ, 1 ГБ, …) в системах, которые поддерживают различные размеры страниц hugetlb. Определения размеров огромных страниц включены в заголовочный файл <linux/memfd.h>.

Дополнительную информацию о кодировании размеров огромных страниц, отсутствующих в заголовочном файле, смотрите в описании сходных по имени констант в mmap(2).

Неиспользуемые биты в flags должны быть равны 0.

В качестве возвращаемого значения memfd_create() возвращает новый файловый дескриптор, который можно использовать для обращения к файлу. Данный файловый дескриптор открыт на чтение и запись (O_RDWR) и в файловом дескрипторе установлен флаг O_LARGEFILE.

При вызове fork(2) и execve(2) с файловым дескриптором, созданным memfd_create(), применяется обычная семантика. Копия файлового дескриптора наследуется потомком, созданным fork(2), указывает на тот же файл. Файловый дескриптор сохраняется при после execve(2), если не установлен флаг close-on-exec.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении memfd_create() возвращает новый файловый дескриптор. При ошибке возвращается -1, и errno устанавливается в соответствующее значение.

## ОШИБКИ
EFAULT

Некорректный адрес в name.

EINVAL

В flags указаны неизвестные биты.

EINVAL

Значение name было слишком длинным (ограничено 249 байтами, не считая конечный байт null).

EINVAL

В flags указаны MFD_HUGETLB и MFD_ALLOW_SEALING одновременно.

EMFILE

Было достигнуто ограничение по количеству открытых файловых дескрипторов на процесс.

ENFILE

Достигнуто максимальное количество открытых файлов в системе.

ENOMEM

Недостаточно памяти для создания нового анонимного файла.

## ВЕРСИИ
Системный вызов memfd_create() появился в Linux 3.17; поддержка в glibc началась с версии 2.27.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Системный вызов memfd_create() есть только в Linux.

## ЗАМЕЧАНИЯ
Системный вызов memfd_create() предоставляет простую альтернативу ручному монтированию файловой системы tmpfs(5), созданию и открытию файла в этой файловой системе. Основным предназначением memfd_create() является создание файлов и соответствующих файловых дескрипторов, которые используются с программным интерфейсом опечатывания файлов, предоставляемым fcntl(2).

Системный вызов memfd_create() также используется и без опечатывания файла (вот почему опечатывание файлов отключено, если этого не запросить явно с помощью флага MFD_ALLOW_SEALING). В частности, он может использоваться как альтернатива созданию файлов в tmp или использованию open(2) с O_TMPFILE в случаях, когда не требуется реальная ссылка на конечный файл в файловой системе.

### Опечатывание файла (file sealing)
Ели файл не опечатан, то процессы, которые связываются через общую память, должны или доверять друг другу, или учитывать возможность того, что недоверенная сторона может работать с общей памятью проблемным способом. Например, недоверенная сторона может изменить содержимое общей памяти в любое время или уменьшить область общей памяти. Первая возможность делает локальный процесс уязвимым к состязательности условий «момент проверки — момент использования» (обычно решается копированием данных из области общей памяти перед проверкой и использованием). Последняя возможность делает локальный процесс уязвимым к сигналам SIGBUS, которые возникают при попытке получить доступ к теперь несуществующему расположению в области общей памяти (решается использованием обработчика сигнала SIGBUS).

Взаимодействие с недоверенными сторонами приводит к усложнению кода для работы с общей памятью. Опечатывание памяти позволяет устранить эту сложность, позволяя процессу безопасно работать, зная что его партнёр не может изменить общую память нежелательным способом.

В примере использования механизма опечатывания происходит следующее:

1.

Первый процесс создаёт файл tmpfs(5) с помощью memfd_create(). Вызов возвращает файловый дескриптор, используемый далее.

2.

Первый процесс задаёт размер файла, созданного ранее, с помощью ftruncate(2), отображает его с помощью mmap(2) и заполняется общую память нужными данными.

3.

Первый процесс использует fcntl(2) с операцией F_ADD_SEALS для установки одной или более печатей на файл, чтобы в дальнейшем ограничить изменение файла (если устанавливается печать F_SEAL_WRITE, то сначала нужно удалить общее доступное на запись отображение, созданное ранее).

4.

Второй процесс получает файловый дескриптор файла tmpfs(5) и отображает его. Варианты того, как это можно сделать:

- Процесс, вызвавший memfd_create(), может переслать полученный файловый дескриптор второму процессу через доменный сокет UNIX (смотрите unix(7) и cmsg(3)). Второй процесс затем отображает файл с помощью mmap(2).

- Второй процесс создаётся с помощью fork(2) и, таким образом, наследует файловый дескриптор и отображение (заметим, что в этом случае и следующем образуется природное доверие между двумя процессами, так как они работают с правами одного пользовательского идентификатора. Поэтому опечатывание файла здесь не нужно).

- Второй процесс открывает файл /proc/<pid>/fd/<fd>, где <pid> — PID первого процесса (вызвавшего memfd_create()), а <fd> — номер файлового дескриптора, возвращённого вызовом memfd_create() в этом процессе. Затем второй процесс отображает файл с помощью mmap(2).

5.

Второй процесс использует fcntl(2) с операцией F_GET_SEALS для получения битовой маски печатей, которые были применены к файлу. Данная маска проверяется, чтобы определить какие ограничения наложены на изменения файла. Если требуется, то второй процесс может наложить дополнительные печати, что ещё ограничить действия (возможно до тех пор, пока не будет наложена печать F_SEAL_SEAL).

## ПРИМЕР
Далее показано два примера программы, в которых продемонстрировано использование memfd_create() и программный интерфейс опечатывания файла.

Первая программа, t_memfd_create.c, создаёт файл tmpfs(5) с помощью memfd_create(), изменяет его размер, отображает в память и, возможно, накладывает несколько печатей на файл. Программа принимает не более трёх аргументов командной строки, два первых обязательные. Первым аргументом задаётся имя файла, во втором — размер файла, а в необязательном третьем — строка символов, задающих устанавливаемые печати на файл.

Вторая программа, t_get_seals.c, может использоваться для открытия существующего файла, созданного memfd_create(), и проверки набора печатей, применённых к файлу.

Следующий пример сеанса показывает как использовать программу. Сначала создаётся файл tmpfs(5) и накладываются печати:

```
$ ./t_memfd_create my_memfd_file 4096 sw &
[1] 11775
PID: 11775; fd: 3; /proc/11775/fd/3
```

После этого программа t_memfd_create продолжает выполняться в фоновом режиме. Из другой программы можно получить дескриптор файла, созданный memfd_create(), открыв файл /proc/[pid]/fd, который соответствует файловому дескриптору, открытому memfd_create(). Используя это имя, можно просмотреть содержимое символьной ссылки /proc/[pid]/fd и использовать программу t_get_seals для просмотра печатей, которые установлены на файл:

```
$ readlink /proc/11775/fd/3
/memfd:my_memfd_file (удалён)
$ ./t_get_seals /proc/11775/fd/3
Наложенные печати: WRITE SHRINK
```

### Исходный код программы: t_memfd_create.c

```
#define _GNU_SOURCE
#include <sys/mman.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \

                        } while (0)
int
main(int argc, char *argv[])
{

    int fd;

    unsigned int seals;

    char *addr;

    char *name, *seals_arg;

    ssize_t len;

    if (argc < 3) {

        fprintf(stderr, "%s имя размер [печати]\n", argv[0]);

        fprintf(stderr, "\t в 'печати' могут быть "

                "следующие символы:\n");

        fprintf(stderr, "\t\tg - F_SEAL_GROW\n");

        fprintf(stderr, "\t\ts - F_SEAL_SHRINK\n");

        fprintf(stderr, "\t\tw - F_SEAL_WRITE\n");

        fprintf(stderr, "\t\tS - F_SEAL_SEAL\n");

        exit(EXIT_FAILURE);

    }

    name = argv[1];

    len = atoi(argv[2]);

    seals_arg = argv[3];

    /* Создаётся анонимный файл в tmpfs; на файл

       накладываются указанные печати */

    fd = memfd_create(name, MFD_ALLOW_SEALING);

    if (fd == -1)

        errExit("memfd_create");

    /* Размер файл как указано в командной строке */

    if (ftruncate(fd, len) == -1)

        errExit("truncate");

    printf("PID: %ld; fd: %d; /proc/%ld/fd/%d\n",

            (long) getpid(), fd, (long) getpid(), fd);

    /* Здесь может быть код для отображения файла и заполнения данными */

    /* Если в командной строке задан параметр 'печати', то

       накладываем их на файл */

    if (seals_arg != NULL) {

        seals = 0;

        if (strchr(seals_arg, 'g') != NULL)

            seals |= F_SEAL_GROW;

        if (strchr(seals_arg, 's') != NULL)

            seals |= F_SEAL_SHRINK;

        if (strchr(seals_arg, 'w') != NULL)

            seals |= F_SEAL_WRITE;

        if (strchr(seals_arg, 'S') != NULL)

            seals |= F_SEAL_SEAL;

        if (fcntl(fd, F_ADD_SEALS, seals) == -1)

            errExit("fcntl");

    }

    /* Продолжаем выполнение для того, чтобы файл, созданный memfd_create(),

       продолжал существовать */

    pause();

    exit(EXIT_SUCCESS);
}
```

### Исходный код программы: t_get_seals.c

```
#define _GNU_SOURCE
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \

                        } while (0)
int
main(int argc, char *argv[])
{

    int fd;

    unsigned int seals;

    if (argc != 2) {

        fprintf(stderr, "%s /proc/PID/fd/FD\n", argv[0]);

        exit(EXIT_FAILURE);

    }

    fd = open(argv[1], O_RDWR);

    if (fd == -1)

        errExit("open");

    seals = fcntl(fd, F_GET_SEALS);

    if (seals == -1)

        errExit("fcntl");

    printf("Наложенные печати:");

    if (seals & F_SEAL_SEAL)

        printf(" SEAL");

    if (seals & F_SEAL_GROW)

        printf(" GROW");

    if (seals & F_SEAL_WRITE)

        printf(" WRITE");

    if (seals & F_SEAL_SHRINK)

        printf(" SHRINK");

    printf("\n");

    /* Здесь может быть код для отображения и доступа к содержимому файла */

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
fcntl(2), ftruncate(2), mmap(2), shmget(2), shm_open(3)


title: migrate_pages(2)

text:
# migrate_pages(2)

## ИМЯ
migrate_pages - переносит все страницы процесса на другой набор узлов

## ОБЗОР

```
#include <numaif.h>
```

```
long migrate_pages(int pid, unsigned long maxnode,
                   const unsigned long *old_nodes,
                   const unsigned long *new_nodes);
```

Компонуется при указании параметра -lnuma.

## ОПИСАНИЕ
Вызов migrate_pages() пытается перенести все страницы процесса с идентификатором pid, находящиеся в памяти узлов old_nodes, в память узлов new_nodes. Страницы, не расположенные в узлах old_nodes, не переносятся. При переносе на new_nodes ядро в максимально возможной степени поддерживает относительную топологию связи внутри old_nodes.

Аргументы old_nodes и new_nodes представляют собой указатели на маски битов номеров узлов, до maxnode в каждой маске. Эти маски обрабатываются как массивы беззнаковых целых long (в последнем целом long биты, лежащие за пределом maxnode, игнорируются). Аргумент maxnode представляет собой максимальный номер узла в битовой маске плюс 1 (также как в mbind(2), но отличается от select(2)).

В аргументе pid задаётся идентификатор процесса, чьи страницы будут перемещаться. Чтобы перемещать страницы не своего процесса, вызывающий должен быть привилегированным (CAP_SYS_NICE) или реальный или эффективный ID пользователя вызывающего процесса должен совпадать с реальным или сохранённым ID пользователя процесса назначения. Если pid равен 0, то migrate_pages() перемещает страницы вызвавшего процесса.

Совместно используемые с другими процессами страницы будут перемещаться только, если первоначальный процесс имеет мандат CAP_SYS_NICE.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При нормальном завершении работы migrate_pages() возвращает количество неперемещённых страниц (то есть, ноль означает, что все страницы успешно перемещены). В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EFAULT

Часть или весь диапазон памяти, заданный в old_nodes/new_nodes и maxnode, указывает за пределы доступного адресного пространства.

EINVAL

Значение maxnode превышает введённое ядром ограничение. В old_nodes или new_nodes задан один или более ID узлов, превышающих поддерживаемый максимальный ID узла. Или ни один из ID узлов, указанных в new_nodes, включен и доступен из контекста текущего набора процессоров процесса, или ни один из узлов не содержит память.

EPERM

Недостаточно прав (CAP_SYS_NICE) для перемещения страниц процесса, заданного pid, или недостаточно прав (CAP_SYS_NICE) для доступа к указанным узлам назначения.

ESRCH

Не найден процесс с указанным pid.

## ВЕРСИИ
Вызов migrate_pages() впервые появился в Linux в ядре версии 2.6.16.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Данный вызов есть только в Linux.

## ЗАМЕЧАНИЯ
Информация о библиотеке доступна в numa(7).

Используйте get_mempolicy(2) с флагом MPOL_F_MEMS_ALLOWED для получения набора узлов, которые доступны в наборе ЦП вызывающему процессу. Заметим, что эта информация может измениться в любое время вручную или при автоматической перенастройке набора ЦП.

Использование migrate_pages() может привести к тому, что расположение страниц (на узле) нарушит политику памяти, установленную для заданных адресов (см. mbind(2)) и/или заданного процесса (см. set_mempolicy(2)). То есть политика памяти не ограничивает узлы назначения, используемые migrate_pages().

Заголовочный файл <numaif.h> не включён в glibc, его можно найти в пакете с именем libnuma-devel или подобным названием.

## СМОТРИТЕ ТАКЖЕ
get_mempolicy(2), mbind(2), set_mempolicy(2), numa(3), numa_maps(5), cpuset(7), numa(7), migratepages(8), numastat(8)

Файл Documentation/vm/page_migration.rst в дереве исходного кода ядра Linux


mincore

title: mincore(2)

text:
# mincore(2)

## ИМЯ
mincore - определяет, хранятся ли страницы в памяти

## ОБЗОР
\#include <unistd.h>

\#include <sys/mman.h>

int mincore(void *addr, size_t length, unsigned char *vec);

Требования макроса тестирования свойств для glibc (смотрите feature_test_macros(7)):

mincore():

начиная с glibc 2.19:

_DEFAULT_SOURCE

в glibc 2.19 и старее:

_BSD_SOURCE || _SVID_SOURCE

## ОПИСАНИЕ
mincore() возвращает вектор, описывающий страницы виртуальной памяти вызывающего процесса, которые находятся в физической памяти (core, RAM) и поэтому доступ к ним не приводит к обращению к дискам. Ядро возвращает информацию о страницах, которые расположены начиная с адреса addr и занимают length байт.

Значение аргумента addr должно быть кратно размеру системной страницы. Значение аргумента length может быть не кратно размеру страницы, но так как возвращается информация по целым страницам, length округляется до следующего значения, кратного размеру страницы. Размер страницы (PAGE_SIZE) может быть получен с помощью sysconf(_SC_PAGESIZE).

Аргумент vec должен указывать на массив размером не менее (length+PAGE_SIZE-1) / PAGE_SIZE байт. При возврате самый младший значимый бит каждого байта будет установлен, если соответствующая страница находится в памяти, и будет сброшен, если это не так. (Значения других битов каждого байта не определено; эти биты зарезервированы для использования в будущем.) Естественно, информация, возвращаемая в vec, носит моментальный характер: страницы, которые не заблокированы в памяти, могут быть удалены из неё или добавлены в любой момент, и содержимое vec может стать неактуальным уже на момент возврата из вызова.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При нормальном завершении работы mincore() возвращает ноль. При ошибках возвращается -1, а переменной errno присваивается соответствующее значение.

## ОШИБКИ
EAGAIN ядру временно не хватает ресурсов.

EFAULT

vec указывает на неправильный адрес.

EINVAL

Значение addr не кратно размеру страницы.

ENOMEM

Значение length больше чем (TASK_SIZE - addr). (Это может произойти, если в length указано отрицательное значение, так как это значение воспринимается как большое беззнаковое целое.) В Linux 2.6.11 и более ранних версиях в этом случае возвращалась ошибка EINVAL.

ENOMEM

С адреса addr по адрес addr + length содержится память без отображения.

## ВЕРСИИ
Доступен начиная с Linux 2.3.99pre1 и glibc 2.2.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Системный вызов mincore() не определён в стандарте POSIX.1 и отсутствует во всех реализациях UNIX.

## ДЕФЕКТЫ
До ядра версии 2.6.21, mincore() не возвращал правильные данные для отображений MAP_PRIVATE или для нелинейных отображений (заданных с помощью remap_file_pages(2)).

## СМОТРИТЕ ТАКЖЕ
fincore(1), madvise(2), mlock(2), mmap(2), posix_fadvise(2), posix_madvise(3)


mkdir

title: mkdir(2)

summary: создаёт каталог

text:
# mkdir(2)

## ИМЯ
mkdir, mkdirat - создаёт каталог

## ОБЗОР

```
#include <sys/stat.h>
#include <sys/types.h>
```

```
int mkdir(const char *pathname, mode_t mode);
#include <fcntl.h>           /* определения констант AT_* */
#include <sys/stat.h>
```

```
int mkdirat(int dirfd, const char *pathname, mode_t mode);
```

Требования макроса тестирования свойств для glibc (смотрите feature_test_macros(7)):

mkdirat():

Начиная с glibc 2.10:

_POSIX_C_SOURCE >= 200809L

До glibc 2.10:

_ATFILE_SOURCE

## ОПИСАНИЕ
Функция mkdir() пытается создать каталог с именем pathname.

В аргументе mode задаются права доступа к новому каталогу (смотрите inode(7)). Эти права стандартным образом изменяются с помощью согласно umask процесса: при отсутствии списка доступа по умолчанию права на созданный каталог будут рассчитаны как (mode & ~umask & 0777). Другие биты mode на создаваемый каталог зависят от операционной системы. Для Linux они описаны в ЗАМЕЧАНИЯХ.

Создаваемый каталог будет принадлежать фактическому владельцу процесса. Если у родительского каталога установлен флаг set-group-ID, или файловая система смонтирована с семантикой групп в стиле BSD (mount -o bsdgroups или, что одно и тоже, mount -o grpid), то новый каталог унаследует группу владельца от своего родительского каталога; в противном случае группой владельцем станет фактическая группа процесса.

Если у родительского каталога установлен бит set-group-ID, то он будет установлен также и у создаваемого каталога.

### mkdirat()
Системный вызов mkdirat() работает также как системный вызов mkdir(), за исключением случаев, описанных здесь.

Если в pathname задан относительный путь, то он считается относительно каталога, на который ссылается файловый дескриптор dirfd (а не относительно текущего рабочего каталога вызывающего процесса, как это делается в mkdir()).

Если в pathname задан относительный путь и dirfd равно специальному значению AT_FDCWD, то pathname рассматривается относительно текущего рабочего каталога вызывающего процесса (как mkdir()).

Если в pathname задан абсолютный путь, то dirfd игнорируется.

Смотрите в openat(2) объяснение необходимости mkdirat().

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении вызовов mkdir() и mkdirat() возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EACCES

У процесса нет прав на запись в родительский каталог, или в одном из каталогов в pathname не разрешён поиск (смотрите также path_resolution(7)).

EDQUOT

Исчерпана пользовательская квота на дисковые блоки или иноды файловой системы.

EEXIST

pathname уже существует (и необязательно как каталог). В этом случае pathname может быть символьной ссылкой, повисшей или нет.

EFAULT

Аргумент pathname указывает за пределы доступного адресного пространства.

EINVAL

Последний компонент («основная часть» (basename)) нового каталога pathname некорректен (например, содержит недопустимые в нижележащей файловой системе символы).

ELOOP

Во время определения pathname встретилось слишком много символьных ссылок.

EMLINK

Количество ссылок на родительский каталог превысило бы LINK_MAX.

ENAMETOOLONG

pathname слишком длинен.

ENOENT

Один из каталогов в pathname не существует или является повисшей символьной ссылкой.

ENOMEM

Недостаточное количество памяти ядра.

ENOSPC

На устройстве, содержащем pathname, нет места для создания нового каталога.

ENOSPC

Новый каталог не может быть создан, так как превышена пользовательская дисковая квота.

ENOTDIR

Компонент пути, использованный как каталог в pathname, в действительности таковым не является.

EPERM

Файловая система, содержащая pathname, не поддерживает создание каталогов.

EROFS

pathname указывает на файл в файловой системе, доступной только для чтения.

В mkdirat() дополнительно могут возникнуть следующие ошибки:

EBADF

dirfd не является правильным файловым дескриптором.

ENOTDIR

Значение pathname содержит относительный путь и dirfd содержит файловый дескриптор, указывающий на файл, а не на каталог.

## ВЕРСИИ
Вызов mkdirat() был добавлен в ядро Linux версии 2.6.16; поддержка в glibc доступна с версии 2.4.

## СООТВЕТСТВИЕ СТАНДАРТАМ
mkdir(): SVr4, BSD, POSIX.1-2001, POSIX.1-2008.

mkdirat(): POSIX.1-2008.

## ЗАМЕЧАНИЯ
В Linux кроме битов прав, в mode учитывается также бит S_ISVTX.

В протоколе, на котором работает NFS, есть множество недоработок. Некоторые из них влияют на mkdir().

### Замечания по glibc
В старых ядрах, где mkdirat() отсутствует, обёрточная функция glibc использует mkdir(). Если pathname является относительным путём, то glibc собирает путь относительно символической ссылки в /proc/self/fd, которая соответствует аргументу dirfd.

## СМОТРИТЕ ТАКЖЕ
mkdir(1), chmod(2), chown(2), mknod(2), mount(2), rmdir(2), stat(2), umask(2), unlink(2), acl(5) path_resolution(7)


mknod

title: mknod(2)

summary: создаёт специальный или обычный файл

text:
# mknod(2)

## ИМЯ
mknod, mknodat - создаёт специальный или обычный файл

## ОБЗОР

```
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
```

```
int mknod(const char *pathname, mode_t mode, dev_t dev);
#include <fcntl.h>           /* определения констант AT_* */
#include <sys/stat.h>
```

```
int mknodat(int dirfd, const char *pathname, mode_t mode, dev_t dev);
```

Требования макроса тестирования свойств для glibc (смотрите feature_test_macros(7)):

mknod():

_XOPEN_SOURCE >= 500

|| /* Since glibc 2.19: */ _DEFAULT_SOURCE

|| /* Glibc versions <= 2.19: */ _BSD_SOURCE || _SVID_SOURCE

## ОПИСАНИЕ
Системный вызов mknod() создаёт запись (node) в файловой системе (обычный файл, файл устройства или именованный канал) с именем pathname и атрибутами, заданными в mode и dev.

В аргументе mode указывается используемый режим файла и тип создаваемого узла. В этом параметре должна быть битовая комбинация (используя побитовое логическое сложение ИЛИ) нуля или более режимов файла, перечисленных в inode(7).

Режим файла изменяется согласно значению umask процесса: при отсутствии списка контроля доступа по умолчанию права на создаваемый узел становятся равны (mode & ~umask).

Для указания обычного файла, специального символьного файла, специального блочного файла, FIFO (именованного канала) или доменного сокета UNIX типом должен быть один из S_IFREG, S_IFCHR, S_IFBLK, S_IFIFO или S_IFSOCK, соответственно (нулевой тип файла эквивалентен типу S_IFREG).

Если тип файла равен S_IFCHR или S_IFBLK, то в dev задаётся основной и вспомогательный номера создаваемого специального файла устройства (makedev(3) может оказаться полезной при создании значения для dev); в остальных случаях аргумент игнорируется.

Если pathname уже существует, или является символьной ссылкой, то вызов завершается с ошибкой EEXIST.

Созданный файл будет принадлежать ID эффективного владельца процесса. Если в правах доступа к каталогу, в котором находится файл, установлен бит set-group-ID, или если файловая система смонтирована с семантикой групп BSD, то новый файл унаследует группу-владельца от своего родительского каталога; в противном случае группой-владельцем станет ID эффективной группы процесса.

### mknodat()
Системный вызов mknodat() работает также как системный вызов mknod(), за исключением случаев, описанных здесь.

Если в pathname задан относительный путь, то он считается относительно каталога, на который ссылается файловый дескриптор dirfd (а не относительно текущего рабочего каталога вызывающего процесса, как это делается в mknod()).

Если в pathname задан относительный путь и dirfd равно специальному значению AT_FDCWD, то pathname рассматривается относительно текущего рабочего каталога вызывающего процесса (как mknod()).

Если в pathname задан абсолютный путь, то dirfd игнорируется.

Смотрите в openat(2) объяснение необходимости mknodat().

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении вызовов mknod() и mknodat() возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EACCES

У процесса нет прав на запись в родительский каталог, или в одном из каталогов в pathname не разрешён поиск (смотрите также path_resolution(7)).

EDQUOT

Исчерпана пользовательская квота на дисковые блоки или иноды файловой системы.

EEXIST

pathname уже существует. В этом случае pathname может быть символьной ссылкой, повисшей или нет.

EFAULT

Аргумент pathname указывает за пределы доступного адресного пространства.

EINVAL

В аргументе mode указано значение, отличное от значения для обычного файла, специального файла устройства, FIFO или сокета.

ELOOP

Во время определения pathname встретилось слишком много символьных ссылок.

ENAMETOOLONG

pathname слишком длинен.

ENOENT

Один из каталогов в pathname не существует или является повисшей символьной ссылкой.

ENOMEM

Недостаточное количество памяти ядра.

ENOSPC

На устройстве, содержащем pathname, нет места для создания нового элемента.

ENOTDIR

Компонент пути, использованный как каталог в pathname, в действительности таковым не является.

EPERM

В аргументе mode запрошено создание чего-то, отличного от обычного файла, специального файла устройства, FIFO (именованного канала) или доменного сокета UNIX, и у вызвавшего процесса нет прав (Linux: не имеет мандата CAP_MKNOD); также завершается, если файловая система, содержащая pathname, не поддерживает тип запрашиваемой ноды.

EROFS

pathname указывает на файл в файловой системе, доступной только для чтения.

В mknodat() дополнительно могут возникнуть следующие ошибки:

EBADF

dirfd не является правильным файловым дескриптором.

ENOTDIR

Значение pathname содержит относительный путь и dirfd содержит файловый дескриптор, указывающий на файл, а не на каталог.

## ВЕРСИИ
Вызов mknodat() был добавлен в ядро Linux версии 2.6.16; поддержка в glibc доступна с версии 2.4.

## СООТВЕТСТВИЕ СТАНДАРТАМ
mknod(): SVr4, 4.4BSD, POSIX.1-2001 (но смотрите ниже), POSIX.1-2008.

mknodat(): POSIX.1-2008.

## ЗАМЕЧАНИЯ
В POSIX.1-2001 сказано: «Единственный способ, которым можно использовать mknod() в переносимых программах это создание специального файла FIFO. Если значение mode не равно S_IFIFO или dev не равно 0, то поведение mknod() не определено.» Однако, в настоящее время никогда не используйте mknod() для этой цели; вместо этого используйте функцию mkfifo(3), которая создана специально для этого.

В Linux вызов mknod() не может использоваться для создания каталогов. Для этого есть системный вызов mkdir(2).

В протоколе, на котором работает NFS, есть множество недоработок. Некоторые из них влияют на mknod() и mknodat().

## СМОТРИТЕ ТАКЖЕ
mknod(1), chmod(2), chown(2), fcntl(2), mkdir(2), mount(2), socket(2), stat(2), umask(2), unlink(2), makedev(3), mkfifo(3), acl(5) path_resolution(7)


mlock

title: mlock(2)

summary: блокируют и разблокируют

text:
# mlock(2)

## ИМЯ
mlock, mlock2, munlock, mlockall, munlockall - блокируют и разблокируют память

## ОБЗОР

```
#include <sys/mman.h>
```

```
int mlock(const void *addr, size_t len);
int mlock2(const void *addr, size_t len, int flags);
int munlock(const void *addr, size_t len);
```

```
int mlockall(int flags);
int munlockall(void);
```

## ОПИСАНИЕ
Вызовы mlock(), mlock2() и mlockall() блокируют часть или всё виртуальное адресное пространство процесса в ОЗУ, запрещая эту память перемещать в пространство подкачки.

Вызовы munlock() и munlockall() выполняют обратную операцию, разблокируя часть или всё виртуальное адресное пространство процесса, после чего страницы в этом диапазоне виртуальных адресов могут вытесняться в пространство подкачки, если того потребуется менеджеру памяти ядра.

Размер блокировки и разблокировки памяти округляется до целых страниц.

### mlock(), mlock2() и munlock()
Вызов mlock() блокирует страницы в адресном диапазоне, начиная с addr и длиной len байтов. Все страницы, попадающие, даже частично, в заданную область, будут гарантировано помещены в ОЗУ, если системный вызов выполнился успешно; страницы гарантировано останутся в ОЗУ пока не будут разблокированы.

Вызов mlock2() также блокирует страницы в адресном диапазоне, начиная с addr и длиной len байтов. Однако состояние страниц в этом диапазоне после успешного выполнения вызова будет зависеть от значения аргумента flags.

Параметр flags может принимать значение 0 или одну из следующих констант:

MLOCK_ONFAULT

Блокировать страницы, которые в настоящее время уже есть в памяти и пометить весь диапазон так, чтобы оставшиеся вне памяти страницы блокировались, когда они будут заполнены из-за страничного промаха (fault).

Если параметр flags равен 0, то mlock2() ведёт себя точно так же как mlock().

Вызов munlock() разблокирует страницы в области, начинающейся с адреса addr и длиной len байтов. После этого вызова все страницы, попадающие, даже частично, в заданную область, снова могут быть помещены ядром во внешнее пространство подкачки.

### mlockall() и munlockall()
Вызов mlockall() блокирует все страницы, отображённые в адресное пространство вызывающего процесса. Сюда входят страницы сегмента кода, данных и стека, а также общих библиотек, страницы с данными пользовательского пространства ядра, общей памяти и файлов, отображённых в память. Все отображённые страницы гарантировано останутся в ОЗУ, если системный вызов выполнился успешно; страницы гарантировано останутся в ОЗУ пока не будут разблокированы.

Аргумент flags создаётся побитовым сложением одной или более следующих констант:

MCL_CURRENT

Блокировать все страницы, которые в данный момент отображены в адресное пространство процесса.

MCL_FUTURE

Блокировать все страницы, которые будут отображены в адресное пространство процесса в будущем. Это могут быть, например, новые страницы, затребованные для увеличения кучи и стека, а также новые отображённые в память файлы или области общей памяти.

MCL_ONFAULT (начиная с Linux 4.4)

Используется вместе с MCL_CURRENT, MCL_FUTURE или обоими. Пометить все текущие (с MCL_CURRENT) или будущие (с MCL_FUTURE) отображения для блокировки страниц, когда они получаются при сбое (faulted in). При использовании с MCL_CURRENT все существующие страницы блокируются, но mlockall() не будет сбоить на несуществующих страницах. При использовании с MCL_FUTURE все будущие отображения будут помечены для блокировки страниц при сбое, но они не будут заполнены из-за блокировки при создании отображения. Флаг MCL_ONFAULT должен использовать одновременно с MCL_CURRENT или MCL_FUTURE или обоими.

Если указан флаг MCL_FUTURE, то последующий системный вызов (например, mmap(2), sbrk(2), malloc(3)), может завершиться с ошибкой, если бы его работа приводит к превышению разрешённого максимального числа блокируемых байт (см. ниже). Также этот флаг может остановить увеличение стека: ядро будет отказывать в увеличении стека и будет посылать процессу сигнал SIGSEGV.

Вызов munlockall() разблокирует все страницы, отображённые в адресное пространство вызывающего процесса.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении эти системные вызовы возвращают 0. При ошибке возвращается -1, устанавливается соответствующий код ошибки в errno, и никакие блокировки не изменяются в адресном пространстве процесса.

## ОШИБКИ
ENOMEM

(Linux 2.6.9 и новее) У вызывающего процесса установлено ненулевое мягкое ограничение ресурса RLIMIT_MEMLOCK, но он пытается заблокировать больше памяти, чем это разрешено ограничением. Данное ограничение не учитывается у привилегированных процессов (CAP_IPC_LOCK).

ENOMEM

(Linux 2.4 и в более ранних) Вызывающий процесс пытается заблокировать более половины ОЗУ.

EPERM

Вызывающий не имеет прав (CAP_IPC_LOCK) для выполнения запрошенной операции.

Для mlock(), mlock2(), и munlock():

EAGAIN

Невозможно заблокировать некоторую часть или весь диапазон адресов.

EINVAL

Результат добавления addr+len стал меньше чем addr (например, добавление могло привести к переполнению).

EINVAL

(Не в Linux) Значение addr не кратно размеру страницы.

ENOMEM

Часть указанного адресного диапазона не соответствует отображённым страницам адресного пространства процесса.

ENOMEM

Блокировка и разблокировка области привела бы к превышению разрешённого максимума на количество отображений с различающимися атрибутами (блокированных и разблокированных). Например, разблокировка диапазона в середине области в данный момент блокированного отображения привела бы к трём отображениям: два блокированных отображения на концах и доступное разблокированное отображение посередине.

For mlock2():

EINVAL

Указан неизвестный флаг в flags.

У mlockall():

EINVAL

Неизвестное значение в flags или MCL_ONFAULT задан без MCL_FUTURE или MCL_CURRENT.

У munlockall():

EPERM

(Linux 2.6.8 и более ранних) Вызывающий процесс не имеет достаточно прав (CAP_IPC_LOCK).

## ВЕРСИИ
Системный вызов mlock2() появился в Linux 4.4; поддержка в glibc началась с версии 2.27.

## СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SVr4.

Функция mlock2() , определена только в Linux.

## ДОСТУПНОСТЬ
В POSIX-системах, в которых доступны mlock() и munlock(), значение _POSIX_MEMLOCK_RANGE определено в <unistd.h>, а количество байт в странице можно определить из константы PAGESIZE (если определена) в <limits.h> или вызвав sysconf(_SC_PAGESIZE).

В POSIX-системах, в которых доступны mlockall() и munlockall(), значение _POSIX_MEMLOCK, определенное в <unistd.h>, больше нуля (см. также sysconf(3)).

## ЗАМЕЧАНИЯ
Блокировка памяти используется, в основном, в двух случаях: в алгоритмах реального времени и при работе с секретными данными. Программам реального времени необходима предсказуемость времени выполнения, а страничный обмен (наряду с системой переключения процессов) может привести к неожиданным задержкам в работе. Такие приложения часто переключаются в режим реального времени при помощи вызовы sched_setscheduler(2). Криптографические системы защиты данных очень часто содержат важные данные, например, пароли или секретные ключи, в структурах данных. В результате страничного обмена эти данные могут попасть в область подкачки, находящуюся на устройстве длительного хранения, где к этим данным после того, как они пропадут из ОЗУ, может получить доступ практически кто угодно. (Помните, что в режиме приостановки (suspend) на ноутбуках и некоторых компьютерах на жёсткий диск сохраняется копия памяти ОЗУ системы, независимо от блокировок памяти).

Процессы реального времени, использующие mlockall() для устранения задержек при страничных прерываниях (page fault), должны зарезервировать достаточно заблокированных страниц стека до входа в критический ко времени участок, для того, чтобы вызов функции не мог привести к страничному прерыванию. Это можно выполнить с помощью вызова функции, которая выделит место под достаточно большую автоматическую переменную (массив) и выполнит запись в память для того, чтобы этот массив занял место в странице стека. Таким путём будет отображено достаточно страниц для стека, которые можно заблокировать в ОЗУ. Бесполезная запись нужна для того, чтобы в критическом участке не возникло страничное прерывание для копирования страницы при записи.

Блокировка памяти не наследуется дочерними процессами, созданными при помощи fork(2), и автоматически удаляется (разблокируется) при выполнении execve(2) или при завершении работы процесса. Установка MCL_FUTURE и MCL_FUTURE | MCL_ONFAULT в mlockall() не наследуется потомком, созданными при помощи fork(2), и автоматически стирается при выполнении execve(2).

Заметим, что that fork(2) подготовит адресное пространство для операции копирования при записи. Следовательно, любой последующий доступ на запись приведёт к страничному отказу, который, в свою очередь, может привести к большим задержкам в процессах реального времени. Поэтому, существенно важно не вызывать fork(2) после операции mlockall() или mlock() — даже для нитей, которые выполняются с низким приоритетом внутри процесса, который также имеет нить, выполняющуюся с более высоким приоритетом.

Блокировка памяти адресного диапазона автоматически удаляется, если этот диапазон становится неотображаемым с помощью вызова munmap(2).

Блокировки памяти не накапливаются, то есть, если страница была заблокирована вызовами mlock(), mlock2() или mlockall() несколько раз, то она будет разблокирована единственным вызовом munlock() для соответствующего диапазона или с помощью вызова munlockall(). Страницы, которые были отображены в несколько мест или несколькими процессами, останутся заблокированными в ОЗУ до тех пор, пока они блокируются хотя бы в одном месте или хотя бы в одном процессе.

Если послед вызова mlockall() с флагом MCL_FUTURE идёт другой вызов, у которого нет этого флага, то изменения, сделанные вызовом с MCL_FUTURE будут потеряны.

Флаг MLOCK_ONFAULT у mlock2() и MCL_ONFAULT у mlockall() позволяют эффективно блокировать память в приложениях, которые работают с большим количеством отображений, где только задействуется часть (малая) страниц в отображении. В таких случаях блокировка всех страниц в отображении приводила бы к значительным простоям из-за блокировки памяти.

### Замечания, касающиеся Linux
В Linux, mlock(), mlock2() и munlock() автоматически округляют addr в меньшую сторону к размеру границы ближайшей страницы. Однако, в POSIX.1 указано, что реализации mlock() и munlock() разрешено требовать, чтобы значение addr было выровнено по размеру страницы, поэтому переносимые приложения должны выполнять выравнивание.

В поле VmLck, имеющемся только в Linux файле /proc/[pid]/status, показано сколько килобайт памяти заблокировал процесс с идентификатором PID с помощью mlock(), mlock2(), mlockall() и mmap(2) с флагом MAP_LOCKED.

### Ограничения и права доступа
В Linux версии 2.6.8 и более ранних для блокировки памяти процесс должен иметь мандат (CAP_IPC_LOCK), а мягкое ограничение ресурса RLIMIT_MEMLOCK определяет как много памяти можно заблокировать.

Начиная с Linux 2.6.9, привилегированный процесс не имеет ограничения на ограничиваемое количество памяти, а мягкое ограничение ресурса RLIMIT_MEMLOCK определяет предел ограничиваемой памяти для непривилегированных процессов.

## ДЕФЕКТЫ
В Linux 4.8 и старее имеется дефект учёта блокированной памяти непривилегированных процессов (т. е., без CAP_IPC_LOCK) в ядре, состоящий в том, что если область, указанная addr и len перекрывает существующую блокировку, то при проверке ограничений уже заблокированные байты перекрывающей области учитываются дважды. Из-за такого двойного учёта может некорректно вычисляться значение «общего количества заблокированной памяти», и процесс, который превышает ограничение RLIMIT_MEMLOCK, в результате mlock() и mlock2() получит ошибку при запросах, которые должны выполняться успешно. Этот дефект был исправлен в Linux 4.9.

В ветви 2.4 ядер Linux до версии 2.4.17 включительно есть дефект, из-за которого флаг MCL_FUTURE у mlockall() наследуется при fork(2). Он устранён в версии 2.4.18.

Начиная с ядра версии 2.6.9, если привилегированный процесс вызывает mlockall(MCL_FUTURE) и, позднее, отказывается от прав (теряет мандат CAP_IPC_LOCK, например, устанавливая свой эффективный UID в ненулевое значение), то последующие выделения памяти (например, с помощью mmap(2), brk(2)) будут завершаться с ошибкой при достижении предела ресурса RLIMIT_MEMLOCK.

## СМОТРИТЕ ТАКЖЕ
mincore(2), mmap(2), setrlimit(2), shmctl(2), sysconf(3), proc(5), capabilities(7)


mmap

title: mmap(2)

text:
# mmap(2)

## ИМЯ
mmap, munmap - отображает файлы или устройства в памяти, или удаляет их отображение

## ОБЗОР

```
#include <sys/mman.h>
```

```
void *mmap(void *addr, size_t length, int prot, int flags,
           int fd, off_t offset);
int munmap(void *addr, size_t length);
```

Информацию по требованиям макроса тестирования свойств смотрите в разделе ЗАМЕЧАНИЯ.

## ОПИСАНИЕ
Вызов mmap() создаёт новое отображение в виртуальном адресном пространстве вызывающего процесса. Адрес начала нового отображения указывается в addr. В аргументе length задаётся длина отображения (должна быть больше 0).

Если значение addr равно NULL, то ядро само выбирает адрес (выровненный по странице), по которому создаётся отображение; это наиболее переносимый метод создания нового отображения. Если значение addr не равно NULL, то ядро учитывает это при размещении отображения; в Linux ядро выберет ближайшую к границе страницу (но всегда выше или равною значению, заданному в /proc/sys/vm/mmap_min_addr) и попытается создать отображение. Если по этому адресу уже есть отображение, то ядро выберет новый адрес, который может и не зависеть от подсказки. Адрес нового отображения возвращается как результат вызова.

Содержимое файлового отображения (в отличие от анонимного отображения; смотрите MAP_ANONYMOUS далее) инициализируется данными из файла (или объекта), на который указывает файловый дескриптор fd, длиной length байт, начиная со смещения offset. Значение offset должно быть кратно размеру (возвращается sysconf(_SC_PAGE_SIZE)) страницы.

После возврата из вызова mmap() файловый дескриптор fd может быть немедленно закрыт без признания отображения недействительным.

В аргументе prot указывается желаемая защита памяти отображения (не должна конфликтовать с режимом открытого файла). Значением может быть PROT_NONE или побитово сложенные (OR) следующие флаги:

PROT_EXEC

Страницы доступны для исполнения.

PROT_READ

Страницы доступны для чтения.

PROT_WRITE

Страницы доступны для записи.

PROT_NONE

Страницы недоступны.

В аргументе flags задаётся будут ли изменения отображения видимы другим процессам, отображающим ту же область, и будут ли изменения перенесены в отображённый файл. Данное поведение определяется в flags одним из следующих значений:

MAP_SHARED

Сделать отображение общим. Изменения отображения видимы всем процессам, отображающим ту же область и (если отображение выполняется из файла) изменения заносятся в отображённый файл (для более точного контроля над изменениями файла нужно использовать msync(2)).

MAP_SHARED_VALIDATE (начиная с Linux 4.15)

Данный флаг представляет тоже, что и MAP_SHARED, отображения MAP_SHARED игнорируют неизвестные флаги flags. Если же отображение создаётся с MAP_SHARED_VALIDATE, ядро проверят, что ему известны все переданные флаги и завершает отображение ошибкой EOPNOTSUPP, если есть неизвестные флаги. Этот тип отображения также требуется для использования некоторых флагов отображения (например, MAP_SYNC).

MAP_PRIVATE

Создать закрытое отображение с механизмом копирования при записи. Изменения отображения невидимы другим процессам, отображающим тот же файл, и сам файл не изменяется. Не определено, будут ли видимы в отображённой области изменения в файле, сделанные после вызова mmap().

Флаги MAP_SHARED и MAP_PRIVATE описаны в POSIX.1-2001 и POSIX.1-2008. Флаг MAP_SHARED_VALIDATE является расширением Linux.

Кроме этого в flags могут быть указаны (побитовым сложением):

MAP_32BIT (начиная с Linux 2.4.20, 2.6)

Поместить отображение в первые 2 гигабайта адресного пространства процесса. Этот флаг поддерживается только на архитектуре x86-64 для 64-битных программ. Он был добавлен для размещения стеков нитей в первых 2 ГБ памяти, что даёт увеличение производительности при переключения контекста на некоторых первых 64-битных процессорах. В современных процессорах x86-64 такой проблемы с производительностью больше нет, поэтому на таких системах данный флаг больше не требуется. Он игнорируется, если указан флаг MAP_FIXED.

MAP_ANON

Синоним MAP_ANONYMOUS. Устарел.

MAP_ANONYMOUS

Отображение не привязанное к файлу; его содержимое инициализируется нулями. Аргумент fd игнорируется ; однако в некоторых реализациях при указании MAP_ANONYMOUS (или MAP_ANON) требуется указывать fd равное -1, и так нужно поступать для переносимости приложений. Аргумент offset должен быть ноль. Использование MAP_ANONYMOUS вместе с MAP_SHARED поддерживается в Linux только начиная с ядра версии 2.4.

MAP_DENYWRITE

Этот флаг игнорируется (раньше — Linux 2.0 и старее — он обозначал, что попытки записи в подчинённые файлы должны завершаться с кодом ошибки ETXTBUSY. Но это стало основой для атак типа отказа в обслуживании).

MAP_EXECUTABLE

Этот флаг игнорируется.

MAP_FILE

Флаг для совместимости, игнорируется.

MAP_FIXED

Не учитывать addr как подсказку: помещать отображение точно по этому адресу. Значение addr должно быть выровнено соответствующим образом: на большинстве архитектур оно должно быть кратно размеру страницы; однако некоторые архитектуры могут накладывать дополнительные ограничения. Если область памяти, задаваемая addr и len, перекрывается со страницами существующих отображений, то перекрывающаяся часть существующих отображений будет отброшена. Если заданный адрес не может быть использован, то вызов mmap() завершается ошибкой.

В переносимом ПО флаг MAP_FIXED нужно использовать осторожно, так как точная раскладка процесса в памяти, доступная для изменения, может значительно отличаться в разных версиях ядер, библиотеки С и выпусках операционной системы. Внимательно прочитайте описание этого флага в ЗАМЕЧАНИЯХ!

MAP_FIXED_NOREPLACE (начиная с Linux 4.17)

Данный флаг действует схожим с MAP_FIXED образом при контроле addr, но в отличие от него, флаг MAP_FIXED_NOREPLACE никогда не разделяет уже существующий отображённый диапазон. Если запрошенный диапазон пересекается с существующим отображением, то такой вызов завершается ошибкой EEXIST. Поэтому данный флаг можно использовать как атомарную (если есть другие нити) попытку отображения адресного диапазона: для одной нити она закончится успешно; все остальные получат ошибку.

Заметим, что старые ядра, не понимающие флаг MAP_FIXED_NOREPLACE, обычно (при обнаружении пересечения с существующим отображением) переходят к запасному варианту поведения, «не MAP_FIXED»: они возвращают адрес, отличающийся от запрашиваемого адреса. Поэтому, ПО с обратной совместимостью должно сравнивать возращённый адрес с запрашиваемым.

MAP_GROWSDOWN

Этот флаг используется для стеков. Для виртуальной системы памяти ядра он обозначает, что отображение должно расширяться вниз по памяти. Возвращаемый адрес указывает на одну страницу ниже области памяти, которая в действительности создаётся в виртуальном адресном пространстве процесса. Обращение к адресу ниже «защитной» страницы отображения приведёт к расширению отображения на страницу. Увеличение таким способом можно повторять до тех пор, пока рост отображения страницы верхним концом не достигнет следующего нижнего отображения, при таком обращении к «защитной» страницы возникнет сигнал SIGSEGV.

MAP_HUGETLB (начиная с Linux 2.6.32)

Выделять отображение используя «огромные страницы». Дополнительную информацию смотрите в файле исходного кода ядра Linux Documentation/admin-guide/mm/hugetlbpage.rst, а также следующее дополнение.

MAP_HUGE_2MB, MAP_HUGE_1GB (начиная с Linux 3.8)

Используется как дополнение к MAP_HUGETLB для выбора размера страницы hugetlb (2 МБ и 1 ГБ, соответственно), сработает только в системе которая поддерживает различные размеры больших страниц.

Вообще, желаемый размер огромной страницы можно настроить закодировав логарифм 2 от желаемого размера страницы в шести битах со смещением MAP_HUGE_SHIFT (значение нуля в этом битовом поле означает выбор значения огромной страницы по умолчанию; это значение можно найти в поле Hugepagesize просмотрев файл /proc/meminfo). Таким образом две показанные выше константы определены как:

```
#define MAP_HUGE_2MB    (21 << MAP_HUGE_SHIFT)
#define MAP_HUGE_1GB    (30 << MAP_HUGE_SHIFT)

```

Рабочий диапазон страниц огромного размера может быть обнаружен, перечислив подкаталоги в /sys/kernel/mm/hugepages.

MAP_LOCKED (начиная с Linux 2.5.37)

Пометить отображаемую область как заблокированную таким же образом как с помощью mlock(2). Данная реализация будет пытаться заполнить (предотказ) область полностью, но вызов mmap() не завершится ошибкой ENOMEM, если это не удастся сделать. Поэтому действительные отказы могут произойти позднее. Такой алгоритм не совпадает с mlock(2). Нужно использовать mmap() плюс mlock(2), если действительные отказы недопустимы после инициализации отображения. В старых ядрах флаг MAP_LOCKED игнорируется.

MAP_NONBLOCK (начиная с Linux 2.5.46)

Данный флаг имеет смысл только вместе с MAP_POPULATE. Не выполнять упреждающее чтение: только создать записи в таблице страниц для страниц, которые уже есть ОЗУ. Начиная с Linux 2.6.23 этот флаг приводит к тому, что выполнение работы MAP_POPULATE отменяется. Когда-нибудь комбинация MAP_POPULATE и MAP_NONBLOCK может быть реализована заново.

MAP_NORESERVE

Не резервировать страницы пространства подкачки для этого отображения. Если пространство подкачки резервируется, то для отображения гарантируется возможность изменения. Если оно не резервируется, то можно получить сигнал SIGSEGV при записи, если физическая память будет недоступна. Смотрите также описание файла /proc/sys/vm/overcommit_memory в proc(5). В ядрах до 2.6 этот флаг действовал только для частных доступных на запись отображений.

MAP_POPULATE (начиная с Linux 2.5.46)

Наполнить (до возникновения страничного прерывания, prefault) страничные таблицы отображения. Для файлового отображения это приводит к опережающему чтению из файла. В дальнейшем это помогает сократить блокировку по отказу страниц. Флаг MAP_POPULATE поддерживается для закрытых отображений только начиная с Linux 2.6.23.

MAP_STACK (начиная с Linux 2.6.27)

Разместить отображение по адресу, пригодному для процесса или для стека нити. В настоящее время для этого флага не выполняются какие-либо действия, но он используется для реализации нитей в glibc; если на какой-то архитектуре потребуются специальные действия по выделению стека, то позже их поддержка может быть прозрачно добавлена в glibc.

MAP_SYNC (начиная с Linux 4.15)

Данный флаг доступен только с типом отображения MAP_SHARED_VALIDATE; отображения с типом MAP_SHARED будут просто игнорировать этот флаг. Этот флаг поддерживается только для файлов поддерживаемых DAX (прямое отображение в постоянную память). Для остальных файлов, создание отображения с этим флагом приводит к возврату ошибки EOPNOTSUPP.

Общие файловые отображения с этим флагом представляют гарантию того, что пока есть часть памяти отображённая для записи в адресном пространстве процесса, она будет видима в том же файле по тому же смещению даже после падения или перезагрузки системы. Вместе с использованием соответствующих инструкций ЦП это позволяет пользователям таких отображений эффективней выполнять устойчивые изменения данных.

MAP_UNINITIALIZED (начиная с Linux 2.6.33)

Не очищать анонимные страницы. Этот флаг предназначен для повышения производительности на встраиваемых устройствах. Он учитывается, только если ядро было собрано с поддержкой параметра CONFIG_MMAP_ALLOW_UNINITIALIZED. Так как этот параметр может привести к нарушению безопасности, обычно он устанавливается только на встраиваемых устройствах (то есть, устройствах, где только один человек имеет полный контроль над содержимым пользовательской памяти).

Из флагов, перечисленных выше, в POSIX.1-2001 и POSIX.1-2008 определён только MAP_FIXED. Однако, большинство систем также поддерживают MAP_ANONYMOUS (или его синоним MAP_ANON).

Память, отображённая с помощью mmap(), сохраняется при fork(2) с теми же атрибутами.

Файл отображается по кратному размеру страницы. Для файла, который не кратен размеру страницы, оставшаяся память при отображении заполняется нулями, и запись в эту область не приводит к изменению файла. Действия при изменении размера отображаемого файла на страницы, которые соответствуют добавленным или удалённым областям файла, не определены.

### munmap()
Системный вызов munmap() удаляет отображение для указанного адресного диапазона и это приводит к тому, что дальнейшее обращение по адресам внутри диапазона приводит к генерации неправильных ссылок на память. Также для диапазона отображение автоматически удаляется при завершении работы процесса. С другой стороны, закрытие файлового дескриптора не приводит к удалению отображения диапазона.

Адрес addr должен быть кратен размеру страницы (но значения length это не касается). Все страницы, содержащие часть указанного диапазона, удаляются из отображения и последующие ссылки на эти страницы приводят к генерации сигнала SIGSEGV. Это не ошибка, если указанный диапазон не содержит каких-либо отображённых страниц.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении mmap() возвращается указатель на отображённую область. При ошибке возвращается значение MAP_FAILED (а именно, (void *) -1) и errno устанавливается в соответствующее значение.

При успешном выполнении munmap() возвращает 0. При сбои возвращается -1, и код ошибки кладётся в errno (скорее всего EINVAL).

## ОШИБКИ
EACCES

Файловый дескриптор указывает на не обычный файл. Или было запрошено отображение файла (mapping), но fd не открыт на чтение. Или был указан флаг MAP_SHARED и установлен бит PROT_WRITE, но fd не открыт в режиме чтения/записи (O_RDWR). Или был указан флаг PROT_WRITE, но файл доступен только для дополнения.

EAGAIN

Файл заблокирован, или блокируется слишком много памяти (смотрите setrlimit(2)).

EBADF

Значение fd не является правильным файловым дескриптором (и MAP_ANONYMOUS не установлен).

EEXIST

В flags указан MAP_FIXED_NOREPLACE и диапазон, покрываемый addr и length, пересекается с существующим отображением.

EINVAL

Неправильное значение addr, length или offset (например, оно либо слишком велико, либо не выровнено по границе страницы).

EINVAL

(начиная с Linux 2.6.12) Значение length равно 0.

EINVAL

В flags отсутствует MAP_PRIVATE, MAP_SHARED или MAP_SHARED_VALIDATE.

ENFILE

Достигнуто максимальное количество открытых файлов в системе.

ENODEV

Используемая файловая система для указанного файла не поддерживает отображение памяти.

ENOMEM

Больше нет доступной памяти.

ENOMEM

Процесс превысил бы ограничение на максимальное количество отображений. Эта ошибка также может возникнуть в munmap() при удалении отображения области в середине существующего отображения, так как при этом выполняется удаление отображения двух отображений меньшего размера на любом конце области.

ENOMEM

(начиная с Linux 4.7) Было бы превышено ограничение процесса RLIMIT_DATA, описанное в getrlimit(2).

EOVERFLOW

На 32-битной архитектуре вместе с расширением для больших файлов (т.е., используется 64-битный off_t): количество страниц, используемых для length плюс количество страниц, используемых для offset приводит к переполнению unsigned long (32 бита).

EPERM

Аргументом prot запрашивается PROT_EXEC, но отображённая область принадлежит файлу на файловой системе, которая смонтирована с флагом no-exec.

EPERM

Выполнение операции предотвращено опечатыванием (file seal); смотрите fcntl(2).

ETXTBSY

Был задан флаг MAP_DENYWRITE, но объект, указываемый fd, открыт на запись.

При использовании отображаемой области памяти могут возникать следующие сигналы:

SIGSEGV

Попытка записи в область, отображённую только для чтения.

SIGBUS

Попытка доступа к части буфера, которая не совпадает файлом (например, она может находиться за пределами файла. Подобной является ситуация, когда другой процесс уменьшил длину файла).

## АТРИБУТЫ
Описание терминов данного раздела смотрите в attributes(7).

Интерфейс

Атрибут

Значение

mmap(), munmap()

Безвредность в нитях

MT-Safe

## СООТВЕТСТВИЕ СТАНДАРТАМ
POSIX.1-2001, POSIX.1-2008, SVr4, 4.4BSD.

## ДОСТУПНОСТЬ
В системах POSIX, в которых есть вызовы mmap(), msync(2) и munmap(), значение _POSIX_MAPPED_FILES, определённое в <unistd.h>, больше 0 (смотрите также sysconf(3)).

## ЗАМЕЧАНИЯ
На некоторых архитектурах (например, i386), флаг PROT_WRITE подразумевает флаг PROT_READ. Также от архитектуры зависит подразумевает ли PROT_READ флаг PROT_EXEC или нет. Переносимые программы должны всегда устанавливать PROT_EXEC, если они собираются выполнять код, находящийся в отображении.

Переносимый способ создания отображения: указать в addr значение 0 (NULL) и убрать MAP_FIXED из flags. В этом случае, система сама выберет адрес для отображения; адрес, выбранный таким образом, не будет будет конфликтовать с существующими отображениями и не будет равен 0. Если указан флаг MAP_FIXED и значение addr равно 0 (NULL), то адрес отображения будет равен 0 (NULL).

Некоторые константы flags определены только, если определён подходящий макрос тестирования свойств (возможно, по умолчанию): _DEFAULT_SOURCE в glibc 2.19 и новее; _BSD_SOURCE или _SVID_SOURCE в glibc 2.19 и старее (также достаточно использовать _GNU_SOURCE и требовать, этот макрос логично, так как данные флаги есть только в Linux). Соответственно, флаги: MAP_32BIT, MAP_ANONYMOUS (и синоним MAP_ANON), MAP_DENYWRITE, MAP_EXECUTABLE, MAP_FILE, MAP_GROWSDOWN, MAP_HUGETLB, MAP_LOCKED, MAP_NONBLOCK, MAP_NORESERVE, MAP_POPULATE и MAP_STACK.

Приложение может определить какие страницы отображены в данный момент в буфере/страничном кэше с помощью mincore(2).

### Безопасное использование MAP_FIXED
Единственным вариантом безопасного использования MAP_FIXED является предварительное резервирование адресного пространства, указываемого в addr и length, другим отображением; в остальных случаях использование MAP_FIXED опасно, так как оно выполняет принудительное удаление существующих отображений, что позволяет легко повредить собственное адресное пространство многонитевого процесса.

Предположим, например, что нить A просматривает /proc/<pid>/mapsв поиске неиспользуемого адресного диапазона, который она сможет отобразить используя MAP_FIXED, но одновременно с этим нить B захватывает часть или весь этот же адресный диапазон. Когда после этого нить A запустит mmap(MAP_FIXED), это, фактически, разобьёт отображение, созданное нитью B. В этом сценарии нити B не нужно создавать отображение явным образом; будет достаточно просто сделать библиотечный вызов, например, dlopen(3) для загрузки какой-то другой общей библиотеки. Вызов dlopen(3) отобразит библиотеку в адресное пространство процесса. Более того, почти каждый библиотечный вызов можно реализовать так, чтобы он добавлял отображения памяти в адресное пространство с помощью этого метода или просто выделяя память. Например, такими вызовами являются brk(2), malloc(3), pthread_create(3) и библиотеки PAM http://www.linux-pam.org.

Начиная с Linux 4.17, в многонитевых программах можно использовать флаг MAP_FIXED_NOREPLACE и, тем самым, избежать опасности, описанной выше, когда выполняется попытка создать отображение по фиксированному адресу, который не был зарезервирован существующим отображением.

### Изменение временных отметок для отображённых файлов
У отображённых файлов поле st_atime может измениться в любой момент между вызовом mmap() и соответствующим удалением отображения; первое обращение к отображённой странице приведёт к обновлению поля, если это ещё не было сделано.

Поля st_ctime и st_mtime у отображённого с помощью флагов PROT_WRITE и MAP_SHARED файла будут обновлены после записи отображённой области и перед последующим вызовом msync(2) с флагом MS_SYNC или MS_ASYNC, если он будет вызван.

### Отображения огромных страниц (Huge TLB)
Для отображений, работающих с огромными страницами, требования к аргументам mmap() и munmap() несколько отличаются от требований к отображениям, в которых используются страницы с системным размером.

Для mmap(), offset должно быть кратно размеру нижележащей огромной страницы. Система автоматически выравнивает length до кратного значения размера нижележащей огромной страницы.

Для munmap(), addr и length должны быть кратны размеру нижележащей огромной страницы.

### Отличия между библиотекой C и ядром
В данной странице описывается интерфейс, предоставляемый обёрточной функцией glibc mmap(). Раньше, эта функция обращалась к системному вызову с тем же именем. Начиная с ядра 2.4, данный системный вызов был заменён на mmap2(2). В настоящее время обёрточная функция glibc, mmap(), вызывает mmap2(2) с подходящим подкорректированным значением offset.

## ДЕФЕКТЫ
В Linux не гарантируется результат флага MAP_NORESERVE, описанный выше. По умолчанию, любой процесс может быть принудительно завершён в любой момент, если в системе закончилась память.

В ядрах до версии 2.6.7 флаг MAP_POPULATE учитывается только, если значение prot равно PROT_NONE.

В SUSv3 указано, что mmap() должен завершаться с ошибкой, если length равно 0. Однако в ядрах до версии 2.6.12 вызов mmap() в этом случае выполняется успешно: отображение не создаётся и вызов возвращает addr. Начиная с ядра версии 2.6.12, в этом случае вызов mmap() завершается с ошибкой EINVAL.

В POSIX сказано, что система всегда должна заполнять нулями любую частичную страницу у конца объекта и что система никогда не должна вносить любые изменения вне пределов объекта. В Linux, если вы пишите данные в такую частичную страницу за концом объекта, то данные остаются в страничном кэше даже после закрытия и выключения отображения файла и хотя данные никогда не пишутся в сам файл, последующие отображения могут увидеть изменённое содержимое. В некоторых случаях это можно исправить вызвав msync(2) перед выключением отображения; однако это не работает на tmpfs(5) (например, когда используется интерфейс общей памяти POSIX, описанный в shm_overview(7)).

## ПРИМЕР
Следующая программа выводит часть файла, указанного в первом аргументе командной строки, в стандартный вывод. Диапазон выдаваемых байт задаётся смещением и длиной во втором и третьем аргументах командной строки. Программа создаёт отображение требуемых страниц файла и затем использует write(2) для вывода запрошенных байт.

### Исходный код программы

```
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define handle_error(msg) \

    do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{

    char *addr;

    int fd;

    struct stat sb;

    off_t offset, pa_offset;

    size_t length;

    ssize_t s;

    if (argc < 3 || argc > 4) {

        fprintf(stderr, "%s файл смещение [длина]\n", argv[0]);

        exit(EXIT_FAILURE);

    }

    fd = open(argv[1], O_RDONLY);

    if (fd == -1)

        handle_error("open");

    if (fstat(fd, &sb) == -1)           /* получение размера файла */

        handle_error("fstat");

    offset = atoi(argv[2]);

    pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);

        /* для mmap() нужно выронить смещение */

    if (offset >= sb.st_size) {

        fprintf(stderr, "указанное смещение находится за концом файла\n");

        exit(EXIT_FAILURE);

    }

    if (argc == 4) {

        length = atoi(argv[3]);

        if (offset + length > sb.st_size)

            length = sb.st_size - offset;

                /* Нельзя показать байты за концом файла */

    } else {    /* Не указана длина ==> показать всё до конца файла */

        length = sb.st_size - offset;

    }

    addr = mmap(NULL, length + offset - pa_offset, PROT_READ,

                MAP_PRIVATE, fd, pa_offset);

    if (addr == MAP_FAILED)

        handle_error("mmap");

    s = write(STDOUT_FILENO, addr + offset - pa_offset, length);

    if (s != length) {

        if (s == -1)

            handle_error("write");

        fprintf(stderr, "частичная запись");

        exit(EXIT_FAILURE);

    }

    munmap(addr, length + offset - pa_offset);

    close(fd);

    exit(EXIT_SUCCESS);
}
```

## СМОТРИТЕ ТАКЖЕ
ftruncate(2), getpagesize(2), memfd_create(2), mincore(2), mlock(2), mmap2(2), mprotect(2), mremap(2), msync(2), remap_file_pages(2), setrlimit(2), shmat(2), userfaultfd(2), shm_open(3), shm_overview(7)

Описание в proc(5) следующих файлов: /proc/[pid]/maps, /proc/[pid]/map_files и /proc/[pid]/smaps.

B.O. Gallmeister, POSIX.4, O'Reilly, страницы 128–129 и 389–391.


title: mmap2(2)

text:
# mmap2(2)

## ИМЯ
mmap2 - отображает файлы или устройства в память

## ОБЗОР

```
#include <sys/mman.h>
```

```
void *mmap2(void *addr, size_t length, int prot,
             int flags, int fd, off_t pgoffset);
```

## ОПИСАНИЕ
Вероятно, вам нужен не сам системный вызов; смотрите mmap(2), описывающую обёрточную функцию glibc, которая вызывает данный системный вызов.

Системный вызов mmap2() предоставляет тот же интерфейс что и mmap(2), за исключением того, что последний аргумент задаёт смещение в файле в 4096-байтовых единицах (вместо байт, как это делается в mmap(2)). Это позволяет приложениям использовать 32-битное значение off_t для отображения больших файлов (до 2^44 байт).

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При удачном завершении mmap2() возвращает указатель на область отображения. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EFAULT

Проблема получения данных из пользовательского пространства.

EINVAL

(Различные платформы, где размер страницы не равен 4096 байтам.) Значение offset * 4096 не кратно размеру страницы системы.

Вызов mmap2() также может вернуть любую ошибку из описанных в mmap(2).

## ВЕРСИИ
Вызов mmap2() доступен начиная с Linux 2.3.31.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Данный вызов есть только в Linux.

## ЗАМЕЧАНИЯ
На архитектурах, имеющих данный системный вызов, обёрточная функция glibc mmap() вызывает данный системный вызов вместо системного вызова mmap(2).

Этот системный вызов отсутствует на x86-64.

На ia64 единица offset на самом деле имеет размер страницы системы, а не равна 4096 байтам.

## СМОТРИТЕ ТАКЖЕ
getpagesize(2), mmap(2), mremap(2), msync(2), shm_open(3)


title: modify_ldt(2)

text:
# modify_ldt(2)

## ИМЯ
modify_ldt - возвращает или изменяет запись LDT у процесса

## ОБЗОР

```
#include <sys/types.h>
```

```
int modify_ldt(int func, void *ptr, unsigned long bytecount);
```

Замечание: В glibc нет обёрточной функции для данного системного вызова; смотрите ЗАМЕЧАНИЯ.

## ОПИСАНИЕ
Вызов modify_ldt() считывает или записывает таблицу локальных дескрипторов (LDT) процесса. LDT представляет собой массив дескрипторов сегментов, которые могут использоваться в пользовательском коде. В Linux процессам разрешено настраивать попроцессные (в действительности, пространство памяти) LDT. Дополнительную информацию о LDT, смотрите в Intel Software Developer's Manual или AMD Architecture Programming Manual.

Если func равно 0, то modify_ldt() читает LDT в память, на которую указывает ptr. Количество читаемых байт — меньшее из bytecount и реального размера LDT несмотря на то, что ядро может действовать как будто LDT заполняется дополнительными нулевыми байтами в конце. При успешном выполнении modify_ldt() возвращает количество прочитанных байт.

Если значение func равно 1 или 0x11, то modify_ldt() изменяет запись LDT, на которую указывает ptr->entry_number. Значение ptr указывает на структуру user_desc, а bytecount должно быть равно размеру этой структуры.

Структура user_desc определена в <asm/ldt.h> следующим образом:

```
struct user_desc {

    unsigned int  entry_number;

    unsigned long base_addr;

    unsigned int  limit;

    unsigned int  seg_32bit:1;

    unsigned int  contents:2;

    unsigned int  read_exec_only:1;

    unsigned int  limit_in_pages:1;

    unsigned int  seg_not_present:1;

    unsigned int  useable:1;
};
```

В Linux версии 2.4 и более ранних эта структура называлась modify_ldt_ldt_s.

В поле contents определяется тип сегмента (данные, данные, расширяемые вниз (expand-down data), не соответствующий код (non-conforming code) или соответствующий код). Назначение других полей совпадает с их описанием в руководстве к процессору, несмотря на то, что modify_ldt() не может изменить аппаратно-определяемый бит «доступа», описанный в руководстве к ЦП.

A user_desc считается «пустым», если read_exec_only и seg_not_present равны 1, а все остальные поля равны 0. Элемент LDT можно очистить, назначив ему «пустой» user_desc или, если func равно 1, установив base и limit в 0.

Сегмент соответствующего кода (conforming code segment, т. е., с contents==3) будет отклонён, если func равно 1 или если seg_not_present равно 0.

Если func равно 2, то modify_ldt() прочитает нули. Это, кажется, пережиток из Linux 2.4.

## ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
При успешном выполнении modify_ldt() возвращается реальное количество прочитанных байт (при чтении) или 0 (при записи). При ошибке modify_ldt() возвращает -1, а errno устанавливается в соответствующее значение.

## ОШИБКИ
EFAULT

Значение ptr указывает за пределы адресного пространства.

EINVAL

Значение ptr равно 0, или func равно 1, а bytecount не равно размеру структуры user_desc, или func равно 1 или 0x11, а новый элемент LDT содержит неправильные значения.

ENOSYS

Значение func не равно 0, 1, 2 или 0x11.

## СООТВЕТСТВИЕ СТАНДАРТАМ
Данный вызов есть только в Linux и не должен использоваться в программах, которые должны быть переносимыми.

## ЗАМЕЧАНИЯ
В glibc нет обёртки для данного системного вызова; запускайте его с помощью syscall(2).

Вызов modify_ldt() не должен использоваться для локального хранилища нити, так как это замедляет переключение контекста и поддерживается только для ограниченного количества нитей. Вместо этого в библиотеках нитей должны использоваться set_thread_area(2) или arch_prctl(2), только если не нужна поддержка старых ядер, где нет этих вызовов.

Обычно, modify_ldt() используют для запуска старого 16-битного или сегментированного 32-битного кода. Однако, не все ядра допускают установку 16-битных сегментов.

Даже в 64-битных ядрах вызов modify_ldt() нельзя использовать для создания сегмента кода в длинном режиме (т. е., 64-битного). Недокументированное поле «lm» в user_desc не помогает и, несмотря на имя, не образует сегмент в длинном режиме.

## ДЕФЕКТЫ
В 64-битных ядрах до Linux 3.19, установка бита «lm» в user_desc приводила к тому, что дескриптор переставал считаться пустым. Учтите, что бит «lm» не существует в 32-битных заголовках, но есть дефектные ядра, которые по-прежнему сообщают о бите даже в 32-битном процессе.

## СМОТРИТЕ ТАКЖЕ
arch_prctl(2), set_thread_area(2), vm86(2)