前言
這是我在網上看到的關於檔案操作的文章的一個整理和集合,這是第一版。
主要參考:
其原文或有重複,或不妥當之處,均按我的理解在文中做了修改。
第一部分 檔案的結構
一,檔案的定義
struct file結構體定義在/linux/include/linux/fs.h(Linux 2.6.11 核心)中,其原型是:
722 /* 723 * fu_list becomes invalid after file_free is called and queued via 724 * fu_rcuhead for RCU freeing 725 */ 726 union { 727 struct list_head fu_list; 728 struct rcu_head fu_rcuhead; 729 } f_u; 730 struct path f_path; 731#define f_dentry f_path.dentry 732#define f_vfsmnt f_path.mnt 733 const struct file_operations *f_op; 734 atomic_t f_count; 735 unsigned int f_flags; 736 mode_t f_mode; 737 loff_t f_pos; 738 struct fown_struct f_owner; 739 unsigned int f_uid, f_gid; 740 struct file_ra_state f_ra; 741 742 unsigned long f_version; 743#ifdef CONFIG_SECURITY 744 void *f_security; 745#endif 746 /* needed for tty driver, and maybe others */ 747 void *private_data; 748 749#ifdef CONFIG_EPOLL 750 /* Used by fs/eventpoll.c to link all the hooks to this file */ 751 struct list_head f_ep_links; 752 spinlock_t f_ep_lock; 753#endif /* #ifdef CONFIG_EPOLL */ 754 struct address_space *f_mapping; |
二、作用:
檔案結構體代表一個開啟的檔案,系統中每個開啟的檔案在核心空間都有一個關聯的struct file。它由核心在開啟檔案時建立,並傳遞給在檔案上進行操作的任何函式。在檔案的所有例項都關閉後,核心釋放這個資料結構。在核心建立和驅動原始碼中,struct file的指標通常被命名為file或filp。
三、各個欄位詳解:
1、
union {
struct list_head fu_list;
struct rcu_head rcuhead;
}f_u;
其中的struct list_head定義在 linux/include/linux/list.h中,原型為:
union {
struct list_head fu_list;
struct rcu_head rcuhead;
}f_u;
其中的struct list_head定義在 linux/include/linux/list.h中,原型為:
list_head是核心中最常用的建立雙向迴圈連結串列的結構,在此用於通用檔案物件連結串列的指標。
struct rcu_head定義在linux/include/linux/rcupdate.h中,其原型為:
struct rcu_head定義在linux/include/linux/rcupdate.h中,其原型為:
在此用於更新檔案。fu_list在file_free()函式被呼叫以後就無效了,佇列通過rcu_head來釋放RCU。
2、struct path f_path;
被定義在linux/include/linux/namei.h中,其原型為:
2、struct path f_path;
被定義在linux/include/linux/namei.h中,其原型為:
在早些版本的核心中並沒有此結構,而是直接將path的兩個資料成員作為struct file的資料成員,
struct vfsmount *mnt的作用是指出該檔案的已安裝檔案系統,
struct dentry *dentry是與檔案相關的目錄項物件。
3、const struct file_operations *f_op;
被定義在linux/include/linux/fs.h中,其中包含著與檔案關聯的操作,如:
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
等。當開啟一個檔案時,核心就建立一個與該檔案相關聯的struct file結構,其中的*f_op就指向的是具體對該檔案進行操作的函式。例如使用者呼叫系統呼叫read來讀取該檔案的內容時,那麼系統呼叫read最終會陷入核心呼叫sys_read函式,而 sys_read最終會呼叫與該檔案關聯的struct file結構中的f_op->read函式對檔案內容進行讀取。
4、atomic_t f_count;
atomic_t被定義為:
typedef struct { volatile int counter; } atomic_t;
volatile修飾欄位告訴gcc不要對該型別的資料做優化處理,對它的訪問都是對記憶體的訪問,而不是對暫存器的訪問。本質是int型別,之所以這樣寫是讓編譯器對基於該型別變數的操作進行嚴格的型別檢查。此處f_count的作用是記錄對檔案物件的引用計數,也即當前有多少個使用CLONE_FILES標誌克隆的程式在使用該檔案。典型的應用是在POSIX執行緒中。就像在核心中普通的引用計數模組一樣,最後一個程式呼叫put_files_struct()來釋放檔案描述符。
5、unsigned int f_flags;
當開啟檔案時指定的標誌,對應系統呼叫open的int flags引數。驅動程式為了支援非阻塞型操作需要檢查這個標誌。
六、mode_t f_mode;
對檔案的讀寫模式,對應系統呼叫open的mod_t mode引數。如果驅動程式需要這個值,可以直接讀取這個欄位。
mod_t被定義為:
typedef unsigned int __kernel_mode_t;
typedef __kernel_mode_t mode_t;
7、loff_t f_pos;
當前的檔案指標位置,即檔案的讀寫位置。
loff_t被定義為:
typedef long long __kernel_loff_t;
typedef __kernel_loff_t loff_t;
8、struct fown_struct f_owner;
struct fown_struct在linux/include/linux/fs.h被定義,原型為:
struct vfsmount *mnt的作用是指出該檔案的已安裝檔案系統,
struct dentry *dentry是與檔案相關的目錄項物件。
3、const struct file_operations *f_op;
被定義在linux/include/linux/fs.h中,其中包含著與檔案關聯的操作,如:
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
等。當開啟一個檔案時,核心就建立一個與該檔案相關聯的struct file結構,其中的*f_op就指向的是具體對該檔案進行操作的函式。例如使用者呼叫系統呼叫read來讀取該檔案的內容時,那麼系統呼叫read最終會陷入核心呼叫sys_read函式,而 sys_read最終會呼叫與該檔案關聯的struct file結構中的f_op->read函式對檔案內容進行讀取。
4、atomic_t f_count;
atomic_t被定義為:
typedef struct { volatile int counter; } atomic_t;
volatile修飾欄位告訴gcc不要對該型別的資料做優化處理,對它的訪問都是對記憶體的訪問,而不是對暫存器的訪問。本質是int型別,之所以這樣寫是讓編譯器對基於該型別變數的操作進行嚴格的型別檢查。此處f_count的作用是記錄對檔案物件的引用計數,也即當前有多少個使用CLONE_FILES標誌克隆的程式在使用該檔案。典型的應用是在POSIX執行緒中。就像在核心中普通的引用計數模組一樣,最後一個程式呼叫put_files_struct()來釋放檔案描述符。
5、unsigned int f_flags;
當開啟檔案時指定的標誌,對應系統呼叫open的int flags引數。驅動程式為了支援非阻塞型操作需要檢查這個標誌。
六、mode_t f_mode;
對檔案的讀寫模式,對應系統呼叫open的mod_t mode引數。如果驅動程式需要這個值,可以直接讀取這個欄位。
mod_t被定義為:
typedef unsigned int __kernel_mode_t;
typedef __kernel_mode_t mode_t;
7、loff_t f_pos;
當前的檔案指標位置,即檔案的讀寫位置。
loff_t被定義為:
typedef long long __kernel_loff_t;
typedef __kernel_loff_t loff_t;
8、struct fown_struct f_owner;
struct fown_struct在linux/include/linux/fs.h被定義,原型為:
688struct fown_struct { 689 rwlock_t lock; /* protects pid, uid, euid fields */ 690 struct pid *pid; /* pid or -pgrp where SIGIO should be sent */ 691 enum pid_type pid_type;/*Kind of process group SIGIO should be sent to*/ 692 uid_t uid, euid; /* uid/euid of process setting the owner */ 693 int signum; /* posix.1b rt signal to be delivered on IO */ 694}; |
該結構的作用是通過訊號進行I/O時間通知的資料。
9、unsigned int f_uid, f_gid;
標識檔案的所有者id,所有者所在組的id.
10、struct file_ra_state f_ra;
struct file_ra_state結構被定義在/linux/include/linux/fs.h中,原型為:
9、unsigned int f_uid, f_gid;
標識檔案的所有者id,所有者所在組的id.
10、struct file_ra_state f_ra;
struct file_ra_state結構被定義在/linux/include/linux/fs.h中,原型為:
700 pgoff_t start; /* where readahead started */ 701 unsigned long size; /* # of readahead pages */ 702 unsigned long async_size; /* do asynchronous readahead when 703 there are only # of pages ahead */ 704 705 unsigned long ra_pages; /* Maximum readahead window */ 706 unsigned long mmap_hit; /* Cache hit stat for mmap accesses */ 707 unsigned long mmap_miss; /* Cache miss stat for mmap accesses */ 708 unsigned long prev_index; /* Cache last read() position */ 709 unsigned int prev_offset; /* Offset where last read() ended in a page */ |
檔案預讀狀態,檔案預讀演算法使用的主要資料結構,當開啟一個檔案時,f_ra中除了perv_page(預設為-1)和ra_apges(對該檔案允許的最大預讀量)這兩個欄位外,其他的所有字端都置為0。
11、unsigned long f_version;
記錄檔案的版本號,每次使用後都自動遞增。
12、
11、unsigned long f_version;
記錄檔案的版本號,每次使用後都自動遞增。
12、
#ifdef CONFIG_SECURITY
void *f_security;
#endif
此處我的理解是如果在編譯核心時配置了安全措施,那麼struct file結構中就會有void *f_security資料項,用來描述安全措施或者是記錄與安全有關的資訊。
13、void *private_data;
系統在呼叫驅動程式的open方法前將這個指標置為NULL。驅動程式可以將這個欄位用於任意目的,也可以忽略這個欄位。驅動程式可以用這個欄位指向已分配的資料,但是一定要在核心釋放file結構前的release方法中清除它。
14、
#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 */
被用在fs/eventpoll.c來連結所有鉤到這個檔案上。其中f_ep_links是檔案的事件輪詢等待者連結串列的頭,f_ep_lock是保護f_ep_links連結串列的自旋鎖。
15、struct address_space *f_mapping;
struct address_space被定義在/linux/include/linux/fs.h中,此處是指向檔案地址空間的指標。
四、應用:
在驅動開發中,檔案讀/寫模式mode、標誌f_flags都是裝置驅動關心的內容,而私有資料指標private_data在驅動中被廣泛使用,大多被指向裝置驅動自定義的用於描述裝置的結構體。驅動程式中常用如下類似的程式碼來檢測使用者開啟檔案的讀寫方式:
if (file->f_mode & FMODE_WRITE) //使用者要求可寫
{
}
if (file->f_mode & FMODE_READ) //使用者要求可讀
{
}
下面的程式碼可用於判斷以阻塞還是非阻塞方式開啟裝置檔案:
if (file->f_flags & O_NONBLOCK) //非阻塞
pr_debug(“open:non-blocking
“);
else //阻塞
pr_debug(“open:blocking
“);
void *f_security;
#endif
此處我的理解是如果在編譯核心時配置了安全措施,那麼struct file結構中就會有void *f_security資料項,用來描述安全措施或者是記錄與安全有關的資訊。
13、void *private_data;
系統在呼叫驅動程式的open方法前將這個指標置為NULL。驅動程式可以將這個欄位用於任意目的,也可以忽略這個欄位。驅動程式可以用這個欄位指向已分配的資料,但是一定要在核心釋放file結構前的release方法中清除它。
14、
#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 */
被用在fs/eventpoll.c來連結所有鉤到這個檔案上。其中f_ep_links是檔案的事件輪詢等待者連結串列的頭,f_ep_lock是保護f_ep_links連結串列的自旋鎖。
15、struct address_space *f_mapping;
struct address_space被定義在/linux/include/linux/fs.h中,此處是指向檔案地址空間的指標。
四、應用:
在驅動開發中,檔案讀/寫模式mode、標誌f_flags都是裝置驅動關心的內容,而私有資料指標private_data在驅動中被廣泛使用,大多被指向裝置驅動自定義的用於描述裝置的結構體。驅動程式中常用如下類似的程式碼來檢測使用者開啟檔案的讀寫方式:
if (file->f_mode & FMODE_WRITE) //使用者要求可寫
{
}
if (file->f_mode & FMODE_READ) //使用者要求可讀
{
}
下面的程式碼可用於判斷以阻塞還是非阻塞方式開啟裝置檔案:
if (file->f_flags & O_NONBLOCK) //非阻塞
pr_debug(“open:non-blocking
“);
else //阻塞
pr_debug(“open:blocking
“);