The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/file.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *  linux/fs/file.c
    3  *
    4  *  Copyright (C) 1998-1999, Stephen Tweedie and Bill Hawes
    5  *
    6  *  Manage the dynamic fd arrays in the process files_struct.
    7  */
    8 
    9 #include <linux/fs.h>
   10 #include <linux/mm.h>
   11 #include <linux/sched.h>
   12 #include <linux/slab.h>
   13 #include <linux/vmalloc.h>
   14 
   15 #include <asm/bitops.h>
   16 
   17 
   18 /*
   19  * Allocate an fd array, using kmalloc or vmalloc.
   20  * Note: the array isn't cleared at allocation time.
   21  */
   22 struct file ** alloc_fd_array(int num)
   23 {
   24         struct file **new_fds;
   25         int size = num * sizeof(struct file *);
   26 
   27         if (size <= PAGE_SIZE)
   28                 new_fds = (struct file **) kmalloc(size, GFP_KERNEL);
   29         else 
   30                 new_fds = (struct file **) vmalloc(size);
   31         return new_fds;
   32 }
   33 
   34 void free_fd_array(struct file **array, int num)
   35 {
   36         int size = num * sizeof(struct file *);
   37 
   38         if (!array) {
   39                 printk(KERN_ERR "%s array = 0 (num = %d)\n",
   40                                 __FUNCTION__, num);
   41                 return;
   42         }
   43 
   44         if (num <= NR_OPEN_DEFAULT) /* Don't free the embedded fd array! */
   45                 return;
   46         else if (size <= PAGE_SIZE)
   47                 kfree(array);
   48         else
   49                 vfree(array);
   50 }
   51 
   52 /*
   53  * Expand the fd array in the files_struct.  Called with the files
   54  * spinlock held for write.
   55  */
   56 
   57 int expand_fd_array(struct files_struct *files, int nr)
   58 {
   59         struct file **new_fds;
   60         int error, nfds;
   61 
   62         
   63         error = -EMFILE;
   64         if (files->max_fds >= NR_OPEN || nr >= NR_OPEN)
   65                 goto out;
   66 
   67         nfds = files->max_fds;
   68         write_unlock(&files->file_lock);
   69 
   70         /* 
   71          * Expand to the max in easy steps, and keep expanding it until
   72          * we have enough for the requested fd array size. 
   73          */
   74 
   75         do {
   76 #if NR_OPEN_DEFAULT < 256
   77                 if (nfds < 256)
   78                         nfds = 256;
   79                 else 
   80 #endif
   81                 if (nfds < (PAGE_SIZE / sizeof(struct file *)))
   82                         nfds = PAGE_SIZE / sizeof(struct file *);
   83                 else {
   84                         nfds = nfds * 2;
   85                         if (nfds > NR_OPEN)
   86                                 nfds = NR_OPEN;
   87                 }
   88         } while (nfds <= nr);
   89 
   90         error = -ENOMEM;
   91         new_fds = alloc_fd_array(nfds);
   92         write_lock(&files->file_lock);
   93         if (!new_fds)
   94                 goto out;
   95 
   96         /* Copy the existing array and install the new pointer */
   97 
   98         if (nfds > files->max_fds) {
   99                 struct file **old_fds;
  100                 int i;
  101                 
  102                 old_fds = xchg(&files->fd, new_fds);
  103                 i = xchg(&files->max_fds, nfds);
  104 
  105                 /* Don't copy/clear the array if we are creating a new
  106                    fd array for fork() */
  107                 if (i) {
  108                         memcpy(new_fds, old_fds, i * sizeof(struct file *));
  109                         /* clear the remainder of the array */
  110                         memset(&new_fds[i], 0,
  111                                (nfds-i) * sizeof(struct file *)); 
  112 
  113                         write_unlock(&files->file_lock);
  114                         free_fd_array(old_fds, i);
  115                         write_lock(&files->file_lock);
  116                 }
  117         } else {
  118                 /* Somebody expanded the array while we slept ... */
  119                 write_unlock(&files->file_lock);
  120                 free_fd_array(new_fds, nfds);
  121                 write_lock(&files->file_lock);
  122         }
  123         error = 0;
  124 out:
  125         return error;
  126 }
  127 
  128 /*
  129  * Allocate an fdset array, using kmalloc or vmalloc.
  130  * Note: the array isn't cleared at allocation time.
  131  */
  132 fd_set * alloc_fdset(int num)
  133 {
  134         fd_set *new_fdset;
  135         int size = num / 8;
  136 
  137         if (size <= PAGE_SIZE)
  138                 new_fdset = (fd_set *) kmalloc(size, GFP_KERNEL);
  139         else
  140                 new_fdset = (fd_set *) vmalloc(size);
  141         return new_fdset;
  142 }
  143 
  144 void free_fdset(fd_set *array, int num)
  145 {
  146         int size = num / 8;
  147 
  148         if (!array) {
  149                 printk(KERN_ERR "%s array = 0 (num = %d)\n",
  150                                 __FUNCTION__, num);
  151                 return;
  152         }
  153         
  154         if (num <= __FD_SETSIZE) /* Don't free an embedded fdset */
  155                 return;
  156         else if (size <= PAGE_SIZE)
  157                 kfree(array);
  158         else
  159                 vfree(array);
  160 }
  161 
  162 /*
  163  * Expand the fdset in the files_struct.  Called with the files spinlock
  164  * held for write.
  165  */
  166 int expand_fdset(struct files_struct *files, int nr)
  167 {
  168         fd_set *new_openset = 0, *new_execset = 0;
  169         int error, nfds = 0;
  170 
  171         error = -EMFILE;
  172         if (files->max_fdset >= NR_OPEN || nr >= NR_OPEN)
  173                 goto out;
  174 
  175         nfds = files->max_fdset;
  176         write_unlock(&files->file_lock);
  177 
  178         /* Expand to the max in easy steps */
  179         do {
  180                 if (nfds < (PAGE_SIZE * 8))
  181                         nfds = PAGE_SIZE * 8;
  182                 else {
  183                         nfds = nfds * 2;
  184                         if (nfds > NR_OPEN)
  185                                 nfds = NR_OPEN;
  186                 }
  187         } while (nfds <= nr);
  188 
  189         error = -ENOMEM;
  190         new_openset = alloc_fdset(nfds);
  191         new_execset = alloc_fdset(nfds);
  192         write_lock(&files->file_lock);
  193         if (!new_openset || !new_execset)
  194                 goto out;
  195 
  196         error = 0;
  197         
  198         /* Copy the existing tables and install the new pointers */
  199         if (nfds > files->max_fdset) {
  200                 int i = files->max_fdset / (sizeof(unsigned long) * 8);
  201                 int count = (nfds - files->max_fdset) / 8;
  202                 
  203                 /* 
  204                  * Don't copy the entire array if the current fdset is
  205                  * not yet initialised.  
  206                  */
  207                 if (i) {
  208                         memcpy (new_openset, files->open_fds, files->max_fdset/8);
  209                         memcpy (new_execset, files->close_on_exec, files->max_fdset/8);
  210                         memset (&new_openset->fds_bits[i], 0, count);
  211                         memset (&new_execset->fds_bits[i], 0, count);
  212                 }
  213                 
  214                 nfds = xchg(&files->max_fdset, nfds);
  215                 new_openset = xchg(&files->open_fds, new_openset);
  216                 new_execset = xchg(&files->close_on_exec, new_execset);
  217                 write_unlock(&files->file_lock);
  218                 free_fdset (new_openset, nfds);
  219                 free_fdset (new_execset, nfds);
  220                 write_lock(&files->file_lock);
  221                 return 0;
  222         } 
  223         /* Somebody expanded the array while we slept ... */
  224 
  225 out:
  226         write_unlock(&files->file_lock);
  227         if (new_openset)
  228                 free_fdset(new_openset, nfds);
  229         if (new_execset)
  230                 free_fdset(new_execset, nfds);
  231         write_lock(&files->file_lock);
  232         return error;
  233 }
  234 

Cache object: 954b2adbb8be01bd97b050de667dc9b8


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.