linux内核中的文件描述符(六)--fd的分配--expand_files

2016-03-02来源: eefocus关键字:linux内核中  文件描述符
Kernel version:2.6.14

CPU architecture:ARM920T

Author:ce123(http://blog.csdn.net/ce123)

我们先贴出expand_files函数的源码:

 

[plain] view plain copy
 
 print?
  1. int expand_files(struct files_struct *files, int nr)  
  2. {  
  3.     int err, expand = 0;  
  4.     struct fdtable *fdt;  
  5.   
  6.     fdt = files_fdtable(files);  
  7.     if (nr >= fdt->max_fdset || nr >= fdt->max_fds) {   //我们在前面的文章中已经分析过,初始时max_fdset = 1024,max_fds = 32  
  8.         if (fdt->max_fdset >= NR_OPEN ||   //#define NR_OPEN (1024*1024)  /* Absolute upper limit on fd num */  
  9.             fdt->max_fds >= NR_OPEN || nr >= NR_OPEN) {  
  10.             err = -EMFILE;  //max_fdset和max_fds都不能大于 NR_OPEN,否则返回 -EMFILE,即打开太多的文件  
  11.   
  12.             goto out;  
  13.         }  
  14.         expand = 1;  
  15.         if ((err = expand_fdtable(files, nr)))//真正进行扩展  
  16.             goto out;  
  17.     }  
  18.     err = expand;  
  19. out:  
  20.     return err;  
  21. }  

 

expand_files函数进行一些检查后调用expand_fdtable进行文件描述符表的扩展,下面分析expand_fdtable函数。

 

[plain] view plain copy
 
 print?
  1. static int expand_fdtable(struct files_struct *files, int nr)  
  2.     __releases(files->file_lock)  
  3.     __acquires(files->file_lock)  
  4. {  
  5.     int error = 0;  
  6.     struct fdtable *fdt;  
  7.     struct fdtable *nfdt = NULL;  
  8.   
  9.     spin_unlock(&files->file_lock);  
  10.     nfdt = alloc_fdtable(nr);//根据nr重新创建一个新的fdtable  
  11.     if (!nfdt) {  
  12.         error = -ENOMEM;  
  13.         spin_lock(&files->file_lock);  
  14.         goto out;  
  15.     }  
  16.   
  17.     spin_lock(&files->file_lock);  
  18.     fdt = files_fdtable(files);  
  19.     /*  
  20.      * Check again since another task may have expanded the  
  21.      * fd table while we dropped the lock  
  22.      */  
  23.     if (nr >= fdt->max_fds || nr >= fdt->max_fdset) { //nr值必须大于max_fds和max_fdset值,这里再次进行检查是防止另一个进程进行了expand  
  24.         copy_fdtable(nfdt, fdt); //将旧的fdtable中的内容拷贝至新的fdtable  
  25.     } else {  
  26.         /* Somebody expanded while we dropped file_lock */  
  27.         spin_unlock(&files->file_lock);  
  28.         __free_fdtable(nfdt);  
  29.         spin_lock(&files->file_lock);  
  30.         goto out;  
  31.     }  
  32.     rcu_assign_pointer(files->fdt, nfdt);//用新的fdtable替换旧的fdtable    
  33.     free_fdtable(fdt);//释放旧的fdtable   
  34. out:  
  35.     return error;  
  36. }  
我们再来看一下扩展文件描述符表的关键函数alloc_fdtable,其定义如下:

 

 

[plain] view plain copy
 
 print?
  1. static struct fdtable *alloc_fdtable(int nr)  
  2. {  
  3.     struct fdtable *fdt = NULL;  
  4.     int nfds = 0;  
  5.     fd_set *new_openset = NULL, *new_execset = NULL;  
  6.     struct file **new_fds;  
  7.   
  8.     fdt = kmalloc(sizeof(*fdt), GFP_KERNEL);  
  9.     if (!fdt)  
  10.         goto out;  
  11.     memset(fdt, 0, sizeof(*fdt));  
  12.   
  13.     nfds = __FD_SETSIZE;  //#define __FD_SETSIZE    1024  
  14.                   //  #define PAGE_SHIFT        12  
  15.                   //  #define PAGE_SIZE     (1UL << PAGE_SHIFT)  
  16.     /* Expand to the max in easy steps */  
  17.     do {  
  18.         if (nfds < (PAGE_SIZE * 8))//dfds = 1024  
  19.             nfds = PAGE_SIZE * 8;  
  20.         else {  
  21.             nfds = nfds * 2;  
  22.             if (nfds > NR_OPEN)  
  23.                 nfds = NR_OPEN;  
  24.         }  
  25.     } while (nfds <= nr);//第一次expand时,nr应该等于32  
  26.   
  27.     new_openset = alloc_fdset(nfds);//分配打开文件位图  
  28.     new_execset = alloc_fdset(nfds);  
  29.     if (!new_openset || !new_execset)  
  30.         goto out;  
  31.     fdt->open_fds = new_openset;  
  32.     fdt->close_on_exec = new_execset;  
  33.     fdt->max_fdset = nfds;//更新max_fdset值,此时这个值为32k  
  34.   
  35.     nfds = NR_OPEN_DEFAULT;//nfds = 32  
  36.     /*  
  37.      * Expand to the max in easy steps, and keep expanding it until  
  38.      * we have enough for the requested fd array size.  
  39.      */  
  40.     do {  
  41. #if NR_OPEN_DEFAULT < 256  
  42.         if (nfds < 256)  
  43.             nfds = 256;//nfds = 256(32->256->1024)  
  44.             //无法超过1024,因为在最开始的就进行了检查,一定要小于current->signal->rlim[RLIMIT_NOFILE].rlim_cur)  
  45.         else  
  46. #endif  
  47.         if (nfds < (PAGE_SIZE / sizeof(struct file *)))  
  48.             nfds = PAGE_SIZE / sizeof(struct file *);  
  49.         else {  
  50.             nfds = nfds * 2;  
  51.             if (nfds > NR_OPEN)  
  52.                 nfds = NR_OPEN;  
  53.         }  
  54.     } while (nfds <= nr);  
  55.     new_fds = alloc_fd_array(nfds);//分配文件描述符数组  
  56.     if (!new_fds)  
  57.         goto out;  
  58.     fdt->fd = new_fds;  
  59.     fdt->max_fds = nfds;//更新max_fds  
  60.     fdt->free_files = NULL;  
  61.     return fdt;  
  62. out:  
  63.     if (new_openset)  
  64.         free_fdset(new_openset, nfds);  
  65.     if (new_execset)  
  66.         free_fdset(new_execset, nfds);  
  67.     kfree(fdt);  
  68.     return NULL;  
  69. }  
alloc_fd_array和alloc_fdset采用kmalloc或者vmalloc进行内存分配。
关键字:linux内核中  文件描述符 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/article_2016030224878.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:linux内核中的likely和unlikely
下一篇:linux内核中的文件描述符(五)--fd的分配--locate_fd

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

linux内核中的copy_to_user和copy_from_user(一)
Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blog.csdn.net/ce123)   1.copy_from_user 在学习Linux内核驱动的时候,经常会碰到copy_from_user和copy_to_user这两个函数,设备驱动程序中的ioctl函数就经常会用到。这两个函数负责在用户空间和内核空间传递数据。首先看看它们的定义(linux/include/asm-arm/uaccess.h),先看copy_from_user:   [plain] view plain 
发表于 2016-03-02
linux内核中的文件描述符(一)--基础知识简介
; int (*flock) (struct file *, int, struct file_lock *);   };   从上面的代码可以看到,结构中是一系列函数的指针,这里有我们比较熟悉的read、open、write和close等函数的指针。进程就是通过这些函数访问一个文件的,file_operations是linux虚拟文件系统VFS和进程之间的接口。   2.文件描述符 下面进一步介绍进程对自己所访问的file对象的管理方法。linux中使用一个数组来管理进程打开
发表于 2016-03-02
linux内核中的文件描述符(一)--基础知识简介
linux内核中的文件描述符(二)--socket和文件描述符
;   retval = sock_map_fd(sock);//分配一个未使用的文件描述符fd,并将socket和fd建立联系       if (retval < 0)           goto out_release;      out:       
发表于 2016-03-02
linux内核中的文件描述符(二)--socket和文件描述符
linux内核中的文件描述符(三)--fd的回收
Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blog.csdn.net/ce123) 1.close函数   上图说明了close(fd)的执行过程,主要包括两部分:释放文件描述符fd,关闭文件file。   [plain] view plain copy    print? //fs/open.c   asmlinkage long sys_close(unsigned int 
发表于 2016-03-02
linux内核中的文件描述符(三)--fd的回收
linux内核中的文件描述符(四)--fd的分配--get_unused_fd
Kernel version:2.6.14 CPU architecture:ARM920T Author:ce123(http://blog.csdn.net/ce123) 在linux内核中主要有两个函数涉及到文件描述符的分配:get_unused_fd和locate_fd。本文主要讲解get_unused_fd,将会在下一篇文章中介绍locate_fd。首先给出get_unused_fd的定义(fs/open.c):   [plain] view plain copy    print? int get_unused_fd(void
发表于 2016-03-02
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved