Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b2b2af8e authored by Dave Chinner's avatar Dave Chinner Committed by Al Viro
Browse files

fs: factor inode disposal



We have a couple of places that dispose of inodes. factor the
disposal into evict() to isolate this code and make it simpler to
peel away the inode_lock from the code.

While doing this, change the logic flow in iput_final() to separate
the different cases that need to be handled to make the transitions
the inode goes through more obvious.

Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 250df6ed
Loading
Loading
Loading
Loading
+41 −63
Original line number Original line Diff line number Diff line
@@ -422,17 +422,6 @@ void __insert_inode_hash(struct inode *inode, unsigned long hashval)
}
}
EXPORT_SYMBOL(__insert_inode_hash);
EXPORT_SYMBOL(__insert_inode_hash);


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

/**
/**
 *	remove_inode_hash - remove an inode from the hash
 *	remove_inode_hash - remove an inode from the hash
 *	@inode: inode to unhash
 *	@inode: inode to unhash
@@ -462,10 +451,31 @@ void end_writeback(struct inode *inode)
}
}
EXPORT_SYMBOL(end_writeback);
EXPORT_SYMBOL(end_writeback);


/*
 * 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)
static void evict(struct inode *inode)
{
{
	const struct super_operations *op = inode->i_sb->s_op;
	const struct super_operations *op = inode->i_sb->s_op;


	BUG_ON(!(inode->i_state & I_FREEING));
	BUG_ON(!list_empty(&inode->i_lru));

	spin_lock(&inode_lock);
	list_del_init(&inode->i_wb_list);
	__inode_sb_list_del(inode);
	spin_unlock(&inode_lock);

	if (op->evict_inode) {
	if (op->evict_inode) {
		op->evict_inode(inode);
		op->evict_inode(inode);
	} else {
	} else {
@@ -477,6 +487,15 @@ static void evict(struct inode *inode)
		bd_forget(inode);
		bd_forget(inode);
	if (S_ISCHR(inode->i_mode) && inode->i_cdev)
	if (S_ISCHR(inode->i_mode) && inode->i_cdev)
		cd_forget(inode);
		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);
}
}


/*
/*
@@ -495,16 +514,6 @@ static void dispose_list(struct list_head *head)
		list_del_init(&inode->i_lru);
		list_del_init(&inode->i_lru);


		evict(inode);
		evict(inode);

		spin_lock(&inode_lock);
		__remove_inode_hash(inode);
		__inode_sb_list_del(inode);
		spin_unlock(&inode_lock);

		spin_lock(&inode->i_lock);
		wake_up_bit(&inode->i_state, __I_NEW);
		spin_unlock(&inode->i_lock);
		destroy_inode(inode);
	}
	}
}
}


@@ -537,13 +546,7 @@ void evict_inodes(struct super_block *sb)
		if (!(inode->i_state & (I_DIRTY | I_SYNC)))
		if (!(inode->i_state & (I_DIRTY | I_SYNC)))
			inodes_stat.nr_unused--;
			inodes_stat.nr_unused--;
		spin_unlock(&inode->i_lock);
		spin_unlock(&inode->i_lock);

		/*
		 * Move the inode off the IO lists and LRU once I_FREEING is
		 * set so that it won't get moved back on there if it is dirty.
		 */
		list_move(&inode->i_lru, &dispose);
		list_move(&inode->i_lru, &dispose);
		list_del_init(&inode->i_wb_list);
	}
	}
	spin_unlock(&inode_lock);
	spin_unlock(&inode_lock);


@@ -596,13 +599,7 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty)
		if (!(inode->i_state & (I_DIRTY | I_SYNC)))
		if (!(inode->i_state & (I_DIRTY | I_SYNC)))
			inodes_stat.nr_unused--;
			inodes_stat.nr_unused--;
		spin_unlock(&inode->i_lock);
		spin_unlock(&inode->i_lock);

		/*
		 * Move the inode off the IO lists and LRU once I_FREEING is
		 * set so that it won't get moved back on there if it is dirty.
		 */
		list_move(&inode->i_lru, &dispose);
		list_move(&inode->i_lru, &dispose);
		list_del_init(&inode->i_wb_list);
	}
	}
	spin_unlock(&inode_lock);
	spin_unlock(&inode_lock);


@@ -699,12 +696,7 @@ static void prune_icache(int nr_to_scan)
		inode->i_state |= I_FREEING;
		inode->i_state |= I_FREEING;
		spin_unlock(&inode->i_lock);
		spin_unlock(&inode->i_lock);


		/*
		 * Move the inode off the IO lists and LRU once I_FREEING is
		 * set so that it won't get moved back on there if it is dirty.
		 */
		list_move(&inode->i_lru, &freeable);
		list_move(&inode->i_lru, &freeable);
		list_del_init(&inode->i_wb_list);
		inodes_stat.nr_unused--;
		inodes_stat.nr_unused--;
	}
	}
	if (current_is_kswapd())
	if (current_is_kswapd())
@@ -1434,16 +1426,16 @@ static void iput_final(struct inode *inode)
	else
	else
		drop = generic_drop_inode(inode);
		drop = generic_drop_inode(inode);


	if (!drop) {
	if (!drop && (sb->s_flags & MS_ACTIVE)) {
		if (sb->s_flags & MS_ACTIVE) {
		inode->i_state |= I_REFERENCED;
		inode->i_state |= I_REFERENCED;
			if (!(inode->i_state & (I_DIRTY|I_SYNC))) {
		if (!(inode->i_state & (I_DIRTY|I_SYNC)))
			inode_lru_list_add(inode);
			inode_lru_list_add(inode);
			}
		spin_unlock(&inode->i_lock);
		spin_unlock(&inode->i_lock);
		spin_unlock(&inode_lock);
		spin_unlock(&inode_lock);
		return;
		return;
	}
	}

	if (!drop) {
		inode->i_state |= I_WILL_FREE;
		inode->i_state |= I_WILL_FREE;
		spin_unlock(&inode->i_lock);
		spin_unlock(&inode->i_lock);
		spin_unlock(&inode_lock);
		spin_unlock(&inode_lock);
@@ -1452,28 +1444,14 @@ static void iput_final(struct inode *inode)
		spin_lock(&inode->i_lock);
		spin_lock(&inode->i_lock);
		WARN_ON(inode->i_state & I_NEW);
		WARN_ON(inode->i_state & I_NEW);
		inode->i_state &= ~I_WILL_FREE;
		inode->i_state &= ~I_WILL_FREE;
		__remove_inode_hash(inode);
	}
	}


	inode->i_state |= I_FREEING;
	inode->i_state |= I_FREEING;
	spin_unlock(&inode->i_lock);

	/*
	 * Move the inode off the IO lists and LRU once I_FREEING is
	 * set so that it won't get moved back on there if it is dirty.
	 */
	inode_lru_list_del(inode);
	inode_lru_list_del(inode);
	list_del_init(&inode->i_wb_list);
	spin_unlock(&inode->i_lock);

	__inode_sb_list_del(inode);
	spin_unlock(&inode_lock);
	spin_unlock(&inode_lock);

	evict(inode);
	evict(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);
}
}


/**
/**