在學習字符設備驅動的開始,我們必須了解的是三個很重要的數據結構,他們分別是file_operations、inode、file。下面陶毛毛同學就和大家一起來學習這三個數據結構。
struct _file_operations在Fs.h這個文件里面被定義的,如下所示:
struct file_operations {
struct module *owner;//擁有該結構的模塊的指針,一般為THIS_MODULES
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 *);//向設備發送數據ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一個異步的讀取操作
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);//初始化一個異步的寫入操作
int (*readdir) (struct file *, void *, filldir_t);//僅用於讀取目錄,對於設備文件,該字段為NULL
unsigned int (*poll) (struct file *, struct poll_table_struct *); //輪詢函數,判斷目前是否可以進行非阻塞的讀寫或寫入
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); //執行設備I/O控制命令
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); //不使用BLK文件系統,將使用此種函數指針代替ioctl
long (*compat_ioctl) (struct file *, unsigned int, unsigned long); //在64位系統上,32位的ioctl調用將使用此函數指針代替
int (*mmap) (struct file *, struct vm_area_struct *); //用於請求將設備內存映射到進程地址空間
int (*open) (struct inode *, struct file *); //打開
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *); //關閉
int (*fsync) (struct file *, struct dentry *, int datasync); //刷新待處理的數據
int (*aio_fsync) (struct kiocb *, int datasync); //異步刷新待處理的數據
int (*fasync) (int, struct file *, int); //通知設備FASYNC標志發生變化
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
};Linux使用file_operations結構訪問驅動程序的函數,這個結構的每一個成員的名字都對應着一個調用。用戶進程利用在對設備文件進行諸如read/write操作的時候,系統調用通過設備文件的主設備號找到相應的設備驅動程序,然后讀取這個數據結構相應的函數指針,接着把控制權交給該函數,這是Linux的設備驅動程序工作的基本原理。
下面是struct inode結構體。
struct inode {
struct hlist_node i_hash; //哈希表
struct list_head i_list; //索引節點鏈表
struct list_head i_sb_list;//目錄項鏈表
struct list_head i_dentry;
unsigned long i_ino; //節點號
atomic_t i_count; //引用記數
unsigned int i_nlink; //硬鏈接數
uid_t i_uid; /*使用者id */
gid_t i_gid; /*使用者id組*/
dev_t i_rdev; //該成員表示設備文件的inode結構,它包含了真正的設備編號。
u64 i_version;
loff_t i_size; /*inode多代表的文件的大小*/
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
struct timespec i_atime; /*inode最后一次存取的時間*/
struct timespec i_mtime; /*inode最后一次修改的時間*/
struct timespec i_ctime; /*inode的創建時間*/
unsigned int i_blkbits; /*inode在做I/O時的區塊大小*/
blkcnt_t i_blocks; /*inode所石油的block塊數*/
unsigned short i_bytes;
umode_t i_mode; /*inode的權限*/
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
struct mutex i_mutex;
struct rw_semaphore i_alloc_sem;
const struct inode_operations *i_op;
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
struct super_block *i_sb;
struct file_lock *i_flock;
struct address_space *i_mapping;
struct address_space i_data;
#ifdef CONFIG_QUOTA
struct dquot *i_dquot[MAXQUOTAS];
#endif
struct list_head i_devices; /*若是字符設備,為其對應的cdev結構體指針*/
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev; /*若是塊設備,為其對應的cdev結構體指針*/
struct cdev *i_cdev; //該成員表示字符設備的內核的 內部結構。當inode指向一個字符設備文件時,該成員包含了指向struct cdev結構的指針,其中cdev結構是字符設備結構體。
};
int i_cindex;
__u32 i_generation;
#ifdef CONFIG_DNOTIFY
unsigned long i_dnotify_mask; /* Directory notify events */
struct dnotify_struct *i_dnotify; /* for directory notifications */
#endif
#ifdef CONFIG_INOTIFY
struct list_head inotify_watches; /* watches on this inode */
struct mutex inotify_mutex; /* protects the watches list */
#endif
unsigned long i_state;
unsigned long dirtied_when; /* jiffies of first dirtying */
unsigned int i_flags;
atomic_t i_writecount;
#ifdef CONFIG_SECURITY
void *i_security;
#endif
void *i_private; /* fs or device private pointer */
};
內核中用inode結構表示具體的文件,也就是對應與硬盤上面具體的文件。提供了設備文件的信息。inode譯成中文就是索引節點。每個存儲設備或存儲設備的分區(存儲設備是硬盤、軟盤、U盤 ... ... )被格式化為文件系統后,應該有兩部份,一部份是inode,另一部份是Block,Block是用來存儲數據用的。而inode呢,就是用來存儲這些數據的信息,這些信息包括文件大小、屬主、歸屬的用戶組、讀寫權限等。inode為每個文件進行信息索引,所以就有了inode的數值。操作系統根據指令,能通過inode值最快的找到相對應的文件。
最后是struct file。
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; //該操作 是定義文件關聯的操作的。內核在執行open時對這個指針賦值。
atomic_long_t f_count;//文件的引用計數(有多少進程打開該文件)
unsigned int f_flags; //該成員是文件標志。
mode_t f_mode;//讀寫模式:open的mod_t mode參數
loff_t f_pos;//該文件在當前進程中的文件偏移量
struct fown_struct f_owner;//該結構的作用是通過信號進行I/O時間通知的數據
unsigned int f_uid, f_gid;//文件所有者id,所有者組id
struct file_ra_state f_ra;
u64 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;
#ifdef CONFIG_DEBUG_WRITECOUNT
unsigned long f_mnt_write_state;
#endif
};
文件結構代表一個打開的文件描述符,它不是專門給驅動程序使用的,系統中每一個打開的文件在內核中都有一個關聯的struct file。它由內核在open時創建,並傳遞給在文件上操作的任何函數,知道最后關閉。當文件的所有實例都關閉之后,內核釋放這個數據結構。
最后:總結一下,struct operations存在於設備驅動程序內部,起着聯系應用程序和設備驅動的作用。struct inode存在於磁盤上,作為描述設備驅動文件的信息的作用。struct file是在執行open函數時產生的,每打開一個文件就產生一個struct file,供設備驅動關聯的函數使用。