Linux implements file operation in virtual file system / proc

Posted by pramodv on Sat, 20 Nov 2021 12:11:32 +0100

1, Experimental purpose
1. Understand the content of virtual file system in Linux
2. Learn how to write kernel modules
3. Implementation of file operation algorithm in virtual file system / proc
2, Experimental environment
Centos7.9,vim
3, Experimental content
Write a kernel module, add a directory hello in the / proc file system, and add a file world in this directory. The content of the file is hello world.
4, Experimental principle system call function used in experiment
/proc file system is a virtual file system on Linux. It stores a series of special files of the current kernel running state. Users can view the information about the system hardware and the running process through these files, and even change some of them to change the kernel running state.
1. Create directory function proc in proc_mkdir the prototype of this function is: struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent); Name: name of the directory to be created. Parent: pointer to the parent directory of the directory. Returns the pointer structure pointing to the current directory.
2. The function to create the version file is proc_create. The prototype of this function is: static inline struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops); The first parameter name is the file name, the second parameter mode is the read-write permission of the file, the third parameter parent is the structure pointer of its parent directory, and the fourth parameter pr
3. Realize the data transfer function between kernel space and user space: copy_ to_ User () and copy_ from_ The user() functions. (the old kernel is the two functions of raw_copy_to_user() and raw_copy_from_user())_ to_ The complete form of the user() function is unsigned long copy_to_user(void *to, const void *from, unsigned long count); The function copies kernel space data to user space. Where to: destination address (user space)
4. Remove a file function from / proc remove_ proc_ The prototype of the entry() function is: remove_proc_entry(const char *name, struct proc_dir_entry *parent) name: the name of the file to be deleted. Parent: the location of the file in the / proc file system

5, Analysis of experimental results (screen capture of experimental results, experimental analysis corresponding to experimental results)
1. Get kernel source code
apt-get install linux-source-3.10.0
Download to / usr/src / directory by default
Get the linux-source-3.10.0.tar.xz compressed package and move it to the desktop
Unzip tar -xjf *.tar.xz
Get linux-source-3.10.0
Open ~ / linux-source-3.10.0/fs/proc to view the files of the proc file system





2. Create directory file and write proc_hello.c and Makefile
Write proc_hello.c file

Writing Makefile files

3. Operation and verification
Will proc_ Copy the hello. C file to the Linux/fs/proc directory. Since there are Makefile files in this directory, the original Makefile files should be backed up and then copied to the files in beiben experiment
mv Makefile Makefile.bak
mv my_makefile Makefile

1. First compile with make... # sudo make

2. Modinfo command to view the properties of the. Ko file generated by make... #modinfo proc_hello.ko

Then use the "vim /etc/profile" command to enter the / etc/profile file and modify the PATH to
PATH= P A T H : PATH: PATH:HOME/bin:/sbin:/usr/bin:/usr/sbin
Restart the virtual machine and execute "modinfo proc_hello.ko" again

3. Load kernel module:.......... # insmod proc_hello.ko

4. View new module found:.... # lsmod

5. View kernel log information:.... #dmesg | tail


6. Open / proc/hello/world to verify:... #cat /proc/hello/world


7. Uninstall module:... #rmmod proc_hello.ko

8. View the print information during unloading:.... #dmesg | tail

map_driver.c

#Include < Linux / kernel. H > / / common kernel functions
#Include < Linux / module. H > / / version control of modules
#Include < Linux / init. H > / / contains macros
#include<linux/fs.h>
#include <linux/cdev.h>
#include<linux/string.h>
#include<linux/errno.h>
#include<linux/mm.h>
#include<linux/vmalloc.h>
#include<linux/slab.h>
#include<linux/sched.h>
#include<linux/io.h>
#include<linux/mman.h>

#define MAP_PAGE_COUNT  10
#define MAPLEN(PAGE_SIZE *MAP_PAGE_COUNT)
#define MAP_DEV_MAJOR  240
#define MAP_DEV_NAME  "mapnopage"

extern struct mm_struct init_mm;
void map_vopen(struct vm_area_struct *vma);
void map_vclose(struct vm_area_struct *vma);
/* device mmap */
static int mapdrv_mmap(struct file *file, struct vm_area_struct *vma);
static int mapdrv_open(struct inode *inode, struct file *file);
/*vm.area nopage */
static int map_fault(struct vm_fault *vmf);

static struct file_operations mapdrvo_fops={
	.owner=THIS_MODULE,
	.mmap=mapdrv_mmap,
	.open=mapdrv_open,
};

static struct vm_operations _struct map_vm_ops={
	.open=map_vopen,
	.close=map_vclose,
	.fault=map_fault,
};

static char *vmalloc_area=NULL;

MODULE_LICENSE("GPL");

static int __init mapdrv_init(void)  /* Load function */
{
	int result;
	unsigned long virt_addr;
	int i=1;
	result=register_chrdev(MAP_DEV_MAJOR,MAP_DEV_NAME,&mapdrvo_fops);
	if(result<0)
	{
		return result;
	}
	vmalloc_area=vmalloc(MAPLEN);
	virt_addr=(unsigned long)vmalloc_area;
	for(virt_addr=(unsigned long)vmalloc_area; virt_addr<(unsigned long) vmalloc_area+MAPLEN; virt_addr+=PAGE_SIZE)
	{
		SetPageReserved(vmalloc_to_page((void*)virt_addr));
		Sprintf((char*)virt_addr, "test %d",i++);
	}
	printk("vmalloc_area apply completely!");
return 0;
}

static void __exit mapdrv_exit(void)  /* Unload function */
{
	unsigned long virt_addr;
/* unreserve all pages  */
	for(virt_addr=(unsigned long) vmalloc_area; virt_addr<(unsigned long) vmalloc_area+MAPLEN; virt_addr+=PAGE_SIZE)
	{
		ClearPageReserved(vmalloc_to_page((void*)virt_addr));
	}
   /*  and free the two areas  */
	if(vmalloc_area)
		vfree(vmalloc_area);
	unregister_chrdev(MAP_DEV_MAJOR,MAP_DEV_NAME);
}

static int mapdrv_mmap(struct file *file, struct vm-area_struct *vma)
{
	unsigned long offset=vma->vm_pgoff<<PAGE_SHIFT;
	unsigned long size=vma->vm_end-vma->vm_start;
	if(size>MAPLEN)
	{
		printk("size too big\n");
		return FNXIO;
	}
	/*  only support shared mapping  */
	if((vma->vm_flags&VM_WRITE)&&!(vma->vm_flags&VM_SHARED))
	{
		printk("writeable mappings must be shared, rejecting\n");
		return –EINVAL;
	}
	/*  do not want to have this area swapped out, lock it  */
	vma->vm_flags|=VM_LOCKONFAULT;
	if(offset==0)
		vma->vm_ops=&map_vm_ops;
	else
	{
		printk("offset out of range\n");
		return –ENXIO;
	}
	return 0;
}

static int mapdrv_open(struct inode *inoe, struct file *file)
{
	printk("process: %s(%d)\n", current->comm, current->pid);
	return 0;
}

/*  open handler for vm area  */
void map_vopen(struct vm_area_struct *vma)
{
	printk("mapping vma is opened..\n");
}

/*  close handler for vm.area  */
void map_vclose(struct vm_area_struct *vma)
{
	printk("mapping vma is closed ..\n");
}

/*  page fault handler  */
static int map_fault(struct vm_fault *vmf)
{
	struct page *page;
	void *page_ptr;
	unsigned long offset=vmf->address-vmf->vma->vm_start;
	unsigned long virt_start=(unsigned long)vmalloc_area+( unsigned long)(vmf->pgoff<<PAGE_SHIFT);
	printk("\n");
	page_ptr=NULL;
	if((vmf->vma==NULL)||(vmalloc_area==NULL))
	{
		printk("return VM_FAULT_SIGBUS!\n");
		return VM_FAULT_SIGBUS;
	}
	if(offset>=MAPLEN)
	{
		printk("return VM_FAULT_SIGBUS!\n");
		return VM_FAULT_SIGBUS;
	}
	page_ptr=vmalloc_area+offset;
	page=vmalloc_to_page(page_ptr);
	get_page(page);
	vmf->page=page;
	printk("%s: map ox%lx (ox%016lx) to ox%lx,size: ox%lx,
	page:%ld \n",_func_, virt_start, pfn_start<<PAGE_SHIFT, vmf->address, PAGE_SIZE, VMF->PGOFF);
	return 0;
}

module_init(mapdrv_init);
module_exit(mapdrv_exit);

Topics: Linux Operation & Maintenance