#linux-kernel #linux-device-driver #block-device #nvme
Вопрос:
Я пытаюсь понять драйверы nvme linux. Сейчас я занимаюсь функцией nvme_user_submit_cmd, о которой я частично сообщаю здесь:
static int nvme_submit_user_cmd(struct request_queue *q,
struct nvme_command *cmd, void __user *ubuffer,
unsigned bufflen, void __user *meta_buffer, unsigned meta_len,
u32 meta_seed, u32 *result, unsigned timeout)
{
bool write = nvme_is_write(cmd);
struct nvme_ns *ns = q->queuedata;
struct gendisk *disk = ns ? ns->disk : NULL;
struct request *req;
struct bio *bio = NULL;
void *meta = NULL;
int ret;
req = nvme_alloc_request(q, cmd, 0, NVME_QID_ANY);
[...]
if (ubuffer amp;amp; bufflen) {
ret = blk_rq_map_user(q, req, NULL, ubuffer, bufflen,
GFP_KERNEL);
[...]
Это ubuffer
указатель на некоторые данные в виртуальном адресном пространстве (поскольку это происходит из ioctl
команды пользовательского приложения).
После blk_rq_map_user
этого я ожидал какого-то mmap
механизма для преобразования адреса пользовательского пространства в физический адрес, но я не могу понять, что делает функция. Для справки вот цепочка вызовов:
blk_rq_map_user
-> import_single_range -> blk_rq_map_user_iov
Следование этой функции только что создало для меня еще большую путаницу, и я хотел бы получить некоторую помощь.
Причина, по которой я думаю, что эта функция выполняет своего рода mmap, заключается в том (помимо имени), что этот адрес будет частью struct request
in struct request queue
, который в конечном итоге будет обработан драйвером диска NVME (https://lwn.net/Articles/738449 /) и я предполагаю, что диску нужен физический адрес при выполнении запросов.
Однако я не понимаю, как выполняется это сопоставление.
Ответ №1:
ubuffer — это виртуальный адрес пользователя, что означает, что его можно использовать только в контексте пользовательского процесса, которым он является при вызове submit. Чтобы использовать этот буфер после завершения этого вызова, он должен быть сопоставлен с одним или несколькими физическими адресами для bios / bvecs. Вызов unmap освобождает сопоставление после завершения ввода-вывода. Если устройство не может напрямую обращаться к пользовательскому буферу из-за аппаратных ограничений, тогда будет отображен буфер отказов и будет сделана копия данных.
Редактировать: обратите внимание, что, если не требуется копирование, виртуальный адрес ядра не отображается в буфер, потому что ядру никогда не нужно прикасаться к данным.