aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorVadim Lobanov <vlobanov@speakeasy.net>2006-12-10 05:21:12 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-10 12:57:22 -0500
commitbbea9f69668a3d0cf9feba15a724cd02896f8675 (patch)
treebc58506e4daba4a04309181a5501ae4eb5424783 /fs
parentf3d19c90fb117a5f080310a4592929aa8e1ad8e9 (diff)
[PATCH] fdtable: Make fdarray and fdsets equal in size
Currently, each fdtable supports three dynamically-sized arrays of data: the fdarray and two fdsets. The code allows the number of fds supported by the fdarray (fdtable->max_fds) to differ from the number of fds supported by each of the fdsets (fdtable->max_fdset). In practice, it is wasteful for these two sizes to differ: whenever we hit a limit on the smaller-capacity structure, we will reallocate the entire fdtable and all the dynamic arrays within it, so any delta in the memory used by the larger-capacity structure will never be touched at all. Rather than hogging this excess, we shouldn't even allocate it in the first place, and keep the capacities of the fdarray and the fdsets equal. This patch removes fdtable->max_fdset. As an added bonus, most of the supporting code becomes simpler. Signed-off-by: Vadim Lobanov <vlobanov@speakeasy.net> Cc: Christoph Hellwig <hch@lst.de> Cc: Al Viro <viro@zeniv.linux.org.uk> Cc: Dipankar Sarma <dipankar@in.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/compat.c10
-rw-r--r--fs/exec.c2
-rw-r--r--fs/fcntl.c5
-rw-r--r--fs/file.c56
-rw-r--r--fs/open.c3
-rw-r--r--fs/select.c10
6 files changed, 36 insertions, 50 deletions
diff --git a/fs/compat.c b/fs/compat.c
index b766964a625c..0ec70e3cee0a 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1679,19 +1679,19 @@ int compat_core_sys_select(int n, compat_ulong_t __user *inp,
1679{ 1679{
1680 fd_set_bits fds; 1680 fd_set_bits fds;
1681 char *bits; 1681 char *bits;
1682 int size, max_fdset, ret = -EINVAL; 1682 int size, max_fds, ret = -EINVAL;
1683 struct fdtable *fdt; 1683 struct fdtable *fdt;
1684 1684
1685 if (n < 0) 1685 if (n < 0)
1686 goto out_nofds; 1686 goto out_nofds;
1687 1687
1688 /* max_fdset can increase, so grab it once to avoid race */ 1688 /* max_fds can increase, so grab it once to avoid race */
1689 rcu_read_lock(); 1689 rcu_read_lock();
1690 fdt = files_fdtable(current->files); 1690 fdt = files_fdtable(current->files);
1691 max_fdset = fdt->max_fdset; 1691 max_fds = fdt->max_fds;
1692 rcu_read_unlock(); 1692 rcu_read_unlock();
1693 if (n > max_fdset) 1693 if (n > max_fds)
1694 n = max_fdset; 1694 n = max_fds;
1695 1695
1696 /* 1696 /*
1697 * We need 6 bitmaps (in/out/ex for both incoming and outgoing), 1697 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
diff --git a/fs/exec.c b/fs/exec.c
index 12d8cd461b41..11fe93f7363c 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -783,7 +783,7 @@ static void flush_old_files(struct files_struct * files)
783 j++; 783 j++;
784 i = j * __NFDBITS; 784 i = j * __NFDBITS;
785 fdt = files_fdtable(files); 785 fdt = files_fdtable(files);
786 if (i >= fdt->max_fds || i >= fdt->max_fdset) 786 if (i >= fdt->max_fds)
787 break; 787 break;
788 set = fdt->close_on_exec->fds_bits[j]; 788 set = fdt->close_on_exec->fds_bits[j];
789 if (!set) 789 if (!set)
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 2bdaef35da54..8e382a5d51bd 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -77,10 +77,9 @@ repeat:
77 start = files->next_fd; 77 start = files->next_fd;
78 78
79 newfd = start; 79 newfd = start;
80 if (start < fdt->max_fdset) { 80 if (start < fdt->max_fds)
81 newfd = find_next_zero_bit(fdt->open_fds->fds_bits, 81 newfd = find_next_zero_bit(fdt->open_fds->fds_bits,
82 fdt->max_fdset, start); 82 fdt->max_fds, start);
83 }
84 83
85 error = -EMFILE; 84 error = -EMFILE;
86 if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) 85 if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
diff --git a/fs/file.c b/fs/file.c
index 51aef675470f..fb3d2038dc21 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -68,8 +68,8 @@ void free_fd_array(struct file **array, int num)
68 68
69static void __free_fdtable(struct fdtable *fdt) 69static void __free_fdtable(struct fdtable *fdt)
70{ 70{
71 free_fdset(fdt->open_fds, fdt->max_fdset); 71 free_fdset(fdt->open_fds, fdt->max_fds);
72 free_fdset(fdt->close_on_exec, fdt->max_fdset); 72 free_fdset(fdt->close_on_exec, fdt->max_fds);
73 free_fd_array(fdt->fd, fdt->max_fds); 73 free_fd_array(fdt->fd, fdt->max_fds);
74 kfree(fdt); 74 kfree(fdt);
75} 75}
@@ -98,7 +98,7 @@ static void free_fdtable_rcu(struct rcu_head *rcu)
98 struct fdtable_defer *fddef; 98 struct fdtable_defer *fddef;
99 99
100 BUG_ON(!fdt); 100 BUG_ON(!fdt);
101 fdset_size = fdt->max_fdset / 8; 101 fdset_size = fdt->max_fds / 8;
102 fdarray_size = fdt->max_fds * sizeof(struct file *); 102 fdarray_size = fdt->max_fds * sizeof(struct file *);
103 103
104 if (fdt->free_files) { 104 if (fdt->free_files) {
@@ -110,13 +110,11 @@ static void free_fdtable_rcu(struct rcu_head *rcu)
110 kmem_cache_free(files_cachep, fdt->free_files); 110 kmem_cache_free(files_cachep, fdt->free_files);
111 return; 111 return;
112 } 112 }
113 if (fdt->max_fdset <= EMBEDDED_FD_SET_SIZE && 113 if (fdt->max_fds <= NR_OPEN_DEFAULT)
114 fdt->max_fds <= NR_OPEN_DEFAULT) {
115 /* 114 /*
116 * The fdtable was embedded 115 * The fdtable was embedded
117 */ 116 */
118 return; 117 return;
119 }
120 if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) { 118 if (fdset_size <= PAGE_SIZE && fdarray_size <= PAGE_SIZE) {
121 kfree(fdt->open_fds); 119 kfree(fdt->open_fds);
122 kfree(fdt->close_on_exec); 120 kfree(fdt->close_on_exec);
@@ -136,9 +134,7 @@ static void free_fdtable_rcu(struct rcu_head *rcu)
136 134
137void free_fdtable(struct fdtable *fdt) 135void free_fdtable(struct fdtable *fdt)
138{ 136{
139 if (fdt->free_files || 137 if (fdt->free_files || fdt->max_fds > NR_OPEN_DEFAULT)
140 fdt->max_fdset > EMBEDDED_FD_SET_SIZE ||
141 fdt->max_fds > NR_OPEN_DEFAULT)
142 call_rcu(&fdt->rcu, free_fdtable_rcu); 138 call_rcu(&fdt->rcu, free_fdtable_rcu);
143} 139}
144 140
@@ -151,12 +147,11 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt)
151 int i; 147 int i;
152 int count; 148 int count;
153 149
154 BUG_ON(nfdt->max_fdset < fdt->max_fdset);
155 BUG_ON(nfdt->max_fds < fdt->max_fds); 150 BUG_ON(nfdt->max_fds < fdt->max_fds);
156 /* Copy the existing tables and install the new pointers */ 151 /* Copy the existing tables and install the new pointers */
157 152
158 i = fdt->max_fdset / (sizeof(unsigned long) * 8); 153 i = fdt->max_fds / (sizeof(unsigned long) * 8);
159 count = (nfdt->max_fdset - fdt->max_fdset) / 8; 154 count = (nfdt->max_fds - fdt->max_fds) / 8;
160 155
161 /* 156 /*
162 * Don't copy the entire array if the current fdset is 157 * Don't copy the entire array if the current fdset is
@@ -164,9 +159,9 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *fdt)
164 */ 159 */
165 if (i) { 160 if (i) {
166 memcpy (nfdt->open_fds, fdt->open_fds, 161 memcpy (nfdt->open_fds, fdt->open_fds,
167 fdt->max_fdset/8); 162 fdt->max_fds/8);
168 memcpy (nfdt->close_on_exec, fdt->close_on_exec, 163 memcpy (nfdt->close_on_exec, fdt->close_on_exec,
169 fdt->max_fdset/8); 164 fdt->max_fds/8);
170 memset (&nfdt->open_fds->fds_bits[i], 0, count); 165 memset (&nfdt->open_fds->fds_bits[i], 0, count);
171 memset (&nfdt->close_on_exec->fds_bits[i], 0, count); 166 memset (&nfdt->close_on_exec->fds_bits[i], 0, count);
172 } 167 }
@@ -201,7 +196,7 @@ fd_set * alloc_fdset(int num)
201 196
202void free_fdset(fd_set *array, int num) 197void free_fdset(fd_set *array, int num)
203{ 198{
204 if (num <= EMBEDDED_FD_SET_SIZE) /* Don't free an embedded fdset */ 199 if (num <= NR_OPEN_DEFAULT) /* Don't free an embedded fdset */
205 return; 200 return;
206 else if (num <= 8 * PAGE_SIZE) 201 else if (num <= 8 * PAGE_SIZE)
207 kfree(array); 202 kfree(array);
@@ -220,18 +215,6 @@ static struct fdtable *alloc_fdtable(int nr)
220 if (!fdt) 215 if (!fdt)
221 goto out; 216 goto out;
222 217
223 nfds = max_t(int, 8 * L1_CACHE_BYTES, roundup_pow_of_two(nr + 1));
224 if (nfds > NR_OPEN)
225 nfds = NR_OPEN;
226
227 new_openset = alloc_fdset(nfds);
228 new_execset = alloc_fdset(nfds);
229 if (!new_openset || !new_execset)
230 goto out;
231 fdt->open_fds = new_openset;
232 fdt->close_on_exec = new_execset;
233 fdt->max_fdset = nfds;
234
235 nfds = NR_OPEN_DEFAULT; 218 nfds = NR_OPEN_DEFAULT;
236 /* 219 /*
237 * Expand to the max in easy steps, and keep expanding it until 220 * Expand to the max in easy steps, and keep expanding it until
@@ -251,15 +234,21 @@ static struct fdtable *alloc_fdtable(int nr)
251 nfds = NR_OPEN; 234 nfds = NR_OPEN;
252 } 235 }
253 } while (nfds <= nr); 236 } while (nfds <= nr);
237
238 new_openset = alloc_fdset(nfds);
239 new_execset = alloc_fdset(nfds);
240 if (!new_openset || !new_execset)
241 goto out;
242 fdt->open_fds = new_openset;
243 fdt->close_on_exec = new_execset;
244
254 new_fds = alloc_fd_array(nfds); 245 new_fds = alloc_fd_array(nfds);
255 if (!new_fds) 246 if (!new_fds)
256 goto out2; 247 goto out;
257 fdt->fd = new_fds; 248 fdt->fd = new_fds;
258 fdt->max_fds = nfds; 249 fdt->max_fds = nfds;
259 fdt->free_files = NULL; 250 fdt->free_files = NULL;
260 return fdt; 251 return fdt;
261out2:
262 nfds = fdt->max_fdset;
263out: 252out:
264 free_fdset(new_openset, nfds); 253 free_fdset(new_openset, nfds);
265 free_fdset(new_execset, nfds); 254 free_fdset(new_execset, nfds);
@@ -290,7 +279,7 @@ static int expand_fdtable(struct files_struct *files, int nr)
290 * we dropped the lock 279 * we dropped the lock
291 */ 280 */
292 cur_fdt = files_fdtable(files); 281 cur_fdt = files_fdtable(files);
293 if (nr >= cur_fdt->max_fds || nr >= cur_fdt->max_fdset) { 282 if (nr >= cur_fdt->max_fds) {
294 /* Continue as planned */ 283 /* Continue as planned */
295 copy_fdtable(new_fdt, cur_fdt); 284 copy_fdtable(new_fdt, cur_fdt);
296 rcu_assign_pointer(files->fdt, new_fdt); 285 rcu_assign_pointer(files->fdt, new_fdt);
@@ -316,11 +305,10 @@ int expand_files(struct files_struct *files, int nr)
316 305
317 fdt = files_fdtable(files); 306 fdt = files_fdtable(files);
318 /* Do we need to expand? */ 307 /* Do we need to expand? */
319 if (nr < fdt->max_fdset && nr < fdt->max_fds) 308 if (nr < fdt->max_fds)
320 return 0; 309 return 0;
321 /* Can we expand? */ 310 /* Can we expand? */
322 if (fdt->max_fdset >= NR_OPEN || fdt->max_fds >= NR_OPEN || 311 if (nr >= NR_OPEN)
323 nr >= NR_OPEN)
324 return -EMFILE; 312 return -EMFILE;
325 313
326 /* All good, so we try */ 314 /* All good, so we try */
diff --git a/fs/open.c b/fs/open.c
index 0d94319e8681..c989fb4cf7b9 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -864,8 +864,7 @@ int get_unused_fd(void)
864 864
865repeat: 865repeat:
866 fdt = files_fdtable(files); 866 fdt = files_fdtable(files);
867 fd = find_next_zero_bit(fdt->open_fds->fds_bits, 867 fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
868 fdt->max_fdset,
869 files->next_fd); 868 files->next_fd);
870 869
871 /* 870 /*
diff --git a/fs/select.c b/fs/select.c
index dcbc1112b7ec..fe0893afd931 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -311,7 +311,7 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
311{ 311{
312 fd_set_bits fds; 312 fd_set_bits fds;
313 void *bits; 313 void *bits;
314 int ret, max_fdset; 314 int ret, max_fds;
315 unsigned int size; 315 unsigned int size;
316 struct fdtable *fdt; 316 struct fdtable *fdt;
317 /* Allocate small arguments on the stack to save memory and be faster */ 317 /* Allocate small arguments on the stack to save memory and be faster */
@@ -321,13 +321,13 @@ static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
321 if (n < 0) 321 if (n < 0)
322 goto out_nofds; 322 goto out_nofds;
323 323
324 /* max_fdset can increase, so grab it once to avoid race */ 324 /* max_fds can increase, so grab it once to avoid race */
325 rcu_read_lock(); 325 rcu_read_lock();
326 fdt = files_fdtable(current->files); 326 fdt = files_fdtable(current->files);
327 max_fdset = fdt->max_fdset; 327 max_fds = fdt->max_fds;
328 rcu_read_unlock(); 328 rcu_read_unlock();
329 if (n > max_fdset) 329 if (n > max_fds)
330 n = max_fdset; 330 n = max_fds;
331 331
332 /* 332 /*
333 * We need 6 bitmaps (in/out/ex for both incoming and outgoing), 333 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),