Linux 2.6.36以后file

今天尝试移植了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 athttp://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>中,完整如下:

引用

structfile{union{structlist_headfu_list;structrcu_headfu_rcuhead;}f_u;structpathf_path;#definef_dentry f_path.dentry#definef_vfsmnt f_path.mntconststructfile_operations*f_op;spinlock_tf_lock;atomic_long_tf_count;unsignedintf_flags;fmode_tf_mode;loff_tf_pos;structfown_structf_owner;conststructcred*f_cred;structfile_ra_statef_ra;u64f_version;#ifdef CONFIG_SECURITYvoid*f_security;#endifvoid*private_data;#ifdef CONFIG_EPOLLstructlist_headf_ep_links;#endifstructaddress_space*f_mapping;#ifdef CONFIG_DEBUG_WRITECOUNTunsignedlongf_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这个结构。

片的时光如浮云般流过,我们的青春单薄的穿梭在蓝天之上。

Linux 2.6.36以后file

相关文章:

你感兴趣的文章:

标签云: