2015-04-01 4 views
6

Я пишу драйвер ядра Linux и для каждой функции, которая отправляет данные до пользовательского пространства или считывает данные из пользовательского пространства, я использую copy_to_user() и copy_from_user(). Мой вопрос: нужно ли использовать эти вызовы, если я просто копирую базовый тип данных, например, u32 или int?copy_to_user() и copy_from_user() для базового типа данных

+0

Существует некоторая путаница в том, что вы просите. Было бы полезно объявление образца функции, показывающее, передаете ли вы 'int' или указатель на' int'. Два ответа, опубликованные до сих пор, основаны на двух разных интерпретациях вашего вопроса. –

ответ

7

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

Обратите внимание, что значение указателя передается по значению (как и все параметры C), поэтому вам не нужно делать copy_from_user(), чтобы получить значение указателя, прежде чем вы сможете указать copy_from_user() данные, на которые он указывает.

Числовые аргументы работают так же, как аргументы указателя; в терминах С, они оба являются скалярами. Вам не нужно использовать copy_from_user() для копирования значения параметра; это уже скопировано. Вам нужно использовать его только для копирования данных, на которые указывает пройденный указатель.

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

+0

Я не согласен с вами. предположим, что указатель в пользовательском пространстве не выравнивается по странице, и вам нужно собрать обе части указателя, чтобы получить его? Единственное, что вы получаете от пользователя уже как параметр для вызова, - это указатель пользователя, но если он указывает на другой указатель пользователя, этот указатель должен быть приобретен с помощью user_copy. В 64-битных средах пользовательский указатель имеет ширину 8 байтов и может быть разделен на границе страницы, поэтому вам необходимо получить доступ к таблицам виртуальной страницы, чтобы перевести их из пользовательского пространства в ядро. Кроме того, страницы пользовательского пространства могут быть заменены, поэтому будьте осторожны с этим. –

+0

Когда вы говорите, что указатель не выравнивается по странице, вы имеете в виду, что сам объект-указатель смещен или данные, на которые он указывает? Указатели являются скалярами и всегда передаются по значению. Если системный вызов имеет, скажем, параметр 'void *', функция ядра, которая обрабатывает системный вызов, получает * копию * указателя; выравнивание объекта указателя на стороне вызывающего абонента не имеет значения. –

+0

Для указателей простых типов данных (например, 'int *') также могут использоваться 'put_user' и' get_user'. – holgac

2

Когда пользователь передает данные в пространство ядра, эти данные могут быть разделены на несколько страниц, и эти страницы могут быть даже в заменены памятью. В этих случаях вам придется ждать, пока ядро ​​поменяется на странице и получит доступ к странице, на которой находятся данные. В случае элементарных типов данных (например, int или указатели) также верно, что некоторые архитектуры (особенно x86 intel) не заставляют пользователя выровнять данные, поэтому даже целое число можно разделить на границе страницы. Вы можете иметь доступ к первой части целого числа, но ждать, пока второй будет заменен менеджером памяти до того, как все будет доступно.

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

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

+0

Луис: Я думаю, что вы неправильно интерпретировали OP. Все ОП пытается сделать, это передать одно значение базового типа данных. ОП действительно спрашивает, можно ли передавать базовые данные по значению, а не по ссылке. Как указывал @Keith, обычно передается указатель, и этот указатель IS передается по значению, поэтому к нему можно получить доступ напрямую. Однако, если вы хотите разыменовать пользовательский указатель, вы должны использовать функцию copy_from_user() или get_user(), когда в ядре. –

+0

Извините, но, как он говорит: * если я просто копирую базовый тип данных, такой как u32 или int *, означающий копирование, поэтому я предполагал, что int передается по ссылке (например, для возврата некоторого значения). Конечно, это если он передает значение только ядру (но не возвращается к пользовательскому пространству), он может сделать это. Я не думаю об ioctl, вот где это имеет смысл. Предположим, он пытается «int a; write (fc, & a, sizeof a); '... –

+0

Конечно, вы можете ** использовать ** указатель, переданный в пространство ядра в ** write (2) ** в качестве данных, но не так много смысла при создании драйвер понравится. Он говорит * ... и для каждой функции ... * –