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  */
alloc_fd_array(int num)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 
free_fd_array(struct file ** array,int num)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 
expand_fd_array(struct files_struct * files,int nr)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  */
alloc_fdset(int num)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 
free_fdset(fd_set * array,int num)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  */
expand_fdset(struct files_struct * files,int nr)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 
235