kernel_read() returns -EFAULT when passing with the O_DIRECT flag (linux kernel v5.4.0)
by Chibi Gwen from LinuxQuestions.org on (#6P2XY)
Hi all,
I'd like to read file contents directly from the disk (bypass kernel's page cache mechanism). In user space, I've achived this by using the O_DIRECT flag with libc's open() function.
To achieve the same goal in kernel space, I've written the following code and compiled it as a kernel module (inspired by this link https://stackoverflow.com/questions/...ry-from-kernel).
Code:#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/err.h>
#include <linux/fcntl.h>
#include <linux/uio.h>
static int __init start(void)
{
printk(KERN_INFO, "module installed\n");
struct file *fp = filp_open("/home/chibigwen/Desktop/ko/nonsense", O_RDONLY | O_DIRECT, 0);
int rv;
mm_segment_t old_fs;
old_fs = get_fs();
set_fs(USER_DS);
if (IS_ERR(fp)) {
printk("filp_open() failed\n");
rv = PTR_ERR(fp);
}
else
{
loff_t pos = 0;
unsigned char *big_buf = kmalloc(0x2000, GFP_KERNEL);
if(big_buf == NULL)
{
printk("bad kmalloc\n");
}
// it seems like we don't need alignment
unsigned char *kread_buf = (unsigned char *)((unsigned long)(big_buf + 0xfff) & ~0xfff);
rv = kernel_read(fp, kread_buf, 0x1000, &pos);
if (rv < 0)
{
printk("bad kernel_read(), rv: %d\n", rv);
}
else
{
printk("kernel_read() reads %d bytes\n", rv);
printk("on disk: %x %x %x\n", kread_buf[0x100], kread_buf[0x101], kread_buf[0x102]);
}
kfree(big_buf);
}
filp_close(fp, NULL);
set_fs(old_fs);
return 0;
}
static void __exit end(void)
{
printk(KERN_INFO, "module uninstalled\n");
}
module_init(start);
module_exit(end);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chibi Gwen");
MODULE_DESCRIPTION("A module to test Direct I/O");
MODULE_VERSION("0.1");However, kernel_read() returns -EFAULT. After some googling, I've found this https://linux-kernel.vger.kernel.nar...-with-o-direct. It seems that my code is obsolete, and kernel_read()/vfs_read() does not work with the O_DIRECT flag. When I remove the O_DIRECT flag, kernel_read() successfully reads data from the file, but it uses the page cache, which is not desired.
I'm wondering if there are alternative methods to perform direct I/O in kernel space. Any suggestions or insights would be greatly appreciated. Thanks in advance!
I'd like to read file contents directly from the disk (bypass kernel's page cache mechanism). In user space, I've achived this by using the O_DIRECT flag with libc's open() function.
To achieve the same goal in kernel space, I've written the following code and compiled it as a kernel module (inspired by this link https://stackoverflow.com/questions/...ry-from-kernel).
Code:#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/err.h>
#include <linux/fcntl.h>
#include <linux/uio.h>
static int __init start(void)
{
printk(KERN_INFO, "module installed\n");
struct file *fp = filp_open("/home/chibigwen/Desktop/ko/nonsense", O_RDONLY | O_DIRECT, 0);
int rv;
mm_segment_t old_fs;
old_fs = get_fs();
set_fs(USER_DS);
if (IS_ERR(fp)) {
printk("filp_open() failed\n");
rv = PTR_ERR(fp);
}
else
{
loff_t pos = 0;
unsigned char *big_buf = kmalloc(0x2000, GFP_KERNEL);
if(big_buf == NULL)
{
printk("bad kmalloc\n");
}
// it seems like we don't need alignment
unsigned char *kread_buf = (unsigned char *)((unsigned long)(big_buf + 0xfff) & ~0xfff);
rv = kernel_read(fp, kread_buf, 0x1000, &pos);
if (rv < 0)
{
printk("bad kernel_read(), rv: %d\n", rv);
}
else
{
printk("kernel_read() reads %d bytes\n", rv);
printk("on disk: %x %x %x\n", kread_buf[0x100], kread_buf[0x101], kread_buf[0x102]);
}
kfree(big_buf);
}
filp_close(fp, NULL);
set_fs(old_fs);
return 0;
}
static void __exit end(void)
{
printk(KERN_INFO, "module uninstalled\n");
}
module_init(start);
module_exit(end);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chibi Gwen");
MODULE_DESCRIPTION("A module to test Direct I/O");
MODULE_VERSION("0.1");However, kernel_read() returns -EFAULT. After some googling, I've found this https://linux-kernel.vger.kernel.nar...-with-o-direct. It seems that my code is obsolete, and kernel_read()/vfs_read() does not work with the O_DIRECT flag. When I remove the O_DIRECT flag, kernel_read() successfully reads data from the file, but it uses the page cache, which is not desired.
I'm wondering if there are alternative methods to perform direct I/O in kernel space. Any suggestions or insights would be greatly appreciated. Thanks in advance!