Linux系統成功的關鍵因素之一就是具有與其他操作系統和諧共存的能力。Linux系統的文件系統由兩層結構構建:第一層是虛擬文件系統(VFS),第二層是各種不同的具體的文件系統。 VFS就是把各種具體的文件系統的公共部分抽取出來,形成一個抽象層,是系統內核的一部分,它位於用戶程式和具體的文件系統之間。 ...
Linux系統成功的關鍵因素之一就是具有與其他操作系統和諧共存的能力。Linux系統的文件系統由兩層結構構建:第一層是虛擬文件系統(VFS),第二層是各種不同的具體的文件系統。
VFS就是把各種具體的文件系統的公共部分抽取出來,形成一個抽象層,是系統內核的一部分,它位於用戶程式和具體的文件系統之間。它對用戶提供了標準的文件系統調用介面,對具體的文件系統(如EXT2、FAT32等),它通過一系列的對不同文件系統公用的函數指針來實際調用具體的文件系統函數,完成實際的各有差異的操作。任何使用文件系統的程式必須經過這層介面來使用它。通過這樣的方式,VFS就對用戶屏蔽了底層文件系統的實現細節和差異。
在VFS的支持下,用戶態進程讀寫任何類型的文件系統都可以使用read和write著兩個系統調用,但是在linux內核中沒有這樣的系統調用我們如何操作文件呢?我們知道read和write在進入內核態之後,實際執行的是sys_read和sys_write,但是查看內核源代碼,發現這些操作文件的函數都沒有導出(使用EXPORT_SYMBOL導出),也就是說在內核模塊中是不能使用的.通過查看sys_open的源碼我們發現,其主要使用了do_filp_open()函數,該函數在fs/namei.c中,而在改文件中,filp_open函數也是調用了do_filp_open函數,並且介面和sys_open函數極為相似,調用參數也和sys_open一樣,並且使用EXPORT_SYMBOL導出了,所以我們猜想該函數可以打開文件,功能和open一樣。使用同樣的查找方法,我們找出了一組在內核中操作文件的函數,如下:
我們註意到在vfs_read和vfs_write函數中,其參數buf指向的用戶空間的記憶體地址,如果我們直接使用內核空間的指針,則會返回-EFALUT。所以我們需要使用set_fs()和get_fs()巨集來改變內核對記憶體地址檢查的處理方式。
另外,使用vfs_read()和vfs_write()需要註意的一點是最後的參數loff_t *pos,pos所指向的值要初始化,表明從文件的什麼地方開始讀寫。例如,可以使用 loff_t pos = fp->f_pos;
實例代碼:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/dcache.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <asm/fcntl.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
int __init hello_init(void)
{
unsigned char buf1[12]="hello world.";
unsigned char buf2[12]="kernel file.";
struct file *fp;
mm_segment_t fs;
loff_t pos;
printk("hello enter\n");
fp = filp_open("/home/kernel_file", O_RDWR | O_CREAT, 0644);
if (IS_ERR(fp)) {
printk("create file error\n");
return -1;
}
fs = get_fs();
set_fs(KERNEL_DS);
pos = fp->f_pos;
vfs_write(fp, buf1, sizeof(buf1), &pos);
fp->f_pos = pos;
pos = fp->f_pos;
vfs_write(fp, buf2, sizeof(buf2), &pos);
fp->f_pos = pos;
set_fs(fs);
filp_close(fp, NULL);
return 0;
}
void __exit hello_exit(void)
{
printk("hello exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
(轉載自 網路 原創不詳)