Open系统调用

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

看一下sys_open函数中调用的这个函数get_unused_fd:

[cpp] view plaincopyprint?
  1. 738 /*
  2. 739  * Find an empty file descriptor entry, and mark it busy.
  3. 740  */
  4. 741 int get_unused_fd(void)
  5. 742 {
  6. 743         struct files_struct * files = current->files;  /* (1)获得当前进程的文件打开表,这个前面已经说过了 */
  7. 744         int fd, error;
  8. 745
  9. 746         error = -EMFILE;
  10. 747         write_lock(&files->file_lock);
  11. 748
  12. 749 repeat:
  13. 750         fd = find_next_zero_bit(files->open_fds,      /* (2)在这个进程文件打开表中寻找还没有使用的fd */
  14. 751                                 files->max_fdset,
  15. 752                                 files->next_fd);
  16. 753
  17. 754         /*
  18. 755          * N.B. For clone tasks sharing a files structure, this test
  19. 756          * will limit the total number of files that can be opened.
  20. 757          */
  21. 758         if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur)  /* 不能超过限制(考虑到fork进程情况,共享fd情况) */
  22. 759                 goto out;
  23. 760
  24. 761         /* Do we need to expand the fdset array? */
  25. 762         if (fd >= files->max_fdset) {    /* 如果当前进程的fd集合中最大fd比当前申请的fd小,那么需要扩大fdset,需要扩容:具体见http://blog.csdn.net/shanshanpt/article/details/38943731中files_struct结构体描述 */
  26. 763                 error = expand_fdset(files, fd);  /* 扩容函数1 */
  27. 764                 if (!error) {
  28. 765                         error = -EMFILE;
  29. 766                         goto repeat;
  30. 767                 }
  31. 768                 goto out;
  32. 769         }
  33. 770
  34. 771         /*
  35. 772          * Check whether we need to expand the fd array.
  36. 773          */
  37. 774         if (fd >= files->max_fds) {    /* 类似于上面,这里是需要扩大fd-array数组,具体见上面链接 */
  38. 775                 error = expand_fd_array(files, fd);  /* 扩容函数2 */
  39. 776                 if (!error) {
  40. 777                         error = -EMFILE;
  41. 778                         goto repeat;
  42. 779                 }
  43. 780                 goto out;
  44. 781         }
  45. 782
  46. 783         FD_SET(fd, files->open_fds);     /* 将fd加入到打开文件描述符中 */
  47. 784         FD_CLR(fd, files->close_on_exec);/* 从close-on-exec中清除 */
  48. 785         files->next_fd = fd + 1;         /* 当前描述符是最大的fd,所有next就是fd+1 */
  49. 786 #if 1
  50. 787         /* Sanity check */
  51. 788         if (files->fd[fd] != NULL) {
  52. 789                 printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd);
  53. 790                 files->fd[fd] = NULL;
  54. 791         }
  55. 792 #endif
  56. 793         error = fd;
  57. 794
  58. 795 out:
  59. 796         write_unlock(&files->file_lock);
  60. 797         return error;
  61. 798 }
  62. 799

ATTENTION:注意上面的max_fdset和max_fds的区别,前者是当前可以容纳的最大的文件描述符的数量大小!后者是当前可以容纳的文件对象的数量大小!对于一个文件对象而言,可以存在多个文件描述符指向这一个文件对象!所以对于申请到的fd,要分别和这两个进行判断!

主要看上面的三个函数,第一个是寻找fd函数find_next_zero_bit:
这个函数的意义就是找到open_fds打开的文件描述符中第一个bit位=0的那一位,作为新的fd返回。(前面也说过,fd的管理是使用位管理的),反正是一堆位运算,慢慢看吧:

[cpp] view plaincopyprint?
  1. 254 static inline unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
  2. 255 {
  3. 256         unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
  4. 257         unsigned long result = offset & ~31UL;
  5. 258         unsigned long tmp;
  6. 259
  7. 260         if (offset >= size)
  8. 261                 return size;
  9. 262         size -= result;
  10. 263         offset &= 31UL;
  11. 264         if (offset) {
  12. 265                 tmp = *(p++);
  13. 266                 tmp |= ~0UL >> (32-offset);
  14. 267                 if (size < 32)
  15. 268                         goto found_first;
  16. 269                 if (~tmp)
  17. 270                         goto found_middle;
  18. 271                 size -= 32;
  19. 272                 result += 32;
  20. 273         }
  21. 274         while (size & ~31UL) {
  22. 275                 if (~(tmp = *(p++)))
  23. 276                         goto found_middle;
  24. 277                 result += 32;
  25. 278                 size -= 32;
  26. 279         }
  27. 280         if (!size)
  28. 281                 return result;
  29. 282         tmp = *p;
  30. 283
  31. 284 found_first:
  32. 285         tmp |= ~0UL << size;
  33. 286         if (tmp == ~0UL)        /* Are any bits zero? */
  34. 287                 return result + size; /* Nope. */
  35. 288 found_middle:
  36. 289         return result + ffz(tmp);
  37. 290 }

扩大fdset集合函数:expand_fdset

[cpp] view plaincopyprint?
  1. 162 /*
  2. 163  * Expand the fdset in the files_struct.  Called with the files spinlock
  3. 164  * held for write.
  4. 165  */
  5. 166 int expand_fdset(struct files_struct *files, int nr)
  6. 167 {
  7. 168         fd_set *new_openset = 0, *new_execset = 0;
  8. 169         int error, nfds = 0;
  9. 170
  10. 171         error = -EMFILE;
  11. 172         if (files->max_fdset >= NR_OPEN || nr >= NR_OPEN)   /* 不能大于系统最大限制 */
  12. 173                 goto out;
  13. 174
  14. 175         nfds = files->max_fdset;   /* 当前最大文件描述符 */
  15. 176         write_unlock(&files->file_lock);
  16. 177
  17. 178         /* Expand to the max in easy steps,下面是一个 简单的扩展过程 */
  18. 179         do {
  19. 180                 if (nfds < (PAGE_SIZE * 8))
  20. 181                         nfds = PAGE_SIZE * 8;
  21. 182                 else {
  22. 183                         nfds = nfds * 2;
  23. 184                         if (nfds > NR_OPEN)
  24. 185                                 nfds = NR_OPEN;
  25. 186                 }
  26. 187         } while (nfds <= nr);
  27. 188
  28. 189         error = -ENOMEM;
  29. 190         new_openset = alloc_fdset(nfds);  /* 根据新的大小分配新的打开set集合 */
  30. 191         new_execset = alloc_fdset(nfds);  /* 根据新的大小分配新的执行时候需要close的set集合 */
  31. 192         write_lock(&files->file_lock);
  32. 193         if (!new_openset || !new_execset)
  33. 194                 goto out;
  34. 195
  35. 196         error = 0;
  36. 197
  37. 198         /* Copy the existing tables and install the new pointers:将老的数据拷贝到新的内存中来 */
  38. 199         if (nfds > files->max_fdset) {
  39. 200                 int i = files->max_fdset / (sizeof(unsigned long) * 8);
  40. 201                 int count = (nfds - files->max_fdset) / 8;
  41. 202
  42. 203                 /*
  43. 204                  * Don't copy the entire array if the current fdset is
  44. 205                  * not yet initialised.
  45. 206                  */
  46. 207                 if (i) {
  47. 208                         memcpy (new_openset, files->open_fds, files->max_fdset/8);
  48. 209                         memcpy (new_execset, files->close_on_exec, files->max_fdset/8);
  49. 210                         memset (&new_openset->fds_bits[i], 0, count);
  50. 211                         memset (&new_execset->fds_bits[i], 0, count);
  51. 212                 }
  52. 213                 /* 下面几步骤很重要,将新分配的挂载到files结构体中去 */
  53. 214                 nfds = xchg(&files->max_fdset, nfds);
  54. 215                 new_openset = xchg(&files->open_fds, new_openset);
  55. 216                 new_execset = xchg(&files->close_on_exec, new_execset);
  56. 217                 write_unlock(&files->file_lock);
  57. 218                 free_fdset (new_openset, nfds);
  58. 219                 free_fdset (new_execset, nfds);
  59. 220                 write_lock(&files->file_lock);
  60. 221                 return 0;
  61. 222         }
  62. 223         /* Somebody expanded the array while we slept ... */
  63. 224
  64. 225 out:
  65. 226         write_unlock(&files->file_lock);
  66. 227         if (new_openset)
  67. 228                 free_fdset(new_openset, nfds);
  68. 229         if (new_execset)
  69. 230                 free_fdset(new_execset, nfds);
  70. 231         write_lock(&files->file_lock);
  71. 232         return error;
  72. 233 }

再看一下具体的alloc_fdset函数:

[cpp] view plaincopyprint?
  1. 128 /*
  2. 129  * Allocate an fdset array, using kmalloc or vmalloc.
  3. 130  * Note: the array isn't cleared at allocation time.
  4. 131  */
  5. 132 fd_set * alloc_fdset(int num)
  6. 133 {
  7. 134         fd_set *new_fdset;
  8. 135         int size = num / 8;
  9. 136
  10. 137         if (size <= PAGE_SIZE)
  11. 138                 new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL);
  12. 139         else
  13. 140                 new_fdset = (fd_set *) vmalloc(size);
  14. 141         return new_fdset;
  15. 142 }

回到上面,看一下扩大fd数组的函数expand_fd_array:

[cpp] view plaincopyprint?
  1. 52 /*
  2. 53  * Expand the fd array in the files_struct.  Called with the files
  3. 54  * spinlock held for write.
  4. 55  */
  5. 56
  6. 57 int expand_fd_array(struct files_struct *files, int nr)
  7. 58 {
  8. 59         struct file **new_fds;
  9. 60         int error, nfds;
  10. 61
  11. 62
  12. 63         error = -EMFILE;
  13. 64         if (files->max_fds >= NR_OPEN || nr >= NR_OPEN)   /* 不能超过最大系统限制 */
  14. 65                 goto out;
  15. 66
  16. 67         nfds = files->max_fds;     /* 当前进程中最大的fd */
  17. 68         write_unlock(&files->file_lock);
  18. 69
  19. 70         /*
  20. 71          * Expand to the max in easy steps, and keep expanding it until
  21. 72          * we have enough for the requested fd array size.
  22. 73          */
  23. 74         /* 简单的扩展策略 */
  24. 75         do {
  25. 76 #if NR_OPEN_DEFAULT < 256
  26. 77                 if (nfds < 256)
  27. 78                         nfds = 256;
  28. 79                 else
  29. 80 #endif
  30. 81                 if (nfds < (PAGE_SIZE / sizeof(struct file *)))
  31. 82                         nfds = PAGE_SIZE / sizeof(struct file *);
  32. 83                 else {
  33. 84                         nfds = nfds * 2;
  34. 85                         if (nfds > NR_OPEN)
  35. 86                                 nfds = NR_OPEN;
  36. 87                 }
  37. 88         } while (nfds <= nr);
  38. 89
  39. 90         error = -ENOMEM;
  40. 91         new_fds = alloc_fd_array(nfds);    /* 分配新的fd_array数组 */
  41. 92         write_lock(&files->file_lock);
  42. 93         if (!new_fds)
  43. 94                 goto out;
  44. 95
  45. 96         /* Copy the existing array and install the new pointer */
  46. 97
  47. 98         if (nfds > files->max_fds) {
  48. 99                 struct file **old_fds;
  49. 100                 int i;
  50. 101                 /* 将当前进行的文件数组指针指向新申请的fd数组! */
  51. 102                 old_fds = xchg(&files->fd, new_fds);
  52. 103                 i = xchg(&files->max_fds, nfds);
  53. 104
  54. 105                 /* Don't copy/clear the array if we are creating a new
  55. 106                    fd array for fork() */
  56. 107                 if (i) {   /* 下面将老的数据拷贝过去 */
  57. 108                         memcpy(new_fds, old_fds, i * sizeof(struct file *));
  58. 109                         /* clear the remainder of the array */
  59. 110                         memset(&new_fds[i], 0,
  60. 111                                (nfds-i) * sizeof(struct file *));
  61. 112
  62. 113                         write_unlock(&files->file_lock);
  63. 114                         free_fd_array(old_fds, i);
  64. 115                         write_lock(&files->file_lock);
  65. 116                 }
  66. 117         } else {
  67. 118                 /* Somebody expanded the array while we slept ... */
  68. 119                 write_unlock(&files->file_lock);
  69. 120                 free_fd_array(new_fds, nfds);
  70. 121                 write_lock(&files->file_lock);
  71. 122         }
  72. 123         error = 0;
  73. 124 out:
  74. 125         return error;
  75. 126 }

Linux文件系统(七)---系统调用之open操作(二) 之 get_unused_fd相关推荐

  1. Linux文件系统及磁盘分区与格式化(二次排版)

    Linux 的文件系统 磁盘物理组成                磁盘的组成与分区:  由图中可以看到磁盘中存储数据的部件为圆形的盘片(磁盘主要记录数据的部分). 盘片的结构      而磁盘的物理 ...

  2. linux 如何赋值目录,Linux文件系统之目录的建立

    一:前言 在用户空间中,建立目录所用的API为mkdir().它在内核中的系统调用入口是sys_mkdir().今天跟踪一下 函数来分析linux文件系统中目录的建立过程. 二:sys_mkdir() ...

  3. linux创建根目录代码,Linux文件系统之目录的建立

    一:前言 在用户空间中,建立目录所用的API为mkdir().它在内核中的系统调用入口是sys_mkdir().今天跟踪一下 函数来分析linux文件系统中目录的建立过程. 二:sys_mkdir() ...

  4. Spark修炼之道(基础篇)——Linux大数据开发基础:第二节:Linux文件系统、文件夹(一)...

    本节主要内容 怎样获取帮助文档 Linux文件系统简单介绍 文件夹操作 訪问权限 1. 怎样获取帮助文档 在实际工作过程其中,常常会忘记命令的使用方式.比如ls命令后面能够跟哪些參数,此时能够使用ma ...

  5. Linux里命令卸载mysql,linux中mysql完整卸载命令操作

    yum方式安装的mysql 1.yum remove mysql mysql-server mysql-libs compat-mysql51 2.rm -rf /var/lib/mysql 3.rm ...

  6. Linux 文件系统与设备文件系统 (二)—— sysfs 文件系统与Linux设备模型

    提到 sysfs 文件系统 ,必须先需要了解的是Linux设备模型,什么是Linux设备模型呢? 一.Linux 设备模型 1.设备模型概述 从2.6版本开始,Linux开发团队便为内核建立起一个统一 ...

  7. Linux文件系统二(虚拟文件系统VFS实现原理)

    创作人QQ:851301776,邮箱:lfr890207@163.com         欢迎大家一起技术交流,本博客主要是自己学习的心得体会,只为每天进步一点点! 个人座右铭:          1 ...

  8. 嵌入式 Linux 入门(二、Linux 文件系统、文件类型及权限管理)

    嵌入式 Linux入 门第二课, linux 文件系统.文件类型及权限管理. ...... 矜辰所致 目录 前言 一.Linux 文件属性 1.1 Linux 文件类型 1.2 Linux 文件权限及 ...

  9. 文件系统调用和Linux文件系统基础

    文件系统调用和Linux文件系统基础 keywords fdisk.LBA.CHS.MBR.super struct.directory.file.inode.inode table.block.fi ...

  10. 第十一、十二、十三、十四章 网络配置管理、归档和远程复制同步文件、软件包管理、创建访问linux文件系统

    第十一章 网络配置管理 网络地址获取方式: 1)DHCP自动获取 2)手动配置 1.网卡配置文件: /etc/sysconfig/network-scripts/ [root@server0 Desk ...

最新文章

  1. mysql安装文件瘦身_MySQL瘦身
  2. Python sort
  3. iOS11和机器学习CoreML库
  4. 130.CDMA全称是什么?
  5. Python 基础教程:切片、迭代和列表生成式
  6. 最舒适的路线 第六届
  7. 蓝桥杯2017初赛-9数算式-dfs
  8. 【Git】GitHub设置README.md引用本repo目录下的图片
  9. Grunt 之通配符
  10. URLencode 转义符
  11. C语言 完数C语言 完数C语言 完数
  12. pdf打开错误之读取本文档时出现问题(14)
  13. 国内用户最多的linux系统,统信UOS将可能超越麒麟系统夺得中国Linux市场份额第一名...
  14. 性能优化: 资源合并与压缩 -- 压缩(前端开发过程中 JavaScript、HTML、CSS 文件的压缩)
  15. 天津学习平面设计培训需要学习多久?
  16. linux上ssh免密登录原理及实现
  17. C语言到底有多强大?
  18. 在K8s上轻松部署Tungsten Fabric的两种方式
  19. 刺激汽车消费政策频出的背后揭露了什么样的车市真相?
  20. 搭建gitblit服务器

热门文章

  1. poj 3694 Network (无向图的 割边 lca )
  2. db2:根据TABLEID找table
  3. 个利用正则表达式解析单句SQL的类SqlParser
  4. PRM–endRequest事件
  5. 系统逻辑架构图_如何画好一张架构图?(内含知识图谱)
  6. mysql复制(高可用架构方案的基础)
  7. NinePatchChunk.java分析
  8. Hyper-v 2.0
  9. C++ primer第一章 C++概述 纪要
  10. 多线程--thread