open系统调用在内核中的流程分析

发布时间:   来源:文档文库   
字号:
一)驱动注册open函数都干了些什么?
register_chrdev->cdev_add->kobj_map
file:fs/char_dev.c
intregister_chrdev(unsignedintmajor,constchar*name,conststructfile_operations*fops{
structchar_device_struct*cd;structcdev*cdev;char*s;
interr=-ENOMEM;
cd=__register_chrdev_region(major,0,256,name;if(IS_ERR(cd
returnPTR_ERR(cd;
cdev=cdev_alloc(;if(!cdevgotoout2;
cdev->owner=fops->owner;
cdev->ops=fops;//注意,在后面的chrdev_open会从cdev再得到fops...}
file:fs/char_dev.c
intcdev_add(structcdev*p,dev_tdev,unsignedcount{
p->dev=dev;p->count=count;
returnkobj_map(cdev_map,dev,count,NULL,exact_match,exact_lock,p;}
file:fs/char_dev.c
staticstructkobject*exact_match(dev_tdev,int*part,void*data{
structcdev*p=data;return&p->kobj;}
file:drivers/base/map.c
intkobj_map(structkobj_map*domain,dev_tdev,unsignedlongrange,structmodule*module,kobj_probe_t*probe,int(*lock(dev_t,void*,void*data{
unsignedn=MAJOR(dev+range-1-MAJOR(dev+1;unsignedindex=MAJOR(dev;

unsignedi;structprobe*p;
if(n>255n=255;
p=kmalloc(sizeof(structprobe*n,GFP_KERNEL;
if(p==NULLreturn-ENOMEM;
for(i=0;ip->owner=module;
p->get=probe;//此处其实就是exact_matchp->lock=lock;p->dev=dev;p->range=range;p->data=data;}
mutex_lock(domain->lock;
for(i=0,p-=n;i
structprobe**s=&domain->probes[index%255];while(*s&&(*s->ranges=&(*s->next;p->next=*s;*s=p;}
mutex_unlock(domain->lock;return0;}
【参考UnderstandingTheLinuxKernel13.5.CharacterDeviceDrivers
Thedevicedrivermodeldefinesakobjectmappingdomainforthecharacterdevices,whichisrepresentedbyadescriptoroftypekobj_mapandisreferencedbythecdev_mapglobalvariable.Thekobj_mapdescriptorincludesahashtableof255entriesindexedbythemajornumberoftheintervals.Thehashtablestoresobjectsoftypeprobe,oneforeachregisteredrangeofmajorandminornumbers,whosefieldsarelistedinTable13-9.
Whenthekobj_map(functionisinvoked,thespecifiedintervalofdevicenumbersisaddedtothehashtable.Thedatafieldofthecorrespondingprobeobjectpointstothecdevdescriptorofthedevicedriver.Thevalueofthisfieldispassedtothegetandlockmethodswhentheyareexecuted.Inthiscase,thegetmethodisimplementedbyashortfunctionthatreturnstheaddressofthekobjectembeddedinthecdevdescriptor;thelockmethod,instead,essentiallyincreasesthereferencecounterintheembeddedkobject.
Thekobj_lookup(functionreceivesasinputparametersakobjectmappingdomainandadevicenumber;itsearchesthehashtableandreturnstheaddressofthekobjectoftheowneroftheintervalincludingthenumber,ifitwasfound.Whenappliedtothemappingdomainofthecharacterdevices,thefunctionreturns

theaddressofthekobjectembeddedinthecdevdescriptorofthedevicedriverthatownstheintervalofdevicenumbers.
二)从系统调用往内核走,看当初驱动里注册的file_operations里的open函数怎么被调用的sys_open->do_sys_open->do_filp_open->nameidata_to_filp->__dentry_open
问题是1__dentry_open如何找到chrdev_open?
2)最终又是如何调用file_operations里的在驱动里面注册的open函数的呢?staticstructfile*__dentry_open(structdentry*dentry,structvfsmount*mnt,intflags,structfile*f,
int(*open(structinode*,structfile*{
structinode*inode;interror;
f->f_flags=flags;
f->f_mode=((flags+1&O_ACCMODE|FMODE_LSEEK|FMODE_PREAD|FMODE_PWRITE;inode=dentry->d_inode;
if(f->f_mode&FMODE_WRITE{
error=__get_file_write_access(inode,mnt;if(error
gotocleanup_file;
if(!special_file(inode->i_modefile_take_write(f;}
f->f_mapping=inode->i_mapping;f->f_path.dentry=dentry;f->f_path.mnt=mnt;f->f_pos=0;
f->f_op=fops_get(inode->i_fop;//此处获得def_chr_fopsfile_move(f,&inode->i_sb->s_files;
error=security_dentry_open(f;if(error
gotocleanup_all;
if(!open&&f->f_op
open=f->f_op->open;//此处调用def_chr_fops里的open函数,即chrdev_open...}
file:fs/char_dev.cchrdev_open({

structcdev*p;
structcdev*new=NULL;intret=0;
spin_lock(&cdev_lock;p=inode->i_cdev;if(!p{
structkobject*kobj;intidx;
spin_unlock(&cdev_lock;
kobj=kobj_lookup(cdev_map,inode->i_rdev,&idx;//找到cdev对应的kobj对象,kobj_map相对应的,反操作if(!kobj
return-ENXIO;
new=container_of(kobj,structcdev,kobj;//找到cdevspin_lock(&cdev_lock;p=inode->i_cdev;if(!p{
inode->i_cdev=p=new;inode->i_cindex=idx;
list_add(&inode->i_devices,&p->list;new=NULL;
}elseif(!cdev_get(pret=-ENXIO;
}elseif(!cdev_get(pret=-ENXIO;
spin_unlock(&cdev_lock;cdev_put(new;if(retreturnret;
filp->f_op=fops_get(p->ops;//这里又找回了当初驱动注册时的file_operations指针if(!filp->f_op{cdev_put(p;return-ENXIO;}
if(filp->f_op->open{lock_kernel(;
ret=filp->f_op->open(inode,filp;//此处算真正的调用了file_operations里的open函数unlock_kernel(;}...}
file:drivers/base/map.c
structkobject*kobj_lookup(structkobj_map*domain,dev_tdev,int*index{
structkobject*kobj;structprobe*p;

unsignedlongbest=~0UL;
retry:
mutex_lock(domain->lock;
for(p=domain->probes[MAJOR(dev%255];p;p=p->next{structkobject*(*probe(dev_t,int*,void*;structmodule*owner;void*data;
if(p->dev>dev||p->dev+p->range-1continue;
if(p->range-1>=bestbreak;
if(!try_module_get(p->ownercontinue;
owner=p->owner;data=p->data;
probe=p->get;//这里其实就是exact_match函数了best=p->range-1;*index=dev-p->dev;
if(p->lock&&p->lock(dev,data<0{module_put(owner;continue;}
mutex_unlock(domain->lock;
kobj=probe(dev,index,data;//这里调用了exact_match函数/*Currently->ownerprotects_only_->probe(itself.*/module_put(owner;if(kobjreturnkobj;gotoretry;}
mutex_unlock(domain->lock;returnNULL;}
【参考UnderstandingTheLinuxKernel13.5.2.AccessingaCharacterDeviceDriver
Wementionedintheearliersection"VFSHandlingofDeviceFiles"thatthedentry_open(functiontriggeredbytheopen(systemcallserviceroutinecustomizesthef_opfieldinthefileobjectofthecharacterdevicefilesothatitpointstothedef_chr_fopstable.Thistableisalmostempty;itonlydefinesthechrdev_open(functionastheopenmethodofthedevicefile.Thismethodisimmediatelyinvokedbydentry_open(.
三)什么时候为字符设备设置的def_chr_fops?
这个跟具体的文件系统有关系的。
现在/dev/下的设备节点都是通过udev动态创建的,udev会去调用mknod(假定是ext2,内核会调

ext2_mknod
如果是char设备,会把def_chr_fops附给inode->i_fop,而ext2_mknod会调用init_special_inode(函数
的部分实现如下:
file:fs/ext2/namei.c
staticintext2_mknod(structinode*dir,structdentry*dentry,intmode,dev_trdev{
structinode*inode;interr;
if(!new_valid_dev(rdevreturn-EINVAL;
inode=ext2_new_inode(dir,mode;err=PTR_ERR(inode;if(!IS_ERR(inode{
init_special_inode(inode,inode->i_mode,rdev;//调用init_special_inode
file:fs/inode.c
voidinit_special_inode(structinode*inode,umode_tmode,dev_trdev{
inode->i_mode=mode;if(S_ISCHR(mode{
inode->i_fop=&def_chr_fops;//这里为char设备设置的缺省操作inode->i_rdev=rdev;}...}
file:fs/char_dev.c
conststructfile_operationsdef_chr_fops={.open=chrdev_open,};
字符设备(chardevice
使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops注册字符设备驱动程序时,如果有多个设备使用该函数注册驱动程序,LED_MAJOR不能相同,否则几个设备都无法注册(我已验证如果模块使用该方式注册并且LED_MAJOR0(自动分配主设备号使用insmod命令加载模块时会在终端显示分配的主设备号和次设备号,在/dev目录下建立该节点,比如设备leds,如果加载该模块时分配的主设备号和次设备号为2530,则建立节点:mknodledsc2530。使用
register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops注册字符设备驱动程序时都要手动建

立节点,否则在应用程序无法打开该设备。
杂项设备(miscdevice
杂项设备也是在嵌入式系统中用得比较多的一种设备驱动。在Linux内核的
include\linux\miscdevice.h文件,要把自己定义的miscdevice从设备定义在这里。其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主设备号10一起归于miscdevice其实misc_register就是用主设备号10调用register_chrdev(的。也就是说,misc设备其实也就是特殊的字符设备。
misc_device是特殊的字符设备。注册驱动程序时采用misc_register函数注册,此函数中会自动创建设备节点,即设备文件。无需mknod指令创建设备文件。因为misc_register(会调用class_device_create(或者device_create(

本文来源:https://www.2haoxitong.net/k/doc/9ae2b400cc17552707220827.html

《open系统调用在内核中的流程分析.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式