diff options
Diffstat (limited to 'fs/inode.c')
| -rw-r--r-- | fs/inode.c | 99 | 
1 files changed, 53 insertions, 46 deletions
diff --git a/fs/inode.c b/fs/inode.c index 8c86c809ca17..42f6d25f32a5 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -804,6 +804,10 @@ repeat:  			__wait_on_freeing_inode(inode);  			goto repeat;  		} +		if (unlikely(inode->i_state & I_CREATING)) { +			spin_unlock(&inode->i_lock); +			return ERR_PTR(-ESTALE); +		}  		__iget(inode);  		spin_unlock(&inode->i_lock);  		return inode; @@ -831,6 +835,10 @@ repeat:  			__wait_on_freeing_inode(inode);  			goto repeat;  		} +		if (unlikely(inode->i_state & I_CREATING)) { +			spin_unlock(&inode->i_lock); +			return ERR_PTR(-ESTALE); +		}  		__iget(inode);  		spin_unlock(&inode->i_lock);  		return inode; @@ -961,13 +969,26 @@ 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; +	inode->i_state &= ~I_NEW & ~I_CREATING;  	smp_mb();  	wake_up_bit(&inode->i_state, __I_NEW);  	spin_unlock(&inode->i_lock);  }  EXPORT_SYMBOL(unlock_new_inode); +void discard_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); +	iput(inode); +} +EXPORT_SYMBOL(discard_new_inode); +  /**   * lock_two_nondirectories - take two i_mutexes on non-directory objects   * @@ -1029,6 +1050,7 @@ struct inode *inode_insert5(struct inode *inode, unsigned long hashval,  {  	struct hlist_head *head = inode_hashtable + hash(inode->i_sb, hashval);  	struct inode *old; +	bool creating = inode->i_state & I_CREATING;  again:  	spin_lock(&inode_hash_lock); @@ -1039,6 +1061,8 @@ again:  		 * Use the old inode instead of the preallocated one.  		 */  		spin_unlock(&inode_hash_lock); +		if (IS_ERR(old)) +			return NULL;  		wait_on_inode(old);  		if (unlikely(inode_unhashed(old))) {  			iput(old); @@ -1060,6 +1084,8 @@ again:  	inode->i_state |= I_NEW;  	hlist_add_head(&inode->i_hash, head);  	spin_unlock(&inode->i_lock); +	if (!creating) +		inode_sb_list_add(inode);  unlock:  	spin_unlock(&inode_hash_lock); @@ -1094,12 +1120,13 @@ struct inode *iget5_locked(struct super_block *sb, unsigned long hashval,  	struct inode *inode = ilookup5(sb, hashval, test, data);  	if (!inode) { -		struct inode *new = new_inode(sb); +		struct inode *new = alloc_inode(sb);  		if (new) { +			new->i_state = 0;  			inode = inode_insert5(new, hashval, test, set, data);  			if (unlikely(inode != new)) -				iput(new); +				destroy_inode(new);  		}  	}  	return inode; @@ -1128,6 +1155,8 @@ again:  	inode = find_inode_fast(sb, head, ino);  	spin_unlock(&inode_hash_lock);  	if (inode) { +		if (IS_ERR(inode)) +			return NULL;  		wait_on_inode(inode);  		if (unlikely(inode_unhashed(inode))) {  			iput(inode); @@ -1165,6 +1194,8 @@ again:  		 */  		spin_unlock(&inode_hash_lock);  		destroy_inode(inode); +		if (IS_ERR(old)) +			return NULL;  		inode = old;  		wait_on_inode(inode);  		if (unlikely(inode_unhashed(inode))) { @@ -1282,7 +1313,7 @@ struct inode *ilookup5_nowait(struct super_block *sb, unsigned long hashval,  	inode = find_inode(sb, head, test, data);  	spin_unlock(&inode_hash_lock); -	return inode; +	return IS_ERR(inode) ? NULL : inode;  }  EXPORT_SYMBOL(ilookup5_nowait); @@ -1338,6 +1369,8 @@ again:  	spin_unlock(&inode_hash_lock);  	if (inode) { +		if (IS_ERR(inode)) +			return NULL;  		wait_on_inode(inode);  		if (unlikely(inode_unhashed(inode))) {  			iput(inode); @@ -1421,12 +1454,17 @@ int insert_inode_locked(struct inode *inode)  		}  		if (likely(!old)) {  			spin_lock(&inode->i_lock); -			inode->i_state |= I_NEW; +			inode->i_state |= I_NEW | I_CREATING;  			hlist_add_head(&inode->i_hash, head);  			spin_unlock(&inode->i_lock);  			spin_unlock(&inode_hash_lock);  			return 0;  		} +		if (unlikely(old->i_state & I_CREATING)) { +			spin_unlock(&old->i_lock); +			spin_unlock(&inode_hash_lock); +			return -EBUSY; +		}  		__iget(old);  		spin_unlock(&old->i_lock);  		spin_unlock(&inode_hash_lock); @@ -1443,7 +1481,10 @@ EXPORT_SYMBOL(insert_inode_locked);  int insert_inode_locked4(struct inode *inode, unsigned long hashval,  		int (*test)(struct inode *, void *), void *data)  { -	struct inode *old = inode_insert5(inode, hashval, test, NULL, data); +	struct inode *old; + +	inode->i_state |= I_CREATING; +	old = inode_insert5(inode, hashval, test, NULL, data);  	if (old != inode) {  		iput(old); @@ -1555,49 +1596,16 @@ sector_t bmap(struct inode *inode, sector_t block)  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) -{ -	struct dentry *upperdentry; - -	/* -	 * Nothing to do if in rcu or if non-overlayfs -	 */ -	if (rcu || likely(!(dentry->d_flags & DCACHE_OP_REAL))) -		return; - -	upperdentry = d_real(dentry, NULL, 0, D_REAL_UPPER); - -	/* -	 * If file is on lower then we can't update atime, so no worries about -	 * stale mtime/ctime. -	 */ -	if (upperdentry) { -		struct inode *realinode = d_inode(upperdentry); - -		if ((!timespec64_equal(&inode->i_mtime, &realinode->i_mtime) || -		     !timespec64_equal(&inode->i_ctime, &realinode->i_ctime))) { -			inode->i_mtime = realinode->i_mtime; -			inode->i_ctime = realinode->i_ctime; -		} -	} -} - -/*   * 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) +static int relatime_need_update(struct vfsmount *mnt, struct inode *inode, +			     struct timespec now)  { -	if (!(path->mnt->mnt_flags & MNT_RELATIME)) +	if (!(mnt->mnt_flags & MNT_RELATIME))  		return 1; - -	update_ovl_inode_times(path->dentry, inode, rcu);  	/*  	 * Is mtime younger than atime? If yes, update atime:  	 */ @@ -1668,8 +1676,7 @@ static int update_time(struct inode *inode, struct timespec64 *time, int flags)   *	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) +bool atime_needs_update(const struct path *path, struct inode *inode)  {  	struct vfsmount *mnt = path->mnt;  	struct timespec64 now; @@ -1695,7 +1702,7 @@ bool __atime_needs_update(const struct path *path, struct inode *inode,  	now = current_time(inode); -	if (!relatime_need_update(path, inode, timespec64_to_timespec(now), rcu)) +	if (!relatime_need_update(mnt, inode, timespec64_to_timespec(now)))  		return false;  	if (timespec64_equal(&inode->i_atime, &now)) @@ -1710,7 +1717,7 @@ void touch_atime(const struct path *path)  	struct inode *inode = d_inode(path->dentry);  	struct timespec64 now; -	if (!__atime_needs_update(path, inode, false)) +	if (!atime_needs_update(path, inode))  		return;  	if (!sb_start_write_trylock(inode->i_sb))  |