Skip to content

Commit 1d3b4be

Browse files
author
Al Viro
committed
alloc_fdtable(): change calling conventions.
First of all, tell it how many slots do we want, not which slot is wanted. It makes one caller (dup_fd()) more straightforward and doesn't harm another (expand_fdtable()). Furthermore, make it return ERR_PTR() on failure rather than returning NULL. Simplifies the callers. Simplify the size calculation, while we are at it - note that we always have slots_wanted greater than BITS_PER_LONG. What the rules boil down to is * use the smallest power of two large enough to give us that many slots * on 32bit skip 64 and 128 - the minimal capacity we want there is 256 slots (i.e. 1Kb fd array). * on 64bit don't skip anything, the minimal capacity is 128 - and we'll never be asked for 64 or less. 128 slots means 1Kb fd array, again. * on 128bit, if that ever happens, don't skip anything - we'll never be asked for 128 or less, so the fd array allocation will be at least 2Kb. Reviewed-by: Christian Brauner <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent 0c40bf4 commit 1d3b4be

File tree

1 file changed

+29
-46
lines changed

1 file changed

+29
-46
lines changed

fs/file.c

Lines changed: 29 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -89,41 +89,44 @@ static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt)
8989
* 'unsigned long' in some places, but simply because that is how the Linux
9090
* kernel bitmaps are defined to work: they are not "bits in an array of bytes",
9191
* they are very much "bits in an array of unsigned long".
92-
*
93-
* The ALIGN(nr, BITS_PER_LONG) here is for clarity: since we just multiplied
94-
* by that "1024/sizeof(ptr)" before, we already know there are sufficient
95-
* clear low bits. Clang seems to realize that, gcc ends up being confused.
96-
*
97-
* On a 128-bit machine, the ALIGN() would actually matter. In the meantime,
98-
* let's consider it documentation (and maybe a test-case for gcc to improve
99-
* its code generation ;)
10092
*/
101-
static struct fdtable * alloc_fdtable(unsigned int nr)
93+
static struct fdtable *alloc_fdtable(unsigned int slots_wanted)
10294
{
10395
struct fdtable *fdt;
96+
unsigned int nr;
10497
void *data;
10598

10699
/*
107100
* Figure out how many fds we actually want to support in this fdtable.
108101
* Allocation steps are keyed to the size of the fdarray, since it
109102
* grows far faster than any of the other dynamic data. We try to fit
110103
* the fdarray into comfortable page-tuned chunks: starting at 1024B
111-
* and growing in powers of two from there on.
104+
* and growing in powers of two from there on. Since we called only
105+
* with slots_wanted > BITS_PER_LONG (embedded instance in files->fdtab
106+
* already gives BITS_PER_LONG slots), the above boils down to
107+
* 1. use the smallest power of two large enough to give us that many
108+
* slots.
109+
* 2. on 32bit skip 64 and 128 - the minimal capacity we want there is
110+
* 256 slots (i.e. 1Kb fd array).
111+
* 3. on 64bit don't skip anything, 1Kb fd array means 128 slots there
112+
* and we are never going to be asked for 64 or less.
112113
*/
113-
nr /= (1024 / sizeof(struct file *));
114-
nr = roundup_pow_of_two(nr + 1);
115-
nr *= (1024 / sizeof(struct file *));
116-
nr = ALIGN(nr, BITS_PER_LONG);
114+
if (IS_ENABLED(CONFIG_32BIT) && slots_wanted < 256)
115+
nr = 256;
116+
else
117+
nr = roundup_pow_of_two(slots_wanted);
117118
/*
118119
* Note that this can drive nr *below* what we had passed if sysctl_nr_open
119-
* had been set lower between the check in expand_files() and here. Deal
120-
* with that in caller, it's cheaper that way.
120+
* had been set lower between the check in expand_files() and here.
121121
*
122122
* We make sure that nr remains a multiple of BITS_PER_LONG - otherwise
123123
* bitmaps handling below becomes unpleasant, to put it mildly...
124124
*/
125-
if (unlikely(nr > sysctl_nr_open))
126-
nr = ((sysctl_nr_open - 1) | (BITS_PER_LONG - 1)) + 1;
125+
if (unlikely(nr > sysctl_nr_open)) {
126+
nr = round_down(sysctl_nr_open, BITS_PER_LONG);
127+
if (nr < slots_wanted)
128+
return ERR_PTR(-EMFILE);
129+
}
127130

128131
fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL_ACCOUNT);
129132
if (!fdt)
@@ -152,7 +155,7 @@ static struct fdtable * alloc_fdtable(unsigned int nr)
152155
out_fdt:
153156
kfree(fdt);
154157
out:
155-
return NULL;
158+
return ERR_PTR(-ENOMEM);
156159
}
157160

158161
/*
@@ -169,7 +172,7 @@ static int expand_fdtable(struct files_struct *files, unsigned int nr)
169172
struct fdtable *new_fdt, *cur_fdt;
170173

171174
spin_unlock(&files->file_lock);
172-
new_fdt = alloc_fdtable(nr);
175+
new_fdt = alloc_fdtable(nr + 1);
173176

174177
/* make sure all fd_install() have seen resize_in_progress
175178
* or have finished their rcu_read_lock_sched() section.
@@ -178,16 +181,8 @@ static int expand_fdtable(struct files_struct *files, unsigned int nr)
178181
synchronize_rcu();
179182

180183
spin_lock(&files->file_lock);
181-
if (!new_fdt)
182-
return -ENOMEM;
183-
/*
184-
* extremely unlikely race - sysctl_nr_open decreased between the check in
185-
* caller and alloc_fdtable(). Cheaper to catch it here...
186-
*/
187-
if (unlikely(new_fdt->max_fds <= nr)) {
188-
__free_fdtable(new_fdt);
189-
return -EMFILE;
190-
}
184+
if (IS_ERR(new_fdt))
185+
return PTR_ERR(new_fdt);
191186
cur_fdt = files_fdtable(files);
192187
BUG_ON(nr < cur_fdt->max_fds);
193188
copy_fdtable(new_fdt, cur_fdt);
@@ -308,7 +303,6 @@ struct files_struct *dup_fd(struct files_struct *oldf, struct fd_range *punch_ho
308303
struct file **old_fds, **new_fds;
309304
unsigned int open_files, i;
310305
struct fdtable *old_fdt, *new_fdt;
311-
int error;
312306

313307
newf = kmem_cache_alloc(files_cachep, GFP_KERNEL);
314308
if (!newf)
@@ -340,17 +334,10 @@ struct files_struct *dup_fd(struct files_struct *oldf, struct fd_range *punch_ho
340334
if (new_fdt != &newf->fdtab)
341335
__free_fdtable(new_fdt);
342336

343-
new_fdt = alloc_fdtable(open_files - 1);
344-
if (!new_fdt) {
345-
error = -ENOMEM;
346-
goto out_release;
347-
}
348-
349-
/* beyond sysctl_nr_open; nothing to do */
350-
if (unlikely(new_fdt->max_fds < open_files)) {
351-
__free_fdtable(new_fdt);
352-
error = -EMFILE;
353-
goto out_release;
337+
new_fdt = alloc_fdtable(open_files);
338+
if (IS_ERR(new_fdt)) {
339+
kmem_cache_free(files_cachep, newf);
340+
return ERR_CAST(new_fdt);
354341
}
355342

356343
/*
@@ -391,10 +378,6 @@ struct files_struct *dup_fd(struct files_struct *oldf, struct fd_range *punch_ho
391378
rcu_assign_pointer(newf->fdt, new_fdt);
392379

393380
return newf;
394-
395-
out_release:
396-
kmem_cache_free(files_cachep, newf);
397-
return ERR_PTR(error);
398381
}
399382

400383
static struct fdtable *close_files(struct files_struct * files)

0 commit comments

Comments
 (0)