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。

? 版權聲明
THE END
喜歡就支持一下吧
點贊11 分享