~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/file.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.