Release 4.7 fs/file.c
/*
* linux/fs/file.c
*
* Copyright (C) 1998-1999, Stephen Tweedie and Bill Hawes
*
* Manage the dynamic fd arrays in the process files_struct.
*/
#include <linux/syscalls.h>
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/mmzone.h>
#include <linux/time.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/file.h>
#include <linux/fdtable.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <linux/workqueue.h>
int sysctl_nr_open __read_mostly = 1024*1024;
int sysctl_nr_open_min = BITS_PER_LONG;
/* our min() is unusable in constant expressions ;-/ */
#define __const_min(x, y) ((x) < (y) ? (x) : (y))
int sysctl_nr_open_max = __const_min(INT_MAX, ~(size_t)0/sizeof(void *)) &
-BITS_PER_LONG;
static void *alloc_fdmem(size_t size)
{
/*
* Very large allocations can stress page reclaim, so fall back to
* vmalloc() if the allocation size will be considered "large" by the VM.
*/
if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
void *data = kmalloc(size, GFP_KERNEL_ACCOUNT |
__GFP_NOWARN | __GFP_NORETRY);
if (data != NULL)
return data;
}
return __vmalloc(size, GFP_KERNEL_ACCOUNT | __GFP_HIGHMEM, PAGE_KERNEL);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
andrew morton | andrew morton | 15 | 25.42% | 1 | 14.29% |
pre-git | pre-git | 14 | 23.73% | 1 | 14.29% |
changli gao | changli gao | 13 | 22.03% | 1 | 14.29% |
vladimir davydov | vladimir davydov | 8 | 13.56% | 1 | 14.29% |
vadim lobanov | vadim lobanov | 6 | 10.17% | 1 | 14.29% |
eric w. biederman | eric w. biederman | 2 | 3.39% | 1 | 14.29% |
david howells | david howells | 1 | 1.69% | 1 | 14.29% |
| Total | 59 | 100.00% | 7 | 100.00% |
static void __free_fdtable(struct fdtable *fdt)
{
kvfree(fdt->fd);
kvfree(fdt->open_fds);
kfree(fdt);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dipankar sarma | dipankar sarma | 12 | 40.00% | 2 | 25.00% |
pre-git | pre-git | 7 | 23.33% | 1 | 12.50% |
changli gao | changli gao | 6 | 20.00% | 1 | 12.50% |
al viro | al viro | 2 | 6.67% | 1 | 12.50% |
vadim lobanov | vadim lobanov | 1 | 3.33% | 1 | 12.50% |
linus torvalds | linus torvalds | 1 | 3.33% | 1 | 12.50% |
prasanna meda | prasanna meda | 1 | 3.33% | 1 | 12.50% |
| Total | 30 | 100.00% | 8 | 100.00% |
static void free_fdtable_rcu(struct rcu_head *rcu)
{
__free_fdtable(container_of(rcu, struct fdtable, rcu));
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dipankar sarma | dipankar sarma | 21 | 87.50% | 1 | 33.33% |
al viro | al viro | 3 | 12.50% | 2 | 66.67% |
| Total | 24 | 100.00% | 3 | 100.00% |
#define BITBIT_NR(nr) BITS_TO_LONGS(BITS_TO_LONGS(nr))
#define BITBIT_SIZE(nr) (BITBIT_NR(nr) * sizeof(long))
/*
* Copy 'count' fd bits from the old table to the new table and clear the extra
* space if any. This does not copy the file pointers. Called with the files
* spinlock held for write.
*/
static void copy_fd_bitmaps(struct fdtable *nfdt, struct fdtable *ofdt,
unsigned int count)
{
unsigned int cpy, set;
cpy = count / BITS_PER_BYTE;
set = (nfdt->max_fds - count) / BITS_PER_BYTE;
memcpy(nfdt->open_fds, ofdt->open_fds, cpy);
memset((char *)nfdt->open_fds + cpy, 0, set);
memcpy(nfdt->close_on_exec, ofdt->close_on_exec, cpy);
memset((char *)nfdt->close_on_exec + cpy, 0, set);
cpy = BITBIT_SIZE(count);
set = BITBIT_SIZE(nfdt->max_fds) - cpy;
memcpy(nfdt->full_fds_bits, ofdt->full_fds_bits, cpy);
memset((char *)nfdt->full_fds_bits + cpy, 0, set);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dipankar sarma | dipankar sarma | 48 | 31.58% | 1 | 20.00% |
vadim lobanov | vadim lobanov | 41 | 26.97% | 2 | 40.00% |
eric biggers | eric biggers | 39 | 25.66% | 1 | 20.00% |
pre-git | pre-git | 24 | 15.79% | 1 | 20.00% |
| Total | 152 | 100.00% | 5 | 100.00% |
/*
* Copy all file descriptors from the old table to the new, expanded table and
* clear the extra space. Called with the files spinlock held for write.
*/
static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt)
{
unsigned int cpy, set;
BUG_ON(nfdt->max_fds < ofdt->max_fds);
cpy = ofdt->max_fds * sizeof(struct file *);
set = (nfdt->max_fds - ofdt->max_fds) * sizeof(struct file *);
memcpy(nfdt->fd, ofdt->fd, cpy);
memset((char *)nfdt->fd + cpy, 0, set);
copy_fd_bitmaps(nfdt, ofdt, ofdt->max_fds);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
eric biggers | eric biggers | 66 | 62.26% | 1 | 33.33% |
linus torvalds | linus torvalds | 39 | 36.79% | 1 | 33.33% |
pre-git | pre-git | 1 | 0.94% | 1 | 33.33% |
| Total | 106 | 100.00% | 3 | 100.00% |
static struct fdtable * alloc_fdtable(unsigned int nr)
{
struct fdtable *fdt;
void *data;
/*
* Figure out how many fds we actually want to support in this fdtable.
* Allocation steps are keyed to the size of the fdarray, since it
* grows far faster than any of the other dynamic data. We try to fit
* the fdarray into comfortable page-tuned chunks: starting at 1024B
* and growing in powers of two from there on.
*/
nr /= (1024 / sizeof(struct file *));
nr = roundup_pow_of_two(nr + 1);
nr *= (1024 / sizeof(struct file *));
/*
* Note that this can drive nr *below* what we had passed if sysctl_nr_open
* had been set lower between the check in expand_files() and here. Deal
* with that in caller, it's cheaper that way.
*
* We make sure that nr remains a multiple of BITS_PER_LONG - otherwise
* bitmaps handling below becomes unpleasant, to put it mildly...
*/
if (unlikely(nr > sysctl_nr_open))
nr = ((sysctl_nr_open - 1) | (BITS_PER_LONG - 1)) + 1;
fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL_ACCOUNT);
if (!fdt)
goto out;
fdt->max_fds = nr;
data = alloc_fdmem(nr * sizeof(struct file *));
if (!data)
goto out_fdt;
fdt->fd = data;
data = alloc_fdmem(max_t(size_t,
2 * nr / BITS_PER_BYTE + BITBIT_SIZE(nr), L1_CACHE_BYTES));
if (!data)
goto out_arr;
fdt->open_fds = data;
data += nr / BITS_PER_BYTE;
fdt->close_on_exec = data;
data += nr / BITS_PER_BYTE;
fdt->full_fds_bits = data;
return fdt;
out_arr:
kvfree(fdt->fd);
out_fdt:
kfree(fdt);
out:
return NULL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
vadim lobanov | vadim lobanov | 105 | 46.67% | 2 | 16.67% |
dipankar sarma | dipankar sarma | 36 | 16.00% | 2 | 16.67% |
pre-git | pre-git | 36 | 16.00% | 1 | 8.33% |
al viro | al viro | 19 | 8.44% | 2 | 16.67% |
linus torvalds | linus torvalds | 17 | 7.56% | 1 | 8.33% |
david howells | david howells | 7 | 3.11% | 1 | 8.33% |
changli gao | changli gao | 2 | 0.89% | 1 | 8.33% |
eric dumazet | eric dumazet | 2 | 0.89% | 1 | 8.33% |
vladimir davydov | vladimir davydov | 1 | 0.44% | 1 | 8.33% |
| Total | 225 | 100.00% | 12 | 100.00% |
/*
* Expand the file descriptor table.
* This function will allocate a new fdtable and both fd array and fdset, of
* the given size.
* Return <0 error code on error; 1 on successful completion.
* The files->file_lock should be held on entry, and will be held on exit.
*/
static int expand_fdtable(struct files_struct *files, int nr)
__releases(files->file_lock)
__acquires(files->file_lock)
{
struct fdtable *new_fdt, *cur_fdt;
spin_unlock(&files->file_lock);
new_fdt = alloc_fdtable(nr);
/* make sure all __fd_install() have seen resize_in_progress
* or have finished their rcu_read_lock_sched() section.
*/
if (atomic_read(&files->count) > 1)
synchronize_sched();
spin_lock(&files->file_lock);
if (!new_fdt)
return -ENOMEM;
/*
* extremely unlikely race - sysctl_nr_open decreased between the check in
* caller and alloc_fdtable(). Cheaper to catch it here...
*/
if (unlikely(new_fdt->max_fds <= nr)) {
__free_fdtable(new_fdt);
return -EMFILE;
}
cur_fdt = files_fdtable(files);
BUG_ON(nr < cur_fdt->max_fds);
copy_fdtable(new_fdt, cur_fdt);
rcu_assign_pointer(files->fdt, new_fdt);
if (cur_fdt != &files->fdtab)
call_rcu(&cur_fdt->rcu, free_fdtable_rcu);
/* coupled with smp_rmb() in __fd_install() */
smp_wmb();
return 1;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
dipankar sarma | dipankar sarma | 51 | 31.29% | 1 | 11.11% |
vadim lobanov | vadim lobanov | 35 | 21.47% | 2 | 22.22% |
al viro | al viro | 32 | 19.63% | 3 | 33.33% |
eric dumazet | eric dumazet | 24 | 14.72% | 1 | 11.11% |
pre-git | pre-git | 20 | 12.27% | 1 | 11.11% |
changli gao | changli gao | 1 | 0.61% | 1 | 11.11% |
| Total | 163 | 100.00% | 9 | 100.00% |
/*
* Expand files.
* This function will expand the file structures, if the requested size exceeds
* the current capacity and there is room for expansion.
* Return <0 error code on error; 0 when nothing done; 1 when files were
* expanded and execution may have blocked.
* The files->file_lock should be held on entry, and will be held on exit.
*/
static int expand_files(struct files_struct *files, int nr)
__releases(files->file_lock)
__acquires(files->file_lock)
{
struct fdtable *fdt;
int expanded = 0;
repeat:
fdt = files_fdtable(files);
/* Do we need to expand? */
if (nr < fdt->max_fds)
return expanded;
/* Can we expand? */
if (nr >= sysctl_nr_open)
return -EMFILE;
if (unlikely(files->resize_in_progress)) {
spin_unlock(&files->file_lock);
expanded = 1;
wait_event(files->resize_wait, !files->resize_in_progress);
spin_lock(&files->file_lock);
goto repeat;
}
/* All good, so we try */
files->resize_in_progress = true;
expanded = expand_fdtable(files, nr);
files->resize_in_progress = false;
wake_up_all(&files->resize_wait);
return expanded;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
eric dumazet | eric dumazet | 92 | 62.59% | 2 | 28.57% |
prasanna meda | prasanna meda | 27 | 18.37% | 1 | 14.29% |
dipankar sarma | dipankar sarma | 19 | 12.93% | 2 | 28.57% |
vadim lobanov | vadim lobanov | 8 | 5.44% | 1 | 14.29% |
al viro | al viro | 1 | 0.68% | 1 | 14.29% |
| Total | 147 | 100.00% | 7 | 100.00% |
static inline void __set_close_on_exec(int fd, struct fdtable *fdt)
{
__set_bit(fd, fdt->close_on_exec);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 24 | 100.00% | 1 | 100.00% |
| Total | 24 | 100.00% | 1 | 100.00% |
static inline void __clear_close_on_exec(int fd, struct fdtable *fdt)
{
if (test_bit(fd, fdt->close_on_exec))
__clear_bit(fd, fdt->close_on_exec);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 24 | 68.57% | 1 | 50.00% |
linus torvalds | linus torvalds | 11 | 31.43% | 1 | 50.00% |
| Total | 35 | 100.00% | 2 | 100.00% |
static inline void __set_open_fd(unsigned int fd, struct fdtable *fdt)
{
__set_bit(fd, fdt->open_fds);
fd /= BITS_PER_LONG;
if (!~fdt->open_fds[fd])
__set_bit(fd, fdt->full_fds_bits);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
linus torvalds | linus torvalds | 25 | 51.02% | 1 | 50.00% |
al viro | al viro | 24 | 48.98% | 1 | 50.00% |
| Total | 49 | 100.00% | 2 | 100.00% |
static inline void __clear_open_fd(unsigned int fd, struct fdtable *fdt)
{
__clear_bit(fd, fdt->open_fds);
__clear_bit(fd / BITS_PER_LONG, fdt->full_fds_bits);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 24 | 66.67% | 1 | 50.00% |
linus torvalds | linus torvalds | 12 | 33.33% | 1 | 50.00% |
| Total | 36 | 100.00% | 2 | 100.00% |
static int count_open_files(struct fdtable *fdt)
{
int size = fdt->max_fds;
int i;
/* Find the last open fd */
for (i = size / BITS_PER_LONG; i > 0; ) {
if (fdt->open_fds[--i])
break;
}
i = (i + 1) * BITS_PER_LONG;
return i;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 59 | 96.72% | 1 | 50.00% |
david howells | david howells | 2 | 3.28% | 1 | 50.00% |
| Total | 61 | 100.00% | 2 | 100.00% |
/*
* Allocate a new files structure and copy contents from the
* passed in files structure.
* errorp will be valid only when the returned files_struct is NULL.
*/
struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
{
struct files_struct *newf;
struct file **old_fds, **new_fds;
int open_files, i;
struct fdtable *old_fdt, *new_fdt;
*errorp = -ENOMEM;
newf = kmem_cache_alloc(files_cachep, GFP_KERNEL);
if (!newf)
goto out;
atomic_set(&newf->count, 1);
spin_lock_init(&newf->file_lock);
newf->resize_in_progress = false;
init_waitqueue_head(&newf->resize_wait);
newf->next_fd = 0;
new_fdt = &newf->fdtab;
new_fdt->max_fds = NR_OPEN_DEFAULT;
new_fdt->close_on_exec = newf->close_on_exec_init;
new_fdt->open_fds = newf->open_fds_init;
new_fdt->full_fds_bits = newf->full_fds_bits_init;
new_fdt->fd = &newf->fd_array[0];
spin_lock(&oldf->file_lock);
old_fdt = files_fdtable(oldf);
open_files = count_open_files(old_fdt);
/*
* Check whether we need to allocate a larger fd array and fd set.
*/
while (unlikely(open_files > new_fdt->max_fds)) {
spin_unlock(&oldf->file_lock);
if (new_fdt != &newf->fdtab)
__free_fdtable(new_fdt);
new_fdt = alloc_fdtable(open_files - 1);
if (!new_fdt) {
*errorp = -ENOMEM;
goto out_release;
}
/* beyond sysctl_nr_open; nothing to do */
if (unlikely(new_fdt->max_fds < open_files)) {
__free_fdtable(new_fdt);
*errorp = -EMFILE;
goto out_release;
}
/*
* Reacquire the oldf lock and a pointer to its fd table
* who knows it may have a new bigger fd table. We need
* the latest pointer.
*/
spin_lock(&oldf->file_lock);
old_fdt = files_fdtable(oldf);
open_files = count_open_files(old_fdt);
}
copy_fd_bitmaps(new_fdt, old_fdt, open_files);
old_fds = old_fdt->fd;
new_fds = new_fdt->fd;
for (i = open_files; i != 0; i--) {
struct file *f = *old_fds++;
if (f) {
get_file(f);
} else {
/*
* The fd may be claimed in the fd bitmap but not yet
* instantiated in the files array if a sibling thread
* is partway through open(). So make sure that this
* fd is available to the new process.
*/
__clear_open_fd(open_files - i, new_fdt);
}
rcu_assign_pointer(*new_fds++, f);
}
spin_unlock(&oldf->file_lock);
/* clear the remainder */
memset(new_fds, 0, (new_fdt->max_fds - open_files) * sizeof(struct file *));
rcu_assign_pointer(newf->fdt, new_fdt);
return newf;
out_release:
kmem_cache_free(files_cachep, newf);
out:
return NULL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 382 | 90.31% | 4 | 44.44% |
eric dumazet | eric dumazet | 14 | 3.31% | 1 | 11.11% |
eric biggers | eric biggers | 13 | 3.07% | 1 | 11.11% |
linus torvalds | linus torvalds | 11 | 2.60% | 1 | 11.11% |
changli gao | changli gao | 2 | 0.47% | 1 | 11.11% |
david howells | david howells | 1 | 0.24% | 1 | 11.11% |
| Total | 423 | 100.00% | 9 | 100.00% |
static struct fdtable *close_files(struct files_struct * files)
{
/*
* It is safe to dereference the fd table without RCU or
* ->file_lock because this is the last reference to the
* files structure.
*/
struct fdtable *fdt = rcu_dereference_raw(files->fdt);
int i, j = 0;
for (;;) {
unsigned long set;
i = j * BITS_PER_LONG;
if (i >= fdt->max_fds)
break;
set = fdt->open_fds[j++];
while (set) {
if (set & 1) {
struct file * file = xchg(&fdt->fd[i], NULL);
if (file) {
filp_close(file, files);
cond_resched_rcu_qs();
}
}
i++;
set >>= 1;
}
}
return fdt;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 107 | 84.25% | 1 | 33.33% |
oleg nesterov | oleg nesterov | 19 | 14.96% | 1 | 33.33% |
paul e. mckenney | paul e. mckenney | 1 | 0.79% | 1 | 33.33% |
| Total | 127 | 100.00% | 3 | 100.00% |
struct files_struct *get_files_struct(struct task_struct *task)
{
struct files_struct *files;
task_lock(task);
files = task->files;
if (files)
atomic_inc(&files->count);
task_unlock(task);
return files;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 48 | 100.00% | 1 | 100.00% |
| Total | 48 | 100.00% | 1 | 100.00% |
void put_files_struct(struct files_struct *files)
{
if (atomic_dec_and_test(&files->count)) {
struct fdtable *fdt = close_files(files);
/* free the arrays if they are not embedded */
if (fdt != &files->fdtab)
__free_fdtable(fdt);
kmem_cache_free(files_cachep, files);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 48 | 88.89% | 2 | 66.67% |
oleg nesterov | oleg nesterov | 6 | 11.11% | 1 | 33.33% |
| Total | 54 | 100.00% | 3 | 100.00% |
void reset_files_struct(struct files_struct *files)
{
struct task_struct *tsk = current;
struct files_struct *old;
old = tsk->files;
task_lock(tsk);
tsk->files = files;
task_unlock(tsk);
put_files_struct(old);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 49 | 100.00% | 1 | 100.00% |
| Total | 49 | 100.00% | 1 | 100.00% |
void exit_files(struct task_struct *tsk)
{
struct files_struct * files = tsk->files;
if (files) {
task_lock(tsk);
tsk->files = NULL;
task_unlock(tsk);
put_files_struct(files);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 46 | 100.00% | 1 | 100.00% |
| Total | 46 | 100.00% | 1 | 100.00% |
struct files_struct init_files = {
.count = ATOMIC_INIT(1),
.fdt = &init_files.fdtab,
.fdtab = {
.max_fds = NR_OPEN_DEFAULT,
.fd = &init_files.fd_array[0],
.close_on_exec = init_files.close_on_exec_init,
.open_fds = init_files.open_fds_init,
.full_fds_bits = init_files.full_fds_bits_init,
},
.file_lock = __SPIN_LOCK_UNLOCKED(init_files.file_lock),
};
static unsigned long find_next_fd(struct fdtable *fdt, unsigned long start)
{
unsigned long maxfd = fdt->max_fds;
unsigned long maxbit = maxfd / BITS_PER_LONG;
unsigned long bitbit = start / BITS_PER_LONG;
bitbit = find_next_zero_bit(fdt->full_fds_bits, maxbit, bitbit) * BITS_PER_LONG;
if (bitbit > maxfd)
return maxfd;
if (bitbit > start)
start = bitbit;
return find_next_zero_bit(fdt->open_fds, maxfd, start);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
linus torvalds | linus torvalds | 86 | 100.00% | 1 | 100.00% |
| Total | 86 | 100.00% | 1 | 100.00% |
/*
* allocate a file descriptor, mark it busy.
*/
int __alloc_fd(struct files_struct *files,
unsigned start, unsigned end, unsigned flags)
{
unsigned int fd;
int error;
struct fdtable *fdt;
spin_lock(&files->file_lock);
repeat:
fdt = files_fdtable(files);
fd = start;
if (fd < files->next_fd)
fd = files->next_fd;
if (fd < fdt->max_fds)
fd = find_next_fd(fdt, fd);
/*
* N.B. For clone tasks sharing a files structure, this test
* will limit the total number of files that can be opened.
*/
error = -EMFILE;
if (fd >= end)
goto out;
error = expand_files(files, fd);
if (error < 0)
goto out;
/*
* If we needed to expand the fs array we
* might have blocked - try again.
*/
if (error)
goto repeat;
if (start <= files->next_fd)
files->next_fd = fd + 1;
__set_open_fd(fd, fdt);
if (flags & O_CLOEXEC)
__set_close_on_exec(fd, fdt);
else
__clear_close_on_exec(fd, fdt);
error = fd;
#if 1
/* Sanity check */
if (rcu_access_pointer(fdt->fd[fd]) != NULL) {
printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd);
rcu_assign_pointer(fdt->fd[fd], NULL);
}
#endif
out:
spin_unlock(&files->file_lock);
return error;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 222 | 97.80% | 3 | 50.00% |
david howells | david howells | 3 | 1.32% | 1 | 16.67% |
linus torvalds | linus torvalds | 1 | 0.44% | 1 | 16.67% |
paul e. mckenney | paul e. mckenney | 1 | 0.44% | 1 | 16.67% |
| Total | 227 | 100.00% | 6 | 100.00% |
static int alloc_fd(unsigned start, unsigned flags)
{
return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 29 | 100.00% | 2 | 100.00% |
| Total | 29 | 100.00% | 2 | 100.00% |
int get_unused_fd_flags(unsigned flags)
{
return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 25 | 100.00% | 3 | 100.00% |
| Total | 25 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(get_unused_fd_flags);
static void __put_unused_fd(struct files_struct *files, unsigned int fd)
{
struct fdtable *fdt = files_fdtable(files);
__clear_open_fd(fd, fdt);
if (fd < files->next_fd)
files->next_fd = fd;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 46 | 100.00% | 1 | 100.00% |
| Total | 46 | 100.00% | 1 | 100.00% |
void put_unused_fd(unsigned int fd)
{
struct files_struct *files = current->files;
spin_lock(&files->file_lock);
__put_unused_fd(files, fd);
spin_unlock(&files->file_lock);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 41 | 100.00% | 1 | 100.00% |
| Total | 41 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(put_unused_fd);
/*
* Install a file pointer in the fd array.
*
* The VFS is full of places where we drop the files lock between
* setting the open_fds bitmap and installing the file in the file
* array. At any such point, we are vulnerable to a dup2() race
* installing a file in the array before us. We need to detect this and
* fput() the struct file we are about to overwrite in this case.
*
* It should never happen - if we allow dup2() do it, _really_ bad things
* will follow.
*
* NOTE: __fd_install() variant is really, really low-level; don't
* use it unless you are forced to by truly lousy API shoved down
* your throat. 'files' *MUST* be either current->files or obtained
* by get_files_struct(current) done by whoever had given it to you,
* or really bad things will happen. Normally you want to use
* fd_install() instead.
*/
void __fd_install(struct files_struct *files, unsigned int fd,
struct file *file)
{
struct fdtable *fdt;
might_sleep();
rcu_read_lock_sched();
while (unlikely(files->resize_in_progress)) {
rcu_read_unlock_sched();
wait_event(files->resize_wait, !files->resize_in_progress);
rcu_read_lock_sched();
}
/* coupled with smp_wmb() in expand_fdtable() */
smp_rmb();
fdt = rcu_dereference_sched(files->fdt);
BUG_ON(fdt->fd[fd] != NULL);
rcu_assign_pointer(fdt->fd[fd], file);
rcu_read_unlock_sched();
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 60 | 60.61% | 2 | 66.67% |
eric dumazet | eric dumazet | 39 | 39.39% | 1 | 33.33% |
| Total | 99 | 100.00% | 3 | 100.00% |
void fd_install(unsigned int fd, struct file *file)
{
__fd_install(current->files, fd, file);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 25 | 100.00% | 1 | 100.00% |
| Total | 25 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(fd_install);
/*
* The same warnings as for __alloc_fd()/__fd_install() apply here...
*/
int __close_fd(struct files_struct *files, unsigned fd)
{
struct file *file;
struct fdtable *fdt;
spin_lock(&files->file_lock);
fdt = files_fdtable(files);
if (fd >= fdt->max_fds)
goto out_unlock;
file = fdt->fd[fd];
if (!file)
goto out_unlock;
rcu_assign_pointer(fdt->fd[fd], NULL);
__clear_close_on_exec(fd, fdt);
__put_unused_fd(files, fd);
spin_unlock(&files->file_lock);
return filp_close(file, files);
out_unlock:
spin_unlock(&files->file_lock);
return -EBADF;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 122 | 100.00% | 1 | 100.00% |
| Total | 122 | 100.00% | 1 | 100.00% |
void do_close_on_exec(struct files_struct *files)
{
unsigned i;
struct fdtable *fdt;
/* exec unshares first */
spin_lock(&files->file_lock);
for (i = 0; ; i++) {
unsigned long set;
unsigned fd = i * BITS_PER_LONG;
fdt = files_fdtable(files);
if (fd >= fdt->max_fds)
break;
set = fdt->close_on_exec[i];
if (!set)
continue;
fdt->close_on_exec[i] = 0;
for ( ; set ; fd++, set >>= 1) {
struct file *file;
if (!(set & 1))
continue;
file = fdt->fd[fd];
if (!file)
continue;
rcu_assign_pointer(fdt->fd[fd], NULL);
__put_unused_fd(files, fd);