File descriptors in the Linux kernel (VI) -- allocation of fd -- expand_files

Publisher:HarmoniousSoulLatest update time:2016-03-02 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
Kernel version:2.6.14

CPU architecture:ARM920T

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

Let's first post the source code of the expand_files function:

 

[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) { // We have analyzed in the previous article that initially 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; //neither max_fdset nor max_fds can be greater than NR_OPEN, otherwise -EMFILE is returned, indicating that too many files are opened  
  11.   
  12.             goto out;  
  13.         }  
  14.         expand = 1;  
  15.         if ((err = expand_fdtable(files, nr)))//actually expand  
  16.             goto out;  
  17.     }  
  18.     err = expand;  
  19. out:  
  20.     return err;  
  21. }  

 

The expand_files function performs some checks and then calls expand_fdtable to expand the file descriptor table. The expand_fdtable function is analyzed below.

 

[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); //Recreate a new fdtable based on nr  
  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 value must be greater than max_fds and max_fdset values. Checking again here is to prevent another process from expanding  
  24.         copy_fdtable(nfdt, fdt); //Copy the contents of the old fdtable to the new 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); //Replace the old fdtable with the new one    
  33.     free_fdtable(fdt); //Release the old fdtable   
  34. out:  
  35.     return error;  
  36. }  
Let's take a look at the key function alloc_fdtable of the extended file descriptor table, which is defined as follows:

 

 

[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); //When expanding for the first time, nr should be equal to 32  
  26.   
  27.     new_openset = alloc_fdset(nfds); // allocate open file bitmap  
  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; //Update max_fdset value, now the value is 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.             //Cannot exceed 1024, because it is checked at the very beginning and must be less than 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); // allocate file descriptor array  
  56.     if (!new_fds)  
  57.         goto out;  
  58.     fdt->fd = new_fds;  
  59.     fdt->max_fds = nfds; //Update 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 and alloc_fdset use kmalloc or vmalloc for memory allocation.
Reference address:File descriptors in the Linux kernel (VI) -- allocation of fd -- expand_files

Previous article:Likely and Unlikely in the Linux Kernel
Next article:File descriptors in the Linux kernel (V) -- allocation of fd -- locate_fd

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号