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