Контекст пользовательского процесса Linux для доступа к пользовательской виртуальной памяти

#memory-management #linux-kernel #kernel

#управление памятью #linux-ядро #ядро

Вопрос:

Допустим, у меня есть данные пользовательского контекста, хранящиеся в указателе памяти ядра. Скажем, у меня также есть указатель на символ пользовательского пространства *. Затем я создаю поток ядра, и поток ядра может иметь эти два указателя. Могу ли я из потока получить доступ к данным пользовательского пространства с помощью указателя? Я могу получить к ним доступ в системном вызове, но вопрос в том, могу ли я получить к ним доступ из потока ядра? Как насчет доступа к ним из рабочей очереди?

Скажем, мой пользовательский процесс вызывает системный вызов

 //User Application
char* abc = "This is data.";
syscall(340, p);
  

в обработчике системного вызова

 void sys_340(void* p) { 
    th = kthread_run("kth", kt_func, p);
    //might also store process context as I am in system call!! How?
}

void kt_func(void *p) { 
    while(1){ printk("Line: %sn",p); sleep(1000); } 
}
  

Я хочу, чтобы kt_func печатал «Это данные» каждые 1 секунду.

Ответ №1:

Потоки ядра могут обращаться к любой части памяти пользовательского пространства (при условии, что у них есть соответствующий указатель на нее). Поскольку ваш код предполагает, что в рамках системного вызова вы хотите запустить новый поток ядра и позволить ему печатать что-то каждые 1 секунду. Я предполагаю, что после создания потока ядра вы вернетесь из системного вызова. Проблема здесь заключается в следующем: после возврата из системного вызова пользовательский процесс также может получить доступ к памяти, на которую указывает p, и поток ядра также может получить к ней доступ. Как бы вы обеспечили доступ к синхронизации указателя p? (Возможно, через другой системный вызов).

Хотя я не вижу ни одного варианта использования того, что вы делаете?

Комментарии:

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

Ответ №2:

В вашем обработчике системного вызова вы могли бы сделать что-то вроде

 struct mm_struct *mm = get_task_mm(current);
  

чтобы скрыть отображение памяти процесса, выполняющего системный вызов. Затем позже в вашем потоке ядра вы можете сделать что-то вроде

 access_remote_vm(mm, p, my_kernel_buf, length, 0);
  

для выполнения эквивалента copy_from_user() в памяти исходной задачи.

Комментарии:

1. Это именно мой вопрос. Как сделать access_remote_vm. Существует ли какая-либо конкретная реализация в ядре 2.6?

2. Не уверен, что вы имеете в виду: да, access_remote_vm() в ядре 2.6 есть функция, которую вы можете вызвать.

3. Извините, я искал функцию access_remote_vm в LXR для 2.6.38 и не смог ее найти. Но теперь я нашел функцию access_remote_vm в LXR для 2.6.39. Попробую это.