Linux kernel operation file

Introduction

There are usually several ways to manipulate files:
1. Open
2. Get file information
3. Read
4. Write. The
same is true in the kernel.

principle

Insert picture description here

File structure analysis

Go directly to the source code:

struct file {
    
    
	union {
    
    
		struct llist_node	fu_llist;
		struct rcu_head 	fu_rcuhead;
	} f_u;
	struct path		f_path;
	struct inode		*f_inode;	/* cached value */
	//与文件相关的操作
	const struct file_operations	*f_op;
 
	/*
	 * Protects f_ep_links, f_flags.
	 * Must not be taken from IRQ context.
	 */
	spinlock_t		f_lock;
	enum rw_hint		f_write_hint;
	atomic_long_t		f_count;
	//文件标志,检查用户请求是否是非阻塞的操作
	unsigned int 		f_flags;
	//文件模式,表示文件可读或可写
	fmode_t			f_mode;
	struct mutex		f_pos_lock;
	loff_t			f_pos;
	struct fown_struct	f_owner;
	const struct cred	*f_cred;
	struct file_ra_state	f_ra;
 
	u64			f_version;
#ifdef CONFIG_SECURITY
	void			*f_security;
#endif
	/* needed for tty driver, and maybe others */
	void			*private_data;
 
#ifdef CONFIG_EPOLL
	/* Used by fs/eventpoll.c to link all the hooks to this file */
	struct list_head	f_ep_links;
	struct list_head	f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */
	struct address_space	*f_mapping;
	errseq_t		f_wb_err;
} __randomize_layout

Function analysis

open a file:

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 IS_ERR() to check its validity.

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 timing of opening. It is easy to appear that the driver that needs to open the file loads and opens the file very early, but the device where the file needs to be opened is not mounted in the file system yet, causing the opening to fail .

open_mode:
The opening mode of the file. Its value is similar to the corresponding parameter of open in the standard library. It can be O_CREAT, O_RDWR, O_RDONLY, etc.

mode:
used when creating a file, set the read and write permissions of the created file, otherwise you can set it to 0 in a hurry

Read and write files:

You can use vfs_read() and vfs_write to read and write files in the kernel. Before using these two functions, you need to explain the two functions get_fs() and set_fs().
The prototypes of the two functions vfs_read() and vfs_write() are as follows:

ssize_t vfs_read(struct file* filp, char __user* buffer, size_t len, loff_t* pos);
ssize_t vfs_write(struct file* filp, const char __user* buffer, size_t len, loff_t* pos);

But in Kernel, it is generally not easy to generate user space pointers.
You need to use the set_fs() function or macro (set_fs() may be a macro definition). If it is a function, its prototype is as follows:

void set_fs(mm_segment_t fs);

The parameter fs of this function has only two values: USER_DS and KERNEL_DS, which represent user space and kernel space respectively. By default, the kernel value is USER_DS

mm_segment_t old_fs;
old_fs = get_fs();
set_fs(KERNEL_DS);
...... //与内存有关的操作
set_fs(old_fs);

There are also some other kernel functions with parameters modified by __user. When you need to replace the memory in the kernel space in the kernel, you can use similar methods.
The last thing to note when using vfs_read() and vfs_write() is that the last parameter loff_t * pos, the value pointed to by pos must be initialized, indicating where to start reading and writing in the file.

Close read and write files:

int filp_close(struct file*filp, fl_owner_t id);

The use of this function is very simple. The second parameter is usually NULL, and current->files is also used as an actual parameter.

Other points to note when using the above functions:

  1. In fact, the members of the Linux Kernel group do not agree to independently read and write files in the kernel (this may affect policy and security issues). The content of the files required by the kernel is best completed by the application layer.
  2. Using this method to read and write files in a loadable kernel module may cause the module to fail to load, because the kernel may not have all these functions that you need to EXPORT.
    3. 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 kernel in the code that is not part of any process, otherwise a crash may occur To avoid this situation, you can create kernel threads in the kernel and place these functions in the thread environment for execution (the way to create kernel threads, please parameter kernel_thread() function).

Instance

#include <linux/syscalls.h> /* get_fs set_fs */
#include <asm/processor.h>
#include <linux/string.h>
#include <asm/uaccess.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include <linux/fs.h>
#include <linux/mm.h>


struct file *fp; //文件 
struct file *newfp; //新文件 
struct kstat *stat;//文件大小 
mm_segment_t old_fs; //设置 
char tmp_file[3000]={
    
    0};  //缓冲存储 
char old_file[300]="/home/darui/file"; //旧文件路径 
char new_file[100]="/home/darui/newfile";   //新文件路径 
 

static int __init file_init(void)
{
    
    
/*	while(flag == 0)//等到flag为1 
	{
		msleep(300); 
	}
	
	if( flag )//可以搞事情了 
*/	
	{
    
    
		
		
		
		//打开旧文件 
		fp = filp_open(old_file, 3, 0);//打开 
		if(fp == NULL)
		{
    
    
			printk(KERN_ALERT "filp_open error.\n");
			return -1;
		}
		old_fs=get_fs();
		set_fs(KERNEL_DS);
		
		//获取旧文件大小 
		stat =(struct kstat *) kmalloc(sizeof(struct kstat),GFP_KERNEL);
		vfs_stat(old_file,stat);
		printk(KERN_ALERT "%d\n",stat->size);
		//读tmp_file
		fp->f_op->read(fp, tmp_file, stat->size , &fp->f_pos);//read函数 读取tmp_file个字 
		
		set_fs(old_fs); 
		printk(KERN_ALERT "old_file:read[%s]\n", tmp_file);//打印读取 
		filp_close(fp, NULL);  
		
		//创建/打开新文件 
		if(newfp == NULL)
            newfp = filp_open(new_file, O_RDWR | O_APPEND | O_CREAT, 0644);
        if (IS_ERR(newfp)) {
    
    
            printk("error occured while opening file %s, exiting...\n", new_file);
            return 0;
        }
        //写入新文件 
		old_fs=get_fs();
		set_fs(KERNEL_DS);
        newfp->f_op->write(newfp, (char *)tmp_file,  stat->size  , &newfp->f_pos);//write函数 写tmp_file个字
        set_fs(old_fs);
        filp_close(newfp, NULL);  
        newfp = NULL;
	}
	
	return 0;
}

static void __exit file_exit(void)
{
    
    
    if(newfp != NULL)
        filp_close(newfp, NULL);
    if(fp != NULL)
        filp_close(fp, NULL);
}


module_init(file_init);
module_exit(file_exit);
MODULE_AUTHOR("darui");

Guess you like

Origin blog.csdn.net/qq_42882717/article/details/114987618