一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

探索Linux內(nèi)核空間文件IO實現(xiàn)(下)

 ningmei0424 2014-11-03

探索Linux內(nèi)核空間文件IO實現(xiàn)

BY Wang BaoYi

Email: wby0322@gmail.com

本文參考《深入理解Linux內(nèi)核》完成,詳情請查閱相關(guān)書籍

意見和建議可以發(fā)送電子郵件至本人郵箱Email。

文章系作者原創(chuàng),轉(zhuǎn)載請注明出處

 

內(nèi)核空間文件操作函數(shù)注釋

內(nèi)核空間讀寫文件的常規(guī)操作步驟同用戶空間一樣

第一步:打開文件,獲取文件指針

第二步:將文件讀入到一段內(nèi)存中

第三步:將一段內(nèi)存中的數(shù)據(jù)寫入到另一個文件中。

完成上述功能要用的內(nèi)核函數(shù)有:

◆打開文件filp_open()

◆關(guān)閉文件filp_close()

◆讀文件內(nèi)容到內(nèi)存中vfs_read()

◆寫內(nèi)存中的數(shù)據(jù)到文件vfs_write()

函數(shù) filp_open(const char* filename, int open_mode, int mode)

函數(shù)功能:在內(nèi)核空間中打開文件

函數(shù)原形:

strcut file* filp_open(const char* filename, int open_mode, int mode);

返回值:strcut file*結(jié)構(gòu)指針,供后繼函數(shù)操作使用,該返回值用IS_ERR()來檢驗其有效性。

參數(shù):

filename:表明要打開或創(chuàng)建文件的名稱(包括路徑部分)。

open_mode:文件的打開方式,O_RDONLY 只讀打開、O_WRONLY 只寫打開、O_RDWR 讀寫打開、O_CREAT 文件不存在則創(chuàng)建。

mode:創(chuàng)建文件時使用,設(shè)置創(chuàng)建文件的權(quán)限,其它情況可以匆略設(shè)為0

示例

struct file *file = NULL;

file = filp_open(/root/test.txt,O_RDWR|O_CREAT,0);

//以讀寫方式(沒有則創(chuàng)建)打開文件/root/test.txt。并返回test.txt的文件指針給file.
函數(shù) filp_close(struct file*filp, fl_owner_t id)

函數(shù)功能:關(guān)閉之前打開文件

函數(shù)原型:int filp_close(struct file*filp, fl_owner_t id);

參數(shù):

struct file*filp:打開文件的文件指針

fl_owner_t id:一般傳遞NULL值,也可用current->files作為實參。

示例

filp_close(file, NULL); //關(guān)閉指針為file的文件。
函數(shù) vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)

函數(shù)功能:讀取已經(jīng)打開的文件到內(nèi)存中

函數(shù)原型:

ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)

{

    ssize_t ret;

    if (!(file->f_mode & FMODE_READ)) //判斷文件是否可讀

        return -EBADF;

    if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read)) //是否定義文件讀方法

        return -EINVAL;

    if (unlikely(!access_ok(VERIFY_WRITE, buf, count))) 

        return -EFAULT;

    ret = rw_verify_area(READ, file, pos, count); //讀校驗 ,

    if (ret >= 0) 

      {

          count = ret;

          if (file->f_op->read) 

          ret = file->f_op->read(file, buf, count, pos); //調(diào)用文件讀操作方法

          else

          ret = do_sync_read(file, buf, count, pos); //通用文件模型讀方法

          if (ret > 0)

            {

                 fsnotify_access(file->f_path.dentry);

                 add_rchar(current, ret);

             }

          inc_syscr(current);

      }

    return ret;

}

通過filp_open我們已經(jīng)可以在當前進程的文件描述表中找到了file , 于是我們就可以調(diào)用保存在file中的文件操作方法(file_operation) file->f_op->read(file, buf, count, pos)來具體的操作文件。

上面的代碼實現(xiàn)并不復雜,在做了一些條件判斷以后,如果該文件索引節(jié)點inode定義了文件的讀實現(xiàn)方法的話,就調(diào)用此方法。Linux下特殊文件讀往往是用此方法, 一些偽文件系統(tǒng)如:proc,sysfs等,讀寫文件也是用此方法。而如果沒有定義此方法就會調(diào)用通用文件模型的讀寫方法.它最終就是讀內(nèi)存,或者需要從存儲介質(zhì)中去讀數(shù)據(jù).

參數(shù):

struct file *file:打開的文件返回的文件指針,(讀的目標文件)

char __user *buf:在用戶空間開辟的一段內(nèi)存空間的首地址,用來保存文件數(shù)據(jù)。

size_t count:指定讀取文件中的多少內(nèi)容。單位字節(jié)

loff_t *pos:文件起始位置偏移值,若從文件頭讀取,則偏移值為0.可以在文件自身的信息中獲取

示例

int *buf;

loff_t *pos = &(file->f_pos);

buf = (int *)kmalloc(fsize+100,GFP_KERNEL);

//分配一個文件自身大小+100字節(jié)邊界的內(nèi)存空間,將用來存放打開的文件,內(nèi)存分配方式為kmalloc的flag標志GFP_KERNEL。

vfs_read(file, buf, fsize, pos); //讀文件(指針為file)到內(nèi)存(buf為起始地址)中,讀取字節(jié)數(shù)定為文件自身大小,偏移為自身.
函數(shù) vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)

函數(shù)功能:將內(nèi)存中的一段數(shù)據(jù)寫到文件中

函數(shù)原形:

ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)

{

    ssize_t ret;

    if (!(file->f_mode & FMODE_WRITE))

        return -EBADF;

    if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))

        return -EINVAL;

    if (unlikely(!access_ok(VERIFY_READ, buf, count)))

        return -EFAULT;

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

    if (ret >= 0) 

      {

         count = ret;

         if (file->f_op->write)

         ret = file->f_op->write(file, buf, count, pos); 

         else

         ret = do_sync_write(file, buf, count, pos);

         if (ret > 0)

           {

                fsnotify_modify(file->f_path.dentry);

                add_wchar(current, ret);

            }

         inc_syscw(current);

      }

    return ret;

}

可以看出這個函數(shù)和vfs_read()是差不多的,只是調(diào)用的文件操作方法不同而已(file->f_op->write) ,如果沒有定義file->f_op->write ,同樣也需要do_sync_write()調(diào)用同樣文件寫操作, 首先把數(shù)據(jù)寫到內(nèi)存中,然后在適當?shù)臅r候把數(shù)據(jù)同步到具體的存儲介質(zhì)中去.

參數(shù):

struct file *file:打開的文件返回的文件指針,(寫的目標文件)

char __user *buf:數(shù)據(jù)在內(nèi)存中的位置,以該地址為起始的一段內(nèi)存數(shù)據(jù)將要寫到文件中

size_t count:指定寫入文件中的多少內(nèi)容。單位字節(jié)

loff_t *pos:文件起始位置偏移值,若從文件頭讀取,則偏移值為0.可以在文件自身的信息中獲取

示例

loff_t *pos = &(file->f_pos);

vfs_write(file,buf,fsize,pos);
獲取文件的大小

我們可以利用文件的inode結(jié)構(gòu)獲得文件的大小,參考代碼如下

struct file *file = NULL;

struct inode *inode = NULL;

file = filp_open(file_path,O_RDWR|O_CREAT,0);

inode = file->f_dentry->d_inode;

fsize = inode->i_size;

printk(KERN_ALERT "size=%d/n",(int)fsize);

示例代碼

此ko模塊代碼在arm架構(gòu)的fpga上已經(jīng)跑通。因為涉及的參數(shù)比較多,為了清楚地重現(xiàn)重要步驟,對每步驟的函數(shù)進行了簡單的封裝。參數(shù)的傳遞只要理解上面的介紹即可區(qū)分清楚。執(zhí)行流程在static int hello_init(void)函數(shù)中

/*

* kernel_hello_file.c

*

* Created on: 2010-11-9

* Author: Wang BaoYi(zats)

* Email:wby0322@gmail.com

*/

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/module.h>

#include <linux/fs.h>

#include <linux/string.h>

#include <linux/mm.h>

#include <linux/syscalls.h>

#include <asm/unistd.h>

#include <asm/uaccess.h>

#define FILE_PATH_READ "/file_read_test"

//打開文件路徑(包括文件名),未來將要讀的

#define FILE_PATH_WRITE "/new_file_test"

//打開文件路徑(包括文件名),未來將要寫的

struct file *file = NULL; //保存打開文件的文件指針變量

struct inode *inode = NULL; //為了獲取文件大小用的inode結(jié)構(gòu)變量

int *file_buf; //保存開辟的內(nèi)存空間的地址的指針變量

loff_t fsize; //保存文件大小的變量

mm_segment_t old_fs; //保存內(nèi)存邊界的變量

/*

* kernel_file_open封裝了文件打開函數(shù)

* 參數(shù)為文件路徑(包含文件名)。

* 操作file類型結(jié)構(gòu)變量。

* 打開方式為讀寫(沒有則創(chuàng)建)

*/

static int kernel_file_open(char *file_path)

{

    file = filp_open(file_path,O_RDWR|O_CREAT,0);

    if (IS_ERR(file)) 

      {

        printk("Open file %s failed./n", file_path);

        return 0;

      }

}

/*

* kernel_file_size封裝了獲取文件大小函數(shù)

* 參數(shù)為待獲取大小的文件指針。

* 操作inode類型結(jié)構(gòu)變量。

* 返回值為文件大小,單位字節(jié)

*/

static loff_t kernel_file_size(struct file *file)

{

    inode = file->f_dentry->d_inode;

    fsize = inode->i_size;

    printk(KERN_ALERT "size=%d/n",(int)fsize);

    return fsize;

}

/*

* kernel_addr_limit_expend封裝了內(nèi)存邊界擴展函數(shù)

* 參數(shù)無。

*/

static int kernel_addr_limit_expend(void)

{

    old_fs = get_fs();

    set_fs(KERNEL_DS);
 
    return 0;

}

/*

* kernel_addr_limit_resume封裝了內(nèi)存邊界恢復函數(shù)

* 參數(shù)無。

*/

static int kernel_addr_limit_resume(void)

{

    set_fs(old_fs);

}

/*

* kernel_file_read封裝了讀文件函數(shù)

* 參數(shù)為open的文件指針,獲取的文件大小

* 返回值為讀入到內(nèi)存中的首地址。

*/

void *kernel_file_read(struct file *file,loff_t fsize)

{

    int *buf;

    loff_t *pos = &(file->f_pos);

    buf = (int *)kmalloc(fsize+100,GFP_KERNEL);

    vfs_read(file, buf, fsize, pos);

    return buf;

}

/*

* kernel_file_ write封裝了讀文件函數(shù)

* 參數(shù)為open的文件指針,數(shù)據(jù)在內(nèi)存中的地址,寫入到文件的字節(jié)數(shù)

*/

static int kernel_file_write(struct file *file,int *buf,loff_t fsize)

{

    loff_t *pos = &(file->f_pos);

    vfs_write(file,buf,fsize,pos);

}

/*

* ko的主函數(shù)

*/

static int hello_init(void) //ko的主函數(shù)

{

    printk(KERN_ALERT "Y(^_^)Y Hello Wang`s file./n");

    kernel_file_open(FILE_PATH_READ); //打開文件file_read_test

    kernel_file_size(file); //獲取file_read_test的大小

    /*read file to mem*/

    kernel_addr_limit_expend(); //邊界擴展

    file_buf = kernel_file_read(file,fsize); //讀操作

    filp_close(file, NULL); //關(guān)閉文件file_read_test

    kernel_addr_limit_resume(); //邊界恢復

    /*write mem to file*/

    kernel_file_open(FILE_PATH_WRITE); //打開文件new_file_test,沒有則創(chuàng)建

    kernel_addr_limit_expend(); //邊界擴展

    kernel_file_write(file,file_buf,fsize); //將前面讀到內(nèi)存中的數(shù)據(jù),寫入到文件new_file_test中

    filp_close(file, NULL); //關(guān)閉文件

    kernel_addr_limit_resume(); //邊界恢復

    return 0;

}

static void hello_exit(void)

{

    printk(KERN_ALERT "BYE BYE file Y(^_^)Y/n");

}

module_init(hello_init);

module_exit(hello_exit);

MODULE_LICENSE("Dual BSD/GPL");

MODULE_AUTHOR("wby");

MODULE_DESCRIPTION("A simple hello world Module with File");

簡單的效果圖

QQ截圖未命名1

上述代碼可以直接復制到你要操作文件的代碼段,也可以把它放到頭文件中使用。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    在线欧美精品二区三区| 欧美黑人精品一区二区在线| 欧美成人黄色一级视频| 亚洲一区二区三区国产| 亚洲一区二区三区在线中文字幕| 色婷婷久久五月中文字幕| 国产男女激情在线视频| 欧美成人黄色一区二区三区| 午夜色午夜视频之日本| 国产精品欧美一区二区三区不卡| 国产一区二区三区不卡| 91亚洲国产成人久久| 国产小青蛙全集免费看| 精品欧美日韩一二三区| 久久91精品国产亚洲| 亚洲精品中文字幕无限乱码| 99香蕉精品视频国产版| 精品精品国产自在久久高清| 日本免费熟女一区二区三区 | 国产亚洲精品香蕉视频播放| 五月婷婷缴情七月丁香 | 国产又粗又猛又长又大| 老司机精品一区二区三区| 玩弄人妻少妇一区二区桃花| 欧美日韩国产精品第五页| 中国少妇精品偷拍视频 | 69久久精品亚洲一区二区| 手机在线不卡国产视频| 中文字幕一区久久综合| 亚洲一区二区三区av高清| 欧美一级特黄大片做受大屁股| 国产成人综合亚洲欧美日韩| 国产a天堂一区二区专区| 日韩少妇人妻中文字幕| 日韩欧美在线看一卡一卡| 欧美日韩国产亚洲三级理论片| 国产户外勾引精品露出一区| 国产免费黄片一区二区| 蜜桃传媒在线正在播放| 午夜福利大片亚洲一区| 99热九九在线中文字幕|