File descriptor (6) in Linux kernel -- FD Allocation -- expand_files
Kernel version:2.6.14
CPU architecture:ARM920T
Author:Ce123. (http://blog.csdn.net/ce123)
First, paste the source code of the expand_files function:
Int expand_files (struct files_struct * files, int nr) {int err, expand = 0; struct fdtable * FDT; FDT = files_fdtable (files ); if (NR> = FDT-> max_fdset | Nr> = FDT-> max_fds) {// We have analyzed it in the previous article. At the beginning, max_fdset = 1024, max_fds = 32if (FDT-> max_fdset> = nr_open | // # define nr_open (1024*1024) /* absolute upper limit on FD num */FDT-> max_fds> = nr_open | Nr> = nr_open) {err =-emfile; // neither max_fdset nor max_fds can be greater than nr_open, otherwise, the-emfile is returned, that is, too many files are opened in GOTO out;} expand = 1; if (ERR = expand_fdtable (files, NR) // actually extended goto out ;} err = expand; Out: Return err ;}
After checking the expand_files function, call expand_fdtable to expand the file descriptor table. The following describes the expand_fdtable function.
Static int expand_fdtable (struct files_struct * files, int nr) _ Releases (files-> file_lock) _ acquires (files-> file_lock) {int error = 0; struct fdtable * FDT; struct fdtable * nfdt = NULL; spin_unlock (& files-> file_lock); nfdt = alloc_fdtable (NR); // create a new fdtableif (! Nfdt) {error =-enomem; spin_lock (& files-> file_lock); goto out;} spin_lock (& files-> file_lock); FDT = files_fdtable (files ); /** check again since another task may have expanded the * FD table while we dropped the lock */If (NR> = FDT-> max_fds | Nr> = FDT-> max_fdset) {// The NR value must be greater than the max_fds and max_fdset values. The next check is to prevent another process from performing expandcopy_fdtable (nfdt, FDT ); // copy the content in the old fdtable to the new fdtable} else {/* somebody expanded while we dropped file_lock */spin_unlock (& files-> file_lock) ;__ free_fdtable (nfdt ); spin_lock (& files-> file_lock); goto out;} rcu_assign_pointer (files-> FDT, nfdt); // replace the old fdtable free_fdtable (FDT) with the new fdtable ); // release the old fdtable out: Return Error ;}
Let's take a look at the key function alloc_fdtable of the extended file descriptor table. Its definition is as follows:
Static struct fdtable * alloc_fdtable (INT nr) {struct fdtable * FDT = NULL; int NFDs = 0; fd_set * new_openset = NULL, * new_execset = NULL; struct file ** new_fds; FDT = kmalloc (sizeof (* FDT), gfp_kernel); If (! FDT) goto out; memset (FDT, 0, sizeof (* FDT); NFDs = _ fd_setsize; // # DEFINE _ fd_setsize1024 // # define page_shift12 // # define page_size (1ul <page_shift) /* expand to the max in easy steps */do {If (NFDs <(page_size * 8) // DFDs = 1024 NFDs = page_size * 8; else {NFDs = NFDs * 2; If (NFDs> nr_open) NFDs = nr_open;} while (NFDs <= nR); // when the first expand, NR should be equal to 32 new_openset = alloc_fdset (NFDs); // allocate the open file bitmap New_execset = alloc_fdset (NFDs); If (! New_openset |! New_execset) goto out; FDT-> open_fds = new_openset; FDT-> close_on_exec = new_execset; FDT-> max_fdset = NFDs; // update the value of max_fdset, in this case, the value is 32 knfds = nr_open_default; // NFDs = 32/** expand to the max in easy steps, and keep expanding it until * we have enough for the requested FD array size. */do {# If nr_open_default <256if (NFDs <256) NFDs = 256; // NFDs = 256 (32-> 256-> 1024) // cannot exceed 1024, because the check is performed at the beginning, it must be smaller than current-> Signal-> rlim [rlimit_nofile]. rlim_cur) else # endifif (NFDs <(page_size/sizeof (struct file *) NFDs = page_size/sizeof (struct file *); else {NFDs = NFDs * 2; if (NFDs> nr_open) NFDs = nr_open;} while (NFDs <= nR); new_fds = alloc_fd_array (NFDs); // assign a file descriptor array if (! New_fds) goto out; FDT-> FD = new_fds; FDT-> max_fds = NFDs; // update max_fdsfdt-> free_files = NULL; return FDT; Out: If (new_openset) free_fdset (new_openset, NFDs); If (new_execset) free_fdset (new_execset, NFDs); kfree (FDT); return NULL ;}
Alloc_fd_array and alloc_fdset use kmalloc or vmalloc to allocate memory.