diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index c6226bae7ad..cdc578eea47 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -4067,36 +4067,40 @@ buf_page_get_gen(
 	ulint		retries = 0;
 	buf_pool_t*	buf_pool = buf_pool_get(page_id);
 
-	ut_ad(mtr->is_active());
+	ut_ad((mtr == NULL) == (mode == BUF_EVICT_IF_IN_POOL));
+	ut_ad(mtr == NULL || mtr->is_active());
 	ut_ad((rw_latch == RW_S_LATCH)
 	      || (rw_latch == RW_X_LATCH)
 	      || (rw_latch == RW_SX_LATCH)
 	      || (rw_latch == RW_NO_LATCH));
 #ifdef UNIV_DEBUG
 	switch (mode) {
+	case BUF_EVICT_IF_IN_POOL:
+		/* After DISCARD TABLESPACE, the tablespace would not exist,
+		but in IMPORT TABLESPACE, PageConverter::operator() must
+		replace any old pages, which were not evicted during DISCARD.
+		Skip the assertion on zip_size. */
+		break;
+	default:
+		ut_error;
 	case BUF_GET_NO_LATCH:
 		ut_ad(rw_latch == RW_NO_LATCH);
-		break;
+		/* fall through */
 	case BUF_GET:
 	case BUF_GET_IF_IN_POOL:
 	case BUF_PEEK_IF_IN_POOL:
 	case BUF_GET_IF_IN_POOL_OR_WATCH:
 	case BUF_GET_POSSIBLY_FREED:
+		bool			found;
+		const page_size_t&	space_page_size
+			= fil_space_get_page_size(page_id.space(), &found);
+		ut_ad(found);
+		ut_ad(page_size.equals_to(space_page_size));
 		break;
-	default:
-		ut_error;
 	}
-
-	bool			found;
-	const page_size_t&	space_page_size
-		= fil_space_get_page_size(page_id.space(), &found);
-
-	ut_ad(found);
-
-	ut_ad(page_size.equals_to(space_page_size));
 #endif /* UNIV_DEBUG */
 
-	ut_ad(!ibuf_inside(mtr)
+	ut_ad(!mtr || !ibuf_inside(mtr)
 	      || ibuf_page_low(page_id, page_size, FALSE, file, line, NULL));
 
 	buf_pool->stat.n_page_gets++;
@@ -4183,13 +4187,13 @@ loop:
 			rw_lock_x_unlock(hash_lock);
 		}
 
-		if (mode == BUF_GET_IF_IN_POOL
-		    || mode == BUF_PEEK_IF_IN_POOL
-		    || mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
-
+		switch (mode) {
+		case BUF_GET_IF_IN_POOL:
+		case BUF_GET_IF_IN_POOL_OR_WATCH:
+		case BUF_PEEK_IF_IN_POOL:
+		case BUF_EVICT_IF_IN_POOL:
 			ut_ad(!rw_lock_own(hash_lock, RW_LOCK_X));
 			ut_ad(!rw_lock_own(hash_lock, RW_LOCK_S));
-
 			return(NULL);
 		}
 
@@ -4248,8 +4252,10 @@ loop:
 
 got_block:
 
-	if (mode == BUF_GET_IF_IN_POOL || mode == BUF_PEEK_IF_IN_POOL) {
-
+	switch (mode) {
+	case BUF_GET_IF_IN_POOL:
+	case BUF_PEEK_IF_IN_POOL:
+	case BUF_EVICT_IF_IN_POOL:
 		buf_page_t*	fix_page = &fix_block->page;
 		BPageMutex*	fix_mutex = buf_page_get_mutex(fix_page);
 		mutex_enter(fix_mutex);
@@ -4271,6 +4277,19 @@ got_block:
 		buf_page_t*	bpage;
 
 	case BUF_BLOCK_FILE_PAGE:
+		if (UNIV_UNLIKELY(mode == BUF_EVICT_IF_IN_POOL)) {
+evict_from_pool:
+			ut_ad(!fix_block->page.oldest_modification);
+			buf_pool_mutex_enter(buf_pool);
+			buf_block_unfix(fix_block);
+
+			if (!buf_LRU_free_page(&fix_block->page, true)) {
+				ut_ad(0);
+			}
+
+			buf_pool_mutex_exit(buf_pool);
+			return(NULL);
+		}
 		bpage = &block->page;
 		if (fsp_is_system_temporary(page_id.space())
 		    && buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
@@ -4315,6 +4334,10 @@ got_block:
 			goto loop;
 		}
 
+		if (UNIV_UNLIKELY(mode == BUF_EVICT_IF_IN_POOL)) {
+			goto evict_from_pool;
+		}
+
 		/* Buffer-fix the block so that it cannot be evicted
 		or relocated while we are attempting to allocate an
 		uncompressed page. */
diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc
index 5a8a3567e0f..edeca87cbf1 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -3809,13 +3809,12 @@ FlushObserver::notify_remove(
 void
 FlushObserver::flush()
 {
-	buf_remove_t	buf_remove;
+	trx_t* trx = m_trx;
+	ut_ad(trx);
 
 	if (m_interrupted) {
-		buf_remove = BUF_REMOVE_FLUSH_NO_WRITE;
+		trx = NULL;
 	} else {
-		buf_remove = BUF_REMOVE_FLUSH_WRITE;
-
 		if (m_stage != NULL) {
 			ulint	pages_to_flush =
 				buf_flush_get_dirty_pages_count(
@@ -3826,7 +3825,7 @@ FlushObserver::flush()
 	}
 
 	/* Flush or remove dirty pages. */
-	buf_LRU_flush_or_remove_pages(m_space_id, buf_remove, m_trx);
+	buf_LRU_flush_or_remove_pages(m_space_id, trx);
 
 	/* Wait for all dirty pages were flushed. */
 	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc
index a78112746f5..785fce68fef 100644
--- a/storage/innobase/buf/buf0lru.cc
+++ b/storage/innobase/buf/buf0lru.cc
@@ -544,11 +544,14 @@ buf_flush_or_remove_page(
 	return(processed);
 }
 
-/******************************************************************//**
-Remove all dirty pages belonging to a given tablespace inside a specific
+/** Remove all dirty pages belonging to a given tablespace inside a specific
 buffer pool instance when we are deleting the data file(s) of that
 tablespace. The pages still remain a part of LRU and are evicted from
 the list as they age towards the tail of the LRU.
+@param[in,out]	buf_pool	buffer pool
+@param[in]	id		tablespace identifier
+@param[in]	trx		transaction (to check for interrupt),
+				or NULL if the files should not be written to
 @retval DB_SUCCESS if all freed
 @retval DB_FAIL if not all freed
 @retval DB_INTERRUPTED if the transaction was interrupted */
@@ -594,7 +597,7 @@ rescan:
 			/* Skip this block, as it does not belong to
 			the target space. */
 
-		} else if (!buf_flush_or_remove_page(buf_pool, bpage, flush)) {
+		} else if (!buf_flush_or_remove_page(buf_pool, bpage, trx)) {
 
 			/* Remove was unsuccessful, we have to try again
 			by scanning the entire list from the end.
@@ -617,7 +620,7 @@ rescan:
 			iteration. */
 
 			all_freed = false;
-		} else if (flush) {
+		} else if (trx) {
 
 			/* The processing was successful. And during the
 			processing we have released the buf_pool mutex
@@ -636,13 +639,11 @@ rescan:
 			processed = 0;
 		}
 
-#ifdef DBUG_OFF
-		if (flush) {
+		if (trx) {
 			DBUG_EXECUTE_IF("ib_export_flush_crash",
 					static ulint	n_pages;
 					if (++n_pages == 4) {DBUG_SUICIDE();});
 		}
-#endif /* DBUG_OFF */
 
 		/* The check for trx is interrupted is expensive, we want
 		to check every N iterations. */
@@ -667,24 +668,27 @@ rescan:
 	return(all_freed ? DB_SUCCESS : DB_FAIL);
 }
 
-/******************************************************************//**
-Remove or flush all the dirty pages that belong to a given tablespace
+/** Remove or flush all the dirty pages that belong to a given tablespace
 inside a specific buffer pool instance. The pages will remain in the LRU
 list and will be evicted from the LRU list as they age and move towards
-the tail of the LRU list. */
+the tail of the LRU list.
+@param[in,out]	buf_pool	buffer pool
+@param[in]	id		tablespace identifier
+@param[in]	observer	flush observer,
+				or NULL if the files should not be written to
+@param[in]	trx		transaction (to check for interrupt),
+				or NULL if the files should not be written to
+*/
 static
 void
 buf_flush_dirty_pages(
-/*==================*/
-	buf_pool_t*	buf_pool,	/*!< buffer pool instance */
-	ulint		id,		/*!< in: space id */
-	FlushObserver*	observer,	/*!< in: flush observer */
-	bool		flush,		/*!< in: flush to disk if true otherwise
-					remove the pages without flushing */
-	const trx_t*	trx)		/*!< to check if the operation must
-					be interrupted */
+	buf_pool_t*	buf_pool,
+	ulint		id,
+	FlushObserver*	observer,
+	const trx_t*	trx)
 {
 	dberr_t		err;
+	bool		flush = trx != NULL;
 
 	do {
 		buf_pool_mutex_enter(buf_pool);
@@ -718,237 +722,30 @@ buf_flush_dirty_pages(
 	      || buf_pool_get_dirty_pages_count(buf_pool, id, observer) == 0);
 }
 
-/******************************************************************//**
-Remove all pages that belong to a given tablespace inside a specific
-buffer pool instance when we are DISCARDing the tablespace. */
-static
-void
-buf_LRU_remove_all_pages(
-/*=====================*/
-	buf_pool_t*	buf_pool,	/*!< buffer pool instance */
-	ulint		id)		/*!< in: space id */
-{
-	buf_page_t*	bpage;
-	ibool		all_freed;
-
-scan_again:
-	buf_pool_mutex_enter(buf_pool);
-
-	all_freed = TRUE;
-
-	for (bpage = UT_LIST_GET_LAST(buf_pool->LRU);
-	     bpage != NULL;
-	     /* No op */) {
-
-		rw_lock_t*	hash_lock;
-		buf_page_t*	prev_bpage;
-		BPageMutex*	block_mutex;
-
-		ut_a(buf_page_in_file(bpage));
-		ut_ad(bpage->in_LRU_list);
-
-		prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
-
-		/* bpage->id.space() and bpage->io_fix are protected by
-		buf_pool->mutex and the block_mutex. It is safe to check
-		them while holding buf_pool->mutex only. */
-
-		if (bpage->id.space() != id) {
-			/* Skip this block, as it does not belong to
-			the space that is being invalidated. */
-			goto next_page;
-		} else if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
-			/* We cannot remove this page during this scan
-			yet; maybe the system is currently reading it
-			in, or flushing the modifications to the file */
-
-			all_freed = FALSE;
-			goto next_page;
-		} else {
-			hash_lock = buf_page_hash_lock_get(buf_pool, bpage->id);
-
-			rw_lock_x_lock(hash_lock);
-
-			block_mutex = buf_page_get_mutex(bpage);
-
-			mutex_enter(block_mutex);
-
-			if (bpage->buf_fix_count > 0) {
-
-				mutex_exit(block_mutex);
-
-				rw_lock_x_unlock(hash_lock);
-
-				/* We cannot remove this page during
-				this scan yet; maybe the system is
-				currently reading it in, or flushing
-				the modifications to the file */
-
-				all_freed = FALSE;
-
-				goto next_page;
-			}
-		}
-
-		ut_ad(mutex_own(block_mutex));
-
-		DBUG_PRINT("ib_buf", ("evict page " UINT32PF ":" UINT32PF
-				      " state %u",
-				      bpage->id.space(),
-				      bpage->id.page_no(),
-				      bpage->state));
-
-		if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
-			/* Do nothing, because the adaptive hash index
-			covers uncompressed pages only. */
-		} else if (((buf_block_t*) bpage)->index) {
-			buf_pool_mutex_exit(buf_pool);
-
-			rw_lock_x_unlock(hash_lock);
-
-			mutex_exit(block_mutex);
-
-			/* Note that the following call will acquire
-			and release block->lock X-latch.
-			Note that the table cannot be evicted during
-			the execution of ALTER TABLE...DISCARD TABLESPACE
-			because MySQL is keeping the table handle open. */
-
-			btr_search_drop_page_hash_when_freed(
-				bpage->id, bpage->size);
-
-			goto scan_again;
-		} else {
-			/* This debug check uses a dirty read that could
-			theoretically cause false positives while
-			buf_pool_clear_hash_index() is executing,
-			if the writes to block->index=NULL and
-			block->n_pointers=0 are reordered.
-			(Other conflicting access paths to the adaptive hash
-			index should not be possible, because when a
-			tablespace is being discarded or dropped, there must
-			be no concurrect access to the contained tables.) */
-			assert_block_ahi_empty((buf_block_t*) bpage);
-		}
-
-		if (bpage->oldest_modification != 0) {
-
-			buf_flush_remove(bpage);
-		}
-
-		ut_ad(!bpage->in_flush_list);
-
-		/* Remove from the LRU list. */
-
-		if (buf_LRU_block_remove_hashed(bpage, true)) {
-			buf_LRU_block_free_hashed_page((buf_block_t*) bpage);
-		} else {
-			ut_ad(block_mutex == &buf_pool->zip_mutex);
-		}
-
-		ut_ad(!mutex_own(block_mutex));
-
-		/* buf_LRU_block_remove_hashed() releases the hash_lock */
-		ut_ad(!rw_lock_own(hash_lock, RW_LOCK_X));
-		ut_ad(!rw_lock_own(hash_lock, RW_LOCK_S));
-
-next_page:
-		bpage = prev_bpage;
-	}
-
-	buf_pool_mutex_exit(buf_pool);
-
-	if (!all_freed) {
-		os_thread_sleep(20000);
-
-		goto scan_again;
-	}
-}
-
-/******************************************************************//**
-Remove pages belonging to a given tablespace inside a specific
-buffer pool instance when we are deleting the data file(s) of that
-tablespace. The pages still remain a part of LRU and are evicted from
-the list as they age towards the tail of the LRU only if buf_remove
-is BUF_REMOVE_FLUSH_NO_WRITE. */
-static
+/** Empty the flush list for all pages belonging to a tablespace.
+@param[in]	id		tablespace identifier
+@param[in]	trx		transaction, for checking for user interrupt;
+				or NULL if nothing is to be written
+@param[in]	drop_ahi	whether to drop the adaptive hash index */
 void
-buf_LRU_remove_pages(
-/*=================*/
-	buf_pool_t*	buf_pool,	/*!< buffer pool instance */
-	ulint		id,		/*!< in: space id */
-	buf_remove_t	buf_remove,	/*!< in: remove or flush strategy */
-	const trx_t*	trx)		/*!< to check if the operation must
-					be interrupted */
+buf_LRU_flush_or_remove_pages(ulint id, const trx_t* trx, bool drop_ahi)
 {
 	FlushObserver*	observer = (trx == NULL) ? NULL : trx->flush_observer;
+	/* Pages in the system tablespace must never be discarded. */
+	ut_ad(id || trx);
 
-	switch (buf_remove) {
-	case BUF_REMOVE_ALL_NO_WRITE:
-		buf_LRU_remove_all_pages(buf_pool, id);
-		break;
-
-	case BUF_REMOVE_FLUSH_NO_WRITE:
-		/* Pass trx as NULL to avoid interruption check. */
-		buf_flush_dirty_pages(buf_pool, id, observer, false, NULL);
-		break;
-
-	case BUF_REMOVE_FLUSH_WRITE:
-		buf_flush_dirty_pages(buf_pool, id, observer, true, trx);
-
-		if (observer == NULL) {
-			/* Ensure that all asynchronous IO is completed. */
-			os_aio_wait_until_no_pending_writes();
-			fil_flush(id);
-		}
-
-		break;
-	}
-}
-
-/******************************************************************//**
-Flushes all dirty pages or removes all pages belonging
-to a given tablespace. A PROBLEM: if readahead is being started, what
-guarantees that it will not try to read in pages after this operation
-has completed? */
-void
-buf_LRU_flush_or_remove_pages(
-/*==========================*/
-	ulint		id,		/*!< in: space id */
-	buf_remove_t	buf_remove,	/*!< in: remove or flush strategy */
-	const trx_t*	trx)		/*!< to check if the operation must
-					be interrupted */
-{
-	ulint		i;
-
-	/* Before we attempt to drop pages one by one we first
-	attempt to drop page hash index entries in batches to make
-	it more efficient. The batching attempt is a best effort
-	attempt and does not guarantee that all pages hash entries
-	will be dropped. We get rid of remaining page hash entries
-	one by one below. */
-	for (i = 0; i < srv_buf_pool_instances; i++) {
-		buf_pool_t*	buf_pool;
-
-		buf_pool = buf_pool_from_array(i);
-
-		switch (buf_remove) {
-		case BUF_REMOVE_ALL_NO_WRITE:
+	for (ulint i = 0; i < srv_buf_pool_instances; i++) {
+		buf_pool_t* buf_pool = buf_pool_from_array(i);
+		if (drop_ahi) {
 			buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
-			break;
-
-		case BUF_REMOVE_FLUSH_NO_WRITE:
-			/* It is a DROP TABLE for a single table
-			tablespace. No AHI entries exist because
-			we already dealt with them when freeing up
-			extents. */
-		case BUF_REMOVE_FLUSH_WRITE:
-			/* We allow read-only queries against the
-			table, there is no need to drop the AHI entries. */
-			break;
 		}
+		buf_flush_dirty_pages(buf_pool, id, observer, trx);
+	}
 
-		buf_LRU_remove_pages(buf_pool, id, buf_remove, trx);
+	if (trx && !observer && !trx_is_interrupted(trx)) {
+		/* Ensure that all asynchronous IO is completed. */
+		os_aio_wait_until_no_pending_writes();
+		fil_flush(id);
 	}
 }
 
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 51a8f9de012..d607beae687 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -1749,7 +1749,7 @@ dict_table_rename_in_cache(
 			return(DB_OUT_OF_MEMORY);
 		}
 
-		fil_delete_tablespace(table->space, BUF_REMOVE_ALL_NO_WRITE);
+		fil_delete_tablespace(table->space, true);
 
 		/* Delete any temp file hanging around. */
 		if (os_file_status(filepath, &exists, &ftype)
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 1ac07f731ee..d7096096582 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -2252,7 +2252,7 @@ fil_recreate_tablespace(
 
 	/* Step-1: Invalidate buffer pool pages belonging to the tablespace
 	to re-create. */
-	buf_LRU_flush_or_remove_pages(space_id, BUF_REMOVE_ALL_NO_WRITE, 0);
+	buf_LRU_flush_or_remove_pages(space_id, NULL);
 
 	/* Remove all insert buffer entries for the tablespace */
 	ibuf_delete_for_discarded_space(space_id);
@@ -2711,7 +2711,7 @@ fil_close_tablespace(
 	completely and permanently. The flag stop_new_ops also prevents
 	fil_flush() from being applied to this tablespace. */
 
-	buf_LRU_flush_or_remove_pages(id, BUF_REMOVE_FLUSH_WRITE, trx);
+	buf_LRU_flush_or_remove_pages(id, trx);
 
 	/* If the free is successful, the X lock will be released before
 	the space memory data structure is freed. */
@@ -2743,17 +2743,12 @@ fil_close_tablespace(
 	return(err);
 }
 
-/** Deletes an IBD tablespace, either general or single-table.
-The tablespace must be cached in the memory cache. This will delete the
-datafile, fil_space_t & fil_node_t entries from the file_system_t cache.
-@param[in]	space_id	Tablespace id
-@param[in]	buf_remove	Specify the action to take on the pages
-for this table in the buffer pool.
-@return DB_SUCCESS or error */
+/** Delete a tablespace and associated .ibd file.
+@param[in]	id		tablespace identifier
+@param[in]	drop_ahi	whether to drop the adaptive hash index
+@return	DB_SUCCESS or error */
 dberr_t
-fil_delete_tablespace(
-	ulint		id,
-	buf_remove_t	buf_remove)
+fil_delete_tablespace(ulint id, bool drop_ahi)
 {
 	char*		path = 0;
 	fil_space_t*	space = 0;
@@ -2797,7 +2792,7 @@ fil_delete_tablespace(
 	To deal with potential read requests, we will check the
 	::stop_new_ops flag in fil_io(). */
 
-	buf_LRU_flush_or_remove_pages(id, buf_remove, 0);
+	buf_LRU_flush_or_remove_pages(id, NULL, drop_ahi);
 
 #endif /* !UNIV_HOTBACKUP */
 
@@ -2907,7 +2902,7 @@ fil_truncate_tablespace(
 
 	/* Step-2: Invalidate buffer pool pages belonging to the tablespace
 	to re-create. Remove all insert buffer entries for the tablespace */
-	buf_LRU_flush_or_remove_pages(space_id, BUF_REMOVE_ALL_NO_WRITE, 0);
+	buf_LRU_flush_or_remove_pages(space_id, NULL);
 
 	/* Step-3: Truncate the tablespace and accordingly update
 	the fil_space_t handler that is used to access this tablespace. */
@@ -3002,7 +2997,7 @@ fil_reinit_space_header_for_table(
 	from disabling AHI during the scan */
 	btr_search_s_lock_all();
 	DEBUG_SYNC_C("simulate_buffer_pool_scan");
-	buf_LRU_flush_or_remove_pages(id, BUF_REMOVE_ALL_NO_WRITE, 0);
+	buf_LRU_flush_or_remove_pages(id, NULL);
 	btr_search_s_unlock_all();
 
 	row_mysql_lock_data_dictionary(trx);
@@ -3119,7 +3114,7 @@ fil_discard_tablespace(
 {
 	dberr_t	err;
 
-	switch (err = fil_delete_tablespace(id, BUF_REMOVE_ALL_NO_WRITE)) {
+	switch (err = fil_delete_tablespace(id, true)) {
 	case DB_SUCCESS:
 		break;
 
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 7497bb1f7df..418f5dcccfd 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -12898,7 +12898,7 @@ innobase_drop_tablespace(
 	}
 
 	/* Delete the physical files, fil_space_t & fil_node_t entries. */
-	err = fil_delete_tablespace(space_id, BUF_REMOVE_FLUSH_NO_WRITE);
+	err = fil_delete_tablespace(space_id, NULL);
 	switch (err) {
 	case DB_TABLESPACE_NOT_FOUND:
 		/* OK if the physical file is mising.
diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
index 0df5cd04c03..97466e7f2ec 100644
--- a/storage/innobase/include/buf0buf.h
+++ b/storage/innobase/include/buf0buf.h
@@ -63,6 +63,7 @@ struct fil_addr_t;
 #define BUF_GET_POSSIBLY_FREED		16
 					/*!< Like BUF_GET, but do not mind
 					if the file page has been freed. */
+#define BUF_EVICT_IF_IN_POOL	20	/*!< evict a clean block if found */
 /* @} */
 /** @name Modes for buf_page_get_known_nowait */
 /* @{ */
diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h
index 0cbd77878ec..733ca727996 100644
--- a/storage/innobase/include/buf0lru.h
+++ b/storage/innobase/include/buf0lru.h
@@ -1,6 +1,7 @@
 /*****************************************************************************
 
 Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, MariaDB Corporation.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -50,18 +51,13 @@ These are low-level functions
 /** Minimum LRU list length for which the LRU_old pointer is defined */
 #define BUF_LRU_OLD_MIN_LEN	512	/* 8 megabytes of 16k pages */
 
-/******************************************************************//**
-Flushes all dirty pages or removes all pages belonging
-to a given tablespace. A PROBLEM: if readahead is being started, what
-guarantees that it will not try to read in pages after this operation
-has completed? */
+/** Empty the flush list for all pages belonging to a tablespace.
+@param[in]	id		tablespace identifier
+@param[in]	trx		transaction, for checking for user interrupt;
+				or NULL if nothing is to be written
+@param[in]	drop_ahi	whether to drop the adaptive hash index */
 void
-buf_LRU_flush_or_remove_pages(
-/*==========================*/
-	ulint		id,		/*!< in: space id */
-	buf_remove_t	buf_remove,	/*!< in: remove or flush strategy */
-	const trx_t*	trx);		/*!< to check if the operation must
-					be interrupted */
+buf_LRU_flush_or_remove_pages(ulint id, const trx_t* trx, bool drop_ahi=false);
 
 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
 /********************************************************************//**
diff --git a/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h
index 102b831ec61..719699f5ee2 100644
--- a/storage/innobase/include/buf0types.h
+++ b/storage/innobase/include/buf0types.h
@@ -59,17 +59,6 @@ enum buf_flush_t {
 	BUF_FLUSH_N_TYPES		/*!< index of last element + 1  */
 };
 
-/** Algorithm to remove the pages for a tablespace from the buffer pool.
-See buf_LRU_flush_or_remove_pages(). */
-enum buf_remove_t {
-	BUF_REMOVE_ALL_NO_WRITE,	/*!< Remove all pages from the buffer
-					pool, don't write or sync to disk */
-	BUF_REMOVE_FLUSH_NO_WRITE,	/*!< Remove only, from the flush list,
-					don't write or sync to disk */
-	BUF_REMOVE_FLUSH_WRITE		/*!< Flush dirty pages to disk only
-					don't remove from the buffer pool */
-};
-
 /** Flags for io_fix types */
 enum buf_io_fix {
 	BUF_IO_NONE = 0,		/**< no pending I/O */
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index f21a2fb44bb..6224bc36b54 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -922,17 +922,12 @@ fil_op_replay_rename(
 	const char*	new_name)
 	MY_ATTRIBUTE((warn_unused_result));
 
-/** Deletes an IBD tablespace, either general or single-table.
-The tablespace must be cached in the memory cache. This will delete the
-datafile, fil_space_t & fil_node_t entries from the file_system_t cache.
-@param[in]	space_id	Tablespace id
-@param[in]	buf_remove	Specify the action to take on the pages
-for this table in the buffer pool.
-@return true if success */
+/** Delete a tablespace and associated .ibd file.
+@param[in]	id		tablespace identifier
+@param[in]	drop_ahi	whether to drop the adaptive hash index
+@return	DB_SUCCESS or error */
 dberr_t
-fil_delete_tablespace(
-	ulint		id,
-	buf_remove_t	buf_remove);
+fil_delete_tablespace(ulint id, bool drop_ahi = false);
 
 /** Truncate the tablespace to needed size.
 @param[in]	space_id	id of tablespace to truncate
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index 35db4f1c80c..4d1cbf74fd4 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -669,8 +669,7 @@ fil_name_parse(
 
 		if (recv_replay_file_ops
 			&& fil_space_get(space_id)) {
-			dberr_t	err = fil_delete_tablespace(
-				space_id, BUF_REMOVE_FLUSH_NO_WRITE);
+			dberr_t	err = fil_delete_tablespace(space_id, NULL);
 			ut_a(err == DB_SUCCESS);
 		}
 
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index 15fc383b249..a8a0ee4a27e 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -1600,18 +1600,16 @@ PageConverter::PageConverter(
 	:
 	AbstractCallback(trx),
 	m_cfg(cfg),
+	m_index(cfg->m_indexes),
+	m_current_lsn(log_get_lsn()),
 	m_page_zip_ptr(0),
-	m_heap(0) UNIV_NOTHROW
+	m_rec_iter(),
+	m_offsets_(), m_offsets(m_offsets_),
+	m_heap(0),
+	m_cluster_index(dict_table_get_first_index(cfg->m_table)) UNIV_NOTHROW
 {
-	m_index = m_cfg->m_indexes;
-
-	m_current_lsn = log_get_lsn();
 	ut_a(m_current_lsn > 0);
-
-	m_offsets = m_offsets_;
 	rec_offs_init(m_offsets_);
-
-	m_cluster_index = dict_table_get_first_index(m_cfg->m_table);
 }
 
 /** Adjust the BLOB reference for a single column that is externally stored
@@ -2055,7 +2053,7 @@ PageConverter::operator() (
 		we can work on them */
 
 		if ((err = update_page(block, page_type)) != DB_SUCCESS) {
-			return(err);
+			break;
 		}
 
 		/* Note: For compressed pages this function will write to the
@@ -2096,9 +2094,15 @@ PageConverter::operator() (
 			<< " at offset " << offset
 			<< " looks corrupted in file " << m_filepath;
 
-		return(DB_CORRUPTION);
+		err = DB_CORRUPTION;
 	}
 
+	/* If we already had and old page with matching number
+	in the buffer pool, evict it now, because
+	we no longer evict the pages on DISCARD TABLESPACE. */
+	buf_page_get_gen(block->page.id, get_page_size(),
+			 RW_NO_LATCH, NULL, BUF_EVICT_IF_IN_POOL,
+			 __FILE__, __LINE__, NULL);
 	return(err);
 }
 
@@ -3925,8 +3929,7 @@ row_import_for_mysql(
 	The only dirty pages generated should be from the pessimistic purge
 	of delete marked records that couldn't be purged in Phase I. */
 
-	buf_LRU_flush_or_remove_pages(
-		prebuilt->table->space, BUF_REMOVE_FLUSH_WRITE,	trx);
+	buf_LRU_flush_or_remove_pages(prebuilt->table->space, trx);
 
 	if (trx_is_interrupted(trx)) {
 		ib::info() << "Phase III - Flush interrupted";
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index c73a6b2c49f..885cde4fab0 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -3147,10 +3147,7 @@ err_exit:
 		/* We already have .ibd file here. it should be deleted. */
 
 		if (dict_table_is_file_per_table(table)
-		    && fil_delete_tablespace(
-			    table->space,
-			    BUF_REMOVE_FLUSH_NO_WRITE)
-		    != DB_SUCCESS) {
+		    && fil_delete_tablespace(table->space) != DB_SUCCESS) {
 
 			ib::error() << "Not able to delete tablespace "
 				<< table->space << " of table "
@@ -3847,9 +3844,6 @@ row_discard_tablespace(
 	4) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0,
 	we do not allow the discard. */
 
-	/* Play safe and remove all insert buffer entries, though we should
-	have removed them already when DISCARD TABLESPACE was called */
-
 	ibuf_delete_for_discarded_space(table->space);
 
 	table_id_t	new_id;
@@ -4238,8 +4232,7 @@ row_drop_single_table_tablespace(
 				<< " for table " << tablename;
 		}
 
-	} else if (fil_delete_tablespace(space_id, BUF_REMOVE_FLUSH_NO_WRITE)
-		   != DB_SUCCESS) {
+	} else if (fil_delete_tablespace(space_id) != DB_SUCCESS) {
 
 		ib::error() << "We removed the InnoDB internal data"
 			" dictionary entry of table " << tablename
diff --git a/storage/innobase/row/row0quiesce.cc b/storage/innobase/row/row0quiesce.cc
index 4d3b3c2b261..0d07c5d54d4 100644
--- a/storage/innobase/row/row0quiesce.cc
+++ b/storage/innobase/row/row0quiesce.cc
@@ -1,6 +1,7 @@
 /*****************************************************************************
 
 Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2017, MariaDB Corporation.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -747,8 +748,7 @@ row_quiesce_table_start(
 			mutex_enter(&master_key_id_mutex);
 		}
 
-		buf_LRU_flush_or_remove_pages(
-			table->space, BUF_REMOVE_FLUSH_WRITE, trx);
+		buf_LRU_flush_or_remove_pages(table->space, trx);
 
 		if (dict_table_is_encrypted(table)) {
 			mutex_exit(&master_key_id_mutex);
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index 6f9b58ecb17..0a5f1b0b494 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -1072,21 +1072,22 @@ srv_undo_tablespaces_init(
 		mtr_commit(&mtr);
 
 		/* Step-2: Flush the dirty pages from the buffer pool. */
+		trx_t* trx = trx_allocate_for_background();
+
 		for (undo::undo_spaces_t::const_iterator it
 			     = undo::Truncate::s_fix_up_spaces.begin();
 		     it != undo::Truncate::s_fix_up_spaces.end();
 		     ++it) {
 
-			buf_LRU_flush_or_remove_pages(
-				TRX_SYS_SPACE, BUF_REMOVE_FLUSH_WRITE, NULL);
+			buf_LRU_flush_or_remove_pages(TRX_SYS_SPACE, trx);
 
-			buf_LRU_flush_or_remove_pages(
-				*it, BUF_REMOVE_FLUSH_WRITE, NULL);
+			buf_LRU_flush_or_remove_pages(*it, trx);
 
 			/* Remove the truncate redo log file. */
 			undo::Truncate	undo_trunc;
 			undo_trunc.done_logging(*it);
 		}
+		trx_free_for_background(trx);
 	}
 
 	return(DB_SUCCESS);
