linux核心程式設計-核心態檔案操作
一、檔案開啟函式
struct file *filp_open(const char *filename, int flags, umode_t mode)
定義在:fs/open.c
標頭檔案:<linux/fs.h>
詳解:
1.在使用者態open函式是個變參函式,umode_t mode引數只有在O_CREAT標誌指定時才出現。在核心態如果O_CREAT標誌指定mode引數指定許可權,否則為0
2.filename引數和flags和使用者態一樣,指定檔案路徑和開啟標誌
3.返回值,如果成功返回struct file 型別變數。失敗時要注意,它失敗了返回的不是NULL,而是一個錯誤碼。所以對於返回值的判斷應該用下面的方式
if(IS_ERR(file))
IS_ERR(file)為真開啟失敗,為假開啟成功。linux核心為什麼這麼設計,可以參考https://blog.csdn.net/yaozhenguo2006/article/details/7967547
二、讀寫函式
使用者態讀寫檔案只提供了一種方法read、write。而在核心態讀寫檔案可以有好幾種,接下來分別看看這幾張方法,並對其進行一下比較
方法1:當開啟檔案成功後,返回了struct file型別變數,此變數中包含了struct file_operations檔案操作函式集所以可以如下操作
file->f_op->read(file,buf,size,&pos);
file->f_op->write(file,buf,size,&pos);
方法二:使用vfs_read、vfs_write函式,他是核心對file->f_op->read、write的封裝。定義在fs/read_write.c,標頭檔案<linux/fs.h>
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos);
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos);
注意:以上兩種方法中,函式對buf引數進行了__user限定,核心會對buf地址進行檢測。也就是說buf的地址必須是使用者空間的地址,如果在核心中使用會返回-EFAULT錯誤。所以在呼叫以上兩種方法中的函式時可以使用set_fs()、get_fs()來解決。
使用方法:
mm_segmet_t old_fs;
.........
old_fs = get_fs();
set_fs(get_ds());
vfs_read(file,buf,size,&pos);
set_fs(old_fs);
進行了set_fs設定後,核心就不在對記憶體地址進行檢測。關於set_fs()可以參考:https://www.cnblogs.com/soul-stone/p/6367696.html
方法三:先說讀函式,可以使用kernel_read函式,這個函式其實就是加入了set_fs()、get_fs()函式。在4.14前
定義為int kernel_read(struct file *file, loff_t offset, char *addr, unsigned long conut),定義在fs/exec.c中,標頭檔案<linux/fs.h>
在4.14及之後的版本中定義為ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos),定義在fs/read_write.c中,標頭檔案<linux/fs.h>
接下來再說寫函式,__kernel_write和kernel_write函式,在3.9之前沒有這兩個函式,3.9版本中定義了__kernel_write函式,但是沒有匯出符合,模組程式設計中也調用不了,我們可以仿照此函式編寫一個自己的kern_write函式。在3.18版本後__kernel_write函式匯出了。其定義:ssize_t __kernle_write(struct file *file, const char *buf, size_t count, loff_t *pos),定義在fs/read_write.c中,標頭檔案<linux/fs.h>。kernel_write函式在4.14版本開始定義和__kernel_write引數一樣,且匯出了此符合。
三、檔案關閉
int filp_close(struct file *file, fl_owner_t id)。定義在fs/open.c,標頭檔案<linux/fs>
用法:一般為 filp_close(file,NULL);