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 */
20 #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);
137 result = ERR_PTR(retval);
138 }
139 }
140 return result;
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;
122 return retval;
123 }
/* 2 */:这一步是须要找到一个没有使用的文件描写叙述符fd
看一下这个函数get_unused_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
654 * 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 }
这个函数比較复杂,请看这个链接:open_namei
回头再看这个函数,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 style="white-space:pre"> </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);
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
看一下这个函数get_empty_filp,得到一个空的file结构体:
<span style="font-size:14px;"> </span>26 /* Find an unused file structure and return a pointer to it.
27 * Returns NULL, if there are no more free file structures or
28 * we run out of memory.
29 *
30 * SMP-safe.
31 */
32 struct file * get_empty_filp(void)
33 {
34 static int old_max = 0;
35 struct file * f;
36
37 file_list_lock();
38 if (files_stat.nr_free_files > NR_RESERVED_FILES) { /* 假设同意打开的数量已经超过系统同意的 */
39 used_one:
40 f = list_entry(free_list.next, struct file, f_list); /* 在free_list中删除一个,留下了给新的file使用 */
41 list_del(&f->f_list);
42 files_stat.nr_free_files--;
43 new_one: /* 以下创建一个新的file结构体 */
44 memset(f, 0, sizeof(*f));
45 atomic_set(&f->f_count,1);
46 f->f_version = ++event;
47 f->f_uid = current->fsuid;
48 f->f_gid = current->fsgid;
49 f->f_maxcount = INT_MAX;
50 list_add(&f->f_list, &anon_list);
51 file_list_unlock();
52 return f; /* 返回file */
53 }
54 /*
55 * Use a reserved one if we're the superuser
56 */
57 if (files_stat.nr_free_files && !current->euid)
58 goto used_one;
59 /*
60 * Allocate a new one if we're below the limit. 假设还能够创建file结构体,那么创建一个新的就OK
61 */
62 if (files_stat.nr_files < files_stat.max_files) {
63 file_list_unlock();
64 f = kmem_cache_alloc(filp_cachep, SLAB_KERNEL); /* 在slab中分配一个新的file缓存 */
65 file_list_lock();
66 if (f) {
67 files_stat.nr_files++; /* 数量++ */
68 goto new_one; /* 初始化这个新的值 */
69 }
70 /* Big problems... */
71 printk(KERN_WARNING "VFS: filp allocation failed\n");
72
73 } else if (files_stat.max_files > old_max) {
74 printk(KERN_INFO "VFS: file-max limit %d reached\n", files_stat.max_files);
75 old_max = files_stat.max_files;
76 }
77 file_list_unlock();
78 return NULL;
79 }
/* 4 */:最后看一下fd_install函数,这个函数比較简单。就是将之前申请的文件描写叙述符fd和打开的文件file结构体关联起来:
<span style="font-size:14px;"> </span>74 /*
75 * Install a file pointer in the fd array.
76 *
77 * The VFS is full of places where we drop the files lock between
78 * setting the open_fds bitmap and installing the file in the file
79 * array. At any such point, we are vulnerable to a dup2() race
80 * installing a file in the array before us. We need to detect this and
81 * fput() the struct file we are about to overwrite in this case.
82 *
83 * It should never happen - if we allow dup2() do it, _really_ bad things
84 * will follow.
85 */
86
87 void fd_install(unsigned int fd, struct file * file)
88 {
89 struct files_struct *files = current->files; /* 获得当前进程文件打开表 */
90
91 write_lock(&files->file_lock);
92 if (files->fd[fd]) /* 假设这个fd下已经存在文件了,那么error。 */
93 BUG();
94 files->fd[fd] = file;/* 关联这个fd和新打开的文件 */
95 write_unlock(&files->file_lock);
96 }
至此。文件open操作完毕了~~~
Linux文件系统(七)---系统调用之open操作(一)的更多相关文章
- 攻城狮在路上(叁)Linux(二十六)--- linux文件系统的特殊查看与操作
一.boot sector 与 super block的关系: 1.boot sector用于存放引导装载程序,占用1024个字节. 2.super block的大小也为1024字节. 3.若bloc ...
- Spark修炼之道(基础篇)——Linux大数据开发基础:第二节:Linux文件系统、文件夹(一)
本节主要内容 怎样获取帮助文档 Linux文件系统简单介绍 文件夹操作 訪问权限 1. 怎样获取帮助文档 在实际工作过程其中,常常会忘记命令的使用方式.比如ls命令后面能够跟哪些參数,此时能够使用ma ...
- Linux命令(五)——磁盘操作及文件系统的管理
文件系统是所有文件夹和文件的基础,磁盘是文件系统的基础,文件系统以磁盘为基础存储文件. 一.linux文件系统类型 1.ext扩展文件系统/ext2二级扩展文件系统/ext3日志式文件系统(默认) 2 ...
- Linux文件系统---用户与内核的交互接口
从磁盘到数据,从数据到文件,从文件到目录,从目录到文件系统,从文件系统到操作系统.构成了计算机中的IO读写机制. 整个磁盘可以分为1个MBR(Master Boot Record)和4个partiti ...
- Linux 文件系统之入门必看!
在 Linux 中,最直观.最可见的部分就是 文件系统(file system).下面我们就来一起探讨一下关于 Linux 中国的文件系统,系统调用以及文件系统实现背后的原理和思想.这些思想中有一些来 ...
- linux文件系统体系结构 和 虚拟文件系统(VFS)
图 1. Linux 文件系统组件的体系结构 用户空间包含一些应用程序(例如,文件系统的使用者)和 GNU C 库(glibc),它们为文件系统调用(打开.读取.写和关闭)提供用户接口.系统调用接口的 ...
- 磁盘、分区及Linux文件系统 [Disk, Partition, Linux File System]
1.磁盘基础知识 1.1 物理结构 硬盘的物理结构一般由磁头与碟片.电动机.主控芯片与排线等部件组成:当主电动机带动碟片旋转时,副电动机带动一组(磁头)到相对应的碟片上并确定读取正面还是反面的碟面,磁 ...
- 24小时学通Linux内核之有关Linux文件系统实现的问题
有时间睡懒觉了,却还是五点多醒了,不过一直躺倒九点多才算起来,昨晚一直在弄飞凌的嵌入式开发板,有些问题没解决,自己电脑系统的问题,虽然Win10发布了,,但我还是好喜欢XP呀,好想回家用用家里的XP来 ...
- Linux文件系统的设计
总论: linux的文件系统设计非常优秀,总的来讲有两大部分,第一部分就是树形的组织结构,第二部分就是vfs,树形的组织结构组织了文件系统的表象,用户非常方便的使用,而vfs是文件系统的实现机理,它处 ...
随机推荐
- Hive不同文件的读取与序列化
Hive不同文件的读取对照 stored as textfile 直接查看hdfs hadoop fs -text hive> create table test_txt(name string ...
- Qt 图像处理之 灰度变换
对图像的亮度.对照度进行变换是非经常常使用的一种图像处理操作,可是Qt 本身却没有提供对应的功能代码.因此我写了个简单的类来实现这些操作.我把这个类称为 BrightnessMapper. 代码例如以 ...
- CGContext含义
代码 含义 CGContextRef context = UIGraphicsGetCurrentContext(); 设置上下文 CGContextMoveToPoint 开始画线 CGContex ...
- Java-MyBatis-3.0:MyBatis 3 简介
ylbtech-Java-MyBatis-3.0:MyBatis 3 简介 1.返回顶部 1. 简介 什么是 MyBatis ? MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程 ...
- Centos上JDK的安装搭建
一.下载 yum search java|grep jdk //查找所有jdk版本 二.选择安装1.8 yum install java-1.8.0-openjdk-src-debug.x86_64 ...
- Asp.net mvc中使用配置Unity
第一步:添加unity.mvc 第二步:在添加之后会在app_start中生成UnityConfig.cs,UnityMvcActivator.cs 第三步:使用 第四步:效果展示
- css实战笔记(一):写网页前的reset工作
reset.css是每个html必备的样式,其中有各种元素属性清零的代码. 为什么要有reset.css 让各个浏览器的CSS样式有一个统一的基准,比如清除各个浏览器为元素自带的margin.padd ...
- vue中采用axios发送请求及拦截器
这几天在使用vue中axios发送get请求的时候很顺手,但是在发送post请求的时候老是在成功的回调函数里边返回参数不存在,当时就纳闷了,经过查阅资料,终于得到了解决方案,在此做一总结: 首先我们在 ...
- 用replaceState操作路由的方法封装
export class Router { ReplaceState(url, data) { var query = this.Generate(data); window.history.repl ...
- paratest
class Program { static void Main(string[] args) { long result = 0; Stopwatch Watch = new Stopwatch() ...