xref: /openbmc/linux/fs/jfs/jfs_metapage.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
37fab479bSDave Kleikamp  *   Copyright (C) International Business Machines Corp., 2000-2005
41da177e4SLinus Torvalds  *   Portions Copyright (C) Christoph Hellwig, 2001-2002
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds #include <linux/fs.h>
87fab479bSDave Kleikamp #include <linux/mm.h>
9b2e03ca7SAlexey Dobriyan #include <linux/module.h>
107fab479bSDave Kleikamp #include <linux/bio.h>
115a0e3ad6STejun Heo #include <linux/slab.h>
121da177e4SLinus Torvalds #include <linux/init.h>
131da177e4SLinus Torvalds #include <linux/buffer_head.h>
141da177e4SLinus Torvalds #include <linux/mempool.h>
15b2e03ca7SAlexey Dobriyan #include <linux/seq_file.h>
16cd78ab11SMatthew Wilcox (Oracle) #include <linux/writeback.h>
171da177e4SLinus Torvalds #include "jfs_incore.h"
181da177e4SLinus Torvalds #include "jfs_superblock.h"
191da177e4SLinus Torvalds #include "jfs_filsys.h"
201da177e4SLinus Torvalds #include "jfs_metapage.h"
211da177e4SLinus Torvalds #include "jfs_txnmgr.h"
221da177e4SLinus Torvalds #include "jfs_debug.h"
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds #ifdef CONFIG_JFS_STATISTICS
251da177e4SLinus Torvalds static struct {
261da177e4SLinus Torvalds 	uint	pagealloc;	/* # of page allocations */
271da177e4SLinus Torvalds 	uint	pagefree;	/* # of page frees */
281da177e4SLinus Torvalds 	uint	lockwait;	/* # of sleeping lock_metapage() calls */
291da177e4SLinus Torvalds } mpStat;
301da177e4SLinus Torvalds #endif
311da177e4SLinus Torvalds 
327fab479bSDave Kleikamp #define metapage_locked(mp) test_bit(META_locked, &(mp)->flag)
3354af6233SNick Piggin #define trylock_metapage(mp) test_and_set_bit_lock(META_locked, &(mp)->flag)
341da177e4SLinus Torvalds 
unlock_metapage(struct metapage * mp)351da177e4SLinus Torvalds static inline void unlock_metapage(struct metapage *mp)
361da177e4SLinus Torvalds {
3754af6233SNick Piggin 	clear_bit_unlock(META_locked, &mp->flag);
381da177e4SLinus Torvalds 	wake_up(&mp->wait);
391da177e4SLinus Torvalds }
401da177e4SLinus Torvalds 
__lock_metapage(struct metapage * mp)417fab479bSDave Kleikamp static inline void __lock_metapage(struct metapage *mp)
421da177e4SLinus Torvalds {
431da177e4SLinus Torvalds 	DECLARE_WAITQUEUE(wait, current);
441da177e4SLinus Torvalds 	INCREMENT(mpStat.lockwait);
451da177e4SLinus Torvalds 	add_wait_queue_exclusive(&mp->wait, &wait);
461da177e4SLinus Torvalds 	do {
471da177e4SLinus Torvalds 		set_current_state(TASK_UNINTERRUPTIBLE);
481da177e4SLinus Torvalds 		if (metapage_locked(mp)) {
497fab479bSDave Kleikamp 			unlock_page(mp->page);
504aa0d230SDave Kleikamp 			io_schedule();
517fab479bSDave Kleikamp 			lock_page(mp->page);
521da177e4SLinus Torvalds 		}
531da177e4SLinus Torvalds 	} while (trylock_metapage(mp));
541da177e4SLinus Torvalds 	__set_current_state(TASK_RUNNING);
551da177e4SLinus Torvalds 	remove_wait_queue(&mp->wait, &wait);
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds 
587fab479bSDave Kleikamp /*
597fab479bSDave Kleikamp  * Must have mp->page locked
607fab479bSDave Kleikamp  */
lock_metapage(struct metapage * mp)611da177e4SLinus Torvalds static inline void lock_metapage(struct metapage *mp)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds 	if (trylock_metapage(mp))
641da177e4SLinus Torvalds 		__lock_metapage(mp);
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds #define METAPOOL_MIN_PAGES 32
68e18b890bSChristoph Lameter static struct kmem_cache *metapage_cache;
691da177e4SLinus Torvalds static mempool_t *metapage_mempool;
701da177e4SLinus Torvalds 
7109cbfeafSKirill A. Shutemov #define MPS_PER_PAGE (PAGE_SIZE >> L2PSIZE)
727fab479bSDave Kleikamp 
737fab479bSDave Kleikamp #if MPS_PER_PAGE > 1
747fab479bSDave Kleikamp 
757fab479bSDave Kleikamp struct meta_anchor {
767fab479bSDave Kleikamp 	int mp_count;
777fab479bSDave Kleikamp 	atomic_t io_count;
787fab479bSDave Kleikamp 	struct metapage *mp[MPS_PER_PAGE];
797fab479bSDave Kleikamp };
804c21e2f2SHugh Dickins #define mp_anchor(page) ((struct meta_anchor *)page_private(page))
817fab479bSDave Kleikamp 
page_to_mp(struct page * page,int offset)82967c9ec4SDave Kleikamp static inline struct metapage *page_to_mp(struct page *page, int offset)
837fab479bSDave Kleikamp {
847fab479bSDave Kleikamp 	if (!PagePrivate(page))
857fab479bSDave Kleikamp 		return NULL;
867fab479bSDave Kleikamp 	return mp_anchor(page)->mp[offset >> L2PSIZE];
877fab479bSDave Kleikamp }
887fab479bSDave Kleikamp 
insert_metapage(struct page * page,struct metapage * mp)897fab479bSDave Kleikamp static inline int insert_metapage(struct page *page, struct metapage *mp)
907fab479bSDave Kleikamp {
917fab479bSDave Kleikamp 	struct meta_anchor *a;
927fab479bSDave Kleikamp 	int index;
937fab479bSDave Kleikamp 	int l2mp_blocks;	/* log2 blocks per metapage */
947fab479bSDave Kleikamp 
957fab479bSDave Kleikamp 	if (PagePrivate(page))
967fab479bSDave Kleikamp 		a = mp_anchor(page);
977fab479bSDave Kleikamp 	else {
985b3030e3SEric Sesterhenn 		a = kzalloc(sizeof(struct meta_anchor), GFP_NOFS);
997fab479bSDave Kleikamp 		if (!a)
1007fab479bSDave Kleikamp 			return -ENOMEM;
1014c21e2f2SHugh Dickins 		set_page_private(page, (unsigned long)a);
1027fab479bSDave Kleikamp 		SetPagePrivate(page);
1037fab479bSDave Kleikamp 		kmap(page);
1047fab479bSDave Kleikamp 	}
1057fab479bSDave Kleikamp 
1067fab479bSDave Kleikamp 	if (mp) {
1077fab479bSDave Kleikamp 		l2mp_blocks = L2PSIZE - page->mapping->host->i_blkbits;
1087fab479bSDave Kleikamp 		index = (mp->index >> l2mp_blocks) & (MPS_PER_PAGE - 1);
1097fab479bSDave Kleikamp 		a->mp_count++;
1107fab479bSDave Kleikamp 		a->mp[index] = mp;
1117fab479bSDave Kleikamp 	}
1127fab479bSDave Kleikamp 
1137fab479bSDave Kleikamp 	return 0;
1147fab479bSDave Kleikamp }
1157fab479bSDave Kleikamp 
remove_metapage(struct page * page,struct metapage * mp)1167fab479bSDave Kleikamp static inline void remove_metapage(struct page *page, struct metapage *mp)
1177fab479bSDave Kleikamp {
1187fab479bSDave Kleikamp 	struct meta_anchor *a = mp_anchor(page);
1197fab479bSDave Kleikamp 	int l2mp_blocks = L2PSIZE - page->mapping->host->i_blkbits;
1207fab479bSDave Kleikamp 	int index;
1217fab479bSDave Kleikamp 
1227fab479bSDave Kleikamp 	index = (mp->index >> l2mp_blocks) & (MPS_PER_PAGE - 1);
1237fab479bSDave Kleikamp 
1247fab479bSDave Kleikamp 	BUG_ON(a->mp[index] != mp);
1257fab479bSDave Kleikamp 
1267fab479bSDave Kleikamp 	a->mp[index] = NULL;
1277fab479bSDave Kleikamp 	if (--a->mp_count == 0) {
1287fab479bSDave Kleikamp 		kfree(a);
1294c21e2f2SHugh Dickins 		set_page_private(page, 0);
1307fab479bSDave Kleikamp 		ClearPagePrivate(page);
1317fab479bSDave Kleikamp 		kunmap(page);
1327fab479bSDave Kleikamp 	}
1337fab479bSDave Kleikamp }
1347fab479bSDave Kleikamp 
inc_io(struct page * page)1357fab479bSDave Kleikamp static inline void inc_io(struct page *page)
1367fab479bSDave Kleikamp {
1377fab479bSDave Kleikamp 	atomic_inc(&mp_anchor(page)->io_count);
1387fab479bSDave Kleikamp }
1397fab479bSDave Kleikamp 
dec_io(struct page * page,void (* handler)(struct page *))1407fab479bSDave Kleikamp static inline void dec_io(struct page *page, void (*handler) (struct page *))
1417fab479bSDave Kleikamp {
1427fab479bSDave Kleikamp 	if (atomic_dec_and_test(&mp_anchor(page)->io_count))
1437fab479bSDave Kleikamp 		handler(page);
1447fab479bSDave Kleikamp }
1457fab479bSDave Kleikamp 
1467fab479bSDave Kleikamp #else
page_to_mp(struct page * page,int offset)147967c9ec4SDave Kleikamp static inline struct metapage *page_to_mp(struct page *page, int offset)
1487fab479bSDave Kleikamp {
1494c21e2f2SHugh Dickins 	return PagePrivate(page) ? (struct metapage *)page_private(page) : NULL;
1507fab479bSDave Kleikamp }
1517fab479bSDave Kleikamp 
insert_metapage(struct page * page,struct metapage * mp)1527fab479bSDave Kleikamp static inline int insert_metapage(struct page *page, struct metapage *mp)
1537fab479bSDave Kleikamp {
1547fab479bSDave Kleikamp 	if (mp) {
1554c21e2f2SHugh Dickins 		set_page_private(page, (unsigned long)mp);
1567fab479bSDave Kleikamp 		SetPagePrivate(page);
1577fab479bSDave Kleikamp 		kmap(page);
1587fab479bSDave Kleikamp 	}
1597fab479bSDave Kleikamp 	return 0;
1607fab479bSDave Kleikamp }
1617fab479bSDave Kleikamp 
remove_metapage(struct page * page,struct metapage * mp)1627fab479bSDave Kleikamp static inline void remove_metapage(struct page *page, struct metapage *mp)
1637fab479bSDave Kleikamp {
1644c21e2f2SHugh Dickins 	set_page_private(page, 0);
1657fab479bSDave Kleikamp 	ClearPagePrivate(page);
1667fab479bSDave Kleikamp 	kunmap(page);
1677fab479bSDave Kleikamp }
1687fab479bSDave Kleikamp 
1697fab479bSDave Kleikamp #define inc_io(page) do {} while(0)
1707fab479bSDave Kleikamp #define dec_io(page, handler) handler(page)
1717fab479bSDave Kleikamp 
1727fab479bSDave Kleikamp #endif
1737fab479bSDave Kleikamp 
alloc_metapage(gfp_t gfp_mask)174ee146245SDavid Rientjes static inline struct metapage *alloc_metapage(gfp_t gfp_mask)
1751da177e4SLinus Torvalds {
176ee146245SDavid Rientjes 	struct metapage *mp = mempool_alloc(metapage_mempool, gfp_mask);
1771da177e4SLinus Torvalds 
178ee146245SDavid Rientjes 	if (mp) {
1791da177e4SLinus Torvalds 		mp->lid = 0;
1801da177e4SLinus Torvalds 		mp->lsn = 0;
1811da177e4SLinus Torvalds 		mp->data = NULL;
1821da177e4SLinus Torvalds 		mp->clsn = 0;
1831da177e4SLinus Torvalds 		mp->log = NULL;
1841da177e4SLinus Torvalds 		init_waitqueue_head(&mp->wait);
1851da177e4SLinus Torvalds 	}
186ee146245SDavid Rientjes 	return mp;
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds 
free_metapage(struct metapage * mp)1891da177e4SLinus Torvalds static inline void free_metapage(struct metapage *mp)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds 	mempool_free(mp, metapage_mempool);
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds 
metapage_init(void)1941da177e4SLinus Torvalds int __init metapage_init(void)
1951da177e4SLinus Torvalds {
1961da177e4SLinus Torvalds 	/*
1971da177e4SLinus Torvalds 	 * Allocate the metapage structures
1981da177e4SLinus Torvalds 	 */
1991da177e4SLinus Torvalds 	metapage_cache = kmem_cache_create("jfs_mp", sizeof(struct metapage),
200ee146245SDavid Rientjes 					   0, 0, NULL);
2011da177e4SLinus Torvalds 	if (metapage_cache == NULL)
2021da177e4SLinus Torvalds 		return -ENOMEM;
2031da177e4SLinus Torvalds 
20493d2341cSMatthew Dobson 	metapage_mempool = mempool_create_slab_pool(METAPOOL_MIN_PAGES,
20593d2341cSMatthew Dobson 						    metapage_cache);
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	if (metapage_mempool == NULL) {
2081da177e4SLinus Torvalds 		kmem_cache_destroy(metapage_cache);
2091da177e4SLinus Torvalds 		return -ENOMEM;
2101da177e4SLinus Torvalds 	}
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 	return 0;
2131da177e4SLinus Torvalds }
2141da177e4SLinus Torvalds 
metapage_exit(void)2151da177e4SLinus Torvalds void metapage_exit(void)
2161da177e4SLinus Torvalds {
2171da177e4SLinus Torvalds 	mempool_destroy(metapage_mempool);
2181da177e4SLinus Torvalds 	kmem_cache_destroy(metapage_cache);
2191da177e4SLinus Torvalds }
2201da177e4SLinus Torvalds 
drop_metapage(struct page * page,struct metapage * mp)2217fab479bSDave Kleikamp static inline void drop_metapage(struct page *page, struct metapage *mp)
2227fab479bSDave Kleikamp {
2237fab479bSDave Kleikamp 	if (mp->count || mp->nohomeok || test_bit(META_dirty, &mp->flag) ||
2247fab479bSDave Kleikamp 	    test_bit(META_io, &mp->flag))
2257fab479bSDave Kleikamp 		return;
2267fab479bSDave Kleikamp 	remove_metapage(page, mp);
2277fab479bSDave Kleikamp 	INCREMENT(mpStat.pagefree);
2287fab479bSDave Kleikamp 	free_metapage(mp);
2297fab479bSDave Kleikamp }
2307fab479bSDave Kleikamp 
2311da177e4SLinus Torvalds /*
2327fab479bSDave Kleikamp  * Metapage address space operations
2331da177e4SLinus Torvalds  */
2347fab479bSDave Kleikamp 
metapage_get_blocks(struct inode * inode,sector_t lblock,int * len)2357fab479bSDave Kleikamp static sector_t metapage_get_blocks(struct inode *inode, sector_t lblock,
236967c9ec4SDave Kleikamp 				    int *len)
2371da177e4SLinus Torvalds {
2387fab479bSDave Kleikamp 	int rc = 0;
2397fab479bSDave Kleikamp 	int xflag;
2407fab479bSDave Kleikamp 	s64 xaddr;
241ba52de12STheodore Ts'o 	sector_t file_blocks = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
2427fab479bSDave Kleikamp 			       inode->i_blkbits;
2437fab479bSDave Kleikamp 
2447fab479bSDave Kleikamp 	if (lblock >= file_blocks)
2457fab479bSDave Kleikamp 		return 0;
2467fab479bSDave Kleikamp 	if (lblock + *len > file_blocks)
2477fab479bSDave Kleikamp 		*len = file_blocks - lblock;
2487fab479bSDave Kleikamp 
2497fab479bSDave Kleikamp 	if (inode->i_ino) {
2507fab479bSDave Kleikamp 		rc = xtLookup(inode, (s64)lblock, *len, &xflag, &xaddr, len, 0);
2517fab479bSDave Kleikamp 		if ((rc == 0) && *len)
2527fab479bSDave Kleikamp 			lblock = (sector_t)xaddr;
2537fab479bSDave Kleikamp 		else
2547fab479bSDave Kleikamp 			lblock = 0;
2557fab479bSDave Kleikamp 	} /* else no mapping */
2567fab479bSDave Kleikamp 
2577fab479bSDave Kleikamp 	return lblock;
2581da177e4SLinus Torvalds }
2591da177e4SLinus Torvalds 
last_read_complete(struct page * page)2607fab479bSDave Kleikamp static void last_read_complete(struct page *page)
2611da177e4SLinus Torvalds {
2627fab479bSDave Kleikamp 	if (!PageError(page))
2637fab479bSDave Kleikamp 		SetPageUptodate(page);
2647fab479bSDave Kleikamp 	unlock_page(page);
2651da177e4SLinus Torvalds }
2661da177e4SLinus Torvalds 
metapage_read_end_io(struct bio * bio)2674246a0b6SChristoph Hellwig static void metapage_read_end_io(struct bio *bio)
2681da177e4SLinus Torvalds {
2697fab479bSDave Kleikamp 	struct page *page = bio->bi_private;
2701da177e4SLinus Torvalds 
2714e4cbee9SChristoph Hellwig 	if (bio->bi_status) {
2727fab479bSDave Kleikamp 		printk(KERN_ERR "metapage_read_end_io: I/O error\n");
2737fab479bSDave Kleikamp 		SetPageError(page);
2741da177e4SLinus Torvalds 	}
2751da177e4SLinus Torvalds 
2767fab479bSDave Kleikamp 	dec_io(page, last_read_complete);
2777fab479bSDave Kleikamp 	bio_put(bio);
2787fab479bSDave Kleikamp }
2797fab479bSDave Kleikamp 
remove_from_logsync(struct metapage * mp)2807fab479bSDave Kleikamp static void remove_from_logsync(struct metapage *mp)
2811da177e4SLinus Torvalds {
2827fab479bSDave Kleikamp 	struct jfs_log *log = mp->log;
2837fab479bSDave Kleikamp 	unsigned long flags;
2847fab479bSDave Kleikamp /*
2857fab479bSDave Kleikamp  * This can race.  Recheck that log hasn't been set to null, and after
2867fab479bSDave Kleikamp  * acquiring logsync lock, recheck lsn
2877fab479bSDave Kleikamp  */
2887fab479bSDave Kleikamp 	if (!log)
2897fab479bSDave Kleikamp 		return;
2907fab479bSDave Kleikamp 
2917fab479bSDave Kleikamp 	LOGSYNC_LOCK(log, flags);
2927fab479bSDave Kleikamp 	if (mp->lsn) {
2937fab479bSDave Kleikamp 		mp->log = NULL;
2947fab479bSDave Kleikamp 		mp->lsn = 0;
2957fab479bSDave Kleikamp 		mp->clsn = 0;
2967fab479bSDave Kleikamp 		log->count--;
2977fab479bSDave Kleikamp 		list_del(&mp->synclist);
2987fab479bSDave Kleikamp 	}
2997fab479bSDave Kleikamp 	LOGSYNC_UNLOCK(log, flags);
3001da177e4SLinus Torvalds }
3011da177e4SLinus Torvalds 
last_write_complete(struct page * page)3027fab479bSDave Kleikamp static void last_write_complete(struct page *page)
3037fab479bSDave Kleikamp {
3047fab479bSDave Kleikamp 	struct metapage *mp;
3057fab479bSDave Kleikamp 	unsigned int offset;
3067fab479bSDave Kleikamp 
30709cbfeafSKirill A. Shutemov 	for (offset = 0; offset < PAGE_SIZE; offset += PSIZE) {
3087fab479bSDave Kleikamp 		mp = page_to_mp(page, offset);
3097fab479bSDave Kleikamp 		if (mp && test_bit(META_io, &mp->flag)) {
3107fab479bSDave Kleikamp 			if (mp->lsn)
3117fab479bSDave Kleikamp 				remove_from_logsync(mp);
3127fab479bSDave Kleikamp 			clear_bit(META_io, &mp->flag);
3131da177e4SLinus Torvalds 		}
3147fab479bSDave Kleikamp 		/*
3157fab479bSDave Kleikamp 		 * I'd like to call drop_metapage here, but I don't think it's
3167fab479bSDave Kleikamp 		 * safe unless I have the page locked
3177fab479bSDave Kleikamp 		 */
3187fab479bSDave Kleikamp 	}
3197fab479bSDave Kleikamp 	end_page_writeback(page);
3207fab479bSDave Kleikamp }
3217fab479bSDave Kleikamp 
metapage_write_end_io(struct bio * bio)3224246a0b6SChristoph Hellwig static void metapage_write_end_io(struct bio *bio)
3237fab479bSDave Kleikamp {
3247fab479bSDave Kleikamp 	struct page *page = bio->bi_private;
3257fab479bSDave Kleikamp 
3267fab479bSDave Kleikamp 	BUG_ON(!PagePrivate(page));
3277fab479bSDave Kleikamp 
3284e4cbee9SChristoph Hellwig 	if (bio->bi_status) {
3297fab479bSDave Kleikamp 		printk(KERN_ERR "metapage_write_end_io: I/O error\n");
3307fab479bSDave Kleikamp 		SetPageError(page);
3317fab479bSDave Kleikamp 	}
3327fab479bSDave Kleikamp 	dec_io(page, last_write_complete);
3337fab479bSDave Kleikamp 	bio_put(bio);
3347fab479bSDave Kleikamp }
3357fab479bSDave Kleikamp 
metapage_writepage(struct page * page,struct writeback_control * wbc)3367fab479bSDave Kleikamp static int metapage_writepage(struct page *page, struct writeback_control *wbc)
3377fab479bSDave Kleikamp {
3387fab479bSDave Kleikamp 	struct bio *bio = NULL;
339967c9ec4SDave Kleikamp 	int block_offset;	/* block offset of mp within page */
3407fab479bSDave Kleikamp 	struct inode *inode = page->mapping->host;
341967c9ec4SDave Kleikamp 	int blocks_per_mp = JFS_SBI(inode->i_sb)->nbperpage;
342967c9ec4SDave Kleikamp 	int len;
343967c9ec4SDave Kleikamp 	int xlen;
3447fab479bSDave Kleikamp 	struct metapage *mp;
3457fab479bSDave Kleikamp 	int redirty = 0;
3467fab479bSDave Kleikamp 	sector_t lblock;
34729a424f2SDave Kleikamp 	int nr_underway = 0;
3487fab479bSDave Kleikamp 	sector_t pblock;
3497fab479bSDave Kleikamp 	sector_t next_block = 0;
3507fab479bSDave Kleikamp 	sector_t page_start;
3517fab479bSDave Kleikamp 	unsigned long bio_bytes = 0;
3527fab479bSDave Kleikamp 	unsigned long bio_offset = 0;
353967c9ec4SDave Kleikamp 	int offset;
3541ad53a98SDave Kleikamp 	int bad_blocks = 0;
3557fab479bSDave Kleikamp 
3567fab479bSDave Kleikamp 	page_start = (sector_t)page->index <<
35709cbfeafSKirill A. Shutemov 		     (PAGE_SHIFT - inode->i_blkbits);
3587fab479bSDave Kleikamp 	BUG_ON(!PageLocked(page));
3597fab479bSDave Kleikamp 	BUG_ON(PageWriteback(page));
36029a424f2SDave Kleikamp 	set_page_writeback(page);
3617fab479bSDave Kleikamp 
36209cbfeafSKirill A. Shutemov 	for (offset = 0; offset < PAGE_SIZE; offset += PSIZE) {
3637fab479bSDave Kleikamp 		mp = page_to_mp(page, offset);
3647fab479bSDave Kleikamp 
3657fab479bSDave Kleikamp 		if (!mp || !test_bit(META_dirty, &mp->flag))
3667fab479bSDave Kleikamp 			continue;
3677fab479bSDave Kleikamp 
3687fab479bSDave Kleikamp 		if (mp->nohomeok && !test_bit(META_forcewrite, &mp->flag)) {
3697fab479bSDave Kleikamp 			redirty = 1;
370ac17b8b5SDave Kleikamp 			/*
371ac17b8b5SDave Kleikamp 			 * Make sure this page isn't blocked indefinitely.
372ac17b8b5SDave Kleikamp 			 * If the journal isn't undergoing I/O, push it
373ac17b8b5SDave Kleikamp 			 */
374ac17b8b5SDave Kleikamp 			if (mp->log && !(mp->log->cflag & logGC_PAGEOUT))
375ac17b8b5SDave Kleikamp 				jfs_flush_journal(mp->log, 0);
3767fab479bSDave Kleikamp 			continue;
3777fab479bSDave Kleikamp 		}
3787fab479bSDave Kleikamp 
3797fab479bSDave Kleikamp 		clear_bit(META_dirty, &mp->flag);
3801ad53a98SDave Kleikamp 		set_bit(META_io, &mp->flag);
3817fab479bSDave Kleikamp 		block_offset = offset >> inode->i_blkbits;
3827fab479bSDave Kleikamp 		lblock = page_start + block_offset;
3837fab479bSDave Kleikamp 		if (bio) {
3847fab479bSDave Kleikamp 			if (xlen && lblock == next_block) {
3857fab479bSDave Kleikamp 				/* Contiguous, in memory & on disk */
3867fab479bSDave Kleikamp 				len = min(xlen, blocks_per_mp);
3877fab479bSDave Kleikamp 				xlen -= len;
3887fab479bSDave Kleikamp 				bio_bytes += len << inode->i_blkbits;
3897fab479bSDave Kleikamp 				continue;
3907fab479bSDave Kleikamp 			}
3917fab479bSDave Kleikamp 			/* Not contiguous */
3927fab479bSDave Kleikamp 			if (bio_add_page(bio, page, bio_bytes, bio_offset) <
3937fab479bSDave Kleikamp 			    bio_bytes)
3947fab479bSDave Kleikamp 				goto add_failed;
3957fab479bSDave Kleikamp 			/*
3967fab479bSDave Kleikamp 			 * Increment counter before submitting i/o to keep
3977fab479bSDave Kleikamp 			 * count from hitting zero before we're through
3987fab479bSDave Kleikamp 			 */
3997fab479bSDave Kleikamp 			inc_io(page);
4004f024f37SKent Overstreet 			if (!bio->bi_iter.bi_size)
4017fab479bSDave Kleikamp 				goto dump_bio;
4024e49ea4aSMike Christie 			submit_bio(bio);
40329a424f2SDave Kleikamp 			nr_underway++;
4047fab479bSDave Kleikamp 			bio = NULL;
40529a424f2SDave Kleikamp 		} else
4067fab479bSDave Kleikamp 			inc_io(page);
40709cbfeafSKirill A. Shutemov 		xlen = (PAGE_SIZE - offset) >> inode->i_blkbits;
4087fab479bSDave Kleikamp 		pblock = metapage_get_blocks(inode, lblock, &xlen);
4097fab479bSDave Kleikamp 		if (!pblock) {
4107fab479bSDave Kleikamp 			printk(KERN_ERR "JFS: metapage_get_blocks failed\n");
4111ad53a98SDave Kleikamp 			/*
4121ad53a98SDave Kleikamp 			 * We already called inc_io(), but can't cancel it
4131ad53a98SDave Kleikamp 			 * with dec_io() until we're done with the page
4141ad53a98SDave Kleikamp 			 */
4151ad53a98SDave Kleikamp 			bad_blocks++;
4167fab479bSDave Kleikamp 			continue;
4177fab479bSDave Kleikamp 		}
418967c9ec4SDave Kleikamp 		len = min(xlen, (int)JFS_SBI(inode->i_sb)->nbperpage);
4197fab479bSDave Kleikamp 
42007888c66SChristoph Hellwig 		bio = bio_alloc(inode->i_sb->s_bdev, 1, REQ_OP_WRITE, GFP_NOFS);
4214f024f37SKent Overstreet 		bio->bi_iter.bi_sector = pblock << (inode->i_blkbits - 9);
4227fab479bSDave Kleikamp 		bio->bi_end_io = metapage_write_end_io;
4237fab479bSDave Kleikamp 		bio->bi_private = page;
4247fab479bSDave Kleikamp 
4257fab479bSDave Kleikamp 		/* Don't call bio_add_page yet, we may add to this vec */
4267fab479bSDave Kleikamp 		bio_offset = offset;
4277fab479bSDave Kleikamp 		bio_bytes = len << inode->i_blkbits;
4287fab479bSDave Kleikamp 
4297fab479bSDave Kleikamp 		xlen -= len;
4307fab479bSDave Kleikamp 		next_block = lblock + len;
4317fab479bSDave Kleikamp 	}
4327fab479bSDave Kleikamp 	if (bio) {
4337fab479bSDave Kleikamp 		if (bio_add_page(bio, page, bio_bytes, bio_offset) < bio_bytes)
4347fab479bSDave Kleikamp 				goto add_failed;
4354f024f37SKent Overstreet 		if (!bio->bi_iter.bi_size)
4367fab479bSDave Kleikamp 			goto dump_bio;
4377fab479bSDave Kleikamp 
4384e49ea4aSMike Christie 		submit_bio(bio);
43929a424f2SDave Kleikamp 		nr_underway++;
4407fab479bSDave Kleikamp 	}
4417fab479bSDave Kleikamp 	if (redirty)
4427fab479bSDave Kleikamp 		redirty_page_for_writepage(wbc, page);
4437fab479bSDave Kleikamp 
4447fab479bSDave Kleikamp 	unlock_page(page);
4457fab479bSDave Kleikamp 
4461ad53a98SDave Kleikamp 	if (bad_blocks)
4471ad53a98SDave Kleikamp 		goto err_out;
4481ad53a98SDave Kleikamp 
44929a424f2SDave Kleikamp 	if (nr_underway == 0)
45029a424f2SDave Kleikamp 		end_page_writeback(page);
45129a424f2SDave Kleikamp 
4527fab479bSDave Kleikamp 	return 0;
4537fab479bSDave Kleikamp add_failed:
4547fab479bSDave Kleikamp 	/* We should never reach here, since we're only adding one vec */
4557fab479bSDave Kleikamp 	printk(KERN_ERR "JFS: bio_add_page failed unexpectedly\n");
4567fab479bSDave Kleikamp 	goto skip;
4577fab479bSDave Kleikamp dump_bio:
458288e4d83SDave Kleikamp 	print_hex_dump(KERN_ERR, "JFS: dump of bio: ", DUMP_PREFIX_ADDRESS, 16,
459288e4d83SDave Kleikamp 		       4, bio, sizeof(*bio), 0);
4607fab479bSDave Kleikamp skip:
4617fab479bSDave Kleikamp 	bio_put(bio);
4627fab479bSDave Kleikamp 	unlock_page(page);
4637fab479bSDave Kleikamp 	dec_io(page, last_write_complete);
4641ad53a98SDave Kleikamp err_out:
4651ad53a98SDave Kleikamp 	while (bad_blocks--)
4661ad53a98SDave Kleikamp 		dec_io(page, last_write_complete);
4677fab479bSDave Kleikamp 	return -EIO;
4687fab479bSDave Kleikamp }
4697fab479bSDave Kleikamp 
metapage_read_folio(struct file * fp,struct folio * folio)470bb8e283aSMatthew Wilcox (Oracle) static int metapage_read_folio(struct file *fp, struct folio *folio)
4717fab479bSDave Kleikamp {
472bb8e283aSMatthew Wilcox (Oracle) 	struct page *page = &folio->page;
4737fab479bSDave Kleikamp 	struct inode *inode = page->mapping->host;
4747fab479bSDave Kleikamp 	struct bio *bio = NULL;
475967c9ec4SDave Kleikamp 	int block_offset;
47624addd84SMatthew Wilcox (Oracle) 	int blocks_per_page = i_blocks_per_page(inode, page);
4777fab479bSDave Kleikamp 	sector_t page_start;	/* address of page in fs blocks */
4787fab479bSDave Kleikamp 	sector_t pblock;
479967c9ec4SDave Kleikamp 	int xlen;
4807fab479bSDave Kleikamp 	unsigned int len;
481967c9ec4SDave Kleikamp 	int offset;
4827fab479bSDave Kleikamp 
4837fab479bSDave Kleikamp 	BUG_ON(!PageLocked(page));
4847fab479bSDave Kleikamp 	page_start = (sector_t)page->index <<
48509cbfeafSKirill A. Shutemov 		     (PAGE_SHIFT - inode->i_blkbits);
4867fab479bSDave Kleikamp 
4877fab479bSDave Kleikamp 	block_offset = 0;
4887fab479bSDave Kleikamp 	while (block_offset < blocks_per_page) {
4897fab479bSDave Kleikamp 		xlen = blocks_per_page - block_offset;
4907fab479bSDave Kleikamp 		pblock = metapage_get_blocks(inode, page_start + block_offset,
4917fab479bSDave Kleikamp 					     &xlen);
4927fab479bSDave Kleikamp 		if (pblock) {
4937fab479bSDave Kleikamp 			if (!PagePrivate(page))
4947fab479bSDave Kleikamp 				insert_metapage(page, NULL);
4957fab479bSDave Kleikamp 			inc_io(page);
4967fab479bSDave Kleikamp 			if (bio)
4974e49ea4aSMike Christie 				submit_bio(bio);
4987fab479bSDave Kleikamp 
49907888c66SChristoph Hellwig 			bio = bio_alloc(inode->i_sb->s_bdev, 1, REQ_OP_READ,
50007888c66SChristoph Hellwig 					GFP_NOFS);
5014f024f37SKent Overstreet 			bio->bi_iter.bi_sector =
5024f024f37SKent Overstreet 				pblock << (inode->i_blkbits - 9);
5037fab479bSDave Kleikamp 			bio->bi_end_io = metapage_read_end_io;
5047fab479bSDave Kleikamp 			bio->bi_private = page;
5057fab479bSDave Kleikamp 			len = xlen << inode->i_blkbits;
5067fab479bSDave Kleikamp 			offset = block_offset << inode->i_blkbits;
5077fab479bSDave Kleikamp 			if (bio_add_page(bio, page, len, offset) < len)
5087fab479bSDave Kleikamp 				goto add_failed;
5097fab479bSDave Kleikamp 			block_offset += xlen;
5107fab479bSDave Kleikamp 		} else
5117fab479bSDave Kleikamp 			block_offset++;
5127fab479bSDave Kleikamp 	}
5137fab479bSDave Kleikamp 	if (bio)
5144e49ea4aSMike Christie 		submit_bio(bio);
5157fab479bSDave Kleikamp 	else
5167fab479bSDave Kleikamp 		unlock_page(page);
5177fab479bSDave Kleikamp 
5187fab479bSDave Kleikamp 	return 0;
5197fab479bSDave Kleikamp 
5207fab479bSDave Kleikamp add_failed:
5217fab479bSDave Kleikamp 	printk(KERN_ERR "JFS: bio_add_page failed unexpectedly\n");
5227fab479bSDave Kleikamp 	bio_put(bio);
5237fab479bSDave Kleikamp 	dec_io(page, last_read_complete);
5247fab479bSDave Kleikamp 	return -EIO;
5257fab479bSDave Kleikamp }
5267fab479bSDave Kleikamp 
metapage_release_folio(struct folio * folio,gfp_t gfp_mask)527a613b861SMatthew Wilcox (Oracle) static bool metapage_release_folio(struct folio *folio, gfp_t gfp_mask)
5287fab479bSDave Kleikamp {
5297fab479bSDave Kleikamp 	struct metapage *mp;
530a613b861SMatthew Wilcox (Oracle) 	bool ret = true;
531967c9ec4SDave Kleikamp 	int offset;
5327fab479bSDave Kleikamp 
53309cbfeafSKirill A. Shutemov 	for (offset = 0; offset < PAGE_SIZE; offset += PSIZE) {
534a613b861SMatthew Wilcox (Oracle) 		mp = page_to_mp(&folio->page, offset);
5357fab479bSDave Kleikamp 
5367fab479bSDave Kleikamp 		if (!mp)
5377fab479bSDave Kleikamp 			continue;
5387fab479bSDave Kleikamp 
539a613b861SMatthew Wilcox (Oracle) 		jfs_info("metapage_release_folio: mp = 0x%p", mp);
540b964638fSDave Kleikamp 		if (mp->count || mp->nohomeok ||
541b964638fSDave Kleikamp 		    test_bit(META_dirty, &mp->flag)) {
5427fab479bSDave Kleikamp 			jfs_info("count = %ld, nohomeok = %d", mp->count,
5437fab479bSDave Kleikamp 				 mp->nohomeok);
544a613b861SMatthew Wilcox (Oracle) 			ret = false;
5457fab479bSDave Kleikamp 			continue;
5467fab479bSDave Kleikamp 		}
5477fab479bSDave Kleikamp 		if (mp->lsn)
5487fab479bSDave Kleikamp 			remove_from_logsync(mp);
549a613b861SMatthew Wilcox (Oracle) 		remove_metapage(&folio->page, mp);
5507fab479bSDave Kleikamp 		INCREMENT(mpStat.pagefree);
5517fab479bSDave Kleikamp 		free_metapage(mp);
5527fab479bSDave Kleikamp 	}
553b964638fSDave Kleikamp 	return ret;
5547fab479bSDave Kleikamp }
5557fab479bSDave Kleikamp 
metapage_invalidate_folio(struct folio * folio,size_t offset,size_t length)556c5b56b50SMatthew Wilcox (Oracle) static void metapage_invalidate_folio(struct folio *folio, size_t offset,
557c5b56b50SMatthew Wilcox (Oracle) 				    size_t length)
5587fab479bSDave Kleikamp {
559c5b56b50SMatthew Wilcox (Oracle) 	BUG_ON(offset || length < folio_size(folio));
5607fab479bSDave Kleikamp 
561c5b56b50SMatthew Wilcox (Oracle) 	BUG_ON(folio_test_writeback(folio));
5627fab479bSDave Kleikamp 
563a613b861SMatthew Wilcox (Oracle) 	metapage_release_folio(folio, 0);
5647fab479bSDave Kleikamp }
5657fab479bSDave Kleikamp 
566f5e54d6eSChristoph Hellwig const struct address_space_operations jfs_metapage_aops = {
567bb8e283aSMatthew Wilcox (Oracle) 	.read_folio	= metapage_read_folio,
5687fab479bSDave Kleikamp 	.writepage	= metapage_writepage,
569a613b861SMatthew Wilcox (Oracle) 	.release_folio	= metapage_release_folio,
570c5b56b50SMatthew Wilcox (Oracle) 	.invalidate_folio = metapage_invalidate_folio,
571187c82cbSMatthew Wilcox (Oracle) 	.dirty_folio	= filemap_dirty_folio,
5727fab479bSDave Kleikamp };
5731da177e4SLinus Torvalds 
__get_metapage(struct inode * inode,unsigned long lblock,unsigned int size,int absolute,unsigned long new)5741da177e4SLinus Torvalds struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
5751da177e4SLinus Torvalds 				unsigned int size, int absolute,
5761da177e4SLinus Torvalds 				unsigned long new)
5771da177e4SLinus Torvalds {
5781da177e4SLinus Torvalds 	int l2BlocksPerPage;
5791da177e4SLinus Torvalds 	int l2bsize;
5801da177e4SLinus Torvalds 	struct address_space *mapping;
5817fab479bSDave Kleikamp 	struct metapage *mp = NULL;
5827fab479bSDave Kleikamp 	struct page *page;
5831da177e4SLinus Torvalds 	unsigned long page_index;
5841da177e4SLinus Torvalds 	unsigned long page_offset;
5851da177e4SLinus Torvalds 
5867fab479bSDave Kleikamp 	jfs_info("__get_metapage: ino = %ld, lblock = 0x%lx, abs=%d",
5877fab479bSDave Kleikamp 		 inode->i_ino, lblock, absolute);
5881da177e4SLinus Torvalds 
5897fab479bSDave Kleikamp 	l2bsize = inode->i_blkbits;
59009cbfeafSKirill A. Shutemov 	l2BlocksPerPage = PAGE_SHIFT - l2bsize;
5917fab479bSDave Kleikamp 	page_index = lblock >> l2BlocksPerPage;
5927fab479bSDave Kleikamp 	page_offset = (lblock - (page_index << l2BlocksPerPage)) << l2bsize;
59309cbfeafSKirill A. Shutemov 	if ((page_offset + size) > PAGE_SIZE) {
5947fab479bSDave Kleikamp 		jfs_err("MetaData crosses page boundary!!");
5957fab479bSDave Kleikamp 		jfs_err("lblock = %lx, size  = %d", lblock, size);
5967fab479bSDave Kleikamp 		dump_stack();
5977fab479bSDave Kleikamp 		return NULL;
5987fab479bSDave Kleikamp 	}
5991da177e4SLinus Torvalds 	if (absolute)
6007fab479bSDave Kleikamp 		mapping = JFS_SBI(inode->i_sb)->direct_inode->i_mapping;
6011da177e4SLinus Torvalds 	else {
6021da177e4SLinus Torvalds 		/*
6031da177e4SLinus Torvalds 		 * If an nfs client tries to read an inode that is larger
6041da177e4SLinus Torvalds 		 * than any existing inodes, we may try to read past the
6051da177e4SLinus Torvalds 		 * end of the inode map
6061da177e4SLinus Torvalds 		 */
6071da177e4SLinus Torvalds 		if ((lblock << inode->i_blkbits) >= inode->i_size)
6081da177e4SLinus Torvalds 			return NULL;
6091da177e4SLinus Torvalds 		mapping = inode->i_mapping;
6101da177e4SLinus Torvalds 	}
6111da177e4SLinus Torvalds 
61209cbfeafSKirill A. Shutemov 	if (new && (PSIZE == PAGE_SIZE)) {
6137fab479bSDave Kleikamp 		page = grab_cache_page(mapping, page_index);
6147fab479bSDave Kleikamp 		if (!page) {
6157fab479bSDave Kleikamp 			jfs_err("grab_cache_page failed!");
6167fab479bSDave Kleikamp 			return NULL;
6177fab479bSDave Kleikamp 		}
6187fab479bSDave Kleikamp 		SetPageUptodate(page);
6197fab479bSDave Kleikamp 	} else {
620090d2b18SPekka Enberg 		page = read_mapping_page(mapping, page_index, NULL);
6213b60d53dSMatthew Wilcox (Oracle) 		if (IS_ERR(page)) {
622090d2b18SPekka Enberg 			jfs_err("read_mapping_page failed!");
6237fab479bSDave Kleikamp 			return NULL;
6247fab479bSDave Kleikamp 		}
6257fab479bSDave Kleikamp 		lock_page(page);
6267fab479bSDave Kleikamp 	}
6277fab479bSDave Kleikamp 
6287fab479bSDave Kleikamp 	mp = page_to_mp(page, page_offset);
6291da177e4SLinus Torvalds 	if (mp) {
6307fab479bSDave Kleikamp 		if (mp->logical_size != size) {
6317fab479bSDave Kleikamp 			jfs_error(inode->i_sb,
632eb8630d7SJoe Perches 				  "get_mp->logical_size != size\n");
6337fab479bSDave Kleikamp 			jfs_err("logical_size = %d, size = %d",
6347fab479bSDave Kleikamp 				mp->logical_size, size);
6357fab479bSDave Kleikamp 			dump_stack();
6367fab479bSDave Kleikamp 			goto unlock;
6371da177e4SLinus Torvalds 		}
6381da177e4SLinus Torvalds 		mp->count++;
6391da177e4SLinus Torvalds 		lock_metapage(mp);
6401da177e4SLinus Torvalds 		if (test_bit(META_discard, &mp->flag)) {
6411da177e4SLinus Torvalds 			if (!new) {
6421da177e4SLinus Torvalds 				jfs_error(inode->i_sb,
643eb8630d7SJoe Perches 					  "using a discarded metapage\n");
6447fab479bSDave Kleikamp 				discard_metapage(mp);
6457fab479bSDave Kleikamp 				goto unlock;
6461da177e4SLinus Torvalds 			}
6471da177e4SLinus Torvalds 			clear_bit(META_discard, &mp->flag);
6481da177e4SLinus Torvalds 		}
6491da177e4SLinus Torvalds 	} else {
6507fab479bSDave Kleikamp 		INCREMENT(mpStat.pagealloc);
6511da177e4SLinus Torvalds 		mp = alloc_metapage(GFP_NOFS);
65288a96fa8SJuerg Haefliger 		if (!mp)
65388a96fa8SJuerg Haefliger 			goto unlock;
6547fab479bSDave Kleikamp 		mp->page = page;
65511ab8319SDave Kleikamp 		mp->sb = inode->i_sb;
6561da177e4SLinus Torvalds 		mp->flag = 0;
6571da177e4SLinus Torvalds 		mp->xflag = COMMIT_PAGE;
6581da177e4SLinus Torvalds 		mp->count = 1;
6597fab479bSDave Kleikamp 		mp->nohomeok = 0;
6601da177e4SLinus Torvalds 		mp->logical_size = size;
6617fab479bSDave Kleikamp 		mp->data = page_address(page) + page_offset;
6627fab479bSDave Kleikamp 		mp->index = lblock;
6637fab479bSDave Kleikamp 		if (unlikely(insert_metapage(page, mp))) {
6647fab479bSDave Kleikamp 			free_metapage(mp);
6657fab479bSDave Kleikamp 			goto unlock;
6667fab479bSDave Kleikamp 		}
6677fab479bSDave Kleikamp 		lock_metapage(mp);
6687fab479bSDave Kleikamp 	}
6691da177e4SLinus Torvalds 
6701da177e4SLinus Torvalds 	if (new) {
6717fab479bSDave Kleikamp 		jfs_info("zeroing mp = 0x%p", mp);
6721da177e4SLinus Torvalds 		memset(mp->data, 0, PSIZE);
6737fab479bSDave Kleikamp 	}
6741da177e4SLinus Torvalds 
6757fab479bSDave Kleikamp 	unlock_page(page);
6767fab479bSDave Kleikamp 	jfs_info("__get_metapage: returning = 0x%p data = 0x%p", mp, mp->data);
6771da177e4SLinus Torvalds 	return mp;
6781da177e4SLinus Torvalds 
6797fab479bSDave Kleikamp unlock:
6807fab479bSDave Kleikamp 	unlock_page(page);
6811da177e4SLinus Torvalds 	return NULL;
6821da177e4SLinus Torvalds }
6831da177e4SLinus Torvalds 
grab_metapage(struct metapage * mp)6847fab479bSDave Kleikamp void grab_metapage(struct metapage * mp)
6851da177e4SLinus Torvalds {
6867fab479bSDave Kleikamp 	jfs_info("grab_metapage: mp = 0x%p", mp);
68709cbfeafSKirill A. Shutemov 	get_page(mp->page);
6881da177e4SLinus Torvalds 	lock_page(mp->page);
6897fab479bSDave Kleikamp 	mp->count++;
6907fab479bSDave Kleikamp 	lock_metapage(mp);
6911da177e4SLinus Torvalds 	unlock_page(mp->page);
6921da177e4SLinus Torvalds }
6931da177e4SLinus Torvalds 
metapage_write_one(struct page * page)694*2d683175SChristoph Hellwig static int metapage_write_one(struct page *page)
695*2d683175SChristoph Hellwig {
696*2d683175SChristoph Hellwig 	struct folio *folio = page_folio(page);
697*2d683175SChristoph Hellwig 	struct address_space *mapping = folio->mapping;
698*2d683175SChristoph Hellwig 	struct writeback_control wbc = {
699*2d683175SChristoph Hellwig 		.sync_mode = WB_SYNC_ALL,
700*2d683175SChristoph Hellwig 		.nr_to_write = folio_nr_pages(folio),
701*2d683175SChristoph Hellwig 	};
702*2d683175SChristoph Hellwig 	int ret = 0;
703*2d683175SChristoph Hellwig 
704*2d683175SChristoph Hellwig 	BUG_ON(!folio_test_locked(folio));
705*2d683175SChristoph Hellwig 
706*2d683175SChristoph Hellwig 	folio_wait_writeback(folio);
707*2d683175SChristoph Hellwig 
708*2d683175SChristoph Hellwig 	if (folio_clear_dirty_for_io(folio)) {
709*2d683175SChristoph Hellwig 		folio_get(folio);
710*2d683175SChristoph Hellwig 		ret = metapage_writepage(page, &wbc);
711*2d683175SChristoph Hellwig 		if (ret == 0)
712*2d683175SChristoph Hellwig 			folio_wait_writeback(folio);
713*2d683175SChristoph Hellwig 		folio_put(folio);
714*2d683175SChristoph Hellwig 	} else {
715*2d683175SChristoph Hellwig 		folio_unlock(folio);
716*2d683175SChristoph Hellwig 	}
717*2d683175SChristoph Hellwig 
718*2d683175SChristoph Hellwig 	if (!ret)
719*2d683175SChristoph Hellwig 		ret = filemap_check_errors(mapping);
720*2d683175SChristoph Hellwig 	return ret;
721*2d683175SChristoph Hellwig }
722*2d683175SChristoph Hellwig 
force_metapage(struct metapage * mp)7237fab479bSDave Kleikamp void force_metapage(struct metapage *mp)
7241da177e4SLinus Torvalds {
7251da177e4SLinus Torvalds 	struct page *page = mp->page;
7267fab479bSDave Kleikamp 	jfs_info("force_metapage: mp = 0x%p", mp);
7277fab479bSDave Kleikamp 	set_bit(META_forcewrite, &mp->flag);
7287fab479bSDave Kleikamp 	clear_bit(META_sync, &mp->flag);
72909cbfeafSKirill A. Shutemov 	get_page(page);
7301da177e4SLinus Torvalds 	lock_page(page);
7317fab479bSDave Kleikamp 	set_page_dirty(page);
732*2d683175SChristoph Hellwig 	if (metapage_write_one(page))
733*2d683175SChristoph Hellwig 		jfs_error(mp->sb, "metapage_write_one() failed\n");
7347fab479bSDave Kleikamp 	clear_bit(META_forcewrite, &mp->flag);
73509cbfeafSKirill A. Shutemov 	put_page(page);
7361da177e4SLinus Torvalds }
7371da177e4SLinus Torvalds 
hold_metapage(struct metapage * mp)7381868f4aaSDave Kleikamp void hold_metapage(struct metapage *mp)
7397fab479bSDave Kleikamp {
7407fab479bSDave Kleikamp 	lock_page(mp->page);
7417fab479bSDave Kleikamp }
7427fab479bSDave Kleikamp 
put_metapage(struct metapage * mp)7431868f4aaSDave Kleikamp void put_metapage(struct metapage *mp)
7447fab479bSDave Kleikamp {
7457fab479bSDave Kleikamp 	if (mp->count || mp->nohomeok) {
7467fab479bSDave Kleikamp 		/* Someone else will release this */
7477fab479bSDave Kleikamp 		unlock_page(mp->page);
7487fab479bSDave Kleikamp 		return;
7497fab479bSDave Kleikamp 	}
75009cbfeafSKirill A. Shutemov 	get_page(mp->page);
7517fab479bSDave Kleikamp 	mp->count++;
7527fab479bSDave Kleikamp 	lock_metapage(mp);
7537fab479bSDave Kleikamp 	unlock_page(mp->page);
7547fab479bSDave Kleikamp 	release_metapage(mp);
7557fab479bSDave Kleikamp }
7567fab479bSDave Kleikamp 
release_metapage(struct metapage * mp)7571da177e4SLinus Torvalds void release_metapage(struct metapage * mp)
7581da177e4SLinus Torvalds {
7597fab479bSDave Kleikamp 	struct page *page = mp->page;
7601da177e4SLinus Torvalds 	jfs_info("release_metapage: mp = 0x%p, flag = 0x%lx", mp, mp->flag);
7611da177e4SLinus Torvalds 
7627fab479bSDave Kleikamp 	BUG_ON(!page);
7637fab479bSDave Kleikamp 
7647fab479bSDave Kleikamp 	lock_page(page);
7657fab479bSDave Kleikamp 	unlock_metapage(mp);
7661da177e4SLinus Torvalds 
7671da177e4SLinus Torvalds 	assert(mp->count);
7687fab479bSDave Kleikamp 	if (--mp->count || mp->nohomeok) {
7697fab479bSDave Kleikamp 		unlock_page(page);
77009cbfeafSKirill A. Shutemov 		put_page(page);
7711da177e4SLinus Torvalds 		return;
7721da177e4SLinus Torvalds 	}
7731da177e4SLinus Torvalds 
7747fab479bSDave Kleikamp 	if (test_bit(META_dirty, &mp->flag)) {
7757fab479bSDave Kleikamp 		set_page_dirty(page);
7761da177e4SLinus Torvalds 		if (test_bit(META_sync, &mp->flag)) {
7771da177e4SLinus Torvalds 			clear_bit(META_sync, &mp->flag);
778*2d683175SChristoph Hellwig 			if (metapage_write_one(page))
779*2d683175SChristoph Hellwig 				jfs_error(mp->sb, "metapage_write_one() failed\n");
780*2d683175SChristoph Hellwig 			lock_page(page);
7811da177e4SLinus Torvalds 		}
7827fab479bSDave Kleikamp 	} else if (mp->lsn)	/* discard_metapage doesn't remove it */
7837fab479bSDave Kleikamp 		remove_from_logsync(mp);
7841da177e4SLinus Torvalds 
7857fab479bSDave Kleikamp 	/* Try to keep metapages from using up too much memory */
7867fab479bSDave Kleikamp 	drop_metapage(page, mp);
787d0e671a9SDave Kleikamp 
7887fab479bSDave Kleikamp 	unlock_page(page);
78909cbfeafSKirill A. Shutemov 	put_page(page);
7901da177e4SLinus Torvalds }
7911da177e4SLinus Torvalds 
__invalidate_metapages(struct inode * ip,s64 addr,int len)7921da177e4SLinus Torvalds void __invalidate_metapages(struct inode *ip, s64 addr, int len)
7931da177e4SLinus Torvalds {
7947fab479bSDave Kleikamp 	sector_t lblock;
79509cbfeafSKirill A. Shutemov 	int l2BlocksPerPage = PAGE_SHIFT - ip->i_blkbits;
7967fab479bSDave Kleikamp 	int BlocksPerPage = 1 << l2BlocksPerPage;
7971da177e4SLinus Torvalds 	/* All callers are interested in block device's mapping */
7987fab479bSDave Kleikamp 	struct address_space *mapping =
7997fab479bSDave Kleikamp 		JFS_SBI(ip->i_sb)->direct_inode->i_mapping;
8001da177e4SLinus Torvalds 	struct metapage *mp;
8011da177e4SLinus Torvalds 	struct page *page;
8027fab479bSDave Kleikamp 	unsigned int offset;
8031da177e4SLinus Torvalds 
8041da177e4SLinus Torvalds 	/*
8057fab479bSDave Kleikamp 	 * Mark metapages to discard.  They will eventually be
8061da177e4SLinus Torvalds 	 * released, but should not be written.
8071da177e4SLinus Torvalds 	 */
8087fab479bSDave Kleikamp 	for (lblock = addr & ~(BlocksPerPage - 1); lblock < addr + len;
8097fab479bSDave Kleikamp 	     lblock += BlocksPerPage) {
8107fab479bSDave Kleikamp 		page = find_lock_page(mapping, lblock >> l2BlocksPerPage);
8117fab479bSDave Kleikamp 		if (!page)
8127fab479bSDave Kleikamp 			continue;
81309cbfeafSKirill A. Shutemov 		for (offset = 0; offset < PAGE_SIZE; offset += PSIZE) {
8147fab479bSDave Kleikamp 			mp = page_to_mp(page, offset);
8157fab479bSDave Kleikamp 			if (!mp)
8167fab479bSDave Kleikamp 				continue;
8177fab479bSDave Kleikamp 			if (mp->index < addr)
8187fab479bSDave Kleikamp 				continue;
8197fab479bSDave Kleikamp 			if (mp->index >= addr + len)
8207fab479bSDave Kleikamp 				break;
8211da177e4SLinus Torvalds 
8221da177e4SLinus Torvalds 			clear_bit(META_dirty, &mp->flag);
8231da177e4SLinus Torvalds 			set_bit(META_discard, &mp->flag);
8247fab479bSDave Kleikamp 			if (mp->lsn)
8257fab479bSDave Kleikamp 				remove_from_logsync(mp);
8267fab479bSDave Kleikamp 		}
8271da177e4SLinus Torvalds 		unlock_page(page);
82809cbfeafSKirill A. Shutemov 		put_page(page);
8291da177e4SLinus Torvalds 	}
8301da177e4SLinus Torvalds }
8311da177e4SLinus Torvalds 
8321da177e4SLinus Torvalds #ifdef CONFIG_JFS_STATISTICS
jfs_mpstat_proc_show(struct seq_file * m,void * v)83307a3b8edSChristoph Hellwig int jfs_mpstat_proc_show(struct seq_file *m, void *v)
8341da177e4SLinus Torvalds {
835b2e03ca7SAlexey Dobriyan 	seq_printf(m,
8361da177e4SLinus Torvalds 		       "JFS Metapage statistics\n"
8371da177e4SLinus Torvalds 		       "=======================\n"
8381da177e4SLinus Torvalds 		       "page allocations = %d\n"
8391da177e4SLinus Torvalds 		       "page frees = %d\n"
8401da177e4SLinus Torvalds 		       "lock waits = %d\n",
8411da177e4SLinus Torvalds 		       mpStat.pagealloc,
8421da177e4SLinus Torvalds 		       mpStat.pagefree,
8431da177e4SLinus Torvalds 		       mpStat.lockwait);
844b2e03ca7SAlexey Dobriyan 	return 0;
8451da177e4SLinus Torvalds }
8461da177e4SLinus Torvalds #endif
847