Linux⽂件系统(七)---系统调⽤之open操作(⼀)(内核2.4.37)
⼀、
当我们打开⼀个⽂件的时候。须要获得⽂件的⽂件描写叙述符(前⾯已经说过事实上就是⽂件数组下标)。通常是通过函数open来完毕。这个系统调⽤在<unistd.h>头⽂件⾥声明定义,我们看⼀下源代码:
530 static inline long open(const char * name, int mode, int flags)
531 {
532        return sys_open(name, mode, flags);
533 }
Ps:对于这些參数⼀般我们都⾮常熟悉,常常使⽤。这⾥顺便提出记忆⼀下:
mode:參数可选:
32 #define S_IRWXU 00700    ⽂件全部者可读可写可运⾏
33 #define S_IRUSR 00400    ⽂件全部者可读
34 #define S_IWUSR 00200    ⽂件全部者可写
35 #define S_IXUSR 00100    ⽂件全部者可运⾏
36
37 #define S_IRWXG 00070    ⽂件⽤户组可写可读可运⾏
38 #define S_IRGRP 00040    ⽂件⽤户组可读
39 #define S_IWGRP 00020    ⽂件⽤户组可写
40 #define S_IXGRP 00010    ⽂件⽤户组可运⾏
41
42 #define S_IRWXO 00007    其它⽤户可写可读可运⾏
43 #define S_IROTH 00004    其它⽤户可读
44 #define S_IWOTH 00002    其它⽤户可写
45 #define S_IXOTH 00001    其它⽤户可运⾏
flags:在fcntl.h中定义
7 #define O_RDONLY            00
8 #define O_WRONLY            01
9 #define O_RDWR              02
10 #define O_CREAT            0100 /* not fcntl */
11 #define O_EXCL            0200 /* not fcntl */
12 #define O_NOCTTY          0400 /* not fcntl */
13 #define O_TRUNC          01000 /* not fcntl */
14 #define O_APPEND          02000
15 #define O_NONBLOCK        04000
16 #define O_NDELAY        O_NONBLOCK
17 #define O_SYNC          010000
18 #define FASYNC          020000 /* fcntl, for BSD compatibility */
19 #define O_DIRECT        040000 /* direct disk access hint */
百度注册页面代码html20 #define O_LARGEFILE    0100000
21 #define O_DIRECTORY    0200000 /* must be a directory */
22 #define O_NOFOLLOW      0400000 /* don't follow links */
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中):
800 asmlinkage long sys_open(const char * filename, int flags, int mode)
801 {
802        char * tmp;
803        int fd, error;
804
805 #if BITS_PER_LONG != 32
806        flags |= O_LARGEFILE;
807 #endif
808        tmp = getname(filename);  /* 1 */
809        fd = PTR_ERR(tmp);
810        if (!IS_ERR(tmp)) {
811                fd = get_unused_fd();  /* 2 */
812                if (fd >= 0) {
813                        struct file *f = filp_open(tmp, flags, mode); /* 3 */
814                        error = PTR_ERR(f);
815                        if (IS_ERR(f))
816                                goto out_error;
817                        fd_install(fd, f);    /* 4 */
818                }
819 out:
820                putname(tmp);
821        }
822        return fd;
823
824 out_error:
825        put_unused_fd(fd);
826        fd = error;
827        goto out;
828 }
主要看上⾯凝视表⽰的四⼤步骤/* 1 */  /* 2 */  /* 3 */  /* 4 */
/* 1 */:这步是⼀个辅助步骤,将filename从⽤户态复制到内核态变量中。基本步骤涉及⼀下⼏个函数:
125 char * getname(const char * filename)
126 {
127        char *tmp, *result;
128
129        result = ERR_PTR(-ENOMEM);
130        tmp = __getname();    /* 这玩意吧事实上是分配内核中空间⽤户装name */
131        if (tmp)  {
132                int retval = do_getname(filename, tmp);  /* 事实上就是将filename复制到tmp中 */
133
134                result = tmp;
135                if (retval < 0) {
136                        putname(tmp);
dcount函数怎么用137                        result = ERR_PTR(retval);
138                }
139        }
140        return result;
linux建立文件系统的命令
141 }
看⼀下__getname()函数:
1099 #define __getname()    kmem_cache_alloc(names_cachep, SLAB_KERNEL)
就是在内核的slab空间中分配可以容纳name的空间~~~
看⼀下do_getname()函数:
104 static inline int do_getname(const char *filename, char *page)
105 {
106        int retval;
107        unsigned long len = PATH_MAX;
108
109        if ((unsigned long) filename >= TASK_SIZE) {
110                if (!segment_eq(get_fs(), KERNEL_DS))
111                        return -EFAULT;
112        } else if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
113                len = TASK_SIZE - (unsigned long) filename;
114
115        retval = strncpy_from_user((char *)page, filename, len);/* 核⼼的⼀个步骤,事实上就是将filename复制到刚刚在内核中分配的空间中 */
116        if (retval > 0) {
117                if (retval < len)
118                        return 0;
119                return -ENAMETOOLONG;
120        } else if (!retval)
121                retval = -ENOENT;
web服务器是硬件还是软件122        return retval;
123 }
/* 2 */:这⼀步是须要到⼀个没有使⽤的⽂件描写叙述符fd
看⼀下这个函数get_unused_fd:看这个链接:
/* 3 */:再回到上⾯看/* 3 */步骤。到如今为⽌,我们已经到了⼀个可⽤的⽂件描写叙述符fd了,然后我们要做的就是打开指定⽂件,然后将这个fd和打开的⽂件关联就可以,/* 3 */步骤就是打开我们指定的⽂件。
以下会涉及到名字结构nameidata,所以先看看这个结构体:
700 struct nameidata {
701        struct dentry *dentry;  /* 当前⽂件夹项对象 */
702        struct vfsmount *mnt;    /* 已安装的⽂件系统挂载点 */
703        struct qstr last;        /* 路径名称最后⼀部分 */
704        unsigned int flags;      /* 查询标识 */
705        int last_type;          /* 路径名称最后⼀部分类型 */
706 };
看这个函数filp_open:
644 /*
645  * Note that while the flag value (low two bits) for sys_open means:
646  *      00 - read-only
647  *      01 - write-only
648  *      10 - read-write
649  *      11 - special
650  * it is changed into
651  *      00 - no permissions needed
652  *      01 - read-permission
653  *      10 - write-permission
broken654  *      11 - read-write
655  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
656  * used by symlinks.
657  */
658 struct file *filp_open(const char * filename, int flags, int mode)
659 {
660        int namei_flags, error;
661        struct nameidata nd;
662
663        namei_flags = flags;
664        if ((namei_flags+1) & O_ACCMODE)
665                namei_flags++;
666        if (namei_flags & O_TRUNC)
667                namei_flags |= 2;
668        /* 依据⽂件名称打开⽂件 */
669        error = open_namei(filename, namei_flags, mode, &nd);
670        if (!error)  /* 以下打开这个⽂件,这个函数返回的是file结构体指针!
*/ 671 return dentry_open(nd.dentry, nd.mnt, flags); 672 673 return ERR_PTR(error); 674 }这个函数⽐較复杂,请看这个链接:
回头再看这个函数,dentry_open:这个函数返回的file结构体指针:
676 struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
677 {
678        struct file * f;
679        struct inode *inode;
680        static LIST_HEAD(kill_list);
681        int error;
682
683        error = -ENFILE;
684        f = get_empty_filp();    /* 得到⼀个空的file结构体,假设出错或者内存不⾜,返回1error */ 685        if (!f)
686                goto cleanup_dentry;
687        f->f_flags = flags;  /* ⼀些赋值操作 */
688        f->f_mode = (flags+1) & O_ACCMODE;
689        inode = dentry->d_inode; /* 获得⽂件inode */
690        if (f->f_mode & FMODE_WRITE) {
691                error = get_write_access(inode);
692                if (error)
693                        goto cleanup_file;
694        }
695        /* ⼀些赋值操作 */
696        f->f_dentry = dentry; /* ⽂件夹项 */
697        f->f_vfsmnt = mnt;    /* 挂载点 */
698        f->f_pos = 0;        /* ⽂件相对开头偏移 */
699        f->f_reada = 0;      /* 预读标志 */
700        f->f_op = fops_get(inode->i_fop);  /* ⽂件操作函数 */
701        file_move(f, &inode->i_sb->s_files);/* 将新建的file链接进⼊inode相应的超级块的file链表中 */ 702
703        /* preallocate kiobuf for O_DIRECT */
704        f->f_iobuf = NULL;
705        f->f_iobuf_lock = 0;
706        if (f->f_flags & O_DIRECT) {
707                error = alloc_kiovec(1, &f->f_iobuf); /* 分配io buffer */
708                if (error)
709                        goto cleanup_all;
710        }
711 <span > </span>    /* 以下尝试打开⽂件,保证可以正常打开这个⽂件 */ 712        if (f->f_op && f->f_op->open) {
713                error = f->f_op->open(inode,f);
714                if (error)
715                        goto cleanup_all;
716        }
717        f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
lookup使用方法
718
719        return f;  /* 返回创建好的file */
720        /* 以下都是出错处理 */
721 cleanup_all:
722        if (f->f_iobuf)
723                free_kiovec(1, &f->f_iobuf);
724        fops_put(f->f_op);
725        if (f->f_mode & FMODE_WRITE)
726                put_write_access(inode);
727        file_move(f, &kill_list); /* out of the way.. */
728        f->f_dentry = NULL;
729        f->f_vfsmnt = NULL;
730 cleanup_file:
731        put_filp(f);
732 cleanup_dentry:
733        dput(dentry);
734        mntput(mnt);
735        return ERR_PTR(error);
736 }
737

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。