2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > Linux文件系统(七)---系统调用之open操作(一)

Linux文件系统(七)---系统调用之open操作(一)

时间:2022-06-22 21:20:17

相关推荐

Linux文件系统(七)---系统调用之open操作(一)

(内核2.4.37)

一、

当我们打开一个文件的时候,需要获得文件的文件描述符(前面已经说过其实就是文件数组下标),一般是通过函数open来完成,这个系统调用在<unistd.h>头文件中声明定义,我们看一下源码:

[cpp]view plaincopyprint?530staticinlinelongopen(constchar*name,intmode,intflags) 531{ 532returnsys_open(name,mode,flags); 533}

Ps:对于这些参数一般我们都很熟悉,经常使用,这里顺便提出记忆一下:

mode:参数可选:

[cpp]view plaincopyprint?32#defineS_IRWXU00700文件所有者可读可写可执行 33#defineS_IRUSR00400文件所有者可读 34#defineS_IWUSR00200文件所有者可写 35#defineS_IXUSR00100文件所有者可执行 36 37#defineS_IRWXG00070文件用户组可写可读可执行 38#defineS_IRGRP00040文件用户组可读 39#defineS_IWGRP00020文件用户组可写 40#defineS_IXGRP00010文件用户组可执行 41 42#defineS_IRWXO00007其他用户可写可读可执行 43#defineS_IROTH00004其他用户可读 44#defineS_IWOTH00002其他用户可写 45#defineS_IXOTH00001其他用户可执行

flags:在fcntl.h中定义

[cpp]view plaincopyprint?7#defineO_RDONLY00 8#defineO_WRONLY01 9#defineO_RDWR02 10#defineO_CREAT0100/*notfcntl*/ 11#defineO_EXCL0200/*notfcntl*/ 12#defineO_NOCTTY0400/*notfcntl*/ 13#defineO_TRUNC01000/*notfcntl*/ 14#defineO_APPEND02000 15#defineO_NONBLOCK04000 16#defineO_NDELAYO_NONBLOCK 17#defineO_SYNC010000 18#defineFASYNC020000/*fcntl,forBSDcompatibility*/ 19#defineO_DIRECT040000/*directdiskaccesshint*/ 20#defineO_LARGEFILE0100000 21#defineO_DIRECTORY0200000/*mustbeadirectory*/ 22#defineO_NOFOLLOW0400000/*don'tfollowlinks*/ O_RDONLY以只读方式打开文件

O_WRONLY以只写方式打开文件

O_RDWR 以读和写的方式打开文件

上面三个只能选择一个,下面的可以合理的任意组合:

O_CREAT 打开文件,如果文件不存在则建立文件

O_EXCL 如果已经置O_CREAT且文件存在,则强制open()失败

O_TRUNC 将文件的长度截为0

O_APPEND强制write()从文件尾开始

对于终端文件,上面四个是无效,提供了两个新的标志:

O_NOCTTY停止这个终端作为控制终端

O_NONBLOCK 使open()、read()、write()不被阻塞。

我们可以看到,里面实际调用的是sys_open这个系统调用,其实想想也很正常,对于我的一个系统而言,可以存在很多组不同的文件系统,对于不同的文件系统,打开文件的方式肯定是不一样的,所有内核需要根据具体的文件系统的类型去调用不同的函数进行执行。现在看看sys_open函数(fs/open.c中):[cpp]view plaincopyprint?800asmlinkagelongsys_open(constchar*filename,intflags,intmode) 801{ 802char*tmp; 803intfd,error; 804 805#ifBITS_PER_LONG!=32 806flags|=O_LARGEFILE; 807#endif 808tmp=getname(filename);/*1*/ 809fd=PTR_ERR(tmp); 810if(!IS_ERR(tmp)){ 811fd=get_unused_fd();/*2*/ 812if(fd>=0){ 813structfile*f=filp_open(tmp,flags,mode);/*3*/ 814error=PTR_ERR(f); 815if(IS_ERR(f)) 816gotoout_error; 817fd_install(fd,f);/*4*/ 818} 819out: 820putname(tmp); 821} 822returnfd; 823 824out_error: 825put_unused_fd(fd); 826fd=error; 827gotoout; 828}

主要看上面注释表示的四大步骤/* 1 */ /* 2 */ /* 3 */ /* 4 */

/* 1 */:这步是一个辅助步骤,将filename从用户态拷贝到内核态变量中。基本步骤涉及一下几个函数:

[cpp]view plaincopyprint?125char*getname(constchar*filename) 126{ 127char*tmp,*result; 128 129result=ERR_PTR(-ENOMEM); 130tmp=__getname();/*这玩意吧其实是分配内核中空间用户装name*/ 131if(tmp){ 132intretval=do_getname(filename,tmp);/*其实就是将filename拷贝到tmp中*/ 133 134result=tmp; 135if(retval<0){ 136putname(tmp); 137result=ERR_PTR(retval); 138} 139} 140returnresult; 141}

看一下__getname()函数:[cpp]view plaincopyprint?1099#define__getname()kmem_cache_alloc(names_cachep,SLAB_KERNEL) 就是在内核的slab空间中分配能够容纳name的空间~~~

看一下do_getname()函数:

[cpp]view plaincopyprint?104staticinlineintdo_getname(constchar*filename,char*page) 105{ 106intretval; 107unsignedlonglen=PATH_MAX; 108 109if((unsignedlong)filename>=TASK_SIZE){ 110if(!segment_eq(get_fs(),KERNEL_DS)) 111return-EFAULT; 112}elseif(TASK_SIZE-(unsignedlong)filename<PATH_MAX) 113len=TASK_SIZE-(unsignedlong)filename; 114 115retval=strncpy_from_user((char*)page,filename,len);/*核心的一个步骤,其实就是将filename拷贝到刚刚在内核中分配的空间中*/ 116if(retval>0){ 117if(retval<len) 118return0; 119return-ENAMETOOLONG; 120}elseif(!retval) 121retval=-ENOENT; 122returnretval; 123}

/* 2 */:这一步是需要找到一个没有使用的文件描述符fd

看一下这个函数get_unused_fd:看这个链接:get_unused_fd

/* 3 */:再回到上面看/* 3 */步骤,到现在为止,我们已经找到了一个可用的文件描述符fd了,然后我们要做的就是打开指定文件,然后将这个fd和打开的文件关联即可,/* 3 */步骤就是打开我们指定的文件!

下面会涉及到名字结构nameidata,所以先看看这个结构体:

[cpp]view plaincopyprint?700structnameidata{ 701structdentry*dentry;/*当前目录项对象*/ 702structvfsmount*mnt;/*已安装的文件系统挂载点*/ 703structqstrlast;/*路径名称最后一部分*/ 704unsignedintflags;/*查询标识*/ 705intlast_type;/*路径名称最后一部分类型*/ 706};

看这个函数filp_open:

[cpp]view plaincopyprint?644/* 645*Notethatwhiletheflagvalue(lowtwobits)forsys_openmeans: 646*00-read-only 647*01-write-only 648*10-read-write 649*11-special 650*itischangedinto 651*00-nopermissionsneeded 652*01-read-permission 653*10-write-permission 654*11-read-write 655*fortheinternalroutines(ieopen_namei()/follow_link()etc).00is 656*usedbysymlinks. 657*/ 658structfile*filp_open(constchar*filename,intflags,intmode) 659{ 660intnamei_flags,error; 661structnameidatand; 662 663namei_flags=flags; 664if((namei_flags+1)&O_ACCMODE) 665namei_flags++; 666if(namei_flags&O_TRUNC) 667namei_flags|=2; 668/*根据文件名打开文件*/ 669error=open_namei(filename,namei_flags,mode,&nd); 670if(!error)/*下面打开这个文件,这个函数返回的是file结构体指针!!!*/ 671returndentry_open(nd.dentry,nd.mnt,flags); 672 673returnERR_PTR(error); 674}

这个函数比较复杂,请看这个链接:open_namei

回头再看这个函数,dentry_open:这个函数返回的file结构体指针:

[cpp]view plaincopyprint?676structfile*dentry_open(structdentry*dentry,structvfsmount*mnt,intflags) 677{ 678structfile*f; 679structinode*inode; 680staticLIST_HEAD(kill_list); 681interror; 682 683error=-ENFILE; 684f=get_empty_filp();/*得到一个空的file结构体,如果出错或者内存不足,返回1error*/ 685if(!f) 686gotocleanup_dentry; 687f->f_flags=flags;/*一些赋值操作*/ 688f->f_mode=(flags+1)&O_ACCMODE; 689inode=dentry->d_inode;/*获得文件inode*/ 690if(f->f_mode&FMODE_WRITE){ 691error=get_write_access(inode); 692if(error) 693gotocleanup_file; 694} 695/*一些赋值操作*/ 696f->f_dentry=dentry;/*目录项*/ 697f->f_vfsmnt=mnt;/*挂载点*/ 698f->f_pos=0;/*文件相对开头偏移*/ 699f->f_reada=0;/*预读标志*/ 700f->f_op=fops_get(inode->i_fop);/*文件操作函数*/ 701file_move(f,&inode->i_sb->s_files);/*将新建的file链接进入inode对应的超级块的file链表中*/ 702 703/*preallocatekiobufforO_DIRECT*/ 704f->f_iobuf=NULL; 705f->f_iobuf_lock=0; 706if(f->f_flags&O_DIRECT){ 707error=alloc_kiovec(1,&f->f_iobuf);/*分配iobuffer*/ 708if(error) 709gotocleanup_all; 710} 711<spanstyle="white-space:pre"></span>/*下面尝试打开文件,保证能够正常打开这个文件*/ 712if(f->f_op&&f->f_op->open){ 713error=f->f_op->open(inode,f); 714if(error) 715gotocleanup_all; 716} 717f->f_flags&=~(O_CREAT|O_EXCL|O_NOCTTY|O_TRUNC); 718 719returnf;/*返回创建好的file*/ 720/*下面都是出错处理*/ 721cleanup_all: 722if(f->f_iobuf) 723free_kiovec(1,&f->f_iobuf); 724fops_put(f->f_op); 725if(f->f_mode&FMODE_WRITE) 726put_write_access(inode); 727file_move(f,&kill_list);/*outoftheway..*/ 728f->f_dentry=NULL; 729f->f_vfsmnt=NULL; 730cleanup_file: 731put_filp(f); 732cleanup_dentry: 733dput(dentry); 734mntput(mnt); 735returnERR_PTR(error); 736} 737

看一下这个函数get_empty_filp,得到一个空的file结构体:[cpp]view plaincopyprint?<spanstyle="font-size:14px;"></span>26/*Findanunusedfilestructureandreturnapointertoit. 27*ReturnsNULL,iftherearenomorefreefilestructuresor 28*werunoutofmemory. 29* 30*SMP-safe. 31*/ 32structfile*get_empty_filp(void) 33{ 34staticintold_max=0; 35structfile*f; 36 37file_list_lock(); 38if(files_stat.nr_free_files>NR_RESERVED_FILES){/*如果允许打开的数量已经超过系统允许的*/ 39used_one: 40f=list_entry(free_list.next,structfile,f_list);/*在free_list中删除一个,留下了给新的file使用*/ 41list_del(&f->f_list); 42files_stat.nr_free_files--; 43new_one:/*下面创建一个新的file结构体*/ 44memset(f,0,sizeof(*f)); 45atomic_set(&f->f_count,1); 46f->f_version=++event; 47f->f_uid=current->fsuid; 48f->f_gid=current->fsgid; 49f->f_maxcount=INT_MAX; 50list_add(&f->f_list,&anon_list); 51file_list_unlock(); 52returnf;/*返回file*/ 53} 54/* 55*Useareservedoneifwe'rethesuperuser 56*/ 57if(files_stat.nr_free_files&&!current->euid) 58gotoused_one; 59/* 60*Allocateanewoneifwe'rebelowthelimit.如果还可以创建file结构体,那么创建一个新的就OK 61*/ 62if(files_stat.nr_files<files_stat.max_files){ 63file_list_unlock(); 64f=kmem_cache_alloc(filp_cachep,SLAB_KERNEL);/*在slab中分配一个新的file缓存*/ 65file_list_lock(); 66if(f){ 67files_stat.nr_files++;/*数量++*/ 68gotonew_one;/*初始化这个新的值*/ 69} 70/*Bigproblems...*/ 71printk(KERN_WARNING"VFS:filpallocationfailed\n"); 72 73}elseif(files_stat.max_files>old_max){ 74printk(KERN_INFO"VFS:file-maxlimit%dreached\n",files_stat.max_files); 75old_max=files_stat.max_files; 76} 77file_list_unlock(); 78returnNULL; 79}

/* 4 */:最后看一下fd_install函数,这个函数比较简单,就是将之前申请的文件描述符fd和打开的文件file结构体关联起来:

[cpp]view plaincopyprint?<spanstyle="font-size:14px;"></span>74/* 75*Installafilepointerinthefdarray. 76* 77*TheVFSisfullofplaceswherewedropthefileslockbetween 78*settingtheopen_fdsbitmapandinstallingthefileinthefile 79*array.Atanysuchpoint,wearevulnerabletoadup2()race 80*installingafileinthearraybeforeus.Weneedtodetectthisand 81*fput()thestructfileweareabouttooverwriteinthiscase. 82* 83*Itshouldneverhappen-ifweallowdup2()doit,_really_badthings 84*willfollow. 85*/ 86 87voidfd_install(unsignedintfd,structfile*file) 88{ 89structfiles_struct*files=current->files;/*获得当前进程文件打开表*/ 90 91write_lock(&files->file_lock); 92if(files->fd[fd])/*如果这个fd下已经存在文件了,那么error!*/ 93BUG(); 94files->fd[fd]=file;/*关联这个fd和新打开的文件*/ 95write_unlock(&files->file_lock); 96}

至此,文件open操作完成了~~~

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。