现在的位置: 首页 > 综合 > 正文

“asm/semaphore.h: No such file or directory” Linux 2.6.36以后file_operations和DECLARE_MUTEX 和kmem_cache_create的变化

2013年05月30日 ⁄ 综合 ⁄ 共 9058字 ⁄ 字号 评论关闭

今天编译发现一个error: “asm/semaphore.h: No such file or directory” ,发现2.6.19和2.6.31对这个信号量声明并不相同

[patch] include linux/semaphore.h for kernel 2.6.26 and onwards

Description

The kernel/xpp/xpd.h includes <asm/semaphore.h>

As of Linux kernel version 2.6.26, the asm/semaphore.h has been deprecated, favoring an include of <linux/semaphore.h> instead.

When attempting to compile zaptel in Linux 2.6.27, as the current sources are, we get an error 'unable to include <asm/semaphore.h> (because it has been removed now)

This patch performs the check for Linux kernel version 2.6.26, if the version is before this, the existing #include <asm/semaphore.h> is still used,

but if Linux kernel version >= 2.6.26 is found, then #include <linux/semaphore.h> is used instead.

https://issues.asterisk.org/jira/browse/ZAP-353

一些参考文章:

声明一个信号量,使用DECLARE_MUTEX(ADC_LOCK)或DEFINE_SEMAPHORE(ADC_LOCK),这很好懂,但是这个宏到底做了些什么呢?这就要深入到这个宏定义所在文件中研究了(在<linux/semaphore.h>文件中)。

对于这两宏,想说几句,因为最近一次移植新版本的内核(2.6.37.3),就是因为DECLARE_MUTEX不再使用而导致我浪费了几天的时间。据本人考查,最早说要将DECLARE_MUTEX改为DEFINE_SEMAPHORE是在08年10月底,参见地址http://lwn.net/Articles/304725/。而在Linux Cross Reference(网站如http://lxr.free-electrons.com/等等)中发现,直到2.6.36才出现DEFINE_SEMAPHORE,而且这个版本中两个宏同时存在。但是到了2.6.37,DECLARE_MUTEX这个宏却不存在了。

不由得想到某个论坛的签名,原文是英文的,原文及出自一时不知道去哪找了。大意是说UNIX最好的地方是什么?答曰有社区,再问UNIX不好的地方是什么?答曰有太多的社区。像Linux内核这东西,版本更新太快了,各种结构体名称变化、成员变化及新增函数、删除函数,让人目不暇接。虽说一味追求新版本不好,但是心理作用,还是选择新的版本来移植。新的东西当然有它的好,像买台android的手机,就得不停的刷机,不断折腾,这跟搞Linux在某种程度上是一样的。

http://www.latelee.org/embedded-linux/127-mutil-channel-adc-of-s3c2410-write.html

http://71151461.cn/

Linux 2.6.36以后file_operations和DECLARE_MUTEX 和kmem_cache_create的变化

今天尝试在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); /*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.mnt
conststructfile_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_SECURITY
void*f_security;
#endif

void*private_data;

#ifdef CONFIG_EPOLL

structlist_headf_ep_links;
#endif
structaddress_space*f_mapping;
#ifdef CONFIG_DEBUG_WRITECOUNT
unsignedlongf_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 这个结构。

抱歉!评论已关闭.