您好,登錄后才能下訂單哦!
這篇文章主要介紹“linux有沒有內核文件操作函數”,在日常操作中,相信很多人在linux有沒有內核文件操作函數問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”linux有沒有內核文件操作函數”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
linux有內核文件操作函數,例filp_open()函數可用于打開文件、vfs_read()函數可用于讀取文件、vfs_write()函數可用于寫文件、filp_close()函數可用于關閉文件。在vfs_read和vfs_write函數中,其第二個參數指向的用戶空間的內存地址,如果直接使用內核空間的指針,則會返回“-EFALUT”。
1. 內核空間文件操作
功能 | 函數原型 |
---|---|
打開文件 | struct file *filp_open(const char *filename, int flags, int mode) |
讀文件 | 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) |
關閉文件 | int filp_close(struct file *filp, fl_owner_t id) |
2. 內核空間與用戶空間
在vfs_read和vfs_write函數中,其參數buf指向的用戶空間的內存地址,如果我們直接使用內核空間的指針,則會返回-EFALUT。這是因為使用的緩沖區超過了用戶空間的地址范圍。一般系統調用會要求你使用的緩沖區不能在內核區。這個可以用set_fs()、get_fs()
來解決。
在include/asm/uaccess.h
中,有如下定義:
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)
#define USER_DS MAKE_MM_SEG(PAGE_OFFSET)
#define get_ds() (KERNEL_DS)
#define get_fs() (current->addr_limit)
#define set_fs(x) (current->addr_limit = (x))
如果使用,如下:
mm_segment_t fs = get_fs();
set_fs(KERNEL_FS);
//vfs_write();
vfs_read();
set_fs(fs);
詳盡解釋:系統調用本來是提供給用戶空間的程序訪問的,所以,對傳遞給它的參數(比如上面的buf),它默認會認為來自用戶空間,在read或write()函數中,為了保護內核空間,一般會用get_fs()
得到的值來和USER_DS進行比較,從而防止用戶空間程序“蓄意”破壞內核空間;而現在要在內核空間使用系統調用,此時傳遞給read或write()的參數地址就是內核空間的地址了,在USER_DS之上(USER_DS ~ KERNEL_DS),如果不做任何其它處理,在write()函數中,會認為該地址超過了USER_DS范圍,所以會認為是用戶空間的“蓄意破壞”,從而不允許進一步的執行;為了解決這個問題set_fs(KERNEL_DS)
將其能訪問的空間限制擴大到KERNEL_DS,這樣就可以在內核順利使用系統調用了!
3.Linux struct inode結構
/*索引節點對象由inode結構體表示,定義文件在linux/fs.h中
*/
struct inode {
struct hlist_node i_hash; /* 哈希表 */
struct list_head i_list; /* 索引節點鏈表 */
struct list_head i_dentry; /* 目錄項鏈表 */
unsigned long i_ino; /* 節點號 */
atomic_t i_count; /* 引用記數 */
umode_t i_mode; /* 訪問權限控制 */
unsigned int i_nlink; /* 硬鏈接數 */
uid_t i_uid; /* 使用者id */
gid_t i_gid; /* 使用者id組 */
kdev_t i_rdev; /* 實設備標識符 */
loff_t i_size; /* 以字節為單位的文件大小 */
struct timespec i_atime; /* 最后訪問時間 */
struct timespec i_mtime; /* 最后修改(modify)時間 */
struct timespec i_ctime; /* 最后改變(change)時間 */
unsigned int i_blkbits; /* 以位為單位的塊大小 */
unsigned long i_blksize; /* 以字節為單位的塊大小 */
unsigned long i_version; /* 版本號 */
unsigned long i_blocks; /* 文件的塊數 */
unsigned short i_bytes; /* 使用的字節數 */
spinlock_t i_lock; /* 自旋鎖 */
struct rw_semaphore i_alloc_sem; /* 索引節點信號量 */
struct inode_operations *i_op; /* 索引節點操作表 */
struct file_operations *i_fop; /* 默認的索引節點操作 */
struct super_block *i_sb; /* 相關的超級塊 */
struct file_lock *i_flock; /* 文件鎖鏈表 */
struct address_space *i_mapping; /* 相關的地址映射 */
struct address_space i_data; /* 設備地址映射 */
struct dquot *i_dquot[MAXQUOTAS]; /* 節點的磁盤限額 */
struct list_head i_devices; /* 塊設備鏈表 */
struct pipe_inode_info *i_pipe; /* 管道信息 */
struct block_device *i_bdev; /* 塊設備驅動 */
unsigned long i_dnotify_mask; /* 目錄通知掩碼 */
struct dnotify_struct *i_dnotify; /* 目錄通知 */
unsigned long i_state; /* 狀態標志 */
unsigned long dirtied_when; /* 首次修改時間 */
unsigned int i_flags; /* 文件系統標志 */
unsigned char i_sock; /* 可能是個套接字吧 */
atomic_t i_writecount; /* 寫者記數 */
void *i_security; /* 安全模塊 */
__u32 i_generation; /* 索引節點版本號 */
union {
void *generic_ip; /* 文件特殊信息 */
} u;
};
/*
*索引節點的操作inode_operations定義在linux/fs.h中
*/
struct inode_operations {
int (*create) (struct inode *, struct dentry *,int);
/*VFS通過系統調用create()和open()來調用該函數,從而為dentry對象創建一個新的索引節點。在創建時使用mode制定初始模式*/
struct dentry * (*lookup) (struct inode *, struct dentry *);
/*該韓式在特定目錄中尋找索引節點,該索引節點要對應于dentry中給出的文件名*/
int (*link) (struct dentry *, struct inode *, struct dentry *);
/*該函數被系統調用link()電泳,用來創建硬連接。硬鏈接名稱由dentry參數指定,連接對象是dir目錄中ld_dentry目錄想所代表的文件*/
int (*unlink) (struct inode *, struct dentry *);
/*該函數被系統調用unlink()調用,從目錄dir中刪除由目錄項dentry制動的索引節點對象*/
int (*symlink) (struct inode *, struct dentry *, const char *);
/*該函數被系統電泳symlik()調用,創建符號連接,該符號連接名稱由symname指定,連接對象是dir目錄中的dentry目錄項*/
int (*mkdir) (struct inode *, struct dentry *, int);
/*該函數被mkdir()調用,創建一個新魯姆。創建時使用mode制定的初始模式*/
int (*rmdir) (struct inode *, struct dentry *);
/*該函數被系統調用rmdir()調用,刪除dir目錄中的dentry目錄項代表的文件*/
int (*mknod) (struct inode *, struct dentry *, int, dev_t);
/*該函數被系統調用mknod()調用,創建特殊文件(設備文件、命名管道或套接字)。要創建的文件放在dir目錄中,其目錄項問dentry,關聯的設備為rdev,初始權限由mode指定*/
int (*rename) (struct inode *, struct dentry *,
struct inode *, struct dentry *);
/*VFS調用該函數來移動文件。文件源路徑在old_dir目錄中,源文件由old_dentry目錄項所指定,目標路徑在new_dir目錄中,目標文件由new_dentry指定*/
int (*readlink) (struct dentry *, char *, int);
/*該函數被系統調用readlink()調用,拷貝數據到特定的緩沖buffer中。拷貝的數據來自dentry指定的符號鏈接,最大拷貝大小可達到buflen字節*/
int (*follow_link) (struct dentry *, struct nameidata *);
/*該函數由VFS調用,從一個符號連接查找他指向的索引節點,由dentry指向的連接被解析*/
int (*put_link) (struct dentry *, struct nameidata *);
/*在follow_link()調用之后,該函數由vfs調用進行清楚工作*/
void (*truncate) (struct inode *);
/*該函數由VFS調用,修改文件的大小,在調用之前,索引節點的i_size項必須被設置成預期的大小*/
int (*permission) (struct inode *, int);
/*該函數用來檢查給低昂的inode所代表的文件是否允許特定的訪問模式,如果允許特定的訪問模式,返回0,否則返回負值的錯誤碼。多數文件系統 都將此區域設置為null,使用VFS提供的通用方法進行檢查,這種檢查操作僅僅比較索引及誒但對象中的訪問模式位是否和mask一致,比較復雜的系統, 比如支持訪問控制鏈(ACL)的文件系統,需要使用特殊的permission()方法*/
int (*setattr) (struct dentry *, struct iattr *);
/*該函數被notify_change調用,在修改索引節點之后,通知發生了改變事件*/
int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
/*在通知索引節點需要從磁盤中更新時,VFS會調用該函數*/
int (*setxattr) (struct dentry *, const char *,
const void *, size_t, int);
/*該函數由VFS調用,向dentry指定的文件設置擴展屬性,屬性名為name,值為value*/
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
/*該函數被VFS調用,向value中拷貝給定文件的擴展屬性name對應的數值*/
ssize_t (*listxattr) (struct dentry *, char *, size_t);
/*該函數將特定文件所有屬性別表拷貝到一個緩沖列表中*/
int (*removexattr) (struct dentry *, const char *);
/*該函數從給定文件中刪除指定的屬性*/
};
4.Linux struct file結構
struct file結構體定義在/linux/include/linux/fs.h(Linux 2.6.11內核)中,其原型是:
struct file {
/*
* fu_list becomes invalid after file_free is called and queued via
* fu_rcuhead for RCU freeing
*/
union {
struct list_head fu_list;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
#define f_dentry f_path.dentry
#define f_vfsmnt f_path.mnt
const struct file_operations *f_op;
atomic_t f_count;
unsigned int f_flags;
mode_t f_mode;
loff_t f_pos;
struct fown_struct f_owner;
unsigned int f_uid, f_gid;
struct file_ra_state f_ra;
unsigned long 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;
spinlock_t f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
};
文 件結構體代表一個打開的文件,系統中的每個打開的文件在內核空間都有一個關聯的struct file。它由內核在打開文件時創建,并傳遞給在文件上進行操作的任何函數。在文件的所有實例都關閉后,內核釋放這個數據結構。在內核創建和驅動源碼 中,struct file的指針通常被命名為file或filp。
到此,關于“linux有沒有內核文件操作函數”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。