I am trying to write directly from a kernel module into a process that it creates without a copy. Note that I cannot simply allocate the memory in kernel mode and map it to userland like you would normally do, I need the memory to eventually originate from the process itself (eventually from a call to the CUDA runtime).
Right now I have a proc file setup with a write callback which I use to send the buffer from userland:
char *buffer;
const size_t PAGE_SIZE = getpagesize();
posix_memalign(&buffer,PAGE_SIZE,PAGE_SIZE);
*buffer = 89;
FILE *fp = fopen("/proc/dt/alloc", "w");
fwrite(buffer, 1, 100, fp);
In the kernel module I map the page to kernel memory and modify the first byte as follows:
static ssize_t write_proc_alloc(struct file *file, const char __user *ubuf, size_t count, loff_t *data)
{
struct page *pages[1];
mmap_read_lock(current->mm);
pin_user_pages((unsigned long)ubuf,1, FOLL_WRITE, pages);
char *buf = kmap(pages[0]);
*buf = 123;
kunmap(pages[0]);
set_page_dirty(pages[0]);
unpin_user_pages(pages, 1);
mmap_read_unlock(current->mm);
}
I have made sure to set the page to dirty after, and yet still it remains unchanged after fwrite
returns. Why is my modification not visible, and how do I directly modify the provided buffer without having to resort to copy_to_user
and the like?
Thanks to Ian Abbott for leading me down the right path.
The solution was to use a level of indirection, since the pointer passed to the kernel function write_proc_alloc
is not the same one the user provides. Instead you write a pointer, copy that by value using get_user(ptr,(uintptr_t*)ubuf)
and then from there map the memory and write as before.