diff options
Diffstat (limited to 'fs/inode.c')
| -rw-r--r-- | fs/inode.c | 82 | 
1 files changed, 56 insertions, 26 deletions
diff --git a/fs/inode.c b/fs/inode.c index 96c77b81167..ec7924696a1 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -37,7 +37,7 @@   *   inode->i_sb->s_inode_lru, inode->i_lru   * inode_sb_list_lock protects:   *   sb->s_inodes, inode->i_sb_list - * inode_wb_list_lock protects: + * bdi->wb.list_lock protects:   *   bdi->wb.b_{dirty,io,more_io}, inode->i_wb_list   * inode_hash_lock protects:   *   inode_hashtable, inode->i_hash @@ -48,7 +48,7 @@   *   inode->i_lock   *     inode->i_sb->s_inode_lru_lock   * - * inode_wb_list_lock + * bdi->wb.list_lock   *   inode->i_lock   *   * inode_hash_lock @@ -65,7 +65,6 @@ static struct hlist_head *inode_hashtable __read_mostly;  static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock);  __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_sb_list_lock); -__cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_wb_list_lock);  /*   * Empty aops. Can be used for the cases where the user does not @@ -144,6 +143,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)  	inode->i_op = &empty_iops;  	inode->i_fop = &empty_fops;  	inode->i_nlink = 1; +	inode->i_opflags = 0;  	inode->i_uid = 0;  	inode->i_gid = 0;  	atomic_set(&inode->i_writecount, 0); @@ -362,9 +362,11 @@ EXPORT_SYMBOL_GPL(inode_sb_list_add);  static inline void inode_sb_list_del(struct inode *inode)  { -	spin_lock(&inode_sb_list_lock); -	list_del_init(&inode->i_sb_list); -	spin_unlock(&inode_sb_list_lock); +	if (!list_empty(&inode->i_sb_list)) { +		spin_lock(&inode_sb_list_lock); +		list_del_init(&inode->i_sb_list); +		spin_unlock(&inode_sb_list_lock); +	}  }  static unsigned long hash(struct super_block *sb, unsigned long hashval) @@ -398,12 +400,12 @@ void __insert_inode_hash(struct inode *inode, unsigned long hashval)  EXPORT_SYMBOL(__insert_inode_hash);  /** - *	remove_inode_hash - remove an inode from the 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) +void __remove_inode_hash(struct inode *inode)  {  	spin_lock(&inode_hash_lock);  	spin_lock(&inode->i_lock); @@ -411,7 +413,7 @@ void remove_inode_hash(struct inode *inode)  	spin_unlock(&inode->i_lock);  	spin_unlock(&inode_hash_lock);  } -EXPORT_SYMBOL(remove_inode_hash); +EXPORT_SYMBOL(__remove_inode_hash);  void end_writeback(struct inode *inode)  { @@ -453,7 +455,9 @@ static void evict(struct inode *inode)  	BUG_ON(!(inode->i_state & I_FREEING));  	BUG_ON(!list_empty(&inode->i_lru)); -	inode_wb_list_del(inode); +	if (!list_empty(&inode->i_wb_list)) +		inode_wb_list_del(inode); +  	inode_sb_list_del(inode);  	if (op->evict_inode) { @@ -797,6 +801,29 @@ unsigned int get_next_ino(void)  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; +} + +/**   *	new_inode 	- obtain an inode   *	@sb: superblock   * @@ -814,27 +841,16 @@ struct inode *new_inode(struct super_block *sb)  	spin_lock_prefetch(&inode_sb_list_lock); -	inode = alloc_inode(sb); -	if (inode) { -		spin_lock(&inode->i_lock); -		inode->i_state = 0; -		spin_unlock(&inode->i_lock); +	inode = new_inode_pseudo(sb); +	if (inode)  		inode_sb_list_add(inode); -	}  	return inode;  }  EXPORT_SYMBOL(new_inode); -/** - * 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) -{  #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; @@ -850,7 +866,20 @@ void unlock_new_inode(struct inode *inode)  					  &type->i_mutex_dir_key);  		}  	} +} +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; @@ -1308,7 +1337,8 @@ static void iput_final(struct inode *inode)  	}  	inode->i_state |= I_FREEING; -	inode_lru_list_del(inode); +	if (!list_empty(&inode->i_lru)) +		inode_lru_list_del(inode);  	spin_unlock(&inode->i_lock);  	evict(inode);  |