Linux 2.6.36以後file_operationsDECLARE_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


 


2usb_buffer_alloc  usb_buffer_free 


linux2.6.34和之前的代碼中還可以使用usb_buffer_alloc usb_buffer_free 這兩個函數,在2.6.35和之後的內核中
usb_buffer_alloc
usb_buffer_free這兩個函數已不在使用了,可以用usb_alloc_coherent usb_free_coherent代替。


 


3 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_ioctlioctl的函數原型並不一致。


 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 = iminor(file->f_path.dentry->d_inode); /* Which Channel*/


   .....


}


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


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 定義在庫中,它永遠不會出現在內核代碼中。

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_NONBLOCKO_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 這個結構。


 http://hi.baidu.com/kkernel/item/ea0ae8f4abb46929743c4c96

    全站熱搜

    立你斯 發表在 痞客邦 留言(0) 人氣()