Linux kernel read / write file

Posted by kjelle392 on Wed, 22 Dec 2021 22:34:10 +0100

Linux kernel read / write file

Read and write file data in the driver to be debugged. For example, when the driver needs to record more logs, you can write the information printed by printk() function to the file for subsequent analysis. There is no standard library available for operating files in the kernel. Some kernel functions need to be used. These functions mainly include filp_open() filp_close(), kernel_read(),kernel_write() these functions are available in Linux / Fs H and ASM / uaccess H is declared in the header file. The main steps are described below:

1, Open file

filp_open() can open a file in the kernel. Its prototype is as follows:
strcut file* filp_open(const char* filename, int open_mode, int mode);
This function returns the strcut file * structure pointer for subsequent function operations. The return value IS verified by IS ERR().

Parameter Description:
filename: indicates the name of the file to be opened or created (including the path part). When opening a file in the kernel, you need to pay attention to the opening time. It is easy to see that the driver that needs to open the file loads and opens the file early, but the device where the file needs to be opened is not mounted in the file system, resulting in opening failure.

open_mode: the opening method of the file. Its value is similar to the corresponding open parameter in the standard library. You can take O_CREAT,O_RDWR,O_RDONLY et al.
mode: used when creating a file. Set the read-write permission of the created file. In other cases, it can be set to 0

2, Read write file

The kernel can be used for reading and writing files in the kernel_read() and kernel_write is the kernel export function, and the kernel function prototype is:

ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos)
{
	ssize_t ret;

	ret = rw_verify_area(READ, file, pos, count);
	if (ret)
		return ret;
	return __kernel_read(file, buf, count, pos);
}
EXPORT_SYMBOL(kernel_read);

ssize_t kernel_write(struct file *file, const void *buf, size_t count,
			    loff_t *pos)
{
	ssize_t ret;

	ret = rw_verify_area(WRITE, file, pos, count);
	if (ret)
		return ret;

	file_start_write(file);
	ret =  __kernel_write(file, buf, count, pos);
	file_end_write(file);
	return ret;
}
EXPORT_SYMBOL(kernel_write);

The parameters inside are the same as those in ring3. After you get the filp handle, you can read and write the file.

3, Close file

int filp_close(struct file*filp, fl_owner_t id);
The use of this function is very simple. The second parameter generally passes NULL value, and current - > files is also used as the argument.

Other considerations for using the above functions:

  1. In fact, members of the Linux Kernel group do not approve of reading and writing files independently in the kernel (this may affect policy and security issues). The file contents required by the kernel should be completed by the application layer.
  2. Using this method to read and write files in a loadable kernel module may fail to load the module because the kernel may not EXPORT all these functions you need.
    3. By analyzing the parameters of some of the above functions, it can be seen that the correct operation of these functions depends on the process environment. Therefore, some functions cannot be executed in the interrupted handle or the code in the kernel that does not belong to any process, otherwise they may crash. To avoid this, you can create a kernel thread in the kernel, These functions are executed in a threaded environment (for the way to create a kernel thread, please refer to the parameter kernel_thread() function).

4, Driver code

#include <asm/uaccess.h>

#define MY_FILE "/tmp/log.txt"

char buf[256];
loff_t pos = 0;
struct file *filep = NULL;

static int __init init(void)
{
        printk("Hello, I'm the module that intends to write messages to file.\n");

        if(filep == NULL) {
                filep = filp_open(MY_FILE, O_RDWR | O_APPEND | O_CREAT, 0644);
        }

        if (IS_ERR(filep)) {
                printk("Open file %s error\n", MY_FILE);
                return -1;
        }

        sprintf(buf,"%s\n", "This is test message!");

        memset(buf, 0, sizeof(buf));
        kernel_write(filep, buf, strlen(buf), &pos);

        memset(buf, 0, sizeof(buf));
        kernel_read(filep, buf, sizeof(buf), &pos);
        printk("Read buf -> %s\n", buf);

        return 0;
}

static void __exit fini(void)
{
        printk("Kernel read/write exit\n");

        if(filep != NULL) {
                filp_close(filep, NULL);
        }
}

module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");

matters needing attention:

1. When the driver needs to continuously read and write files, it needs to consider the concurrency and lock the read and write of buf.

View log:

curtis@curtis-Aspire-E5-471G:~/write_code/kernel_write$ dmesg
[145731.662192] Hello, I'm the module that intends to write messages to file.
[145731.662206] pos -> 0
[145731.662210] Read buf -> This is test message!
curtis@curtis-Aspire-E5-471G:~/write_code/kernel_write$ cat /tmp/log.txt
This is test message!

Reference link: Method of reading and writing file data in Linux kernel_ wxie's Linux life - CSDN blog

Topics: Linux kernel