cregit-Linux how code gets into the kernel

Release 4.12 fs/file_table.c

Directory: fs
/*
 *  linux/fs/file_table.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *  Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
 */

#include <linux/string.h>
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/fdtable.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/security.h>
#include <linux/cred.h>
#include <linux/eventpoll.h>
#include <linux/rcupdate.h>
#include <linux/mount.h>
#include <linux/capability.h>
#include <linux/cdev.h>
#include <linux/fsnotify.h>
#include <linux/sysctl.h>
#include <linux/percpu_counter.h>
#include <linux/percpu.h>
#include <linux/hardirq.h>
#include <linux/task_work.h>
#include <linux/ima.h>
#include <linux/swap.h>

#include <linux/atomic.h>

#include "internal.h"

/* sysctl tunables... */

struct files_stat_struct files_stat = {
	.max_files = NR_FILE
};

/* SLAB cache for file structures */

static struct kmem_cache *filp_cachep __read_mostly;


static struct percpu_counter nr_files __cacheline_aligned_in_smp;


static void file_free_rcu(struct rcu_head *head) { struct file *f = container_of(head, struct file, f_u.fu_rcuhead); put_cred(f->f_cred); kmem_cache_free(filp_cachep, f); }

Contributors

PersonTokensPropCommitsCommitProp
Dipankar Sarma3276.19%133.33%
David Howells716.67%133.33%
Eric Dumazet37.14%133.33%
Total42100.00%3100.00%


static inline void file_free(struct file *f) { percpu_counter_dec(&nr_files); call_rcu(&f->f_u.fu_rcuhead, file_free_rcu); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton1653.33%125.00%
Dipankar Sarma1136.67%250.00%
Eric Dumazet310.00%125.00%
Total30100.00%4100.00%

/* * Return the total number of open files in the system */
static long get_nr_files(void) { return percpu_counter_read_positive(&nr_files); }

Contributors

PersonTokensPropCommitsCommitProp
Dipankar Sarma1493.33%150.00%
Eric Dumazet16.67%150.00%
Total15100.00%2100.00%

/* * Return the maximum number of open files in the system */
unsigned long get_max_files(void) { return files_stat.max_files; }

Contributors

PersonTokensPropCommitsCommitProp
Dipankar Sarma1184.62%150.00%
Eric Dumazet215.38%150.00%
Total13100.00%2100.00%

EXPORT_SYMBOL_GPL(get_max_files); /* * Handle nr_files sysctl */ #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
int proc_nr_files(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { files_stat.nr_files = get_nr_files(); return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); }

Contributors

PersonTokensPropCommitsCommitProp
Dipankar Sarma4595.74%133.33%
Eric Dumazet12.13%133.33%
Joe Perches12.13%133.33%
Total47100.00%3100.00%

#else
int proc_nr_files(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { return -ENOSYS; }

Contributors

PersonTokensPropCommitsCommitProp
Dipankar Sarma2996.67%150.00%
Joe Perches13.33%150.00%
Total30100.00%2100.00%

#endif /* Find an unused file structure and return a pointer to it. * Returns an error pointer if some error happend e.g. we over file * structures limit, run out of memory or operation is not permitted. * * Be very careful using this. You are responsible for * getting write access to any mount that you might assign * to this filp, if it is opened for write. If this is not * done, you will imbalance int the mount's writer count * and a warning at __fput() time. */
struct file *get_empty_filp(void) { const struct cred *cred = current_cred(); static long old_max; struct file *f; int error; /* * Privileged users can go above max_files */ if (get_nr_files() >= files_stat.max_files && !capable(CAP_SYS_ADMIN)) { /* * percpu_counters are inaccurate. Do an expensive check before * we go and fail. */ if (percpu_counter_sum_positive(&nr_files) >= files_stat.max_files) goto over; } f = kmem_cache_zalloc(filp_cachep, GFP_KERNEL); if (unlikely(!f)) return ERR_PTR(-ENOMEM); percpu_counter_inc(&nr_files); f->f_cred = get_cred(cred); error = security_file_alloc(f); if (unlikely(error)) { file_free(f); return ERR_PTR(error); } atomic_long_set(&f->f_count, 1); rwlock_init(&f->f_owner.lock); spin_lock_init(&f->f_lock); mutex_init(&f->f_pos_lock); eventpoll_init_file(f); /* f->f_version: 0 */ return f; over: /* Ran out of filps - report that */ if (get_nr_files() > old_max) { pr_info("VFS: file-max limit %lu reached\n", get_max_files()); old_max = get_nr_files(); } return ERR_PTR(-ENFILE); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)5325.60%726.92%
Al Viro4119.81%27.69%
Dipankar Sarma2813.53%13.85%
Andrew Morton178.21%311.54%
Benjamin LaHaise146.76%13.85%
Tetsuo Handa94.35%13.85%
Kirill Korotaev94.35%13.85%
Linus Torvalds83.86%13.85%
Jonathan Corbet83.86%13.85%
David Howells62.90%13.85%
Stephen D. Smalley41.93%13.85%
Eric Dumazet31.45%13.85%
Thomas Gleixner20.97%13.85%
James Morris20.97%13.85%
Cheng Renquan10.48%13.85%
Peter Zijlstra10.48%13.85%
Greg Kroah-Hartman10.48%13.85%
Total207100.00%26100.00%

/** * alloc_file - allocate and initialize a 'struct file' * * @path: the (dentry, vfsmount) pair for the new file * @mode: the mode with which the new file will be opened * @fop: the 'struct file_operations' for the new file */
struct file *alloc_file(const struct path *path, fmode_t mode, const struct file_operations *fop) { struct file *file; file = get_empty_filp(); if (IS_ERR(file)) return file; file->f_path = *path; file->f_inode = path->dentry->d_inode; file->f_mapping = path->dentry->d_inode->i_mapping; if ((mode & FMODE_READ) && likely(fop->read || fop->read_iter)) mode |= FMODE_CAN_READ; if ((mode & FMODE_WRITE) && likely(fop->write || fop->write_iter)) mode |= FMODE_CAN_WRITE; file->f_mode = mode; file->f_op = fop; if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_inc(path->dentry->d_inode); return file; }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro7145.81%975.00%
Dave Hansen6340.65%18.33%
Mimi Zohar2012.90%18.33%
Anatol Pomozov10.65%18.33%
Total155100.00%12100.00%

EXPORT_SYMBOL(alloc_file); /* the real guts of fput() - releasing the last reference to file */
static void __fput(struct file *file) { struct dentry *dentry = file->f_path.dentry; struct vfsmount *mnt = file->f_path.mnt; struct inode *inode = file->f_inode; might_sleep(); fsnotify_close(file); /* * The function eventpoll_release() should be the first called * in the file cleanup chain. */ eventpoll_release(file); locks_remove_file(file); if (unlikely(file->f_flags & FASYNC)) { if (file->f_op->fasync) file->f_op->fasync(-1, file, 0); } ima_file_free(file); if (file->f_op->release) file->f_op->release(inode, file); security_file_free(file); if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL && !(file->f_mode & FMODE_PATH))) { cdev_put(inode->i_cdev); } fops_put(file->f_op); put_pid(file->f_owner.pid); if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) i_readcount_dec(inode); if (file->f_mode & FMODE_WRITER) { put_write_access(inode); __mnt_drop_write(mnt); } file->f_path.dentry = NULL; file->f_path.mnt = NULL; file->f_inode = NULL; file_free(file); dput(dentry); mntput(mnt); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro7027.45%516.67%
Linus Torvalds (pre-git)5822.75%723.33%
Mimi Zohar2610.20%26.67%
Linus Torvalds207.84%13.33%
Josef 'Jeff' Sipek124.71%13.33%
Miklos Szeredi114.31%13.33%
Dave Hansen103.92%13.33%
Benjamin LaHaise93.53%13.33%
Eric W. Biedermann93.53%13.33%
Theodore Y. Ts'o72.75%13.33%
Davide Libenzi62.35%26.67%
Robert Love51.96%13.33%
Stephen D. Smalley41.57%13.33%
Ingo Molnar31.18%13.33%
David Howells20.78%13.33%
Greg Kroah-Hartman10.39%13.33%
Jeff Layton10.39%13.33%
Andrew Morton10.39%13.33%
Total255100.00%30100.00%

static LLIST_HEAD(delayed_fput_list);
static void delayed_fput(struct work_struct *unused) { struct llist_node *node = llist_del_all(&delayed_fput_list); struct llist_node *next; for (; node; node = next) { next = llist_next(node); __fput(llist_entry(node, struct file, f_u.fu_llist)); } }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro3050.00%150.00%
Oleg Nesterov3050.00%150.00%
Total60100.00%2100.00%


static void ____fput(struct callback_head *work) { __fput(container_of(work, struct file, f_u.fu_rcuhead)); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro26100.00%1100.00%
Total26100.00%1100.00%

/* * If kernel thread really needs to have the final fput() it has done * to complete, call this. The only user right now is the boot - we * *do* need to make sure our writes to binaries on initramfs has * not left us with opened struct file waiting for __fput() - execve() * won't work without that. Please, don't add more callers without * very good reasons; in particular, never call that with locks * held and never call that from a thread that might need to do * some work on any kind of umount. */
void flush_delayed_fput(void) { delayed_fput(NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro12100.00%1100.00%
Total12100.00%1100.00%

static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput);
void fput(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { struct task_struct *task = current; if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) { init_task_work(&file->f_u.fu_rcuhead, ____fput); if (!task_work_add(task, &file->f_u.fu_rcuhead, true)) return; /* * After this task has run exit_task_work(), * task_work_add() will fail. Fall through to delayed * fput to avoid leaking *file. */ } if (llist_add(&file->f_u.fu_llist, &delayed_fput_list)) schedule_delayed_work(&delayed_fput_work, 1); } }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro6058.25%350.00%
Oleg Nesterov4240.78%233.33%
Andrew Morton10.97%116.67%
Total103100.00%6100.00%

/* * synchronous analog of fput(); for kernel threads that might be needed * in some umount() (and thus can't use flush_delayed_fput() without * risking deadlocks), need to wait for completion of __fput() and know * for this specific struct file it won't involve anything that would * need them. Use only if you really need it - at the very least, * don't blindly convert fput() by kernel thread to that. */
void __fput_sync(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { struct task_struct *task = current; BUG_ON(!(task->flags & PF_KTHREAD)); __fput(file); } }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro46100.00%2100.00%
Total46100.00%2100.00%

EXPORT_SYMBOL(fput);
void put_filp(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { security_file_free(file); file_free(file); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2578.12%342.86%
Stephen D. Smalley412.50%114.29%
Andrew Morton13.12%114.29%
Al Viro13.12%114.29%
Greg Kroah-Hartman13.12%114.29%
Total32100.00%7100.00%


void __init files_init(void) { filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); percpu_counter_init(&nr_files, 0, GFP_KERNEL); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet2153.85%133.33%
Mel Gorman1230.77%133.33%
Andi Kleen615.38%133.33%
Total39100.00%3100.00%

/* * One file with associated inode and dcache is very roughly 1K. Per default * do not use more than 10% of our memory for files. */
void __init files_maxfiles_init(void) { unsigned long n; unsigned long memreserve = (totalram_pages - nr_free_pages()) * 3/2; memreserve = min(memreserve, totalram_pages - 1); n = ((totalram_pages - memreserve) * (PAGE_SIZE / 1024)) / 10; files_stat.max_files = max_t(unsigned long, n, NR_FILE); }

Contributors

PersonTokensPropCommitsCommitProp
Mel Gorman4260.87%133.33%
Andi Kleen1927.54%133.33%
Eric Dumazet811.59%133.33%
Total69100.00%3100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Al Viro39429.56%1718.89%
Dipankar Sarma20615.45%22.22%
Linus Torvalds (pre-git)16312.23%1820.00%
Oleg Nesterov735.48%22.22%
Dave Hansen735.48%22.22%
Mel Gorman584.35%11.11%
Eric Dumazet503.75%33.33%
Mimi Zohar463.45%22.22%
Andrew Morton403.00%44.44%
Linus Torvalds282.10%22.22%
Andi Kleen251.88%11.11%
Benjamin LaHaise231.73%22.22%
Stephen D. Smalley151.13%11.11%
David Howells151.13%33.33%
Josef 'Jeff' Sipek120.90%11.11%
Miklos Szeredi110.83%11.11%
Tetsuo Handa90.68%11.11%
Kirill Korotaev90.68%11.11%
Eric W. Biedermann90.68%11.11%
Davide Libenzi90.68%33.33%
Jonathan Corbet80.60%11.11%
Robert Love80.60%11.11%
Theodore Y. Ts'o70.53%11.11%
Ingo Molnar60.45%22.22%
Roland Dreier50.38%11.11%
Dave Jones40.30%22.22%
Eric Paris30.23%11.11%
Nicholas Piggin30.23%11.11%
Christoph Hellwig30.23%11.11%
Greg Kroah-Hartman30.23%11.11%
Randy Dunlap30.23%11.11%
Thomas Gleixner20.15%11.11%
James Morris20.15%11.11%
Joe Perches20.15%11.11%
Arun Sharma10.08%11.11%
Cheng Renquan10.08%11.11%
Peter Zijlstra10.08%11.11%
Anatol Pomozov10.08%11.11%
Eric Biggers10.08%11.11%
Jeff Layton10.08%11.11%
Total1333100.00%90100.00%
Directory: fs
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.