cregit-Linux how code gets into the kernel

Release 4.13 fs/inode.c

Directory: fs
/*
 * (C) 1997 Linus Torvalds
 * (C) 1999 Andrea Arcangeli <andrea@suse.de> (dynamic inode allocation)
 */
#include <linux/export.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/backing-dev.h>
#include <linux/hash.h>
#include <linux/swap.h>
#include <linux/security.h>
#include <linux/cdev.h>
#include <linux/bootmem.h>
#include <linux/fsnotify.h>
#include <linux/mount.h>
#include <linux/posix_acl.h>
#include <linux/prefetch.h>
#include <linux/buffer_head.h> /* for inode_has_buffers */
#include <linux/ratelimit.h>
#include <linux/list_lru.h>
#include <trace/events/writeback.h>
#include "internal.h"

/*
 * Inode locking rules:
 *
 * inode->i_lock protects:
 *   inode->i_state, inode->i_hash, __iget()
 * Inode LRU list locks protect:
 *   inode->i_sb->s_inode_lru, inode->i_lru
 * inode->i_sb->s_inode_list_lock protects:
 *   inode->i_sb->s_inodes, inode->i_sb_list
 * bdi->wb.list_lock protects:
 *   bdi->wb.b_{dirty,io,more_io,dirty_time}, inode->i_io_list
 * inode_hash_lock protects:
 *   inode_hashtable, inode->i_hash
 *
 * Lock ordering:
 *
 * inode->i_sb->s_inode_list_lock
 *   inode->i_lock
 *     Inode LRU list locks
 *
 * bdi->wb.list_lock
 *   inode->i_lock
 *
 * inode_hash_lock
 *   inode->i_sb->s_inode_list_lock
 *   inode->i_lock
 *
 * iunique_lock
 *   inode_hash_lock
 */


static unsigned int i_hash_mask __read_mostly;

static unsigned int i_hash_shift __read_mostly;

static struct hlist_head *inode_hashtable __read_mostly;
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock);

/*
 * Empty aops. Can be used for the cases where the user does not
 * define any of the address_space operations.
 */

const struct address_space_operations empty_aops = {
};

EXPORT_SYMBOL(empty_aops);

/*
 * Statistics gathering..
 */

struct inodes_stat_t inodes_stat;

static DEFINE_PER_CPU(unsigned long, nr_inodes);
static DEFINE_PER_CPU(unsigned long, nr_unused);


static struct kmem_cache *inode_cachep __read_mostly;


static long get_nr_inodes(void) { int i; long sum = 0; for_each_possible_cpu(i) sum += per_cpu(nr_inodes, i); return sum < 0 ? 0 : sum; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Piggin2565.79%133.33%
Dave Chinner1128.95%133.33%
Glauber de Oliveira Costa25.26%133.33%
Total38100.00%3100.00%


static inline long get_nr_inodes_unused(void) { int i; long sum = 0; for_each_possible_cpu(i) sum += per_cpu(nr_unused, i); return sum < 0 ? 0 : sum; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner3692.31%250.00%
Glauber de Oliveira Costa25.13%125.00%
Nicholas Piggin12.56%125.00%
Total39100.00%4100.00%


long get_nr_dirty_inodes(void) { /* not actually dirty inodes, but a wild approximation */ long nr_dirty = get_nr_inodes() - get_nr_inodes_unused(); return nr_dirty > 0 ? nr_dirty : 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner2388.46%133.33%
Glauber de Oliveira Costa27.69%133.33%
Nicholas Piggin13.85%133.33%
Total26100.00%3100.00%

/* * Handle nr_inode sysctl */ #ifdef CONFIG_SYSCTL
int proc_nr_inodes(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { inodes_stat.nr_inodes = get_nr_inodes(); inodes_stat.nr_unused = get_nr_inodes_unused(); return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner5296.30%250.00%
Glauber de Oliveira Costa11.85%125.00%
Joe Perches11.85%125.00%
Total54100.00%4100.00%

#endif
static int no_open(struct inode *inode, struct file *file) { return -ENXIO; }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro20100.00%1100.00%
Total20100.00%1100.00%

/** * inode_init_always - perform inode structure initialisation * @sb: superblock inode belongs to * @inode: inode to initialise * * These are initializations that need to be done on every inode * allocation as the fields are not initialised by slab allocation. */
int inode_init_always(struct super_block *sb, struct inode *inode) { static const struct inode_operations empty_iops; static const struct file_operations no_open_fops = {.open = no_open}; struct address_space *const mapping = &inode->i_data; inode->i_sb = sb; inode->i_blkbits = sb->s_blocksize_bits; inode->i_flags = 0; atomic_set(&inode->i_count, 1); inode->i_op = &empty_iops; inode->i_fop = &no_open_fops; inode->__i_nlink = 1; inode->i_opflags = 0; if (sb->s_xattr) inode->i_opflags |= IOP_XATTR; i_uid_write(inode, 0); i_gid_write(inode, 0); atomic_set(&inode->i_writecount, 0); inode->i_size = 0; inode->i_write_hint = WRITE_LIFE_NOT_SET; inode->i_blocks = 0; inode->i_bytes = 0; inode->i_generation = 0; inode->i_pipe = NULL; inode->i_bdev = NULL; inode->i_cdev = NULL; inode->i_link = NULL; inode->i_dir_seq = 0; inode->i_rdev = 0; inode->dirtied_when = 0; #ifdef CONFIG_CGROUP_WRITEBACK inode->i_wb_frn_winner = 0; inode->i_wb_frn_avg_time = 0; inode->i_wb_frn_history = 0; #endif if (security_inode_alloc(inode)) goto out; spin_lock_init(&inode->i_lock); lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key); init_rwsem(&inode->i_rwsem); lockdep_set_class(&inode->i_rwsem, &sb->s_type->i_mutex_key); atomic_set(&inode->i_dio_count, 0); mapping->a_ops = &empty_aops; mapping->host = inode; mapping->flags = 0; atomic_set(&mapping->i_mmap_writable, 0); mapping_set_gfp_mask(mapping, GFP_HIGHUSER_MOVABLE); mapping->private_data = NULL; mapping->writeback_index = 0; inode->i_private = NULL; inode->i_mapping = mapping; INIT_HLIST_HEAD(&inode->i_dentry); /* buggered by rcu freeing */ #ifdef CONFIG_FS_POSIX_ACL inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED; #endif #ifdef CONFIG_FSNOTIFY inode->i_fsnotify_mask = 0; #endif inode->i_flctx = NULL; this_cpu_inc(nr_inodes); return 0; out: return -ENOMEM; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds13332.20%24.88%
Al Viro6215.01%1024.39%
Peter Zijlstra5012.11%12.44%
Andrew Morton419.93%512.20%
Tahsin Erdogan235.57%12.44%
Andreas Gruenbacher122.91%12.44%
Eric Paris112.66%12.44%
Christoph Hellwig102.42%37.32%
David Herrmann102.42%12.44%
Eric W. Biedermann81.94%12.44%
David Chinner81.94%12.44%
Chris Wright61.45%12.44%
Jens Axboe61.45%12.44%
Jeff Layton61.45%12.44%
Jan Kara61.45%12.44%
Mimi Zohar51.21%12.44%
Dave Chinner40.97%12.44%
Chris Mason40.97%12.44%
Theodore Y. Ts'o20.48%12.44%
Arjan van de Ven10.24%12.44%
Rafael Aquini10.24%12.44%
Nicholas Piggin10.24%12.44%
Miklos Szeredi10.24%12.44%
Greg Kroah-Hartman10.24%12.44%
Hugh Dickins10.24%12.44%
Total413100.00%41100.00%

EXPORT_SYMBOL(inode_init_always);
static struct inode *alloc_inode(struct super_block *sb) { struct inode *inode; if (sb->s_op->alloc_inode) inode = sb->s_op->alloc_inode(sb); else inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL); if (!inode) return NULL; if (unlikely(inode_init_always(sb, inode))) { if (inode->i_sb->s_op->destroy_inode) inode->i_sb->s_op->destroy_inode(inode); else kmem_cache_free(inode_cachep, inode); return NULL; } return inode; }

Contributors

PersonTokensPropCommitsCommitProp
David Chinner5754.81%133.33%
Christoph Hellwig4341.35%133.33%
Linus Torvalds43.85%133.33%
Total104100.00%3100.00%


void free_inode_nonrcu(struct inode *inode) { kmem_cache_free(inode_cachep, inode); }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Piggin17100.00%1100.00%
Total17100.00%1100.00%

EXPORT_SYMBOL(free_inode_nonrcu);
void __destroy_inode(struct inode *inode) { BUG_ON(inode_has_buffers(inode)); inode_detach_wb(inode); security_inode_free(inode); fsnotify_inode_delete(inode); locks_free_lock_context(inode); if (!inode->i_nlink) { WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0); atomic_long_dec(&inode->i_sb->s_remove_count); } #ifdef CONFIG_FS_POSIX_ACL if (inode->i_acl && !is_uncached_acl(inode->i_acl)) posix_acl_release(inode->i_acl); if (inode->i_default_acl && !is_uncached_acl(inode->i_default_acl)) posix_acl_release(inode->i_default_acl); #endif this_cpu_dec(nr_inodes); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro3931.45%16.67%
Miklos Szeredi3427.42%16.67%
Linus Torvalds (pre-git)129.68%213.33%
Andreas Gruenbacher86.45%16.67%
Eric Paris54.03%16.67%
Jeff Layton54.03%16.67%
Tejun Heo54.03%16.67%
Dave Chinner43.23%16.67%
Stephen D. Smalley43.23%16.67%
Eric Sesterhenn / Snakebyte32.42%16.67%
Christoph Hellwig21.61%16.67%
Nicholas Piggin10.81%16.67%
Linus Torvalds10.81%16.67%
Greg Kroah-Hartman10.81%16.67%
Total124100.00%15100.00%

EXPORT_SYMBOL(__destroy_inode);
static void i_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); kmem_cache_free(inode_cachep, inode); }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Piggin33100.00%1100.00%
Total33100.00%1100.00%


static void destroy_inode(struct inode *inode) { BUG_ON(!list_empty(&inode->i_lru)); __destroy_inode(inode); if (inode->i_sb->s_op->destroy_inode) inode->i_sb->s_op->destroy_inode(inode); else call_rcu(&inode->i_rcu, i_callback); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds2236.67%116.67%
Nicholas Piggin1830.00%233.33%
Christoph Hellwig1525.00%233.33%
Linus Torvalds (pre-git)58.33%116.67%
Total60100.00%6100.00%

/** * drop_nlink - directly drop an inode's link count * @inode: inode * * This is a low-level filesystem helper to replace any * direct filesystem manipulation of i_nlink. In cases * where we are attempting to track writes to the * filesystem, a decrement to zero means an imminent * write when the file is truncated and actually unlinked * on the filesystem. */
void drop_nlink(struct inode *inode) { WARN_ON(inode->i_nlink == 0); inode->__i_nlink--; if (!inode->i_nlink) atomic_long_inc(&inode->i_sb->s_remove_count); }

Contributors

PersonTokensPropCommitsCommitProp
Miklos Szeredi41100.00%1100.00%
Total41100.00%1100.00%

EXPORT_SYMBOL(drop_nlink); /** * clear_nlink - directly zero an inode's link count * @inode: inode * * This is a low-level filesystem helper to replace any * direct filesystem manipulation of i_nlink. See * drop_nlink() for why we care about i_nlink hitting zero. */
void clear_nlink(struct inode *inode) { if (inode->i_nlink) { inode->__i_nlink = 0; atomic_long_inc(&inode->i_sb->s_remove_count); } }

Contributors

PersonTokensPropCommitsCommitProp
Miklos Szeredi34100.00%1100.00%
Total34100.00%1100.00%

EXPORT_SYMBOL(clear_nlink); /** * set_nlink - directly set an inode's link count * @inode: inode * @nlink: new nlink (should be non-zero) * * This is a low-level filesystem helper to replace any * direct filesystem manipulation of i_nlink. */
void set_nlink(struct inode *inode, unsigned int nlink) { if (!nlink) { clear_nlink(inode); } else { /* Yes, some filesystems do change nlink from zero to one */ if (inode->i_nlink == 0) atomic_long_dec(&inode->i_sb->s_remove_count); inode->__i_nlink = nlink; } }

Contributors

PersonTokensPropCommitsCommitProp
Miklos Szeredi54100.00%1100.00%
Total54100.00%1100.00%

EXPORT_SYMBOL(set_nlink); /** * inc_nlink - directly increment an inode's link count * @inode: inode * * This is a low-level filesystem helper to replace any * direct filesystem manipulation of i_nlink. Currently, * it is only here for parity with dec_nlink(). */
void inc_nlink(struct inode *inode) { if (unlikely(inode->i_nlink == 0)) { WARN_ON(!(inode->i_state & I_LINKABLE)); atomic_long_dec(&inode->i_sb->s_remove_count); } inode->__i_nlink++; }

Contributors

PersonTokensPropCommitsCommitProp
Miklos Szeredi3570.00%150.00%
Al Viro1530.00%150.00%
Total50100.00%2100.00%

EXPORT_SYMBOL(inc_nlink);
void address_space_init_once(struct address_space *mapping) { memset(mapping, 0, sizeof(*mapping)); INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC | __GFP_ACCOUNT); spin_lock_init(&mapping->tree_lock); init_rwsem(&mapping->i_mmap_rwsem); INIT_LIST_HEAD(&mapping->private_list); spin_lock_init(&mapping->private_lock); mapping->i_mmap = RB_ROOT; }

Contributors

PersonTokensPropCommitsCommitProp
Miklos Szeredi3041.10%110.00%
Linus Torvalds (pre-git)2939.73%220.00%
Nicholas Piggin56.85%220.00%
Linus Torvalds34.11%220.00%
Michel Lespinasse22.74%110.00%
Vladimir Davydov22.74%110.00%
Davidlohr Bueso A22.74%110.00%
Total73100.00%10100.00%

EXPORT_SYMBOL(address_space_init_once); /* * These are initializations that only need to be done * once, because the fields are idempotent across use * of the inode, so let the slab aware of that. */
void inode_init_once(struct inode *inode) { memset(inode, 0, sizeof(*inode)); INIT_HLIST_NODE(&inode->i_hash); INIT_LIST_HEAD(&inode->i_devices); INIT_LIST_HEAD(&inode->i_io_list); INIT_LIST_HEAD(&inode->i_wb_list); INIT_LIST_HEAD(&inode->i_lru); address_space_init_once(&inode->i_data); i_size_ordered_init(inode); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton2836.84%550.00%
Miklos Szeredi2735.53%110.00%
Dave Chinner911.84%220.00%
Ingo Molnar67.89%110.00%
Linus Torvalds (pre-git)67.89%110.00%
Total76100.00%10100.00%

EXPORT_SYMBOL(inode_init_once);
static void init_once(void *foo) { struct inode *inode = (struct inode *) foo; inode_init_once(inode); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds2385.19%133.33%
Christoph Lameter311.11%133.33%
Linus Torvalds (pre-git)13.70%133.33%
Total27100.00%3100.00%

/* * inode->i_lock must be held */
void __iget(struct inode *inode) { atomic_inc(&inode->i_count); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)1266.67%466.67%
Andrew Morton527.78%116.67%
Nicholas Piggin15.56%116.67%
Total18100.00%6100.00%

/* * get additional reference to inode; caller must already hold one. */
void ihold(struct inode *inode) { WARN_ON(atomic_inc_return(&inode->i_count) < 2); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro23100.00%2100.00%
Total23100.00%2100.00%

EXPORT_SYMBOL(ihold);
static void inode_lru_list_add(struct inode *inode) { if (list_lru_add(&inode->i_sb->s_inode_lru, &inode->i_lru)) this_cpu_inc(nr_unused); else inode->i_state |= I_REFERENCED; }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Piggin1435.00%225.00%
Dave Chinner1025.00%337.50%
Josef Whiter717.50%112.50%
Al Viro717.50%112.50%
Linus Torvalds (pre-git)25.00%112.50%
Total40100.00%8100.00%

/* * Add inode to LRU if needed (inode is unused and clean). * * Needs inode->i_lock held. */
void inode_add_lru(struct inode *inode) { if (!(inode->i_state & (I_DIRTY_ALL | I_SYNC | I_FREEING | I_WILL_FREE)) && !atomic_read(&inode->i_count) && inode->i_sb->s_flags & MS_ACTIVE) inode_lru_list_add(inode); }

Contributors

PersonTokensPropCommitsCommitProp
Jan Kara5098.04%150.00%
Theodore Y. Ts'o11.96%150.00%
Total51100.00%2100.00%


static void inode_lru_list_del(struct inode *inode) { if (list_lru_del(&inode->i_sb->s_inode_lru, &inode->i_lru)) this_cpu_dec(nr_unused); }

Contributors

PersonTokensPropCommitsCommitProp
Nicholas Piggin1442.42%337.50%
Dave Chinner1442.42%450.00%
Linus Torvalds (pre-git)515.15%112.50%
Total33100.00%8100.00%

/** * inode_sb_list_add - add inode to the superblock list of inodes * @inode: inode to add */
void inode_sb_list_add(struct inode *inode) { spin_lock(&inode->i_sb->s_inode_list_lock); list_add(&inode->i_sb_list, &inode->i_sb->s_inodes); spin_unlock(&inode->i_sb->s_inode_list_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig2453.33%133.33%
Dave Chinner2146.67%266.67%
Total45100.00%3100.00%

EXPORT_SYMBOL_GPL(inode_sb_list_add);
static inline void inode_sb_list_del(struct inode *inode) { if (!list_empty(&inode->i_sb_list)) { spin_lock(&inode->i_sb->s_inode_list_lock); list_del_init(&inode->i_sb_list); spin_unlock(&inode->i_sb->s_inode_list_lock); } }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner2139.62%250.00%
Christoph Hellwig1935.85%125.00%
Eric Dumazet1324.53%125.00%
Total53100.00%4100.00%


static unsigned long hash(struct super_block *sb, unsigned long hashval) { unsigned long tmp; tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) / L1_CACHE_BYTES; tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> i_hash_shift); return tmp & i_hash_mask; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner5796.61%150.00%
Christoph Hellwig23.39%150.00%
Total59100.00%2100.00%

/** * __insert_inode_hash - hash an inode * @inode: unhashed inode * @hashval: unsigned long value used to locate this object in the * inode_hashtable. * * Add an inode to the inode hash for this superblock. */
void __insert_inode_hash(struct inode *inode, unsigned long hashval) { struct hlist_head *b = inode_hashtable + hash(inode->i_sb, hashval); spin_lock(&inode_hash_lock); spin_lock(&inode->i_lock); hlist_add_head(&inode->i_hash, b); spin_unlock(&inode->i_lock); spin_unlock(&inode_hash_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner6697.06%375.00%
Christoph Hellwig22.94%125.00%
Total68100.00%4100.00%

EXPORT_SYMBOL(__insert_inode_hash); /** * __remove_inode_hash - remove an inode from the hash * @inode: inode to unhash * * Remove an inode from the superblock. */
void __remove_inode_hash(struct inode *inode) { spin_lock(&inode_hash_lock); spin_lock(&inode->i_lock); hlist_del_init(&inode->i_hash); spin_unlock(&inode->i_lock); spin_unlock(&inode_hash_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner4597.83%375.00%
Eric Dumazet12.17%125.00%
Total46100.00%4100.00%

EXPORT_SYMBOL(__remove_inode_hash);
void clear_inode(struct inode *inode) { might_sleep(); /* * We have to cycle tree_lock here because reclaim can be still in the * process of removing the last page (in __delete_from_page_cache()) * and we must not free mapping under it. */ spin_lock_irq(&inode->i_data.tree_lock); BUG_ON(inode->i_data.nrpages); BUG_ON(inode->i_data.nrexceptional); spin_unlock_irq(&inode->i_data.tree_lock); BUG_ON(!list_empty(&inode->i_data.private_list)); BUG_ON(!(inode->i_state & I_FREEING)); BUG_ON(inode->i_state & I_CLEAR); BUG_ON(!list_empty(&inode->i_wb_list)); /* don't need i_lock here, no concurrent mods to i_state */ inode->i_state = I_FREEING | I_CLEAR; }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro6459.26%114.29%
Jan Kara2220.37%228.57%
Dave Chinner1211.11%114.29%
Johannes Weiner87.41%114.29%
Nicholas Piggin10.93%114.29%
Ross Zwisler10.93%114.29%
Total108100.00%7100.00%

EXPORT_SYMBOL(clear_inode); /* * Free the inode passed in, removing it from the lists it is still connected * to. We remove any pages still attached to the inode and wait for any IO that * is still in progress before finally destroying the inode. * * An inode must already be marked I_FREEING so that we avoid the inode being * moved back onto lists if we race with other code that manipulates the lists * (e.g. writeback_single_inode). The caller is responsible for setting this. * * An inode must already be removed from the LRU list before being evicted from * the cache. This should occur atomically with setting the I_FREEING state * flag, so no inodes here should ever be on the LRU when being evicted. */
static void evict(struct inode *inode) { const struct super_operations *op = inode->i_sb->s_op; BUG_ON(!(inode->i_state & I_FREEING)); BUG_ON(!list_empty(&inode->i_lru)); if (!list_empty(&inode->i_io_list)) inode_io_list_del(inode); inode_sb_list_del(inode); /* * Wait for flusher thread to be done with the inode so that filesystem * does not start destroying it while writeback is still running. Since * the inode has I_FREEING set, flusher thread won't start new work on * the inode. We just have to wait for running writeback to finish. */ inode_wait_for_writeback(inode); if (op->evict_inode) { op->evict_inode(inode); } else { truncate_inode_pages_final(&inode->i_data); clear_inode(inode); } if (S_ISBLK(inode->i_mode) && inode->i_bdev) bd_forget(inode); if (S_ISCHR(inode->i_mode) && inode->i_cdev) cd_forget(inode); remove_inode_hash(inode); spin_lock(&inode->i_lock); wake_up_bit(&inode->i_state, __I_NEW); BUG_ON(inode->i_state != (I_FREEING | I_CLEAR)); spin_unlock(&inode->i_lock); destroy_inode(inode); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro8846.32%433.33%
Dave Chinner8444.21%325.00%
Eric Dumazet105.26%18.33%
Jan Kara73.68%325.00%
Johannes Weiner10.53%18.33%
Total190100.00%12100.00%

/* * dispose_list - dispose of the contents of a local list * @head: the head of the list to free * * Dispose-list gets a local list with local inodes in it, so it doesn't * need to worry about list corruption and SMP locks. */
static void dispose_list(struct list_head *head) { while (!list_empty(head)) { struct inode *inode; inode = list_first_entry(head, struct inode, i_lru); list_del_init(&inode->i_lru); evict(inode); cond_resched(); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3055.56%440.00%
Andrew Morton1629.63%110.00%
Josef Bacik35.56%110.00%
Nicholas Piggin35.56%220.00%
Al Viro11.85%110.00%
Pavel Emelyanov11.85%110.00%
Total54100.00%10100.00%

/** * evict_inodes - evict all evictable inodes for a superblock * @sb: superblock to operate on * * Make sure that no inodes with zero refcount are retained. This is * called by superblock shutdown after having MS_ACTIVE flag removed, * so any inode reaching zero refcount during or after that call will * be immediately evicted. */
void evict_inodes(struct super_block *sb) { struct inode *inode, *next; LIST_HEAD(dispose); again: spin_lock(&sb->s_inode_list_lock); list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { if (atomic_read(&inode->i_count)) continue; spin_lock(&inode->i_lock); if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { spin_unlock(&inode->i_lock); continue; } inode->i_state |= I_FREEING; inode_lru_list_del(inode); spin_unlock(&inode->i_lock); list_add(&inode->i_lru, &dispose); /* * We can have a ton of inodes to evict at unmount time given * enough memory, check to see if we need to go to sleep for a * bit so we don't livelock. */ if (need_resched()) { spin_unlock(&sb->s_inode_list_lock); cond_resched(); dispose_list(&dispose); goto again; } } spin_unlock(&sb->s_inode_list_lock); dispose_list(&dispose); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro4829.81%17.14%
Dave Chinner4427.33%321.43%
Josef Bacik3018.63%17.14%
Linus Torvalds (pre-git)2817.39%750.00%
Nicholas Piggin116.83%214.29%
Total161100.00%14100.00%

/** * invalidate_inodes - attempt to free all inodes on a superblock * @sb: superblock to operate on * @kill_dirty: flag to guide handling of dirty inodes * * Attempts to free all inodes for a given superblock. If there were any * busy inodes return a non-zero value, else zero. * If @kill_dirty is set, discard dirty inodes too, otherwise treat * them as busy. */
int invalidate_inodes(struct super_block *sb, bool kill_dirty) { int busy = 0; struct inode *inode, *next; LIST_HEAD(dispose); spin_lock(&sb->s_inode_list_lock); list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { spin_lock(&inode->i_lock); if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { spin_unlock(&inode->i_lock); continue; } if (inode->i_state & I_DIRTY_ALL && !kill_dirty) { spin_unlock(&inode->i_lock); busy = 1; continue; } if (atomic_read(&inode->i_count)) { spin_unlock(&inode->i_lock); busy = 1; continue; } inode->i_state |= I_FREEING; inode_lru_list_del(inode); spin_unlock(&inode->i_lock); list_add(&inode->i_lru, &dispose); } spin_unlock(&sb->s_inode_list_lock); dispose_list(&dispose); return busy; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner6234.07%312.00%
Linus Torvalds (pre-git)5329.12%1144.00%
Neil Brown2010.99%14.00%
Christoph Hellwig2010.99%312.00%
Nicholas Piggin158.24%312.00%
Al Viro63.30%14.00%
Eric Paris42.20%14.00%
Andrew Morton10.55%14.00%
Theodore Y. Ts'o10.55%14.00%
Total182100.00%25100.00%

/* * Isolate the inode from the LRU in preparation for freeing it. * * Any inodes which are pinned purely because of attached pagecache have their * pagecache removed. If the inode has metadata buffers attached to * mapping->private_list then try to remove them. * * If the inode has the I_REFERENCED flag set, then it means that it has been * used recently - the flag is set in iput_final(). When we encounter such an * inode, clear the flag and move it to the back of the LRU so it gets another * pass through the LRU before it gets reclaimed. This is necessary because of * the fact we are doing lazy LRU updates to minimise lock contention so the * LRU does not have strict ordering. Hence we don't want to reclaim inodes * with this flag set because they are the inodes that are out of order. */
static enum lru_status inode_lru_isolate(struct list_head *item, struct list_lru_one *lru, spinlock_t *lru_lock, void *arg) { struct list_head *freeable = arg; struct inode *inode = container_of(item, struct inode, i_lru); /* * we are inverting the lru lock/inode->i_lock here, so use a trylock. * If we fail to get the lock, just skip it. */ if (!spin_trylock(&inode->i_lock)) return LRU_SKIP; /* * Referenced or dirty inodes are still in use. Give them another pass * through the LRU as we canot reclaim them now. */ if (atomic_read(&inode->i_count) || (inode->i_state & ~I_REFERENCED)) { list_lru_isolate(lru, &inode->i_lru); spin_unlock(&inode->i_lock); this_cpu_dec(nr_unused); return LRU_REMOVED; } /* recently referenced inodes get one more pass */ if (inode->i_state & I_REFERENCED) { inode->i_state &= ~I_REFERENCED; spin_unlock(&inode->i_lock); return LRU_ROTATE; } if (inode_has_buffers(inode) || inode->i_data.nrpages) { __iget(inode); spin_unlock(&inode->i_lock); spin_unlock(lru_lock); if (remove_inode_buffers(inode)) { unsigned long reap; reap = invalidate_mapping_pages(&inode->i_data, 0, -1); if (current_is_kswapd()) __count_vm_events(KSWAPD_INODESTEAL, reap); else __count_vm_events(PGINODESTEAL, reap); if (current->reclaim_state) current->reclaim_state->reclaimed_slab += reap; } iput(inode); spin_lock(lru_lock); return LRU_RETRY; } WARN_ON(inode->i_state & I_NEW); inode->i_state |= I_FREEING; list_lru_isolate_move(lru, &inode->i_lru, freeable); spin_unlock(&inode->i_lock); this_cpu_dec(nr_unused); return LRU_REMOVED; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner13747.24%730.43%
Andrew Morton6321.72%417.39%
Nicholas Piggin5117.59%417.39%
Linus Torvalds (pre-git)237.93%626.09%
Vladimir Davydov113.79%14.35%
Glauber de Oliveira Costa51.72%14.35%
Total290100.00%23100.00%

/* * Walk the superblock inode LRU for freeable inodes and attempt to free them. * This is called from the superblock shrinker function with a number of inodes * to trim from the LRU. Inodes to be freed are moved to a temporary list and * then are freed outside inode_lock by dispose_list(). */
long prune_icache_sb(struct super_block *sb, struct shrink_control *sc) { LIST_HEAD(freeable); long freed; freed = list_lru_shrink_walk(&sb->s_inode_lru, sc, inode_lru_isolate, &freeable); dispose_list(&freeable); return freed; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner3163.27%545.45%
Linus Torvalds (pre-git)816.33%327.27%
Vladimir Davydov612.24%19.09%
Christoph Lameter36.12%19.09%
Andrew Morton12.04%19.09%
Total49100.00%11100.00%

static void __wait_on_freeing_inode(struct inode *inode); /* * Called with the inode lock held. */
static struct inode *find_inode(struct super_block *sb, struct hlist_head *head, int (*test)(struct inode *, void *), void *data) { struct inode *inode = NULL; repeat: hlist_for_each_entry(inode, head, i_hash) { if (inode->i_sb != sb) continue; if (!test(inode, data)) continue; spin_lock(&inode->i_lock); if (inode->i_state & (I_FREEING|I_WILL_FREE)) { __wait_on_freeing_inode(inode); goto repeat; } __iget(inode); spin_unlock(&inode->i_lock); return inode; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3427.42%847.06%
Andrew Morton2318.55%15.88%
Linus Torvalds1713.71%15.88%
Dave Chinner1512.10%15.88%
Jan Harkes1310.48%15.88%
Christoph Hellwig86.45%15.88%
Andi Kleen64.84%15.88%
Matthias Kaehlcke54.03%15.88%
Al Viro21.61%15.88%
Alexander Viro10.81%15.88%
Total124100.00%17100.00%

/* * find_inode_fast is the fast path version of find_inode, see the comment at * iget_locked for details. */
static struct inode *find_inode_fast(struct super_block *sb, struct hlist_head *head, unsigned long ino) { struct inode *inode = NULL; repeat: hlist_for_each_entry(inode, head, i_hash) { if (inode->i_ino != ino) continue; if (inode->i_sb != sb) continue; spin_lock(&inode->i_lock); if (inode->i_state & (I_FREEING|I_WILL_FREE)) { __wait_on_freeing_inode(inode); goto repeat; } __iget(inode); spin_unlock(&inode->i_lock); return inode; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Jan Harkes4137.96%18.33%
Andrew Morton2321.30%18.33%
Dave Chinner1513.89%18.33%
Andi Kleen65.56%18.33%
Christoph Hellwig54.63%18.33%
Matthias Kaehlcke54.63%18.33%
Linus Torvalds43.70%18.33%
Linus Torvalds (pre-git)32.78%216.67%
David Chinner32.78%18.33%
Al Viro21.85%18.33%
Alexander Viro10.93%18.33%
Total108100.00%12100.00%

/* * Each cpu owns a range of LAST_INO_BATCH numbers. * 'shared_last_ino' is dirtied only once out of LAST_INO_BATCH allocations, * to renew the exhausted range. * * This does not significantly increase overflow rate because every CPU can * consume at most LAST_INO_BATCH-1 unused inode numbers. So there is * NR_CPUS*(LAST_INO_BATCH-1) wastage. At 4096 and 1024, this is ~0.1% of the * 2^32 range, and is a worst-case. Even a 50% wastage would only increase * overflow rate by 2x, which does not seem too significant. * * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW * error if st_ino won't fit in target struct field. Use 32bit counter * here to attempt to avoid that. */ #define LAST_INO_BATCH 1024 static DEFINE_PER_CPU(unsigned int, last_ino);
unsigned int get_next_ino(void) { unsigned int *p = &get_cpu_var(last_ino); unsigned int res = *p; #ifdef CONFIG_SMP if (unlikely((res & (LAST_INO_BATCH-1)) == 0)) { static atomic_t shared_last_ino; int next = atomic_add_return(LAST_INO_BATCH, &shared_last_ino); res = next - LAST_INO_BATCH; } #endif res++; /* get_next_ino should not provide a 0 inode number */ if (unlikely(!res)) res++; *p = res; put_cpu_var(last_ino); return res; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet6565.66%133.33%
David Chinner1919.19%133.33%
Carlos Maiolino1515.15%133.33%
Total99100.00%3100.00%

EXPORT_SYMBOL(get_next_ino); /** * new_inode_pseudo - obtain an inode * @sb: superblock * * Allocates a new inode for given superblock. * Inode wont be chained in superblock s_inodes list * This means : * - fs can't be unmount * - quotas, fsnotify, writeback can't work */
struct inode *new_inode_pseudo(struct super_block *sb) { struct inode *inode = alloc_inode(sb); if (inode) { spin_lock(&inode->i_lock); inode->i_state = 0; spin_unlock(&inode->i_lock); INIT_LIST_HEAD(&inode->i_sb_list); } return inode; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3354.10%654.55%
Dave Chinner1118.03%19.09%
Linus Torvalds711.48%19.09%
Eric Dumazet711.48%19.09%
William Lee Irwin III23.28%19.09%
David Chinner11.64%19.09%
Total61100.00%11100.00%

/** * new_inode - obtain an inode * @sb: superblock * * Allocates a new inode for given superblock. The default gfp_mask * for allocations related to inode->i_mapping is GFP_HIGHUSER_MOVABLE. * If HIGHMEM pages are unsuitable or it is known that pages allocated * for the page cache are not reclaimable or migratable, * mapping_set_gfp_mask() must be called with suitable flags on the * newly created inode's mapping * */
struct inode *new_inode(struct super_block *sb) { struct inode *inode; spin_lock_prefetch(&sb->s_inode_list_lock); inode = new_inode_pseudo(sb); if (inode) inode_sb_list_add(inode); return inode; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Dumazet4193.18%150.00%
Dave Chinner36.82%150.00%
Total44100.00%2100.00%

EXPORT_SYMBOL(new_inode); #ifdef CONFIG_DEBUG_LOCK_ALLOC
void lockdep_annotate_inode_mutex_key(struct inode *inode) { if (S_ISDIR(inode->i_mode)) { struct file_system_type *type = inode->i_sb->s_type; /* Set new key only if filesystem hasn't already changed it */ if (lockdep_match_class(&inode->i_rwsem, &type->i_mutex_key)) { /* * ensure nobody is actually holding i_mutex */ // mutex_destroy(&inode->i_mutex); init_rwsem(&inode->i_rwsem); lockdep_set_class(&inode->i_rwsem, &type->i_mutex_dir_key); } } }

Contributors

PersonTokensPropCommitsCommitProp
Peter Zijlstra3750.68%228.57%
Jan Kara1824.66%114.29%
Jan Harkes810.96%114.29%
Al Viro56.85%114.29%
Namhyung Kim34.11%114.29%
Josh Boyer22.74%114.29%
Total73100.00%7100.00%

EXPORT_SYMBOL(lockdep_annotate_inode_mutex_key); #endif /** * unlock_new_inode - clear the I_NEW state and wake up any waiters * @inode: new inode to unlock * * Called when the inode is fully initialised to clear the new state of the * inode and wake up anyone waiting for the inode to finish initialisation. */
void unlock_new_inode(struct inode *inode) { lockdep_annotate_inode_mutex_key(inode); spin_lock(&inode->i_lock); WARN_ON(!(inode->i_state & I_NEW)); inode->i_state &= ~I_NEW; smp_mb(); wake_up_bit(&inode->i_state, __I_NEW); spin_unlock(&inode->i_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner2133.33%114.29%
Josh Boyer1422.22%114.29%
Jan Harkes1219.05%114.29%
Nicholas Piggin1117.46%114.29%
Al Viro34.76%114.29%
Christoph Hellwig11.59%114.29%
Jan Kara11.59%114.29%
Total63100.00%7100.00%

EXPORT_SYMBOL(unlock_new_inode); /** * lock_two_nondirectories - take two i_mutexes on non-directory objects * * Lock any non-NULL argument that is not a directory. * Zero, one or two objects may be locked by this function. * * @inode1: first inode to lock * @inode2: second inode to lock */
void lock_two_nondirectories(struct inode *inode1, struct inode *inode2) { if (inode1 > inode2) swap(inode1, inode2); if (inode1 && !S_ISDIR(inode1->i_mode)) inode_lock(inode1); if (inode2 && !S_ISDIR(inode2->i_mode) && inode2 != inode1) inode_lock_nested(inode2, I_MUTEX_NONDIR2); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields6697.06%375.00%
Al Viro22.94%125.00%
Total68100.00%4100.00%

EXPORT_SYMBOL(lock_two_nondirectories); /** * unlock_two_nondirectories - release locks from lock_two_nondirectories() * @inode1: first inode to unlock * @inode2: second inode to unlock */
void unlock_two_nondirectories(struct inode *inode1, struct inode *inode2) { if (inode1 && !S_ISDIR(inode1->i_mode)) inode_unlock(inode1); if (inode2 && !S_ISDIR(inode2->i_mode) && inode2 != inode1) inode_unlock(inode2); }

Contributors

PersonTokensPropCommitsCommitProp
J. Bruce Fields5196.23%266.67%
Al Viro23.77%133.33%
Total53100.00%3100.00%

EXPORT_SYMBOL(unlock_two_nondirectories); /** * iget5_locked - obtain an inode from a mounted file system * @sb: super block of file system * @hashval: hash value (usually inode number) to get * @test: callback used for comparisons between inodes * @set: callback used to initialize a new struct inode * @data: opaque data pointer to pass to @test and @set * * Search for the inode specified by @hashval and @data in the inode cache, * and if present it is return it with an increased reference count. This is * a generalized version of iget_locked() for file systems where the inode * number is not sufficient for unique identification of an inode. * * If the inode is not in cache, allocate a new inode and return it locked, * hashed, and with the I_NEW flag set. The file system gets to fill it in * before unlocking it via unlock_new_inode(). * * Note both @test and @set are called with the inode_hash_lock held, so can't * sleep. */
struct inode *iget5_locked(struct super_block *sb, unsigned long hashval, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *data) { struct hlist_head *head = inode_hashtable + hash(sb, hashval); struct inode *inode; again: spin_lock(&inode_hash_lock); inode = find_inode(sb, head, test, data); spin_unlock(&inode_hash_lock); if (inode) { wait_on_inode(inode); if (unlikely(inode_unhashed(inode))) { iput(inode); goto again; } return inode; } inode = alloc_inode(sb); if (inode) { struct inode *old; spin_lock(&inode_hash_lock); /* We released the lock, so.. */ old = find_inode(sb, head, test, data); if (!old) { if (set(inode, data)) goto set_failed; spin_lock(&inode->i_lock); inode->i_state = I_NEW; hlist_add_head(&inode->i_hash, head); spin_unlock(&inode->i_lock); inode_sb_list_add(inode); spin_unlock(&inode_hash_lock); /* Return the locked inode with I_NEW set, the * caller is responsible for filling in the contents */ return inode; } /* * Uhhuh, somebody else created the same inode under * us. Use the old inode instead of the one we just * allocated. */ spin_unlock(&inode_hash_lock); destroy_inode(inode); inode = old; wait_on_inode(inode); if (unlikely(inode_unhashed(inode))) { iput(inode); goto again; } } return inode; set_failed: spin_unlock(&inode_hash_lock); destroy_inode(inode); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)9733.22%1047.62%
Christoph Hellwig6522.26%29.52%
Jan Harkes5819.86%29.52%
Al Viro4214.38%14.76%
Dave Chinner258.56%314.29%
Linus Torvalds31.03%14.76%
William Lee Irwin III10.34%14.76%
David Chinner10.34%14.76%
Total292100.00%21100.00%

EXPORT_SYMBOL(iget5_locked); /** * iget_locked - obtain an inode from a mounted file system * @sb: super block of file system * @ino: inode number to get * * Search for the inode specified by @ino in the inode cache and if present * return it with an increased reference count. This is for file systems * where the inode number is sufficient for unique identification of an inode. * * If the inode is not in cache, allocate a new inode and return it locked, * hashed, and with the I_NEW flag set. The file system gets to fill it in * before unlocking it via unlock_new_inode(). */
struct inode *iget_locked(struct super_block *sb, unsigned long ino) { struct hlist_head *head = inode_hashtable + hash(sb, ino); struct inode *inode; again: spin_lock(&inode_hash_lock); inode = find_inode_fast(sb, head, ino); spin_unlock(&inode_hash_lock); if (inode) { wait_on_inode(inode); if (unlikely(inode_unhashed(inode))) { iput(inode); goto again; } return inode; } inode = alloc_inode(sb); if (inode) { struct inode *old; spin_lock(&inode_hash_lock); /* We released the lock, so.. */ old = find_inode_fast(sb, head, ino); if (!old) { inode->i_ino = ino; spin_lock(&inode->i_lock); inode->i_state = I_NEW; hlist_add_head(&inode->i_hash, head); spin_unlock(&inode->i_lock); inode_sb_list_add(inode); spin_unlock(&inode_hash_lock); /* Return the locked inode with I_NEW set, the * caller is responsible for filling in the contents */ return inode; } /* * Uhhuh, somebody else created the same inode under * us. Use the old inode instead of the one we just * allocated. */ spin_unlock(&inode_hash_lock); destroy_inode(inode); inode = old; wait_on_inode(inode); if (unlikely(inode_unhashed(inode))) { iput(inode); goto again; } } return inode; }

Contributors

PersonTokensPropCommitsCommitProp
Jan Harkes10143.16%111.11%
Christoph Hellwig6025.64%222.22%
Al Viro4217.95%111.11%
Dave Chinner2410.26%333.33%
Linus Torvalds (pre-git)62.56%111.11%
David Chinner10.43%111.11%
Total234100.00%9100.00%

EXPORT_SYMBOL(iget_locked); /* * search the inode cache for a matching inode number. * If we find one, then the inode number we are trying to * allocate is not unique and so we should not use it. * * Returns 1 if the inode number is unique, 0 if it is not. */
static int test_inode_iunique(struct super_block *sb, unsigned long ino) { struct hlist_head *b = inode_hashtable + hash(sb, ino); struct inode *inode; spin_lock(&inode_hash_lock); hlist_for_each_entry(inode, b, i_hash) { if (inode->i_ino == ino && inode->i_sb == sb) { spin_unlock(&inode_hash_lock); return 0; } } spin_unlock(&inode_hash_lock); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig6476.19%150.00%
Dave Chinner2023.81%150.00%
Total84100.00%2100.00%

/** * iunique - get a unique inode number * @sb: superblock * @max_reserved: highest reserved inode number * * Obtain an inode number that is unique on the system for a given * superblock. This is used by file systems that have no natural * permanent inode numbering system. An inode number is returned that * is higher than the reserved limit but unique. * * BUGS: * With a large number of inodes live on the file system this function * currently becomes quite slow. */
ino_t iunique(struct super_block *sb, ino_t max_reserved) { /* * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW * error if st_ino won't fit in target struct field. Use 32bit counter * here to attempt to avoid that. */ static DEFINE_SPINLOCK(iunique_lock); static unsigned int counter; ino_t res; spin_lock(&iunique_lock); do { if (counter <= max_reserved) counter = max_reserved + 1; res = counter++; } while (!test_inode_iunique(sb, res)); spin_unlock(&iunique_lock); return res; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3851.35%120.00%
Jeff Layton1621.62%240.00%
Christoph Hellwig1520.27%120.00%
Jan Harkes56.76%120.00%
Total74100.00%5100.00%

EXPORT_SYMBOL(iunique);
struct inode *igrab(struct inode *inode) { spin_lock(&inode->i_lock); if (!(inode->i_state & (I_FREEING|I_WILL_FREE))) { __iget(inode); spin_unlock(&inode->i_lock); } else { spin_unlock(&inode->i_lock); /* * Handle the case where s_op->clear_inode is not been * called yet, and somebody is calling igrab * while the inode is getting freed. */ inode = NULL; } return inode; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4057.97%360.00%
Dave Chinner2536.23%120.00%
Alexander Viro45.80%120.00%
Total69100.00%5100.00%

EXPORT_SYMBOL(igrab); /** * ilookup5_nowait - search for an inode in the inode cache * @sb: super block of file system to search * @hashval: hash value (usually inode number) to search for * @test: callback used for comparisons between inodes * @data: opaque data pointer to pass to @test * * Search for the inode specified by @hashval and @data in the inode cache. * If the inode is in the cache, the inode is returned with an incremented * reference count. * * Note: I_NEW is not waited upon so you have to be very careful what you do * with the returned inode. You probably should be using ilookup5() instead. * * Note2: @test is called with the inode_hash_lock held, so can't sleep. */
struct inode *ilookup5_nowait(struct super_block *sb, unsigned long hashval, int (*test)(struct inode *, void *), void *data) { struct hlist_head *head = inode_hashtable + hash(sb, hashval); struct inode *inode; spin_lock(&inode_hash_lock); inode = find_inode(sb, head, test, data); spin_unlock(&inode_hash_lock); return inode; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4454.32%866.67%
Christoph Hellwig1822.22%18.33%
Jan Harkes1619.75%18.33%
Dave Chinner22.47%18.33%
Anton Altaparmakov11.23%18.33%
Total81100.00%12100.00%

EXPORT_SYMBOL(ilookup5_nowait); /** * ilookup5 - search for an inode in the inode cache * @sb: super block of file system to search * @hashval: hash value (usually inode number) to search for * @test: callback used for comparisons between inodes * @data: opaque data pointer to pass to @test * * Search for the inode specified by @hashval and @data in the inode cache, * and if the inode is in the cache, return the inode with an incremented * reference count. Waits on I_NEW before returning the inode. * returned with an incremented reference count. * * This is a generalized version of ilookup() for file systems where the * inode number is not sufficient for unique identification of an inode. * * Note: @test is called with the inode_hash_lock held, so can't sleep. */
struct inode *ilookup5(struct super_block *sb, unsigned long hashval, int (*test)(struct inode *, void *), void *data) { struct inode *inode; again: inode = ilookup5_nowait(sb, hashval, test, data); if (inode) { wait_on_inode(inode); if (unlikely(inode_unhashed(inode))) { iput(inode); goto again; } } return inode; }

Contributors

PersonTokensPropCommitsCommitProp
Jan Harkes3135.23%228.57%
Al Viro2831.82%114.29%
Christoph Hellwig2427.27%114.29%
Anton Altaparmakov33.41%114.29%
Linus Torvalds (pre-git)22.27%228.57%
Total88100.00%7100.00%

EXPORT_SYMBOL(ilookup5); /** * ilookup - search for an inode in the inode cache * @sb: super block of file system to search * @ino: inode number to search for * * Search for the inode @ino in the inode cache, and if the inode is in the * cache, the inode is returned with an incremented reference count. */
struct inode *ilookup(struct super_block *sb, unsigned long ino) { struct hlist_head *head = inode_hashtable + hash(sb, ino); struct inode *inode; again: spin_lock(&inode_hash_lock); inode = find_inode_fast(sb, head, ino); spin_unlock(&inode_hash_lock); if (inode) { wait_on_inode(inode); if (unlikely(inode_unhashed(inode))) { iput(inode); goto again; } } return inode; }

Contributors

PersonTokensPropCommitsCommitProp
Anton Altaparmakov2829.79%17.69%
Al Viro2425.53%17.69%
Linus Torvalds (pre-git)1819.15%861.54%
Christoph Hellwig1414.89%17.69%
Jan Harkes99.57%17.69%
Andi Kleen11.06%17.69%
Total94100.00%13100.00%

EXPORT_SYMBOL(ilookup); /** * find_inode_nowait - find an inode in the inode cache * @sb: super block of file system to search * @hashval: hash value (usually inode number) to search for * @match: callback used for comparisons between inodes * @data: opaque data pointer to pass to @match * * Search for the inode specified by @hashval and @data in the inode * cache, where the helper function @match will return 0 if the inode * does not match, 1 if the inode does match, and -1 if the search * should be stopped. The @match function must be responsible for * taking the i_lock spin_lock and checking i_state for an inode being * freed or being initialized, and incrementing the reference count * before returning 1. It also must not sleep, since it is called with * the inode_hash_lock spinlock held. * * This is a even more generalized version of ilookup5() when the * function must never block --- find_inode() can block in * __wait_on_freeing_inode() --- or when the caller can not increment * the reference count because the resulting iput() might cause an * inode eviction. The tradeoff is that the @match funtion must be * very carefully implemented. */
struct inode *find_inode_nowait(struct super_block *sb, unsigned long hashval, int (*match)(struct inode *, unsigned long, void *), void *data) { struct hlist_head *head = inode_hashtable + hash(sb, hashval); struct inode *inode, *ret_inode = NULL; int mval; spin_lock(&inode_hash_lock); hlist_for_each_entry(inode, head, i_hash) { if (inode->i_sb != sb) continue; mval = match(inode, hashval, data); if (mval == 0) continue; if (mval == 1) ret_inode = inode; goto out; } out: spin_unlock(&inode_hash_lock); return ret_inode; }

Contributors

PersonTokensPropCommitsCommitProp
Theodore Y. Ts'o131100.00%1100.00%
Total131100.00%1100.00%

EXPORT_SYMBOL(find_inode_nowait);
int insert_inode_locked(struct inode *inode) { struct super_block *sb = inode->i_sb; ino_t ino = inode->i_ino; struct hlist_head *head = inode_hashtable + hash(sb, ino); while (1) { struct inode *old = NULL; spin_lock(&inode_hash_lock); hlist_for_each_entry(old, head, i_hash) { if (old->i_ino != ino) continue; if (old->i_sb != sb) continue; spin_lock(&old->i_lock); if (old->i_state & (I_FREEING|I_WILL_FREE)) { spin_unlock(&old->i_lock); continue; } break; } if (likely(!old)) { spin_lock(&inode->i_lock); inode->i_state |= I_NEW; hlist_add_head(&inode->i_hash, head); spin_unlock(&inode->i_lock); spin_unlock(&inode_hash_lock); return 0; } __iget(old); spin_unlock(&old->i_lock); spin_unlock(&inode_hash_lock); wait_on_inode(old); if (unlikely(!inode_unhashed(old))) { iput(old); return -EBUSY; } iput(old); } }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro16976.47%350.00%
Dave Chinner5123.08%233.33%
Sasha Levin10.45%116.67%
Total221100.00%6100.00%

EXPORT_SYMBOL(insert_inode_locked);
int insert_inode_locked4(struct inode *inode, unsigned long hashval, int (*test)(struct inode *, void *), void *data) { struct super_block *sb = inode->i_sb; struct hlist_head *head = inode_hashtable + hash(sb, hashval); while (1) { struct inode *old = NULL; spin_lock(&inode_hash_lock); hlist_for_each_entry(old, head, i_hash) { if (old->i_sb != sb) continue; if (!test(old, data)) continue; spin_lock(&old->i_lock); if (old->i_state & (I_FREEING|I_WILL_FREE)) { spin_unlock(&old->i_lock); continue; } break; } if (likely(!old)) { spin_lock(&inode->i_lock); inode->i_state |= I_NEW; hlist_add_head(&inode->i_hash, head); spin_unlock(&inode->i_lock); spin_unlock(&inode_hash_lock); return 0; } __iget(old); spin_unlock(&old->i_lock); spin_unlock(&inode_hash_lock); wait_on_inode(old); if (unlikely(!inode_unhashed(old))) { iput(old); return -EBUSY; } iput(old); } }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro18678.15%350.00%
Dave Chinner5121.43%233.33%
Sasha Levin10.42%116.67%
Total238100.00%6100.00%

EXPORT_SYMBOL(insert_inode_locked4);
int generic_delete_inode(struct inode *inode) { return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)538.46%133.33%
Al Viro538.46%133.33%
Arjan van de Ven323.08%133.33%
Total13100.00%3100.00%

EXPORT_SYMBOL(generic_delete_inode); /* * Called when we're dropping the last reference * to an inode. * * Call the FS "drop_inode()" function, defaulting to * the legacy UNIX filesystem behaviour. If it tells * us to evict inode, do so. Otherwise, retain inode * in cache if fs is alive, sync and evict if fs is * shutting down. */
static void iput_final(struct inode *inode) { struct super_block *sb = inode->i_sb; const struct super_operations *op = inode->i_sb->s_op; int drop; WARN_ON(inode->i_state & I_NEW); if (op->drop_inode) drop = op->drop_inode(inode); else drop = generic_drop_inode(inode); if (!drop && (sb->s_flags & MS_ACTIVE)) { inode_add_lru(inode); spin_unlock(&inode->i_lock); return; } if (!drop) { inode->i_state |= I_WILL_FREE; spin_unlock(&inode->i_lock); write_inode_now(inode, 1); spin_lock(&inode->i_lock); WARN_ON(inode->i_state & I_NEW); inode->i_state &= ~I_WILL_FREE; } inode->i_state |= I_FREEING; if (!list_empty(&inode->i_lru)) inode_lru_list_del(inode); spin_unlock(&inode->i_lock); evict(inode); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro4122.40%211.11%
Dave Chinner4021.86%211.11%
Linus Torvalds3116.94%211.11%
Nicholas Piggin2413.11%211.11%
Alexander Viro2111.48%15.56%
Linus Torvalds (pre-git)137.10%633.33%
Eric Dumazet116.01%15.56%
Andrea Arcangeli10.55%15.56%
Jan Kara10.55%15.56%
Total183100.00%18100.00%

/** * iput - put an inode * @inode: inode to put * * Puts an inode, dropping its usage count. If the inode use count hits * zero, the inode is then freed and may also be destroyed. * * Consequently, iput() can sleep. */
void iput(struct inode *inode) { if (!inode) return; BUG_ON(inode->i_state & I_CLEAR); retry: if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock)) { if (inode->i_nlink && (inode->i_state & I_DIRTY_TIME)) { atomic_inc(&inode->i_count); inode->i_state &= ~I_DIRTY_TIME; spin_unlock(&inode->i_lock); trace_writeback_lazytime_iput(inode); mark_inode_dirty_sync(inode); goto retry; } iput_final(inode); } }

Contributors

PersonTokensPropCommitsCommitProp
Theodore Y. Ts'o5756.44%116.67%
Linus Torvalds (pre-git)2019.80%116.67%
Linus Torvalds1716.83%116.67%
Robert Love32.97%116.67%
Dave Chinner32.97%116.67%
Al Viro10.99%116.67%
Total101100.00%6100.00%

EXPORT_SYMBOL(iput); /** * bmap - find a block number in a file * @inode: inode of file * @block: block to find * * Returns the block number on the device holding the inode that * is the disk block number for the block of the file requested. * That is, asked for block 4 of inode 1 the function will return the * disk block relative to the disk start that holds that block of the * file. */
sector_t bmap(struct inode *inode, sector_t block) { sector_t res = 0; if (inode->i_mapping->a_ops->bmap) res = inode->i_mapping->a_ops->bmap(inode->i_mapping, block); return res; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)4593.75%480.00%
Andrew Morton36.25%120.00%
Total48100.00%5100.00%

EXPORT_SYMBOL(bmap); /* * Update times in overlayed inode from underlying real inode */
static void update_ovl_inode_times(struct dentry *dentry, struct inode *inode, bool rcu) { if (!rcu) { struct inode *realinode = d_real_inode(dentry); if (unlikely(inode != realinode) && (!timespec_equal(&inode->i_mtime, &realinode->i_mtime) || !timespec_equal(&inode->i_ctime, &realinode->i_ctime))) { inode->i_mtime = realinode->i_mtime; inode->i_ctime = realinode->i_ctime; } } }

Contributors

PersonTokensPropCommitsCommitProp
Miklos Szeredi93100.00%1100.00%
Total93100.00%1100.00%

/* * With relative atime, only update atime if the previous atime is * earlier than either the ctime or mtime or if at least a day has * passed since the last atime update. */
static int relatime_need_update(const struct path *path, struct inode *inode, struct timespec now, bool rcu) { if (!(path->mnt->mnt_flags & MNT_RELATIME)) return 1; update_ovl_inode_times(path->dentry, inode, rcu); /* * Is mtime younger than atime? If yes, update atime: */ if (timespec_compare(&inode->i_mtime, &inode->i_atime) >= 0) return 1; /* * Is ctime younger than atime? If yes, update atime: */ if (timespec_compare(&inode->i_ctime, &inode->i_atime) >= 0) return 1; /* * Is the previous atime value older than a day? If yes, * update atime: */ if ((long)(now.tv_sec - inode->i_atime.tv_sec) >= 24*60*60) return 1; /* * Good, we can skip the atime update: */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Matthew Garrett10584.68%150.00%
Miklos Szeredi1915.32%150.00%
Total124100.00%2100.00%


int generic_update_time(struct inode *inode, struct timespec *time, int flags) { int iflags = I_DIRTY_TIME; if (flags & S_ATIME) inode->i_atime = *time; if (flags & S_VERSION) inode_inc_iversion(inode); if (flags & S_CTIME) inode->i_ctime = *time; if (flags & S_MTIME) inode->i_mtime = *time; if (!(inode->i_sb->s_flags & MS_LAZYTIME) || (flags & S_VERSION)) iflags |= I_DIRTY_SYNC; __mark_inode_dirty(inode, iflags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Josef Bacik7469.81%150.00%
Theodore Y. Ts'o3230.19%150.00%
Total106100.00%2100.00%

EXPORT_SYMBOL(generic_update_time); /* * This does the actual work of updating an inodes time or version. Must have * had called mnt_want_write() before calling this. */
static int update_time(struct inode *inode, struct timespec *time, int flags) { int (*update_time)(struct inode *, struct timespec *, int); update_time = inode->i_op->update_time ? inode->i_op->update_time : generic_update_time; return update_time(inode, time, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Theodore Y. Ts'o62100.00%1100.00%
Total62100.00%1100.00%

/** * touch_atime - update the access time * @path: the &struct path to update * @inode: inode to update * * Update the accessed time on an inode and mark it for writeback. * This function automatically handles read only file systems and media, * as well as the "noatime" flag and inode specific "noatime" markers. */
bool __atime_needs_update(const struct path *path, struct inode *inode, bool rcu) { struct vfsmount *mnt = path->mnt; struct timespec now; if (inode->i_flags & S_NOATIME) return false; /* Atime updates will likely cause i_uid and i_gid to be written * back improprely if their true value is unknown to the vfs. */ if (HAS_UNMAPPED_ID(inode)) return false; if (IS_NOATIME(inode)) return false; if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)) return false; if (mnt->mnt_flags & MNT_NOATIME) return false; if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)) return false; now = current_time(inode); if (!relatime_need_update(path, inode, now, rcu)) return false; if (timespec_equal(&inode->i_atime, &now)) return false; return true; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig3119.38%211.11%
Neil Brown3119.38%15.56%
Andrew Morton2716.88%316.67%
Linus Torvalds (pre-git)138.12%15.56%
Al Viro127.50%211.11%
Eric W. Biedermann116.88%15.56%
Matthew Garrett95.62%15.56%
Valerie Henson85.00%15.56%
Miklos Szeredi74.38%15.56%
Andi Kleen53.12%211.11%
Eric Dumazet31.88%15.56%
Dave Jones21.25%15.56%
Deepa Dinamani10.62%15.56%
Total160100.00%18100.00%


void touch_atime(const struct path *path) { struct vfsmount *mnt = path->mnt; struct inode *inode = d_inode(path->dentry); struct timespec now; if (!__atime_needs_update(path, inode, false)) return; if (!sb_start_write_trylock(inode->i_sb)) return; if (__mnt_want_write(mnt) != 0) goto skip_update; /* * File systems can error out when updating inodes if they need to * allocate new space to modify an inode (such is the case for * Btrfs), but since we touch atime while walking down the path we * really don't care if we failed to update the atime of the file, * so just ignore the return value. * We may also fail on filesystems that have the ability to make parts * of the fs read only, e.g. subvolumes in Btrfs. */ now = current_time(inode); update_time(inode, &now, S_ATIME); __mnt_drop_write(mnt); skip_update: sb_end_write(inode->i_sb); }

Contributors

PersonTokensPropCommitsCommitProp
Neil Brown5250.00%111.11%
Jan Kara2524.04%111.11%
Andi Kleen1211.54%222.22%
Josef Bacik65.77%111.11%
Dave Hansen43.85%111.11%
Miklos Szeredi32.88%111.11%
Deepa Dinamani10.96%111.11%
Alexander Block10.96%111.11%
Total104100.00%9100.00%

EXPORT_SYMBOL(touch_atime); /* * The logic we want is * * if suid or (sgid and xgrp) * remove privs */
int should_remove_suid(struct dentry *dentry) { umode_t mode = d_inode(dentry)->i_mode; int kill = 0; /* suid always must be killed */ if (unlikely(mode & S_ISUID)) kill = ATTR_KILL_SUID; /* * sgid without any exec bits is just a mandatory locking mark; leave * it alone. If some exec bits are set, it's a real sgid; kill it. */ if (unlikely((mode & S_ISGID) && (mode & S_IXGRP))) kill |= ATTR_KILL_SGID; if (unlikely(kill && !capable(CAP_FSETID) && S_ISREG(mode))) return kill; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang8296.47%150.00%
David Howells33.53%150.00%
Total85100.00%2100.00%

EXPORT_SYMBOL(should_remove_suid); /* * Return mask of changes for notify_change() that need to be done as a * response to write or truncate. Return 0 if nothing has to be changed. * Negative value on error (change should be denied). */
int dentry_needs_remove_privs(struct dentry *dentry) { struct inode *inode = d_inode(dentry); int mask = 0; int ret; if (IS_NOSEC(inode)) return 0; mask = should_remove_suid(dentry); ret = security_inode_need_killpriv(dentry); if (ret < 0) return ret; if (ret) mask |= ATTR_KILL_PRIV; return mask; }

Contributors

PersonTokensPropCommitsCommitProp
Jan Kara72100.00%2100.00%
Total72100.00%2100.00%


static int __remove_privs(struct dentry *dentry, int kill) { struct iattr newattrs; newattrs.ia_valid = ATTR_FORCE | kill; /* * Note we call this on write, so notify_change will not * encounter any conflicting delegations: */ return notify_change(dentry, &newattrs, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang3489.47%133.33%
J. Bruce Fields37.89%133.33%
Jan Kara12.63%133.33%
Total38100.00%3100.00%

/* * Remove special file priviledges (suid, capabilities) when file is written * to or truncated. */
int file_remove_privs(struct file *file) { struct dentry *dentry = file_dentry(file); struct inode *inode = file_inode(file); int kill; int error = 0; /* Fast path for nothing security related */ if (IS_NOSEC(inode)) return 0; kill = dentry_needs_remove_privs(dentry); if (kill < 0) return kill; if (kill) error = __remove_privs(dentry, kill); if (!error) inode_has_no_xattr(inode); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang7178.02%116.67%
Jan Kara1112.09%350.00%
Miklos Szeredi77.69%116.67%
David Howells22.20%116.67%
Total91100.00%6100.00%

EXPORT_SYMBOL(file_remove_privs); /** * file_update_time - update mtime and ctime time * @file: file accessed * * Update the mtime and ctime members of an inode and mark the inode * for writeback. Note that this function is meant exclusively for * usage in the file write path of filesystems, and filesystems may * choose to explicitly ignore update via this function with the * S_NOCMTIME inode flag, e.g. for network filesystem where these * timestamps are handled by the server. This can return an error for * file systems who need to allocate space in order to update an inode. */
int file_update_time(struct file *file) { struct inode *inode = file_inode(file); struct timespec now; int sync_it = 0; int ret; /* First try to exhaust all avenues to not sync */ if (IS_NOCMTIME(inode)) return 0; now = current_time(inode); if (!timespec_equal(&inode->i_mtime, &now)) sync_it = S_MTIME; if (!timespec_equal(&inode->i_ctime, &now)) sync_it |= S_CTIME; if (IS_I_VERSION(inode)) sync_it |= S_VERSION; if (!sync_it) return 0; /* Finally allowed to write? Takes lock. */ if (__mnt_want_write_file(file)) return 0; ret = update_time(inode, &now, sync_it); __mnt_drop_write_file(file); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Andi Kleen5842.65%320.00%
Josef Bacik2316.91%16.67%
Andrew Morton1511.03%213.33%
Christoph Hellwig107.35%16.67%
Jean Noel Cordenner75.15%16.67%
Trond Myklebust53.68%16.67%
Andreas Mohr53.68%16.67%
Dave Hansen42.94%16.67%
Linus Torvalds (pre-git)32.21%16.67%
Al Viro32.21%16.67%
Jan Kara21.47%16.67%
Deepa Dinamani10.74%16.67%
Total136100.00%15100.00%

EXPORT_SYMBOL(file_update_time);
int inode_needs_sync(struct inode *inode) { if (IS_SYNC(inode)) return 1; if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton40100.00%1100.00%
Total40100.00%1100.00%

EXPORT_SYMBOL(inode_needs_sync); /* * If we try to find an inode in the inode hash while it is being * deleted, we have to wait until the filesystem completes its * deletion before reporting that it isn't found. This function waits * until the deletion _might_ have completed. Callers are responsible * to recheck inode state. * * It doesn't matter if I_NEW is not set initially, a call to * wake_up_bit(&inode->i_state, __I_NEW) after removing from the hash list * will DTRT. */
static void __wait_on_freeing_inode(struct inode *inode) { wait_queue_head_t *wq; DEFINE_WAIT_BIT(wait, &inode->i_state, __I_NEW); wq = bit_waitqueue(&inode->i_state, __I_NEW); prepare_to_wait(wq, &wait.wq_entry, TASK_UNINTERRUPTIBLE); spin_unlock(&inode->i_lock); spin_unlock(&inode_hash_lock); schedule(); finish_wait(wq, &wait.wq_entry); spin_lock(&inode_hash_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton5059.52%228.57%
William Lee Irwin III2023.81%114.29%
Dave Chinner1011.90%228.57%
Ingo Molnar22.38%114.29%
Christoph Hellwig22.38%114.29%
Total84100.00%7100.00%

static __initdata unsigned long ihash_entries;
static int __init set_ihash_entries(char *str) { if (!str) return 0; ihash_entries = simple_strtoul(str, &str, 0); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Andrew Morton34100.00%1100.00%
Total34100.00%1100.00%

__setup("ihash_entries=", set_ihash_entries); /* * Initialize the waitqueues and inode hash table. */
void __init inode_init_early(void) { /* If hashes are distributed across NUMA nodes, defer * hash allocation until vmalloc space is available. */ if (hashdist) return; inode_hashtable = alloc_large_system_hash("Inode-cache", sizeof(struct hlist_head), ihash_entries, 14, HASH_EARLY | HASH_ZERO, &i_hash_shift, &i_hash_mask, 0, 0); }

Contributors

PersonTokensPropCommitsCommitProp
David Howells3271.11%120.00%
Brent Casavant920.00%240.00%
Tim Bird24.44%120.00%
Pavel Tatashin24.44%120.00%
Total45100.00%5100.00%


void __init inode_init(void) { /* inode slab cache */ inode_cachep = kmem_cache_create("inode_cache", sizeof(struct inode), 0, (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC| SLAB_MEM_SPREAD|SLAB_ACCOUNT), init_once); /* Hash may have been set up in inode_init_early */ if (!hashdist) return; inode_hashtable = alloc_large_system_hash("Inode-cache", sizeof(struct hlist_head), ihash_entries, 14, HASH_ZERO, &i_hash_shift, &i_hash_mask, 0, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Brent Casavant3345.83%111.11%
Andrew Morton2737.50%222.22%
Paul Jackson45.56%111.11%
Vladimir Davydov22.78%111.11%
Tim Bird22.78%111.11%
Andrea Arcangeli22.78%111.11%
Pavel Tatashin11.39%111.11%
Cheng Renquan11.39%111.11%
Total72100.00%9100.00%


void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) { inode->i_mode = mode; if (S_ISCHR(mode)) { inode->i_fop = &def_chr_fops; inode->i_rdev = rdev; } else if (S_ISBLK(mode)) { inode->i_fop = &def_blk_fops; inode->i_rdev = rdev; } else if (S_ISFIFO(mode)) inode->i_fop = &pipefifo_fops; else if (S_ISSOCK(mode)) ; /* leave it no_open_fops */ else printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for" " inode %s:%lu\n", mode, inode->i_sb->s_id, inode->i_ino); }

Contributors

PersonTokensPropCommitsCommitProp
Brian Gerst9786.61%125.00%
Manish Katiyar1210.71%125.00%
Al Viro32.68%250.00%
Total112100.00%4100.00%

EXPORT_SYMBOL(init_special_inode); /** * inode_init_owner - Init uid,gid,mode for new inode according to posix standards * @inode: New inode * @dir: Directory inode * @mode: mode of the new inode */
void inode_init_owner(struct inode *inode, const struct inode *dir, umode_t mode) { inode->i_uid = current_fsuid(); if (dir && dir->i_mode & S_ISGID) { inode->i_gid = dir->i_gid; if (S_ISDIR(mode)) mode |= S_ISGID; } else inode->i_gid = current_fsgid(); inode->i_mode = mode; }

Contributors

PersonTokensPropCommitsCommitProp
Dmitriy Monakhov7098.59%150.00%
Al Viro11.41%150.00%
Total71100.00%2100.00%

EXPORT_SYMBOL(inode_init_owner); /** * inode_owner_or_capable - check current task permissions to inode * @inode: inode being checked * * Return true if current either has CAP_FOWNER in a namespace with the * inode owner uid mapped, or owns the file. */
bool inode_owner_or_capable(const struct inode *inode) { struct user_namespace *ns; if (uid_eq(current_fsuid(), inode->i_uid)) return true; ns = current_user_ns(); if (kuid_has_mapping(ns, inode->i_uid) && ns_capable(ns, CAP_FOWNER)) return true; return false; }

Contributors

PersonTokensPropCommitsCommitProp
Serge E. Hallyn3456.67%240.00%
Andrew Lutomirski1626.67%120.00%
Kees Cook610.00%120.00%
Eric W. Biedermann46.67%120.00%
Total60100.00%5100.00%

EXPORT_SYMBOL(inode_owner_or_capable); /* * Direct i/o helper functions */
static void __inode_dio_wait(struct inode *inode) { wait_queue_head_t *wq = bit_waitqueue(&inode->i_state, __I_DIO_WAKEUP); DEFINE_WAIT_BIT(q, &inode->i_state, __I_DIO_WAKEUP); do { prepare_to_wait(wq, &q.wq_entry, TASK_UNINTERRUPTIBLE); if (atomic_read(&inode->i_dio_count)) schedule(); } while (atomic_read(&inode->i_dio_count)); finish_wait(wq, &q.wq_entry); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust8497.67%150.00%
Ingo Molnar22.33%150.00%
Total86100.00%2100.00%

/** * inode_dio_wait - wait for outstanding DIO requests to finish * @inode: inode to wait for * * Waits for all pending direct I/O requests to finish so that we can * proceed with a truncate or equivalent operation. * * Must be called under a lock that serializes taking new references * to i_dio_count, usually by inode->i_mutex. */
void inode_dio_wait(struct inode *inode) { if (atomic_read(&inode->i_dio_count)) __inode_dio_wait(inode); }

Contributors

PersonTokensPropCommitsCommitProp
Trond Myklebust25100.00%1100.00%
Total25100.00%1100.00%

EXPORT_SYMBOL(inode_dio_wait); /* * inode_set_flags - atomically set some inode flags * * Note: the caller should be holding i_mutex, or else be sure that * they have exclusive access to the inode structure (i.e., while the * inode is being instantiated). The reason for the cmpxchg() loop * --- which wouldn't be necessary if all code paths which modify * i_flags actually followed this rule, is that there is at least one * code path which doesn't today so we use cmpxchg() out of an abundance * of caution. * * In the long run, i_mutex is overkill, and we should probably look * at using the i_lock spinlock to protect i_flags, and then make sure * it is so documented in include/linux/fs.h and that all code follows * the locking convention!! */
void inode_set_flags(struct inode *inode, unsigned int flags, unsigned int mask) { unsigned int old_flags, new_flags; WARN_ON_ONCE(flags & ~mask); do { old_flags = ACCESS_ONCE(inode->i_flags); new_flags = (old_flags & ~mask) | flags; } while (unlikely(cmpxchg(&inode->i_flags, old_flags, new_flags) != old_flags)); }

Contributors

PersonTokensPropCommitsCommitProp
Theodore Y. Ts'o75100.00%1100.00%
Total75100.00%1100.00%

EXPORT_SYMBOL(inode_set_flags);
void inode_nohighmem(struct inode *inode) { mapping_set_gfp_mask(inode->i_mapping, GFP_USER); }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro19100.00%1100.00%
Total19100.00%1100.00%

EXPORT_SYMBOL(inode_nohighmem); /** * current_time - Return FS time * @inode: inode. * * Return the current time truncated to the time granularity supported by * the fs. * * Note that inode and inode->sb cannot be NULL. * Otherwise, the function warns and returns time without truncation. */
struct timespec current_time(struct inode *inode) { struct timespec now = current_kernel_time(); if (unlikely(!inode->i_sb)) { WARN(1, "current_time() called with uninitialized super_block in the inode"); return now; } return timespec_trunc(now, inode->i_sb->s_time_gran); }

Contributors

PersonTokensPropCommitsCommitProp
Deepa Dinamani52100.00%1100.00%
Total52100.00%1100.00%

EXPORT_SYMBOL(current_time);

Overall Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner110614.37%175.67%
Al Viro99812.97%3511.67%
Linus Torvalds (pre-git)6528.47%4214.00%
Christoph Hellwig4966.44%196.33%
Andrew Morton4365.67%268.67%
Miklos Szeredi4195.44%51.67%
Theodore Y. Ts'o3814.95%41.33%
Jan Harkes2993.89%31.00%
Linus Torvalds2733.55%93.00%
Nicholas Piggin2583.35%82.67%
Jan Kara2222.88%144.67%
Américo Wang1972.56%10.33%
Eric Dumazet1672.17%72.33%
Josef Bacik1371.78%20.67%
J. Bruce Fields1321.72%41.33%
Trond Myklebust1211.57%20.67%
Matthew Garrett1151.49%10.33%
Neil Brown1041.35%20.67%
David Chinner1021.33%20.67%
Brian Gerst971.26%10.33%
Andi Kleen921.20%51.67%
Peter Zijlstra891.16%31.00%
Dmitriy Monakhov750.97%10.33%
Deepa Dinamani610.79%20.67%
Brent Casavant420.55%20.67%
Anton Altaparmakov410.53%20.67%
David Howells400.52%20.67%
Arnaldo Carvalho de Melo390.51%10.33%
Serge E. Hallyn390.51%20.67%
Alexander Viro270.35%10.33%
Jeff Layton270.35%31.00%
Eric Paris250.32%31.00%
Josh Boyer250.32%10.33%
Tahsin Erdogan230.30%10.33%
William Lee Irwin III230.30%20.67%
Eric W. Biedermann230.30%20.67%
Vladimir Davydov210.27%41.33%
Andreas Gruenbacher200.26%20.67%
Jens Axboe190.25%20.67%
Andrew Lutomirski170.22%10.33%
Carlos Maiolino150.19%10.33%
Manish Katiyar140.18%20.67%
Glauber de Oliveira Costa140.18%20.67%
Ingo Molnar100.13%20.67%
Matthias Kaehlcke100.13%10.33%
David Herrmann100.13%10.33%
Arjan van de Ven90.12%31.00%
Johannes Weiner90.12%10.33%
Valerie Henson80.10%10.33%
Christoph Lameter80.10%31.00%
Dave Hansen80.10%20.67%
Josef Whiter70.09%10.33%
Stephen D. Smalley70.09%10.33%
Jean Noel Cordenner70.09%10.33%
Kees Cook60.08%10.33%
Chris Wright60.08%10.33%
Tejun Heo50.06%10.33%
Robert Love50.06%20.67%
Andreas Mohr50.06%10.33%
Mimi Zohar50.06%10.33%
Tim Bird40.05%10.33%
Paul Jackson40.05%10.33%
Chris Mason40.05%10.33%
Pavel Tatashin30.04%10.33%
Namhyung Kim30.04%10.33%
Heiko Carstens30.04%10.33%
Andrea Arcangeli30.04%20.67%
Eric Sesterhenn / Snakebyte30.04%10.33%
Greg Kroah-Hartman20.03%10.33%
Davidlohr Bueso A20.03%10.33%
Sasha Levin20.03%10.33%
Dave Jones20.03%10.33%
Randy Dunlap20.03%20.67%
Michel Lespinasse20.03%10.33%
Pavel Emelyanov10.01%10.33%
Joe Perches10.01%10.33%
Rafael Aquini10.01%10.33%
Alexander Block10.01%10.33%
Ross Zwisler10.01%10.33%
Cheng Renquan10.01%10.33%
Masahiro Yamada10.01%10.33%
Hugh Dickins10.01%10.33%
Ben Hutchings10.01%10.33%
Total7696100.00%300100.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.