Linux 2.6.36以后file_operations…
2013-12-19 20:38
225 查看
今天尝试在2.6.39内核上编译一个驱动,
在编译驱动时发现从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
在运行时初始化得变化(动态分配):
以去除:
void init_MUTEX(struct
semaphore *sem);
void init_MUTEX_LOCKED(struct
semaphore *sem);
可通过以下初始:
void sema_init(struct semaphore
*sem, int val);
2,后备缓存:include/linux/slab.h
kmem_cache_t 类型已改为:
struct kmem_cache
创建缓存对象函数
kmem_cache_t *kmem_cache_create(const
char *name, size_t size,
size_t offset,
unsigned long flags,
void (*constructor)(void *, kmem_cache_t *,
unsigned long flags), void (*destructor)(void *, kmem_cache_t *,
unsigned long flags));
已改为(参数少了一个,返回值内型变化):
struct kmem_cache *kmem_cache_create(const
char *name, size_t size,
size_t offset,
unsigned long flags,
void (*)(void ));
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);
.....
}
--------------------------------------
在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 这个结构。
在编译驱动时发现从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
在运行时初始化得变化(动态分配):
以去除:
void init_MUTEX(struct
semaphore *sem);
void init_MUTEX_LOCKED(struct
semaphore *sem);
可通过以下初始:
void sema_init(struct semaphore
*sem, int val);
2,后备缓存:include/linux/slab.h
kmem_cache_t 类型已改为:
struct kmem_cache
创建缓存对象函数
kmem_cache_t *kmem_cache_create(const
char *name, size_t size,
size_t offset,
unsigned long flags,
void (*constructor)(void *, kmem_cache_t *,
unsigned long flags), void (*destructor)(void *, kmem_cache_t *,
unsigned long flags));
已改为(参数少了一个,返回值内型变化):
struct kmem_cache *kmem_cache_create(const
char *name, size_t size,
size_t offset,
unsigned long flags,
void (*)(void ));
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);
.....
}
--------------------------------------
在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 这个结构。
相关文章推荐
- Linux&nbsp;2.6.36以后file_operations…
- Linux: File not found by glob
- Linux 2.6.36以后file_operations和DECLARE_MUTEX 的变化
- Linux 2.6.36以后file_operations和DECLARE_MUTEX 的变化
- Linux 2.6.36以后file_operations和DECLARE_MUTEX 的变化
- Linux 2.6.36以后file_operations和DECLARE_MUTEX 和kmem_cache_create的变化
- Linux&nbsp;bash和profile比较
- linux centos7 编译安装mysql 5.6
- linux&nbsp;下myls实现
- Arm&nbsp;linux&nbsp;启动流程
- Arm&nbsp;linux启动分析(4)
- linux&nbsp;loop&nbsp;device介绍&nbsp;(转…
- Linux&nbsp;IIC驱动笔记
- Linux&nbsp;内核的排队自旋锁(FIFO&nbsp;Tick…
- linux 基础知识测试
- Linux(ubuntu)+gcc/g++&nbsp;升级
- unix/linux&nbsp;删除特殊字符的文件
- Linux shell脚本全面学习
- linux 配置jdk环境变量
- linux c 的错误判断与陷阱