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

Commit bb730a17 authored by Vinayak Menon's avatar Vinayak Menon
Browse files

mm: swap: don't delay swap free for fast swap devices



There are couple of issues with swapcache usage when ZRAM is used
as swap device.
1) Kernel does a swap readahead which can be around 6 to 8 pages
depending on total ram, which is not required for zram since
accesses are fast.
2) Kernel delays the freeing up of swapcache expecting a later hit,
which again is useless in the case of zram.
3) This is not related to swapcache, but zram usage itself.
As mentioned in (2) kernel delays freeing of swapcache, but along with
that it delays zram compressed page free also. i.e. there can be 2 copies,
though one is compressed.

This patch addresses these issues using two new flags
QUEUE_FLAG_FAST and SWP_FAST, to indicate that accesses to the device
will be fast and cheap, and instructs the swap layer to free up
swap space agressively, and not to do read ahead.

Change-Id: I5d2d5176a5f9420300bb2f843f6ecbdb25ea80e4
Signed-off-by: default avatarVinayak Menon <vinmenon@codeaurora.org>
parent 99fddf1f
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -1271,6 +1271,7 @@ static int zram_add(void)
	zram->disk->private_data = zram;
	zram->disk->private_data = zram;
	snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
	snprintf(zram->disk->disk_name, 16, "zram%d", device_id);


	__set_bit(QUEUE_FLAG_FAST, &zram->disk->queue->queue_flags);
	/* Actual capacity set using syfs (/sys/block/zram<id>/disksize */
	/* Actual capacity set using syfs (/sys/block/zram<id>/disksize */
	set_capacity(zram->disk, 0);
	set_capacity(zram->disk, 0);
	/* zram devices sort of resembles non-rotational disks */
	/* zram devices sort of resembles non-rotational disks */
+2 −0
Original line number Original line Diff line number Diff line
@@ -508,6 +508,7 @@ struct request_queue {
#define QUEUE_FLAG_FUA	       24	/* device supports FUA writes */
#define QUEUE_FLAG_FUA	       24	/* device supports FUA writes */
#define QUEUE_FLAG_FLUSH_NQ    25	/* flush not queueuable */
#define QUEUE_FLAG_FLUSH_NQ    25	/* flush not queueuable */
#define QUEUE_FLAG_DAX         26	/* device supports DAX */
#define QUEUE_FLAG_DAX         26	/* device supports DAX */
#define QUEUE_FLAG_FAST        27	/* fast block device (e.g. ram based) */


#define QUEUE_FLAG_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\
#define QUEUE_FLAG_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\
				 (1 << QUEUE_FLAG_STACKABLE)	|	\
				 (1 << QUEUE_FLAG_STACKABLE)	|	\
@@ -598,6 +599,7 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
#define blk_queue_secure_erase(q) \
#define blk_queue_secure_erase(q) \
	(test_bit(QUEUE_FLAG_SECERASE, &(q)->queue_flags))
	(test_bit(QUEUE_FLAG_SECERASE, &(q)->queue_flags))
#define blk_queue_dax(q)	test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags)
#define blk_queue_dax(q)	test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags)
#define blk_queue_fast(q)	test_bit(QUEUE_FLAG_FAST, &(q)->queue_flags)


#define blk_noretry_request(rq) \
#define blk_noretry_request(rq) \
	((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \
	((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \
+13 −4
Original line number Original line Diff line number Diff line
@@ -151,8 +151,9 @@ enum {
	SWP_AREA_DISCARD = (1 << 8),	/* single-time swap area discards */
	SWP_AREA_DISCARD = (1 << 8),	/* single-time swap area discards */
	SWP_PAGE_DISCARD = (1 << 9),	/* freed swap page-cluster discards */
	SWP_PAGE_DISCARD = (1 << 9),	/* freed swap page-cluster discards */
	SWP_STABLE_WRITES = (1 << 10),	/* no overwrite PG_writeback pages */
	SWP_STABLE_WRITES = (1 << 10),	/* no overwrite PG_writeback pages */
	SWP_FAST	= (1 << 11),	/* blkdev access is fast and cheap */
					/* add others here before... */
					/* add others here before... */
	SWP_SCANNING	= (1 << 11),	/* refcount in scan_swap_map */
	SWP_SCANNING	= (1 << 12),	/* refcount in scan_swap_map */
};
};


#define SWAP_CLUSTER_MAX 32UL
#define SWAP_CLUSTER_MAX 32UL
@@ -389,10 +390,18 @@ extern struct page *swapin_readahead(swp_entry_t, gfp_t,
/* linux/mm/swapfile.c */
/* linux/mm/swapfile.c */
extern atomic_long_t nr_swap_pages;
extern atomic_long_t nr_swap_pages;
extern long total_swap_pages;
extern long total_swap_pages;
extern bool is_swap_fast(swp_entry_t entry);


/* Swap 50% full? Release swapcache more aggressively.. */
/* Swap 50% full? Release swapcache more aggressively.. */
static inline bool vm_swap_full(void)
static inline bool vm_swap_full(struct swap_info_struct *si)
{
{
	/*
	 * If the swap device is fast, return true
	 * not to delay swap free.
	 */
	if (si->flags & SWP_FAST)
		return true;

	return atomic_long_read(&nr_swap_pages) * 2 < total_swap_pages;
	return atomic_long_read(&nr_swap_pages) * 2 < total_swap_pages;
}
}


@@ -428,7 +437,7 @@ struct backing_dev_info;
#define get_nr_swap_pages()			0L
#define get_nr_swap_pages()			0L
#define total_swap_pages			0L
#define total_swap_pages			0L
#define total_swapcache_pages()			0UL
#define total_swapcache_pages()			0UL
#define vm_swap_full()				0
#define vm_swap_full(si)			0


#define si_swapinfo(val) \
#define si_swapinfo(val) \
	do { (val)->freeswap = (val)->totalswap = 0; } while (0)
	do { (val)->freeswap = (val)->totalswap = 0; } while (0)
@@ -579,7 +588,7 @@ static inline long mem_cgroup_get_nr_swap_pages(struct mem_cgroup *memcg)


static inline bool mem_cgroup_swap_full(struct page *page)
static inline bool mem_cgroup_swap_full(struct page *page)
{
{
	return vm_swap_full();
	return vm_swap_full(page_swap_info(page));
}
}
#endif
#endif


+1 −1
Original line number Original line Diff line number Diff line
@@ -5996,7 +5996,7 @@ bool mem_cgroup_swap_full(struct page *page)


	VM_BUG_ON_PAGE(!PageLocked(page), page);
	VM_BUG_ON_PAGE(!PageLocked(page), page);


	if (vm_swap_full())
	if (vm_swap_full(page_swap_info(page)))
		return true;
		return true;
	if (!do_swap_account || !cgroup_subsys_on_dfl(memory_cgrp_subsys))
	if (!do_swap_account || !cgroup_subsys_on_dfl(memory_cgrp_subsys))
		return false;
		return false;
+2 −1
Original line number Original line Diff line number Diff line
@@ -475,7 +475,8 @@ struct page *swapin_readahead(swp_entry_t entry, gfp_t gfp_mask,
	unsigned long entry_offset = swp_offset(entry);
	unsigned long entry_offset = swp_offset(entry);
	unsigned long offset = entry_offset;
	unsigned long offset = entry_offset;
	unsigned long start_offset, end_offset;
	unsigned long start_offset, end_offset;
	unsigned long mask;
	unsigned long mask = is_swap_fast(entry) ? 0 :
				(1UL << page_cluster) - 1;
	struct blk_plug plug;
	struct blk_plug plug;


	mask = swapin_nr_pages(offset) - 1;
	mask = swapin_nr_pages(offset) - 1;
Loading