xref: /linux/mm/page_io.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  linux/mm/page_io.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *  Swap reorganised 29.12.95,
81da177e4SLinus Torvalds  *  Asynchronous swapping added 30.12.95. Stephen Tweedie
91da177e4SLinus Torvalds  *  Removed race in async swapping. 14.4.1996. Bruno Haible
101da177e4SLinus Torvalds  *  Add swap of shared pages through the page cache. 20.2.1998. Stephen Tweedie
111da177e4SLinus Torvalds  *  Always use brw_page, life becomes simpler. 12 May 1998 Eric Biederman
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include <linux/mm.h>
151da177e4SLinus Torvalds #include <linux/kernel_stat.h>
165a0e3ad6STejun Heo #include <linux/gfp.h>
171da177e4SLinus Torvalds #include <linux/pagemap.h>
181da177e4SLinus Torvalds #include <linux/swap.h>
191da177e4SLinus Torvalds #include <linux/bio.h>
201da177e4SLinus Torvalds #include <linux/swapops.h>
211da177e4SLinus Torvalds #include <linux/writeback.h>
22b430e9d1SMinchan Kim #include <linux/blkdev.h>
2393779069SMinchan Kim #include <linux/psi.h>
24e2e40f2cSChristoph Hellwig #include <linux/uio.h>
25b0ba2d0fSTetsuo Handa #include <linux/sched/task.h>
26a3d5dc90SYang Yang #include <linux/delayacct.h>
2742c06a0eSJohannes Weiner #include <linux/zswap.h>
28014bb1deSNeilBrown #include "swap.h"
291da177e4SLinus Torvalds 
__end_swap_bio_write(struct bio * bio)303222d8c2SChristoph Hellwig static void __end_swap_bio_write(struct bio *bio)
311da177e4SLinus Torvalds {
32a3ed1e9bSZhangPeng 	struct folio *folio = bio_first_folio_all(bio);
331da177e4SLinus Torvalds 
344e4cbee9SChristoph Hellwig 	if (bio->bi_status) {
356ddab3b9SPeter Zijlstra 		/*
366ddab3b9SPeter Zijlstra 		 * We failed to write the page out to swap-space.
376ddab3b9SPeter Zijlstra 		 * Re-dirty the page in order to avoid it being reclaimed.
386ddab3b9SPeter Zijlstra 		 * Also print a dire warning that things will go BAD (tm)
396ddab3b9SPeter Zijlstra 		 * very quickly.
406ddab3b9SPeter Zijlstra 		 *
41575ced1cSMatthew Wilcox (Oracle) 		 * Also clear PG_reclaim to avoid folio_rotate_reclaimable()
426ddab3b9SPeter Zijlstra 		 */
43a3ed1e9bSZhangPeng 		folio_mark_dirty(folio);
4425eaab43SGeorgi Djakov 		pr_alert_ratelimited("Write-error on swap-device (%u:%u:%llu)\n",
4574d46992SChristoph Hellwig 				     MAJOR(bio_dev(bio)), MINOR(bio_dev(bio)),
464f024f37SKent Overstreet 				     (unsigned long long)bio->bi_iter.bi_sector);
47a3ed1e9bSZhangPeng 		folio_clear_reclaim(folio);
486ddab3b9SPeter Zijlstra 	}
49a3ed1e9bSZhangPeng 	folio_end_writeback(folio);
503222d8c2SChristoph Hellwig }
513222d8c2SChristoph Hellwig 
end_swap_bio_write(struct bio * bio)523222d8c2SChristoph Hellwig static void end_swap_bio_write(struct bio *bio)
533222d8c2SChristoph Hellwig {
543222d8c2SChristoph Hellwig 	__end_swap_bio_write(bio);
551da177e4SLinus Torvalds 	bio_put(bio);
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds 
__end_swap_bio_read(struct bio * bio)589b4e30bdSChristoph Hellwig static void __end_swap_bio_read(struct bio *bio)
593f2b1a04SMinchan Kim {
60bc74b53fSZhangPeng 	struct folio *folio = bio_first_folio_all(bio);
613f2b1a04SMinchan Kim 
624e4cbee9SChristoph Hellwig 	if (bio->bi_status) {
6325eaab43SGeorgi Djakov 		pr_alert_ratelimited("Read-error on swap-device (%u:%u:%llu)\n",
6474d46992SChristoph Hellwig 				     MAJOR(bio_dev(bio)), MINOR(bio_dev(bio)),
653f2b1a04SMinchan Kim 				     (unsigned long long)bio->bi_iter.bi_sector);
669b4e30bdSChristoph Hellwig 	} else {
67bc74b53fSZhangPeng 		folio_mark_uptodate(folio);
689b4e30bdSChristoph Hellwig 	}
69bc74b53fSZhangPeng 	folio_unlock(folio);
70b430e9d1SMinchan Kim }
71b430e9d1SMinchan Kim 
end_swap_bio_read(struct bio * bio)729b4e30bdSChristoph Hellwig static void end_swap_bio_read(struct bio *bio)
739b4e30bdSChristoph Hellwig {
749b4e30bdSChristoph Hellwig 	__end_swap_bio_read(bio);
751da177e4SLinus Torvalds 	bio_put(bio);
7687518530SOleg Nesterov }
771da177e4SLinus Torvalds 
generic_swapfile_activate(struct swap_info_struct * sis,struct file * swap_file,sector_t * span)78a509bc1aSMel Gorman int generic_swapfile_activate(struct swap_info_struct *sis,
79a509bc1aSMel Gorman 				struct file *swap_file,
80a509bc1aSMel Gorman 				sector_t *span)
81a509bc1aSMel Gorman {
82a509bc1aSMel Gorman 	struct address_space *mapping = swap_file->f_mapping;
83a509bc1aSMel Gorman 	struct inode *inode = mapping->host;
84a509bc1aSMel Gorman 	unsigned blocks_per_page;
85a509bc1aSMel Gorman 	unsigned long page_no;
86a509bc1aSMel Gorman 	unsigned blkbits;
87a509bc1aSMel Gorman 	sector_t probe_block;
88a509bc1aSMel Gorman 	sector_t last_block;
89a509bc1aSMel Gorman 	sector_t lowest_block = -1;
90a509bc1aSMel Gorman 	sector_t highest_block = 0;
91a509bc1aSMel Gorman 	int nr_extents = 0;
92a509bc1aSMel Gorman 	int ret;
93a509bc1aSMel Gorman 
94a509bc1aSMel Gorman 	blkbits = inode->i_blkbits;
95a509bc1aSMel Gorman 	blocks_per_page = PAGE_SIZE >> blkbits;
96a509bc1aSMel Gorman 
97a509bc1aSMel Gorman 	/*
984efaceb1SAaron Lu 	 * Map all the blocks into the extent tree.  This code doesn't try
99a509bc1aSMel Gorman 	 * to be very smart.
100a509bc1aSMel Gorman 	 */
101a509bc1aSMel Gorman 	probe_block = 0;
102a509bc1aSMel Gorman 	page_no = 0;
103a509bc1aSMel Gorman 	last_block = i_size_read(inode) >> blkbits;
104a509bc1aSMel Gorman 	while ((probe_block + blocks_per_page) <= last_block &&
105a509bc1aSMel Gorman 			page_no < sis->max) {
106a509bc1aSMel Gorman 		unsigned block_in_page;
107a509bc1aSMel Gorman 		sector_t first_block;
108a509bc1aSMel Gorman 
1097e4411bfSMikulas Patocka 		cond_resched();
1107e4411bfSMikulas Patocka 
11130460e1eSCarlos Maiolino 		first_block = probe_block;
11230460e1eSCarlos Maiolino 		ret = bmap(inode, &first_block);
11330460e1eSCarlos Maiolino 		if (ret || !first_block)
114a509bc1aSMel Gorman 			goto bad_bmap;
115a509bc1aSMel Gorman 
116a509bc1aSMel Gorman 		/*
117a509bc1aSMel Gorman 		 * It must be PAGE_SIZE aligned on-disk
118a509bc1aSMel Gorman 		 */
119a509bc1aSMel Gorman 		if (first_block & (blocks_per_page - 1)) {
120a509bc1aSMel Gorman 			probe_block++;
121a509bc1aSMel Gorman 			goto reprobe;
122a509bc1aSMel Gorman 		}
123a509bc1aSMel Gorman 
124a509bc1aSMel Gorman 		for (block_in_page = 1; block_in_page < blocks_per_page;
125a509bc1aSMel Gorman 					block_in_page++) {
126a509bc1aSMel Gorman 			sector_t block;
127a509bc1aSMel Gorman 
12830460e1eSCarlos Maiolino 			block = probe_block + block_in_page;
12930460e1eSCarlos Maiolino 			ret = bmap(inode, &block);
13030460e1eSCarlos Maiolino 			if (ret || !block)
131a509bc1aSMel Gorman 				goto bad_bmap;
13230460e1eSCarlos Maiolino 
133a509bc1aSMel Gorman 			if (block != first_block + block_in_page) {
134a509bc1aSMel Gorman 				/* Discontiguity */
135a509bc1aSMel Gorman 				probe_block++;
136a509bc1aSMel Gorman 				goto reprobe;
137a509bc1aSMel Gorman 			}
138a509bc1aSMel Gorman 		}
139a509bc1aSMel Gorman 
140a509bc1aSMel Gorman 		first_block >>= (PAGE_SHIFT - blkbits);
141a509bc1aSMel Gorman 		if (page_no) {	/* exclude the header page */
142a509bc1aSMel Gorman 			if (first_block < lowest_block)
143a509bc1aSMel Gorman 				lowest_block = first_block;
144a509bc1aSMel Gorman 			if (first_block > highest_block)
145a509bc1aSMel Gorman 				highest_block = first_block;
146a509bc1aSMel Gorman 		}
147a509bc1aSMel Gorman 
148a509bc1aSMel Gorman 		/*
149a509bc1aSMel Gorman 		 * We found a PAGE_SIZE-length, PAGE_SIZE-aligned run of blocks
150a509bc1aSMel Gorman 		 */
151a509bc1aSMel Gorman 		ret = add_swap_extent(sis, page_no, 1, first_block);
152a509bc1aSMel Gorman 		if (ret < 0)
153a509bc1aSMel Gorman 			goto out;
154a509bc1aSMel Gorman 		nr_extents += ret;
155a509bc1aSMel Gorman 		page_no++;
156a509bc1aSMel Gorman 		probe_block += blocks_per_page;
157a509bc1aSMel Gorman reprobe:
158a509bc1aSMel Gorman 		continue;
159a509bc1aSMel Gorman 	}
160a509bc1aSMel Gorman 	ret = nr_extents;
161a509bc1aSMel Gorman 	*span = 1 + highest_block - lowest_block;
162a509bc1aSMel Gorman 	if (page_no == 0)
163a509bc1aSMel Gorman 		page_no = 1;	/* force Empty message */
164a509bc1aSMel Gorman 	sis->max = page_no;
165a509bc1aSMel Gorman 	sis->pages = page_no - 1;
166a509bc1aSMel Gorman out:
167a509bc1aSMel Gorman 	return ret;
168a509bc1aSMel Gorman bad_bmap:
1691170532bSJoe Perches 	pr_err("swapon: swapfile has holes\n");
170a509bc1aSMel Gorman 	ret = -EINVAL;
171a509bc1aSMel Gorman 	goto out;
172a509bc1aSMel Gorman }
173a509bc1aSMel Gorman 
is_folio_zero_filled(struct folio * folio)1740ca0c24eSUsama Arif static bool is_folio_zero_filled(struct folio *folio)
1750ca0c24eSUsama Arif {
1760ca0c24eSUsama Arif 	unsigned int pos, last_pos;
1770ca0c24eSUsama Arif 	unsigned long *data;
1780ca0c24eSUsama Arif 	unsigned int i;
1790ca0c24eSUsama Arif 
1800ca0c24eSUsama Arif 	last_pos = PAGE_SIZE / sizeof(*data) - 1;
1810ca0c24eSUsama Arif 	for (i = 0; i < folio_nr_pages(folio); i++) {
1820ca0c24eSUsama Arif 		data = kmap_local_folio(folio, i * PAGE_SIZE);
1830ca0c24eSUsama Arif 		/*
1840ca0c24eSUsama Arif 		 * Check last word first, incase the page is zero-filled at
1850ca0c24eSUsama Arif 		 * the start and has non-zero data at the end, which is common
1860ca0c24eSUsama Arif 		 * in real-world workloads.
1870ca0c24eSUsama Arif 		 */
1880ca0c24eSUsama Arif 		if (data[last_pos]) {
1890ca0c24eSUsama Arif 			kunmap_local(data);
1900ca0c24eSUsama Arif 			return false;
1910ca0c24eSUsama Arif 		}
1920ca0c24eSUsama Arif 		for (pos = 0; pos < last_pos; pos++) {
1930ca0c24eSUsama Arif 			if (data[pos]) {
1940ca0c24eSUsama Arif 				kunmap_local(data);
1950ca0c24eSUsama Arif 				return false;
1960ca0c24eSUsama Arif 			}
1970ca0c24eSUsama Arif 		}
1980ca0c24eSUsama Arif 		kunmap_local(data);
1990ca0c24eSUsama Arif 	}
2000ca0c24eSUsama Arif 
2010ca0c24eSUsama Arif 	return true;
2020ca0c24eSUsama Arif }
2030ca0c24eSUsama Arif 
swap_zeromap_folio_set(struct folio * folio)2040ca0c24eSUsama Arif static void swap_zeromap_folio_set(struct folio *folio)
2050ca0c24eSUsama Arif {
206e7ac4daeSBarry Song 	struct obj_cgroup *objcg = get_obj_cgroup_from_folio(folio);
2070fcf8ef4SKairui Song 	struct swap_info_struct *sis = __swap_entry_to_info(folio->swap);
208e7ac4daeSBarry Song 	int nr_pages = folio_nr_pages(folio);
2090ca0c24eSUsama Arif 	swp_entry_t entry;
2100ca0c24eSUsama Arif 	unsigned int i;
2110ca0c24eSUsama Arif 
2120ca0c24eSUsama Arif 	for (i = 0; i < folio_nr_pages(folio); i++) {
2130ca0c24eSUsama Arif 		entry = page_swap_entry(folio_page(folio, i));
2140ca0c24eSUsama Arif 		set_bit(swp_offset(entry), sis->zeromap);
2150ca0c24eSUsama Arif 	}
216e7ac4daeSBarry Song 
217e7ac4daeSBarry Song 	count_vm_events(SWPOUT_ZERO, nr_pages);
218e7ac4daeSBarry Song 	if (objcg) {
219e7ac4daeSBarry Song 		count_objcg_events(objcg, SWPOUT_ZERO, nr_pages);
220e7ac4daeSBarry Song 		obj_cgroup_put(objcg);
221e7ac4daeSBarry Song 	}
2220ca0c24eSUsama Arif }
2230ca0c24eSUsama Arif 
swap_zeromap_folio_clear(struct folio * folio)2240ca0c24eSUsama Arif static void swap_zeromap_folio_clear(struct folio *folio)
2250ca0c24eSUsama Arif {
2260fcf8ef4SKairui Song 	struct swap_info_struct *sis = __swap_entry_to_info(folio->swap);
2270ca0c24eSUsama Arif 	swp_entry_t entry;
2280ca0c24eSUsama Arif 	unsigned int i;
2290ca0c24eSUsama Arif 
2300ca0c24eSUsama Arif 	for (i = 0; i < folio_nr_pages(folio); i++) {
2310ca0c24eSUsama Arif 		entry = page_swap_entry(folio_page(folio, i));
2320ca0c24eSUsama Arif 		clear_bit(swp_offset(entry), sis->zeromap);
2330ca0c24eSUsama Arif 	}
2340ca0c24eSUsama Arif }
2350ca0c24eSUsama Arif 
2360ca0c24eSUsama Arif /*
2371da177e4SLinus Torvalds  * We may have stale swap cache pages in memory: notice
2381da177e4SLinus Torvalds  * them here and get rid of the unnecessary final write.
2391da177e4SLinus Torvalds  */
swap_writeout(struct folio * folio,struct swap_iocb ** swap_plug)240624043dbSChristoph Hellwig int swap_writeout(struct folio *folio, struct swap_iocb **swap_plug)
2411da177e4SLinus Torvalds {
2422d1844cdSChristoph Hellwig 	int ret = 0;
2431da177e4SLinus Torvalds 
2442d1844cdSChristoph Hellwig 	if (folio_free_swap(folio))
2452d1844cdSChristoph Hellwig 		goto out_unlock;
2462d1844cdSChristoph Hellwig 
2478a84802eSSteven Price 	/*
2488a84802eSSteven Price 	 * Arch code may have to preserve more data than just the page
2498a84802eSSteven Price 	 * contents, e.g. memory tags.
2508a84802eSSteven Price 	 */
251f238b8c3SBarry Song 	ret = arch_prepare_to_swap(folio);
2528a84802eSSteven Price 	if (ret) {
25371fa1a53SMatthew Wilcox (Oracle) 		folio_mark_dirty(folio);
2542d1844cdSChristoph Hellwig 		goto out_unlock;
2558a84802eSSteven Price 	}
2560ca0c24eSUsama Arif 
2570ca0c24eSUsama Arif 	/*
2580ca0c24eSUsama Arif 	 * Use a bitmap (zeromap) to avoid doing IO for zero-filled pages.
2590ca0c24eSUsama Arif 	 * The bits in zeromap are protected by the locked swapcache folio
2600ca0c24eSUsama Arif 	 * and atomic updates are used to protect against read-modify-write
2610ca0c24eSUsama Arif 	 * corruption due to other zero swap entries seeing concurrent updates.
2620ca0c24eSUsama Arif 	 */
2630ca0c24eSUsama Arif 	if (is_folio_zero_filled(folio)) {
2640ca0c24eSUsama Arif 		swap_zeromap_folio_set(folio);
2652d1844cdSChristoph Hellwig 		goto out_unlock;
2662d1844cdSChristoph Hellwig 	}
2672d1844cdSChristoph Hellwig 
2680ca0c24eSUsama Arif 	/*
2692d1844cdSChristoph Hellwig 	 * Clear bits this folio occupies in the zeromap to prevent zero data
2702d1844cdSChristoph Hellwig 	 * being read in from any previous zero writes that occupied the same
2712d1844cdSChristoph Hellwig 	 * swap entries.
2720ca0c24eSUsama Arif 	 */
2730ca0c24eSUsama Arif 	swap_zeromap_folio_clear(folio);
2742d1844cdSChristoph Hellwig 
27534f4c198SMatthew Wilcox (Oracle) 	if (zswap_store(folio)) {
2760c560dd8SKanchana P Sridhar 		count_mthp_stat(folio_order(folio), MTHP_STAT_ZSWPOUT);
2772d1844cdSChristoph Hellwig 		goto out_unlock;
27838b5faf4SDan Magenheimer 	}
2791f6f80c2SMuchun Song 
2801f6f80c2SMuchun Song 	rcu_read_lock();
281501a06feSNhat Pham 	if (!mem_cgroup_zswap_writeback_enabled(folio_memcg(folio))) {
2821f6f80c2SMuchun Song 		rcu_read_unlock();
283501a06feSNhat Pham 		folio_mark_dirty(folio);
284501a06feSNhat Pham 		return AOP_WRITEPAGE_ACTIVATE;
285501a06feSNhat Pham 	}
2861f6f80c2SMuchun Song 	rcu_read_unlock();
287501a06feSNhat Pham 
288624043dbSChristoph Hellwig 	__swap_writepage(folio, swap_plug);
289e3e2762bSChristoph Hellwig 	return 0;
2902d1844cdSChristoph Hellwig out_unlock:
2912d1844cdSChristoph Hellwig 	folio_unlock(folio);
2922d1844cdSChristoph Hellwig 	return ret;
2932f772e6cSSeth Jennings }
2942f772e6cSSeth Jennings 
count_swpout_vm_event(struct folio * folio)2959b72b134SZhangPeng static inline void count_swpout_vm_event(struct folio *folio)
296225311a4SHuang Ying {
297225311a4SHuang Ying #ifdef CONFIG_TRANSPARENT_HUGEPAGE
298811244a5SXin Hao 	if (unlikely(folio_test_pmd_mappable(folio))) {
299811244a5SXin Hao 		count_memcg_folio_events(folio, THP_SWPOUT, 1);
300225311a4SHuang Ying 		count_vm_event(THP_SWPOUT);
301811244a5SXin Hao 	}
302225311a4SHuang Ying #endif
303e26060d1SKanchana P Sridhar 	count_mthp_stat(folio_order(folio), MTHP_STAT_SWPOUT);
30415ff4d40SJingxiang Zeng 	count_memcg_folio_events(folio, PSWPOUT, folio_nr_pages(folio));
3059b72b134SZhangPeng 	count_vm_events(PSWPOUT, folio_nr_pages(folio));
306225311a4SHuang Ying }
307225311a4SHuang Ying 
308a18b9b15SChristoph Hellwig #if defined(CONFIG_MEMCG) && defined(CONFIG_BLK_CGROUP)
bio_associate_blkg_from_page(struct bio * bio,struct folio * folio)30998630cfdSZhangPeng static void bio_associate_blkg_from_page(struct bio *bio, struct folio *folio)
310a18b9b15SChristoph Hellwig {
311a18b9b15SChristoph Hellwig 	struct cgroup_subsys_state *css;
312bcfe06bfSRoman Gushchin 	struct mem_cgroup *memcg;
313a18b9b15SChristoph Hellwig 
3141f6f80c2SMuchun Song 	if (!folio_memcg_charged(folio))
315a18b9b15SChristoph Hellwig 		return;
316a18b9b15SChristoph Hellwig 
317a18b9b15SChristoph Hellwig 	rcu_read_lock();
3181f6f80c2SMuchun Song 	memcg = folio_memcg(folio);
319bcfe06bfSRoman Gushchin 	css = cgroup_e_css(memcg->css.cgroup, &io_cgrp_subsys);
320a18b9b15SChristoph Hellwig 	bio_associate_blkg_from_css(bio, css);
321a18b9b15SChristoph Hellwig 	rcu_read_unlock();
322a18b9b15SChristoph Hellwig }
323a18b9b15SChristoph Hellwig #else
32498630cfdSZhangPeng #define bio_associate_blkg_from_page(bio, folio)		do { } while (0)
325a18b9b15SChristoph Hellwig #endif /* CONFIG_MEMCG && CONFIG_BLK_CGROUP */
326a18b9b15SChristoph Hellwig 
327e1209d3aSNeilBrown struct swap_iocb {
328e1209d3aSNeilBrown 	struct kiocb		iocb;
3295169b844SNeilBrown 	struct bio_vec		bvec[SWAP_CLUSTER_MAX];
3305169b844SNeilBrown 	int			pages;
331a1a0dfd5SNeilBrown 	int			len;
33262c230bcSMel Gorman };
333e1209d3aSNeilBrown static mempool_t *sio_pool;
33462c230bcSMel Gorman 
sio_pool_init(void)335e1209d3aSNeilBrown int sio_pool_init(void)
336e1209d3aSNeilBrown {
337e1209d3aSNeilBrown 	if (!sio_pool) {
338e1209d3aSNeilBrown 		mempool_t *pool = mempool_create_kmalloc_pool(
339e1209d3aSNeilBrown 			SWAP_CLUSTER_MAX, sizeof(struct swap_iocb));
340e1209d3aSNeilBrown 		if (cmpxchg(&sio_pool, NULL, pool))
341e1209d3aSNeilBrown 			mempool_destroy(pool);
342e1209d3aSNeilBrown 	}
343e1209d3aSNeilBrown 	if (!sio_pool)
344e1209d3aSNeilBrown 		return -ENOMEM;
345e1209d3aSNeilBrown 	return 0;
346e1209d3aSNeilBrown }
34762c230bcSMel Gorman 
sio_write_complete(struct kiocb * iocb,long ret)3487eadabc0SNeilBrown static void sio_write_complete(struct kiocb *iocb, long ret)
3491da177e4SLinus Torvalds {
3507eadabc0SNeilBrown 	struct swap_iocb *sio = container_of(iocb, struct swap_iocb, iocb);
3515169b844SNeilBrown 	struct page *page = sio->bvec[0].bv_page;
3522282679fSNeilBrown 	int p;
3531da177e4SLinus Torvalds 
354a1a0dfd5SNeilBrown 	if (ret != sio->len) {
3550cdc444aSMel Gorman 		/*
3560cdc444aSMel Gorman 		 * In the case of swap-over-nfs, this can be a
3570cdc444aSMel Gorman 		 * temporary failure if the system has limited
3580cdc444aSMel Gorman 		 * memory for allocating transmit buffers.
3590cdc444aSMel Gorman 		 * Mark the page dirty and avoid
360575ced1cSMatthew Wilcox (Oracle) 		 * folio_rotate_reclaimable but rate-limit the
361420e05d0SMatthew Wilcox (Oracle) 		 * messages.
3620cdc444aSMel Gorman 		 */
3637eadabc0SNeilBrown 		pr_err_ratelimited("Write error %ld on dio swapfile (%llu)\n",
364545ebe71SKairui Song 				   ret, swap_dev_pos(page_swap_entry(page)));
3652282679fSNeilBrown 		for (p = 0; p < sio->pages; p++) {
3662282679fSNeilBrown 			page = sio->bvec[p].bv_page;
3672d30d31eSJerome Marchand 			set_page_dirty(page);
3680cdc444aSMel Gorman 			ClearPageReclaim(page);
36962c230bcSMel Gorman 		}
37062c230bcSMel Gorman 	}
37162c230bcSMel Gorman 
3722282679fSNeilBrown 	for (p = 0; p < sio->pages; p++)
3732282679fSNeilBrown 		end_page_writeback(sio->bvec[p].bv_page);
3742282679fSNeilBrown 
3757eadabc0SNeilBrown 	mempool_free(sio, sio_pool);
3767eadabc0SNeilBrown }
3777eadabc0SNeilBrown 
swap_writepage_fs(struct folio * folio,struct swap_iocb ** swap_plug)3782ba8ffceSChristoph Hellwig static void swap_writepage_fs(struct folio *folio, struct swap_iocb **swap_plug)
3797eadabc0SNeilBrown {
3802ba8ffceSChristoph Hellwig 	struct swap_iocb *sio = swap_plug ? *swap_plug : NULL;
3810fcf8ef4SKairui Song 	struct swap_info_struct *sis = __swap_entry_to_info(folio->swap);
3827eadabc0SNeilBrown 	struct file *swap_file = sis->swap_file;
383545ebe71SKairui Song 	loff_t pos = swap_dev_pos(folio->swap);
3847eadabc0SNeilBrown 
385bfcd44d5SMatthew Wilcox (Oracle) 	count_swpout_vm_event(folio);
386bfcd44d5SMatthew Wilcox (Oracle) 	folio_start_writeback(folio);
387bfcd44d5SMatthew Wilcox (Oracle) 	folio_unlock(folio);
3882282679fSNeilBrown 	if (sio) {
3892282679fSNeilBrown 		if (sio->iocb.ki_filp != swap_file ||
390a1a0dfd5SNeilBrown 		    sio->iocb.ki_pos + sio->len != pos) {
3912282679fSNeilBrown 			swap_write_unplug(sio);
3922282679fSNeilBrown 			sio = NULL;
3932282679fSNeilBrown 		}
3942282679fSNeilBrown 	}
3952282679fSNeilBrown 	if (!sio) {
3967eadabc0SNeilBrown 		sio = mempool_alloc(sio_pool, GFP_NOIO);
3977eadabc0SNeilBrown 		init_sync_kiocb(&sio->iocb, swap_file);
3987eadabc0SNeilBrown 		sio->iocb.ki_complete = sio_write_complete;
3992282679fSNeilBrown 		sio->iocb.ki_pos = pos;
4002282679fSNeilBrown 		sio->pages = 0;
401a1a0dfd5SNeilBrown 		sio->len = 0;
4022282679fSNeilBrown 	}
403bfcd44d5SMatthew Wilcox (Oracle) 	bvec_set_folio(&sio->bvec[sio->pages], folio, folio_size(folio), 0);
404bfcd44d5SMatthew Wilcox (Oracle) 	sio->len += folio_size(folio);
4052282679fSNeilBrown 	sio->pages += 1;
4062ba8ffceSChristoph Hellwig 	if (sio->pages == ARRAY_SIZE(sio->bvec) || !swap_plug) {
4072282679fSNeilBrown 		swap_write_unplug(sio);
4082282679fSNeilBrown 		sio = NULL;
4092282679fSNeilBrown 	}
4102ba8ffceSChristoph Hellwig 	if (swap_plug)
4112ba8ffceSChristoph Hellwig 		*swap_plug = sio;
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds 
swap_writepage_bdev_sync(struct folio * folio,struct swap_info_struct * sis)4146de62c7bSMatthew Wilcox (Oracle) static void swap_writepage_bdev_sync(struct folio *folio,
4152ba8ffceSChristoph Hellwig 		struct swap_info_struct *sis)
4163222d8c2SChristoph Hellwig {
4173222d8c2SChristoph Hellwig 	struct bio_vec bv;
4183222d8c2SChristoph Hellwig 	struct bio bio;
4193222d8c2SChristoph Hellwig 
4202ba8ffceSChristoph Hellwig 	bio_init(&bio, sis->bdev, &bv, 1, REQ_OP_WRITE | REQ_SWAP);
4213a61e6f6SMatthew Wilcox (Oracle) 	bio.bi_iter.bi_sector = swap_folio_sector(folio);
4226de62c7bSMatthew Wilcox (Oracle) 	bio_add_folio_nofail(&bio, folio, folio_size(folio), 0);
4233222d8c2SChristoph Hellwig 
42498630cfdSZhangPeng 	bio_associate_blkg_from_page(&bio, folio);
4259b72b134SZhangPeng 	count_swpout_vm_event(folio);
4263222d8c2SChristoph Hellwig 
427f54fcaabSZhangPeng 	folio_start_writeback(folio);
428f54fcaabSZhangPeng 	folio_unlock(folio);
4293222d8c2SChristoph Hellwig 
4303222d8c2SChristoph Hellwig 	submit_bio_wait(&bio);
4313222d8c2SChristoph Hellwig 	__end_swap_bio_write(&bio);
4323222d8c2SChristoph Hellwig }
4333222d8c2SChristoph Hellwig 
swap_writepage_bdev_async(struct folio * folio,struct swap_info_struct * sis)434ee1b1d9bSMatthew Wilcox (Oracle) static void swap_writepage_bdev_async(struct folio *folio,
4352ba8ffceSChristoph Hellwig 		struct swap_info_struct *sis)
4367eadabc0SNeilBrown {
4377eadabc0SNeilBrown 	struct bio *bio;
438dd6bd0d9SMatthew Wilcox 
4392ba8ffceSChristoph Hellwig 	bio = bio_alloc(sis->bdev, 1, REQ_OP_WRITE | REQ_SWAP, GFP_NOIO);
4403a61e6f6SMatthew Wilcox (Oracle) 	bio->bi_iter.bi_sector = swap_folio_sector(folio);
441cf1e3fe4SChristoph Hellwig 	bio->bi_end_io = end_swap_bio_write;
442ee1b1d9bSMatthew Wilcox (Oracle) 	bio_add_folio_nofail(bio, folio, folio_size(folio), 0);
44348d15436SChristoph Hellwig 
44498630cfdSZhangPeng 	bio_associate_blkg_from_page(bio, folio);
4459b72b134SZhangPeng 	count_swpout_vm_event(folio);
4462675251dSZhangPeng 	folio_start_writeback(folio);
4472675251dSZhangPeng 	folio_unlock(folio);
4484e49ea4aSMike Christie 	submit_bio(bio);
4491da177e4SLinus Torvalds }
4501da177e4SLinus Torvalds 
__swap_writepage(struct folio * folio,struct swap_iocb ** swap_plug)4512ba8ffceSChristoph Hellwig void __swap_writepage(struct folio *folio, struct swap_iocb **swap_plug)
45205cda97eSChristoph Hellwig {
4530fcf8ef4SKairui Song 	struct swap_info_struct *sis = __swap_entry_to_info(folio->swap);
45405cda97eSChristoph Hellwig 
455b99b4e0dSMatthew Wilcox (Oracle) 	VM_BUG_ON_FOLIO(!folio_test_swapcache(folio), folio);
45605cda97eSChristoph Hellwig 	/*
457f2a48f8fSKexin Sun 	 * ->flags can be updated non-atomically,
45805cda97eSChristoph Hellwig 	 * but that will never affect SWP_FS_OPS, so the data_race
45905cda97eSChristoph Hellwig 	 * is safe.
46005cda97eSChristoph Hellwig 	 */
46105cda97eSChristoph Hellwig 	if (data_race(sis->flags & SWP_FS_OPS))
4622ba8ffceSChristoph Hellwig 		swap_writepage_fs(folio, swap_plug);
4637b7aca6dSPei Li 	/*
464f2a48f8fSKexin Sun 	 * ->flags can be updated non-atomically,
4657b7aca6dSPei Li 	 * but that will never affect SWP_SYNCHRONOUS_IO, so the data_race
4667b7aca6dSPei Li 	 * is safe.
4677b7aca6dSPei Li 	 */
4687b7aca6dSPei Li 	else if (data_race(sis->flags & SWP_SYNCHRONOUS_IO))
4692ba8ffceSChristoph Hellwig 		swap_writepage_bdev_sync(folio, sis);
47005cda97eSChristoph Hellwig 	else
4712ba8ffceSChristoph Hellwig 		swap_writepage_bdev_async(folio, sis);
4721da177e4SLinus Torvalds }
4731da177e4SLinus Torvalds 
swap_write_unplug(struct swap_iocb * sio)4742282679fSNeilBrown void swap_write_unplug(struct swap_iocb *sio)
4752282679fSNeilBrown {
4762282679fSNeilBrown 	struct iov_iter from;
4772282679fSNeilBrown 	struct address_space *mapping = sio->iocb.ki_filp->f_mapping;
4782282679fSNeilBrown 	int ret;
4792282679fSNeilBrown 
480de4eda9dSAl Viro 	iov_iter_bvec(&from, ITER_SOURCE, sio->bvec, sio->pages, sio->len);
4812282679fSNeilBrown 	ret = mapping->a_ops->swap_rw(&sio->iocb, &from);
4822282679fSNeilBrown 	if (ret != -EIOCBQUEUED)
4832282679fSNeilBrown 		sio_write_complete(&sio->iocb, ret);
4842282679fSNeilBrown }
4852282679fSNeilBrown 
sio_read_complete(struct kiocb * iocb,long ret)486e1209d3aSNeilBrown static void sio_read_complete(struct kiocb *iocb, long ret)
487e1209d3aSNeilBrown {
488e1209d3aSNeilBrown 	struct swap_iocb *sio = container_of(iocb, struct swap_iocb, iocb);
4895169b844SNeilBrown 	int p;
490e1209d3aSNeilBrown 
491a1a0dfd5SNeilBrown 	if (ret == sio->len) {
4925169b844SNeilBrown 		for (p = 0; p < sio->pages; p++) {
4936a8c0687SZhangPeng 			struct folio *folio = page_folio(sio->bvec[p].bv_page);
4945169b844SNeilBrown 
495aaf2914aSBarry Song 			count_mthp_stat(folio_order(folio), MTHP_STAT_SWPIN);
49615ff4d40SJingxiang Zeng 			count_memcg_folio_events(folio, PSWPIN, folio_nr_pages(folio));
4976a8c0687SZhangPeng 			folio_mark_uptodate(folio);
4986a8c0687SZhangPeng 			folio_unlock(folio);
4995169b844SNeilBrown 		}
500*df620ec4SDavid Carlier 		count_vm_events(PSWPIN, sio->len >> PAGE_SHIFT);
5015169b844SNeilBrown 	} else {
5025169b844SNeilBrown 		for (p = 0; p < sio->pages; p++) {
5036a8c0687SZhangPeng 			struct folio *folio = page_folio(sio->bvec[p].bv_page);
5045169b844SNeilBrown 
5056a8c0687SZhangPeng 			folio_unlock(folio);
5065169b844SNeilBrown 		}
5075169b844SNeilBrown 		pr_alert_ratelimited("Read-error on swap-device\n");
5085169b844SNeilBrown 	}
509e1209d3aSNeilBrown 	mempool_free(sio, sio_pool);
510e1209d3aSNeilBrown }
511e1209d3aSNeilBrown 
swap_read_folio_zeromap(struct folio * folio)5120ca0c24eSUsama Arif static bool swap_read_folio_zeromap(struct folio *folio)
5130ca0c24eSUsama Arif {
5149d57090eSBarry Song 	int nr_pages = folio_nr_pages(folio);
515e7ac4daeSBarry Song 	struct obj_cgroup *objcg;
5169d57090eSBarry Song 	bool is_zeromap;
5170ca0c24eSUsama Arif 
5180ca0c24eSUsama Arif 	/*
5190ca0c24eSUsama Arif 	 * Swapping in a large folio that is partially in the zeromap is not
5200ca0c24eSUsama Arif 	 * currently handled. Return true without marking the folio uptodate so
5210ca0c24eSUsama Arif 	 * that an IO error is emitted (e.g. do_swap_page() will sigbus).
5220ca0c24eSUsama Arif 	 */
5239d57090eSBarry Song 	if (WARN_ON_ONCE(swap_zeromap_batch(folio->swap, nr_pages,
5249d57090eSBarry Song 			&is_zeromap) != nr_pages))
5250ca0c24eSUsama Arif 		return true;
5260ca0c24eSUsama Arif 
5279d57090eSBarry Song 	if (!is_zeromap)
5289d57090eSBarry Song 		return false;
5299d57090eSBarry Song 
530e7ac4daeSBarry Song 	objcg = get_obj_cgroup_from_folio(folio);
531e7ac4daeSBarry Song 	count_vm_events(SWPIN_ZERO, nr_pages);
532e7ac4daeSBarry Song 	if (objcg) {
533e7ac4daeSBarry Song 		count_objcg_events(objcg, SWPIN_ZERO, nr_pages);
534e7ac4daeSBarry Song 		obj_cgroup_put(objcg);
535e7ac4daeSBarry Song 	}
536e7ac4daeSBarry Song 
5370ca0c24eSUsama Arif 	folio_zero_range(folio, 0, folio_size(folio));
5380ca0c24eSUsama Arif 	folio_mark_uptodate(folio);
5390ca0c24eSUsama Arif 	return true;
5400ca0c24eSUsama Arif }
5410ca0c24eSUsama Arif 
swap_read_folio_fs(struct folio * folio,struct swap_iocb ** plug)542c9bdf768SMatthew Wilcox (Oracle) static void swap_read_folio_fs(struct folio *folio, struct swap_iocb **plug)
543e1209d3aSNeilBrown {
5440fcf8ef4SKairui Song 	struct swap_info_struct *sis = __swap_entry_to_info(folio->swap);
5455169b844SNeilBrown 	struct swap_iocb *sio = NULL;
546545ebe71SKairui Song 	loff_t pos = swap_dev_pos(folio->swap);
547e1209d3aSNeilBrown 
5485169b844SNeilBrown 	if (plug)
5495169b844SNeilBrown 		sio = *plug;
5505169b844SNeilBrown 	if (sio) {
5515169b844SNeilBrown 		if (sio->iocb.ki_filp != sis->swap_file ||
552a1a0dfd5SNeilBrown 		    sio->iocb.ki_pos + sio->len != pos) {
5535169b844SNeilBrown 			swap_read_unplug(sio);
5545169b844SNeilBrown 			sio = NULL;
5555169b844SNeilBrown 		}
5565169b844SNeilBrown 	}
5575169b844SNeilBrown 	if (!sio) {
558e1209d3aSNeilBrown 		sio = mempool_alloc(sio_pool, GFP_KERNEL);
5595169b844SNeilBrown 		init_sync_kiocb(&sio->iocb, sis->swap_file);
560e1209d3aSNeilBrown 		sio->iocb.ki_pos = pos;
561e1209d3aSNeilBrown 		sio->iocb.ki_complete = sio_read_complete;
5625169b844SNeilBrown 		sio->pages = 0;
563a1a0dfd5SNeilBrown 		sio->len = 0;
5645169b844SNeilBrown 	}
56564a24e55SMatthew Wilcox (Oracle) 	bvec_set_folio(&sio->bvec[sio->pages], folio, folio_size(folio), 0);
56664a24e55SMatthew Wilcox (Oracle) 	sio->len += folio_size(folio);
5675169b844SNeilBrown 	sio->pages += 1;
5685169b844SNeilBrown 	if (sio->pages == ARRAY_SIZE(sio->bvec) || !plug) {
5695169b844SNeilBrown 		swap_read_unplug(sio);
5705169b844SNeilBrown 		sio = NULL;
5715169b844SNeilBrown 	}
5725169b844SNeilBrown 	if (plug)
5735169b844SNeilBrown 		*plug = sio;
574e1209d3aSNeilBrown }
575e1209d3aSNeilBrown 
swap_read_folio_bdev_sync(struct folio * folio,struct swap_info_struct * sis)576c9bdf768SMatthew Wilcox (Oracle) static void swap_read_folio_bdev_sync(struct folio *folio,
5779b4e30bdSChristoph Hellwig 		struct swap_info_struct *sis)
5789b4e30bdSChristoph Hellwig {
5799b4e30bdSChristoph Hellwig 	struct bio_vec bv;
5809b4e30bdSChristoph Hellwig 	struct bio bio;
5819b4e30bdSChristoph Hellwig 
5829b4e30bdSChristoph Hellwig 	bio_init(&bio, sis->bdev, &bv, 1, REQ_OP_READ);
5833a61e6f6SMatthew Wilcox (Oracle) 	bio.bi_iter.bi_sector = swap_folio_sector(folio);
5842c184d82SMatthew Wilcox (Oracle) 	bio_add_folio_nofail(&bio, folio, folio_size(folio), 0);
5859b4e30bdSChristoph Hellwig 	/*
5869b4e30bdSChristoph Hellwig 	 * Keep this task valid during swap readpage because the oom killer may
5879b4e30bdSChristoph Hellwig 	 * attempt to access it in the page fault retry time check.
5889b4e30bdSChristoph Hellwig 	 */
5899b4e30bdSChristoph Hellwig 	get_task_struct(current);
590aaf2914aSBarry Song 	count_mthp_stat(folio_order(folio), MTHP_STAT_SWPIN);
59115ff4d40SJingxiang Zeng 	count_memcg_folio_events(folio, PSWPIN, folio_nr_pages(folio));
592b54e1bfeSBarry Song 	count_vm_events(PSWPIN, folio_nr_pages(folio));
5939b4e30bdSChristoph Hellwig 	submit_bio_wait(&bio);
5949b4e30bdSChristoph Hellwig 	__end_swap_bio_read(&bio);
5959b4e30bdSChristoph Hellwig 	put_task_struct(current);
5969b4e30bdSChristoph Hellwig }
5979b4e30bdSChristoph Hellwig 
swap_read_folio_bdev_async(struct folio * folio,struct swap_info_struct * sis)598c9bdf768SMatthew Wilcox (Oracle) static void swap_read_folio_bdev_async(struct folio *folio,
59914bd75f5SChristoph Hellwig 		struct swap_info_struct *sis)
6001da177e4SLinus Torvalds {
6011da177e4SLinus Torvalds 	struct bio *bio;
60262c230bcSMel Gorman 
60307888c66SChristoph Hellwig 	bio = bio_alloc(sis->bdev, 1, REQ_OP_READ, GFP_KERNEL);
6043a61e6f6SMatthew Wilcox (Oracle) 	bio->bi_iter.bi_sector = swap_folio_sector(folio);
60548d15436SChristoph Hellwig 	bio->bi_end_io = end_swap_bio_read;
6063c3ebd82SMatthew Wilcox (Oracle) 	bio_add_folio_nofail(bio, folio, folio_size(folio), 0);
607aaf2914aSBarry Song 	count_mthp_stat(folio_order(folio), MTHP_STAT_SWPIN);
60815ff4d40SJingxiang Zeng 	count_memcg_folio_events(folio, PSWPIN, folio_nr_pages(folio));
609b54e1bfeSBarry Song 	count_vm_events(PSWPIN, folio_nr_pages(folio));
6103e08773cSChristoph Hellwig 	submit_bio(bio);
61114bd75f5SChristoph Hellwig }
61223955622SShaohua Li 
swap_read_folio(struct folio * folio,struct swap_iocb ** plug)613b2d1f38bSYosry Ahmed void swap_read_folio(struct folio *folio, struct swap_iocb **plug)
61414bd75f5SChristoph Hellwig {
6150fcf8ef4SKairui Song 	struct swap_info_struct *sis = __swap_entry_to_info(folio->swap);
616b2d1f38bSYosry Ahmed 	bool synchronous = sis->flags & SWP_SYNCHRONOUS_IO;
617fbcec6a3SMatthew Wilcox (Oracle) 	bool workingset = folio_test_workingset(folio);
6181da177e4SLinus Torvalds 	unsigned long pflags;
6191da177e4SLinus Torvalds 	bool in_thrashing;
6201da177e4SLinus Torvalds 
621fbcec6a3SMatthew Wilcox (Oracle) 	VM_BUG_ON_FOLIO(!folio_test_swapcache(folio) && !synchronous, folio);
622fbcec6a3SMatthew Wilcox (Oracle) 	VM_BUG_ON_FOLIO(!folio_test_locked(folio), folio);
623fbcec6a3SMatthew Wilcox (Oracle) 	VM_BUG_ON_FOLIO(folio_test_uptodate(folio), folio);
6241da177e4SLinus Torvalds 
6251da177e4SLinus Torvalds 	/*
6261da177e4SLinus Torvalds 	 * Count submission time as memory stall and delay. When the device
6271da177e4SLinus Torvalds 	 * is congested, or the submitting cgroup IO-throttled, submission
6281da177e4SLinus Torvalds 	 * can be a significant part of overall IO time.
6291da177e4SLinus Torvalds 	 */
6301da177e4SLinus Torvalds 	if (workingset) {
6311da177e4SLinus Torvalds 		delayacct_thrashing_start(&in_thrashing);
6321da177e4SLinus Torvalds 		psi_memstall_enter(&pflags);
6331da177e4SLinus Torvalds 	}
6341da177e4SLinus Torvalds 	delayacct_swapin_start();
6351da177e4SLinus Torvalds 
6360ca0c24eSUsama Arif 	if (swap_read_folio_zeromap(folio)) {
6370ca0c24eSUsama Arif 		folio_unlock(folio);
6380ca0c24eSUsama Arif 		goto finish;
6390e400844SNhat Pham 	}
6400e400844SNhat Pham 
641ff22f929SNhat Pham 	if (zswap_load(folio) != -ENOENT)
642ff22f929SNhat Pham 		goto finish;
643ff22f929SNhat Pham 
6440e400844SNhat Pham 	/* We have to read from slower devices. Increase zswap protection. */
6450e400844SNhat Pham 	zswap_folio_swapin(folio);
6460e400844SNhat Pham 
6470e400844SNhat Pham 	if (data_race(sis->flags & SWP_FS_OPS)) {
648c9bdf768SMatthew Wilcox (Oracle) 		swap_read_folio_fs(folio, plug);
649b2d1f38bSYosry Ahmed 	} else if (synchronous) {
650c9bdf768SMatthew Wilcox (Oracle) 		swap_read_folio_bdev_sync(folio, sis);
65114bd75f5SChristoph Hellwig 	} else {
652c9bdf768SMatthew Wilcox (Oracle) 		swap_read_folio_bdev_async(folio, sis);
6531da177e4SLinus Torvalds 	}
6541da177e4SLinus Torvalds 
6550e400844SNhat Pham finish:
6563a9bb7b1SYang Yang 	if (workingset) {
6573a9bb7b1SYang Yang 		delayacct_thrashing_end(&in_thrashing);
65893779069SMinchan Kim 		psi_memstall_leave(&pflags);
6593a9bb7b1SYang Yang 	}
660a3d5dc90SYang Yang 	delayacct_swapin_end();
6611da177e4SLinus Torvalds }
66262c230bcSMel Gorman 
__swap_read_unplug(struct swap_iocb * sio)6635169b844SNeilBrown void __swap_read_unplug(struct swap_iocb *sio)
66462c230bcSMel Gorman {
6655169b844SNeilBrown 	struct iov_iter from;
6665169b844SNeilBrown 	struct address_space *mapping = sio->iocb.ki_filp->f_mapping;
6675169b844SNeilBrown 	int ret;
66862c230bcSMel Gorman 
669de4eda9dSAl Viro 	iov_iter_bvec(&from, ITER_DEST, sio->bvec, sio->pages, sio->len);
6705169b844SNeilBrown 	ret = mapping->a_ops->swap_rw(&sio->iocb, &from);
6715169b844SNeilBrown 	if (ret != -EIOCBQUEUED)
6725169b844SNeilBrown 		sio_read_complete(&sio->iocb, ret);
67362c230bcSMel Gorman }
674