static struct fdtable *alloc_fdtable(int nr) { struct fdtable *fdt = NULL; int nfds = 0; fd_set *new_openset = NULL, *new_execset = NULL; struct file **new_fds; fdt = kzalloc(sizeof(*fdt), GFP_KERNEL); if (!fdt) goto out; nfds = max_t(int, 8 * L1_CACHE_BYTES, roundup_pow_of_two(nr + 1)); if (nfds > NR_OPEN) nfds = NR_OPEN; new_openset = alloc_fdset(nfds); new_execset = alloc_fdset(nfds); if (!new_openset || !new_execset) goto out; fdt->open_fds = new_openset; fdt->close_on_exec = new_execset; fdt->max_fdset = nfds; nfds = NR_OPEN_DEFAULT; /* * Expand to the max in easy steps, and keep expanding it until * we have enough for the requested fd array size. */ do { #if NR_OPEN_DEFAULT < 256 if (nfds < 256) nfds = 256; else #endif if (nfds < (PAGE_SIZE / sizeof(struct file *))) nfds = PAGE_SIZE / sizeof(struct file *); else { nfds = nfds * 2; if (nfds > NR_OPEN) nfds = NR_OPEN; } } while (nfds <= nr); new_fds = alloc_fd_array(nfds); if (!new_fds) goto out2; fdt->fd = new_fds; fdt->max_fds = nfds; fdt->free_files = NULL; return fdt; out2: nfds = fdt->max_fdset; out: if (new_openset) free_fdset(new_openset, nfds); if (new_execset) free_fdset(new_execset, nfds); kfree(fdt); return NULL; }
/* * Expand the fdset in the files_struct. Called with the files spinlock * held for write. */ int expand_fdset(struct files_struct *files, int nr) { fd_set *new_openset = NULL, *new_execset = NULL; int error, nfds = 0; error = -EMFILE; if (files->max_fdset >= NR_OPEN || nr >= NR_OPEN) goto out; nfds = files->max_fdset; spin_unlock(&files->file_lock); /* Expand to the max in easy steps */ do { if (nfds < (PAGE_SIZE * 8)) nfds = PAGE_SIZE * 8; else { nfds = nfds * 2; if (nfds > NR_OPEN) nfds = NR_OPEN; } } while (nfds <= nr); error = -ENOMEM; new_openset = alloc_fdset(nfds); new_execset = alloc_fdset(nfds); spin_lock(&files->file_lock); if (!new_openset || !new_execset) goto out; error = 0; /* Copy the existing tables and install the new pointers */ if (nfds > files->max_fdset) { int i = files->max_fdset / (sizeof(unsigned long) * 8); int count = (nfds - files->max_fdset) / 8; /* * Don't copy the entire array if the current fdset is * not yet initialised. */ if (i) { memcpy (new_openset, files->open_fds, files->max_fdset/8); memcpy (new_execset, files->close_on_exec, files->max_fdset/8); memset (&new_openset->fds_bits[i], 0, count); memset (&new_execset->fds_bits[i], 0, count); } nfds = xchg(&files->max_fdset, nfds); new_openset = xchg(&files->open_fds, new_openset); new_execset = xchg(&files->close_on_exec, new_execset); spin_unlock(&files->file_lock); free_fdset (new_openset, nfds); free_fdset (new_execset, nfds); spin_lock(&files->file_lock); return 0; } /* Somebody expanded the array while we slept ... */ out: spin_unlock(&files->file_lock); if (new_openset) free_fdset(new_openset, nfds); if (new_execset) free_fdset(new_execset, nfds); spin_lock(&files->file_lock); return error; }