Linux 2.6.36以後file_operations和DECLARE_MUTEX 的變化

今天嘗試移植了2.6.38的內核到AT91SAM9260上,在編譯驅動時發現從2.6.36的內核開始,include/linux/semaphore.h 和 include/linux/fs.h中有了兩處變化與驅動相關:

1, 在include/linux/semaphore.h 中

將#define DECLARE_MUTEX(name)   改成了 #define DEFINE_SEMAPHORE(name) 

 

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)

DECLARE_MUTEX(led_sem);

#else

DEFINE_SEMAPHORE(led_sem);

#endif

 

2, file_operations結構體有了一些變化,它去掉了:

  int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

另外添加了:

    long (*fallocate)(struct file *file, int mode, loff_t offset,loff_t len);


這是2.6.36的內核裏的定義include/linux/fs.h:

struct file_operations {

    struct module *owner;

    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);

    unsigned int (*poll) (struct file *, struct poll_table_struct *);

  //從2.6.36開始刪除ioctl(), 2.6.35中有

    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

    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 *, int datasync);

    int (*aio_fsync) (struct kiocb *, int datasync);

    int (*fasync) (int, struct file *, int);

    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 **);

//    long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len);  從2.6.38內核開始添加該項,2.6.37以下無

};


下面是Linux-2.6.35裏的file_operations

struct file_operations {

    struct module *owner;

    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);

    unsigned int (*poll) (struct file *, struct poll_table_struct *);

    int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

    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);

    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 **);

};


[guowenxue@localhost at91sam9260]$ make

make[1]: Entering directory `/usr/.devices_group/guowenxue/l350-dev06/src/kernel/linux-2.6.38'

  CC [M]  /usr/.devices_group/guowenxue/embedded_project/drivers/at91sam9260/dev_skeleton.o

/usr/.devices_group/guowenxue/embedded_project/drivers/at91sam9260/dev_skeleton.c:93: error: unknown field 'ioctl' specified in initializer

/usr/.devices_group/guowenxue/embedded_project/drivers/at91sam9260/dev_skeleton.c:93: warning: initialization from incompatible pointer type

make[2]: *** [/usr/.devices_group/guowenxue/embedded_project/drivers/at91sam9260/dev_skeleton.o] Error 1

make[1]: *** [_module_/usr/.devices_group/guowenxue/embedded_project/drivers/at91sam9260] Error 2

make[1]: Leaving directory `/usr/.devices_group/guowenxue/l350-dev06/src/kernel/linux-2.6.38'

make: *** [modules] Error 2


參考別的字符設備的驅動drivers/char/ppdev.c:

static const struct file_operations pp_fops = {

    .owner      = THIS_MODULE,

    .llseek     = no_llseek,

    .read       = pp_read,

    .write      = pp_write,

    .poll       = pp_poll,

    .unlocked_ioctl = pp_ioctl,

    .open       = pp_open,

    .release    = pp_release,

};

這裏ioctl()已使用unlocked_ioctl代替。


但這裏不是一個簡單的替換,要注意unlocked_ioctl和ioctl的函數原型並不一致。

 unlocked_ioctl:  long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

               ioctl: int(*ioctl) (struct inode *,struct file *, unsigned int, unsigned long);

    The 'inode' value that was passed to 'ioctl' function is available for use with the 'unlocked_ioctl' function by way of filp->d_entry->d_inode:

    long (*unlocked_ioctl) (struct file *filp, unsigned int cmd, unsigned long arg);
    ...
    struct inode *inode = filp->f_path.dentry->d_inode

There is a nice explanation of this at http://lwn.net/Articles/119652/


如:

static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

{

    int  index = NUM(file->f_path.dentry->d_inode->i_rdev); /*Which LED*/

   .....

}

--------------------------------------

在file_operations 結構體中,會看到許多函數指針所指向的函數都必須傳進struct file 結構體指針struct file * 作爲參數。struct file 結構體定義在<linux/fs.h> 中,完整如下:

引用

struct file {
       
        union {
               struct list_head        fu_list;
               struct rcu_head        fu_rcuhead;
        } f_u;
        struct path             f_path;
#definef_dentry        f_path.dentry
#definef_vfsmnt        f_path.mnt
        const struct file_operations    *f_op;
        spinlock_t             f_lock;
        atomic_long_t           f_count;
        unsigned int           f_flags;
        fmode_t                f_mode;
        loff_t                 f_pos;
        struct fown_struct      f_owner;
        const struct cred       *f_cred;
        struct file_ra_state    f_ra;

        u64                    f_version;
#ifdef CONFIG_SECURITY
        void                   *f_security;
#endif
       
        void                   *private_data;

#ifdef CONFIG_EPOLL
       
        struct list_head        f_ep_links;
#endif
        struct address_space    *f_mapping;
#ifdef CONFIG_DEBUG_WRITECOUNT
        unsigned long f_mnt_write_state;
#endif
};


在設備驅動中,struct file 結構體也是一個非常重要的數據結構。注意的是,這裏的file 和應用程序中的FILE 流指針沒有什麼關係,FILE 定義在C 庫中,它永遠不會出現在內核代碼中。

file structure 結構代表一個打開的文件(open file).(打開的文件並沒有確切的指定到哪個設備驅動,實際上每個打開的文件都與內核空間中的struct file 結構相關聯)。

file structure 結構在調用open 打開一個文件時由內核創建,並會被傳遞給任一個對這個打開文件進行操作的函數;當所有事情都做完後,會調用close() 關閉掉文件,此時內核釋放這個數據結構。

一般地,在內核源碼中,struct file 結構體的指針往往寫成filp 。

struct file 中的幾個重要成員

mode_t f_mode;
文件模式根據FMMODE_READ 和FMODE_WRITE 位來識別文件是否可讀或可寫,或是可讀可寫。在read() 和write() 系統調用中,沒有必要對此權限進行檢查,因爲內核已經在你的系統調用之前已經做了檢查。如果文件沒有相應的讀或寫權限,那麼如果嘗試讀寫都將被拒絕,驅動程序甚至對此情況毫無知覺。

loff_t f_pos;
此變量表示當前的文件讀寫位置。loff_t 在所有的平臺上都是64 位的變量( long long 型, gcc 專用術語)。驅動程序如果想知道當前在文件中所處位置,那麼可以通過讀取此變量得知,但是一般地不應直接對此進行更改。通過llseek() 方法可以改變文件位置。

unsigned int f_flags;
這是表示如O_RDONLY, O_NONBLOCK與O_SYNC 這樣的標誌。一個驅動程序應該檢查O_NONBLOCK 標誌,以查看是否有非阻塞操作的請求。其它的標誌用得比較少。需要注意的是,檢查read/write 權限應該是通過檢查f_mode 得到而不是f_flags 。所有的標誌定義在頭文件linux/fcntl.h 中可以看到。

struct file_operations*f_op;
內核安排這個指針作爲它的open 實現的一部分,當需要分派什麼操作時,會讀取它。filp->f_op 因爲不會被內核保存起來以在其後之用,所以我們可以改變我們對相關文件的操作,在對文件使用新的操作方法時,我們就會轉移到相應調用上。

void *private_data;
在對驅動調用open 方法之前,open() 系統調用會這個指針設置爲NULL 。用戶可以自由使用這個域,或者對其忽略。可以使用這個域之想分配的數據空間,但必須記得在內核銷燬file structure 之前在release 方法裏釋放掉原來分配的內存。private_data 對於系統調用之間信息的保存會顯得非常有用。

struct dentry*f_dentry;
目錄入口(dentry) 結構與文件相關。一般的,除了在以filp->f_dentry->d_inode 來訪問inode 結構時,我們不太關心dentry 這個結構。

發佈了18 篇原創文章 · 獲贊 10 · 訪問量 32萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章