1ae98043fSRyusuke Konishi // SPDX-License-Identifier: GPL-2.0+ 20bd49f94SRyusuke Konishi /* 394ee1d91SRyusuke Konishi * Buffer/page management specific to NILFS 40bd49f94SRyusuke Konishi * 50bd49f94SRyusuke Konishi * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation. 60bd49f94SRyusuke Konishi * 74b420ab4SRyusuke Konishi * Written by Ryusuke Konishi and Seiji Kihara. 80bd49f94SRyusuke Konishi */ 90bd49f94SRyusuke Konishi 100bd49f94SRyusuke Konishi #include <linux/pagemap.h> 110bd49f94SRyusuke Konishi #include <linux/writeback.h> 120bd49f94SRyusuke Konishi #include <linux/swap.h> 130bd49f94SRyusuke Konishi #include <linux/bitops.h> 140bd49f94SRyusuke Konishi #include <linux/page-flags.h> 150bd49f94SRyusuke Konishi #include <linux/list.h> 160bd49f94SRyusuke Konishi #include <linux/highmem.h> 170bd49f94SRyusuke Konishi #include <linux/pagevec.h> 185a0e3ad6STejun Heo #include <linux/gfp.h> 190bd49f94SRyusuke Konishi #include "nilfs.h" 200bd49f94SRyusuke Konishi #include "page.h" 210bd49f94SRyusuke Konishi #include "mdt.h" 220bd49f94SRyusuke Konishi 230bd49f94SRyusuke Konishi 240bd49f94SRyusuke Konishi #define NILFS_BUFFER_INHERENT_BITS \ 254ce5c342SRyusuke Konishi (BIT(BH_Uptodate) | BIT(BH_Mapped) | BIT(BH_NILFS_Node) | \ 264ce5c342SRyusuke Konishi BIT(BH_NILFS_Volatile) | BIT(BH_NILFS_Checked)) 270bd49f94SRyusuke Konishi 280bd49f94SRyusuke Konishi static struct buffer_head * 290bd49f94SRyusuke Konishi __nilfs_get_page_block(struct page *page, unsigned long block, pgoff_t index, 300bd49f94SRyusuke Konishi int blkbits, unsigned long b_state) 310bd49f94SRyusuke Konishi 320bd49f94SRyusuke Konishi { 330bd49f94SRyusuke Konishi unsigned long first_block; 340bd49f94SRyusuke Konishi struct buffer_head *bh; 350bd49f94SRyusuke Konishi 360bd49f94SRyusuke Konishi if (!page_has_buffers(page)) 370bd49f94SRyusuke Konishi create_empty_buffers(page, 1 << blkbits, b_state); 380bd49f94SRyusuke Konishi 3909cbfeafSKirill A. Shutemov first_block = (unsigned long)index << (PAGE_SHIFT - blkbits); 400bd49f94SRyusuke Konishi bh = nilfs_page_get_nth_block(page, block - first_block); 410bd49f94SRyusuke Konishi 420bd49f94SRyusuke Konishi touch_buffer(bh); 430bd49f94SRyusuke Konishi wait_on_buffer(bh); 440bd49f94SRyusuke Konishi return bh; 450bd49f94SRyusuke Konishi } 460bd49f94SRyusuke Konishi 470bd49f94SRyusuke Konishi struct buffer_head *nilfs_grab_buffer(struct inode *inode, 480bd49f94SRyusuke Konishi struct address_space *mapping, 490bd49f94SRyusuke Konishi unsigned long blkoff, 500bd49f94SRyusuke Konishi unsigned long b_state) 510bd49f94SRyusuke Konishi { 520bd49f94SRyusuke Konishi int blkbits = inode->i_blkbits; 5309cbfeafSKirill A. Shutemov pgoff_t index = blkoff >> (PAGE_SHIFT - blkbits); 54c1c1d709SRyusuke Konishi struct page *page; 55c1c1d709SRyusuke Konishi struct buffer_head *bh; 560bd49f94SRyusuke Konishi 570bd49f94SRyusuke Konishi page = grab_cache_page(mapping, index); 580bd49f94SRyusuke Konishi if (unlikely(!page)) 590bd49f94SRyusuke Konishi return NULL; 600bd49f94SRyusuke Konishi 610bd49f94SRyusuke Konishi bh = __nilfs_get_page_block(page, blkoff, index, blkbits, b_state); 620bd49f94SRyusuke Konishi if (unlikely(!bh)) { 630bd49f94SRyusuke Konishi unlock_page(page); 6409cbfeafSKirill A. Shutemov put_page(page); 650bd49f94SRyusuke Konishi return NULL; 660bd49f94SRyusuke Konishi } 670bd49f94SRyusuke Konishi return bh; 680bd49f94SRyusuke Konishi } 690bd49f94SRyusuke Konishi 700bd49f94SRyusuke Konishi /** 710bd49f94SRyusuke Konishi * nilfs_forget_buffer - discard dirty state 720bd49f94SRyusuke Konishi * @bh: buffer head of the buffer to be discarded 730bd49f94SRyusuke Konishi */ 740bd49f94SRyusuke Konishi void nilfs_forget_buffer(struct buffer_head *bh) 750bd49f94SRyusuke Konishi { 760bd49f94SRyusuke Konishi struct page *page = bh->b_page; 77ead8ecffSRyusuke Konishi const unsigned long clear_bits = 784ce5c342SRyusuke Konishi (BIT(BH_Uptodate) | BIT(BH_Dirty) | BIT(BH_Mapped) | 794ce5c342SRyusuke Konishi BIT(BH_Async_Write) | BIT(BH_NILFS_Volatile) | 804ce5c342SRyusuke Konishi BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected)); 810bd49f94SRyusuke Konishi 820bd49f94SRyusuke Konishi lock_buffer(bh); 83ead8ecffSRyusuke Konishi set_mask_bits(&bh->b_state, clear_bits, 0); 8484338237SRyusuke Konishi if (nilfs_page_buffers_clean(page)) 850bd49f94SRyusuke Konishi __nilfs_clear_page_dirty(page); 860bd49f94SRyusuke Konishi 870bd49f94SRyusuke Konishi bh->b_blocknr = -1; 880bd49f94SRyusuke Konishi ClearPageUptodate(page); 890bd49f94SRyusuke Konishi ClearPageMappedToDisk(page); 900bd49f94SRyusuke Konishi unlock_buffer(bh); 910bd49f94SRyusuke Konishi brelse(bh); 920bd49f94SRyusuke Konishi } 930bd49f94SRyusuke Konishi 940bd49f94SRyusuke Konishi /** 950bd49f94SRyusuke Konishi * nilfs_copy_buffer -- copy buffer data and flags 960bd49f94SRyusuke Konishi * @dbh: destination buffer 970bd49f94SRyusuke Konishi * @sbh: source buffer 980bd49f94SRyusuke Konishi */ 990bd49f94SRyusuke Konishi void nilfs_copy_buffer(struct buffer_head *dbh, struct buffer_head *sbh) 1000bd49f94SRyusuke Konishi { 1010bd49f94SRyusuke Konishi void *kaddr0, *kaddr1; 1020bd49f94SRyusuke Konishi unsigned long bits; 1030bd49f94SRyusuke Konishi struct page *spage = sbh->b_page, *dpage = dbh->b_page; 1040bd49f94SRyusuke Konishi struct buffer_head *bh; 1050bd49f94SRyusuke Konishi 1067b9c0976SCong Wang kaddr0 = kmap_atomic(spage); 1077b9c0976SCong Wang kaddr1 = kmap_atomic(dpage); 1080bd49f94SRyusuke Konishi memcpy(kaddr1 + bh_offset(dbh), kaddr0 + bh_offset(sbh), sbh->b_size); 1097b9c0976SCong Wang kunmap_atomic(kaddr1); 1107b9c0976SCong Wang kunmap_atomic(kaddr0); 1110bd49f94SRyusuke Konishi 1120bd49f94SRyusuke Konishi dbh->b_state = sbh->b_state & NILFS_BUFFER_INHERENT_BITS; 1130bd49f94SRyusuke Konishi dbh->b_blocknr = sbh->b_blocknr; 1140bd49f94SRyusuke Konishi dbh->b_bdev = sbh->b_bdev; 1150bd49f94SRyusuke Konishi 1160bd49f94SRyusuke Konishi bh = dbh; 1174ce5c342SRyusuke Konishi bits = sbh->b_state & (BIT(BH_Uptodate) | BIT(BH_Mapped)); 1180bd49f94SRyusuke Konishi while ((bh = bh->b_this_page) != dbh) { 1190bd49f94SRyusuke Konishi lock_buffer(bh); 1200bd49f94SRyusuke Konishi bits &= bh->b_state; 1210bd49f94SRyusuke Konishi unlock_buffer(bh); 1220bd49f94SRyusuke Konishi } 1234ce5c342SRyusuke Konishi if (bits & BIT(BH_Uptodate)) 1240bd49f94SRyusuke Konishi SetPageUptodate(dpage); 1250bd49f94SRyusuke Konishi else 1260bd49f94SRyusuke Konishi ClearPageUptodate(dpage); 1274ce5c342SRyusuke Konishi if (bits & BIT(BH_Mapped)) 1280bd49f94SRyusuke Konishi SetPageMappedToDisk(dpage); 1290bd49f94SRyusuke Konishi else 1300bd49f94SRyusuke Konishi ClearPageMappedToDisk(dpage); 1310bd49f94SRyusuke Konishi } 1320bd49f94SRyusuke Konishi 1330bd49f94SRyusuke Konishi /** 1340bd49f94SRyusuke Konishi * nilfs_page_buffers_clean - check if a page has dirty buffers or not. 1350bd49f94SRyusuke Konishi * @page: page to be checked 1360bd49f94SRyusuke Konishi * 1370bd49f94SRyusuke Konishi * nilfs_page_buffers_clean() returns zero if the page has dirty buffers. 1380bd49f94SRyusuke Konishi * Otherwise, it returns non-zero value. 1390bd49f94SRyusuke Konishi */ 1400bd49f94SRyusuke Konishi int nilfs_page_buffers_clean(struct page *page) 1410bd49f94SRyusuke Konishi { 1420bd49f94SRyusuke Konishi struct buffer_head *bh, *head; 1430bd49f94SRyusuke Konishi 1440bd49f94SRyusuke Konishi bh = head = page_buffers(page); 1450bd49f94SRyusuke Konishi do { 1460bd49f94SRyusuke Konishi if (buffer_dirty(bh)) 1470bd49f94SRyusuke Konishi return 0; 1480bd49f94SRyusuke Konishi bh = bh->b_this_page; 1490bd49f94SRyusuke Konishi } while (bh != head); 1500bd49f94SRyusuke Konishi return 1; 1510bd49f94SRyusuke Konishi } 1520bd49f94SRyusuke Konishi 1530bd49f94SRyusuke Konishi void nilfs_page_bug(struct page *page) 1540bd49f94SRyusuke Konishi { 1550bd49f94SRyusuke Konishi struct address_space *m; 156aa405b1fSRyusuke Konishi unsigned long ino; 1570bd49f94SRyusuke Konishi 1580bd49f94SRyusuke Konishi if (unlikely(!page)) { 1590bd49f94SRyusuke Konishi printk(KERN_CRIT "NILFS_PAGE_BUG(NULL)\n"); 1600bd49f94SRyusuke Konishi return; 1610bd49f94SRyusuke Konishi } 1620bd49f94SRyusuke Konishi 1630bd49f94SRyusuke Konishi m = page->mapping; 164aa405b1fSRyusuke Konishi ino = m ? m->host->i_ino : 0; 165aa405b1fSRyusuke Konishi 1660bd49f94SRyusuke Konishi printk(KERN_CRIT "NILFS_PAGE_BUG(%p): cnt=%d index#=%llu flags=0x%lx " 1670bd49f94SRyusuke Konishi "mapping=%p ino=%lu\n", 168fe896d18SJoonsoo Kim page, page_ref_count(page), 1690bd49f94SRyusuke Konishi (unsigned long long)page->index, page->flags, m, ino); 1700bd49f94SRyusuke Konishi 1710bd49f94SRyusuke Konishi if (page_has_buffers(page)) { 1720bd49f94SRyusuke Konishi struct buffer_head *bh, *head; 1730bd49f94SRyusuke Konishi int i = 0; 1740bd49f94SRyusuke Konishi 1750bd49f94SRyusuke Konishi bh = head = page_buffers(page); 1760bd49f94SRyusuke Konishi do { 1770bd49f94SRyusuke Konishi printk(KERN_CRIT 1780bd49f94SRyusuke Konishi " BH[%d] %p: cnt=%d block#=%llu state=0x%lx\n", 1790bd49f94SRyusuke Konishi i++, bh, atomic_read(&bh->b_count), 1800bd49f94SRyusuke Konishi (unsigned long long)bh->b_blocknr, bh->b_state); 1810bd49f94SRyusuke Konishi bh = bh->b_this_page; 1820bd49f94SRyusuke Konishi } while (bh != head); 1830bd49f94SRyusuke Konishi } 1840bd49f94SRyusuke Konishi } 1850bd49f94SRyusuke Konishi 1860bd49f94SRyusuke Konishi /** 1870bd49f94SRyusuke Konishi * nilfs_copy_page -- copy the page with buffers 1880bd49f94SRyusuke Konishi * @dst: destination page 1890bd49f94SRyusuke Konishi * @src: source page 1900bd49f94SRyusuke Konishi * @copy_dirty: flag whether to copy dirty states on the page's buffer heads. 1910bd49f94SRyusuke Konishi * 1927a65004bSRyusuke Konishi * This function is for both data pages and btnode pages. The dirty flag 1930bd49f94SRyusuke Konishi * should be treated by caller. The page must not be under i/o. 1940bd49f94SRyusuke Konishi * Both src and dst page must be locked 1950bd49f94SRyusuke Konishi */ 1960bd49f94SRyusuke Konishi static void nilfs_copy_page(struct page *dst, struct page *src, int copy_dirty) 1970bd49f94SRyusuke Konishi { 198e1ce8a97SColin Ian King struct buffer_head *dbh, *dbufs, *sbh; 1990bd49f94SRyusuke Konishi unsigned long mask = NILFS_BUFFER_INHERENT_BITS; 2000bd49f94SRyusuke Konishi 2010bd49f94SRyusuke Konishi BUG_ON(PageWriteback(dst)); 2020bd49f94SRyusuke Konishi 203e1ce8a97SColin Ian King sbh = page_buffers(src); 2040bd49f94SRyusuke Konishi if (!page_has_buffers(dst)) 2050bd49f94SRyusuke Konishi create_empty_buffers(dst, sbh->b_size, 0); 2060bd49f94SRyusuke Konishi 2070bd49f94SRyusuke Konishi if (copy_dirty) 2084ce5c342SRyusuke Konishi mask |= BIT(BH_Dirty); 2090bd49f94SRyusuke Konishi 2100bd49f94SRyusuke Konishi dbh = dbufs = page_buffers(dst); 2110bd49f94SRyusuke Konishi do { 2120bd49f94SRyusuke Konishi lock_buffer(sbh); 2130bd49f94SRyusuke Konishi lock_buffer(dbh); 2140bd49f94SRyusuke Konishi dbh->b_state = sbh->b_state & mask; 2150bd49f94SRyusuke Konishi dbh->b_blocknr = sbh->b_blocknr; 2160bd49f94SRyusuke Konishi dbh->b_bdev = sbh->b_bdev; 2170bd49f94SRyusuke Konishi sbh = sbh->b_this_page; 2180bd49f94SRyusuke Konishi dbh = dbh->b_this_page; 2190bd49f94SRyusuke Konishi } while (dbh != dbufs); 2200bd49f94SRyusuke Konishi 2210bd49f94SRyusuke Konishi copy_highpage(dst, src); 2220bd49f94SRyusuke Konishi 2230bd49f94SRyusuke Konishi if (PageUptodate(src) && !PageUptodate(dst)) 2240bd49f94SRyusuke Konishi SetPageUptodate(dst); 2250bd49f94SRyusuke Konishi else if (!PageUptodate(src) && PageUptodate(dst)) 2260bd49f94SRyusuke Konishi ClearPageUptodate(dst); 2270bd49f94SRyusuke Konishi if (PageMappedToDisk(src) && !PageMappedToDisk(dst)) 2280bd49f94SRyusuke Konishi SetPageMappedToDisk(dst); 2290bd49f94SRyusuke Konishi else if (!PageMappedToDisk(src) && PageMappedToDisk(dst)) 2300bd49f94SRyusuke Konishi ClearPageMappedToDisk(dst); 2310bd49f94SRyusuke Konishi 2320bd49f94SRyusuke Konishi do { 2330bd49f94SRyusuke Konishi unlock_buffer(sbh); 2340bd49f94SRyusuke Konishi unlock_buffer(dbh); 2350bd49f94SRyusuke Konishi sbh = sbh->b_this_page; 2360bd49f94SRyusuke Konishi dbh = dbh->b_this_page; 2370bd49f94SRyusuke Konishi } while (dbh != dbufs); 2380bd49f94SRyusuke Konishi } 2390bd49f94SRyusuke Konishi 2400bd49f94SRyusuke Konishi int nilfs_copy_dirty_pages(struct address_space *dmap, 2410bd49f94SRyusuke Konishi struct address_space *smap) 2420bd49f94SRyusuke Konishi { 2430bd49f94SRyusuke Konishi struct pagevec pvec; 2440bd49f94SRyusuke Konishi unsigned int i; 2450bd49f94SRyusuke Konishi pgoff_t index = 0; 2460bd49f94SRyusuke Konishi int err = 0; 2470bd49f94SRyusuke Konishi 24886679820SMel Gorman pagevec_init(&pvec); 2490bd49f94SRyusuke Konishi repeat: 25067fd707fSJan Kara if (!pagevec_lookup_tag(&pvec, smap, &index, PAGECACHE_TAG_DIRTY)) 2510bd49f94SRyusuke Konishi return 0; 2520bd49f94SRyusuke Konishi 2530bd49f94SRyusuke Konishi for (i = 0; i < pagevec_count(&pvec); i++) { 2540bd49f94SRyusuke Konishi struct page *page = pvec.pages[i], *dpage; 2550bd49f94SRyusuke Konishi 2560bd49f94SRyusuke Konishi lock_page(page); 2570bd49f94SRyusuke Konishi if (unlikely(!PageDirty(page))) 2580bd49f94SRyusuke Konishi NILFS_PAGE_BUG(page, "inconsistent dirty state"); 2590bd49f94SRyusuke Konishi 2600bd49f94SRyusuke Konishi dpage = grab_cache_page(dmap, page->index); 2610bd49f94SRyusuke Konishi if (unlikely(!dpage)) { 2620bd49f94SRyusuke Konishi /* No empty page is added to the page cache */ 2630bd49f94SRyusuke Konishi err = -ENOMEM; 2640bd49f94SRyusuke Konishi unlock_page(page); 2650bd49f94SRyusuke Konishi break; 2660bd49f94SRyusuke Konishi } 2670bd49f94SRyusuke Konishi if (unlikely(!page_has_buffers(page))) 2680bd49f94SRyusuke Konishi NILFS_PAGE_BUG(page, 2690bd49f94SRyusuke Konishi "found empty page in dat page cache"); 2700bd49f94SRyusuke Konishi 2710bd49f94SRyusuke Konishi nilfs_copy_page(dpage, page, 1); 2720bd49f94SRyusuke Konishi __set_page_dirty_nobuffers(dpage); 2730bd49f94SRyusuke Konishi 2740bd49f94SRyusuke Konishi unlock_page(dpage); 27509cbfeafSKirill A. Shutemov put_page(dpage); 2760bd49f94SRyusuke Konishi unlock_page(page); 2770bd49f94SRyusuke Konishi } 2780bd49f94SRyusuke Konishi pagevec_release(&pvec); 2790bd49f94SRyusuke Konishi cond_resched(); 2800bd49f94SRyusuke Konishi 2810bd49f94SRyusuke Konishi if (likely(!err)) 2820bd49f94SRyusuke Konishi goto repeat; 2830bd49f94SRyusuke Konishi return err; 2840bd49f94SRyusuke Konishi } 2850bd49f94SRyusuke Konishi 2860bd49f94SRyusuke Konishi /** 2877a65004bSRyusuke Konishi * nilfs_copy_back_pages -- copy back pages to original cache from shadow cache 2880bd49f94SRyusuke Konishi * @dmap: destination page cache 2890bd49f94SRyusuke Konishi * @smap: source page cache 2900bd49f94SRyusuke Konishi * 291f611ff63SMatthew Wilcox * No pages must be added to the cache during this process. 2920bd49f94SRyusuke Konishi * This must be ensured by the caller. 2930bd49f94SRyusuke Konishi */ 2940bd49f94SRyusuke Konishi void nilfs_copy_back_pages(struct address_space *dmap, 2950bd49f94SRyusuke Konishi struct address_space *smap) 2960bd49f94SRyusuke Konishi { 297f6e0e173SMatthew Wilcox (Oracle) struct folio_batch fbatch; 2980bd49f94SRyusuke Konishi unsigned int i, n; 299f6e0e173SMatthew Wilcox (Oracle) pgoff_t start = 0; 3000bd49f94SRyusuke Konishi 301f6e0e173SMatthew Wilcox (Oracle) folio_batch_init(&fbatch); 3020bd49f94SRyusuke Konishi repeat: 303f6e0e173SMatthew Wilcox (Oracle) n = filemap_get_folios(smap, &start, ~0UL, &fbatch); 3040bd49f94SRyusuke Konishi if (!n) 3050bd49f94SRyusuke Konishi return; 3060bd49f94SRyusuke Konishi 307f6e0e173SMatthew Wilcox (Oracle) for (i = 0; i < folio_batch_count(&fbatch); i++) { 308f6e0e173SMatthew Wilcox (Oracle) struct folio *folio = fbatch.folios[i], *dfolio; 309f6e0e173SMatthew Wilcox (Oracle) pgoff_t index = folio->index; 3100bd49f94SRyusuke Konishi 311f6e0e173SMatthew Wilcox (Oracle) folio_lock(folio); 312f6e0e173SMatthew Wilcox (Oracle) dfolio = filemap_lock_folio(dmap, index); 313f6e0e173SMatthew Wilcox (Oracle) if (dfolio) { 314f6e0e173SMatthew Wilcox (Oracle) /* overwrite existing folio in the destination cache */ 315f6e0e173SMatthew Wilcox (Oracle) WARN_ON(folio_test_dirty(dfolio)); 316f6e0e173SMatthew Wilcox (Oracle) nilfs_copy_page(&dfolio->page, &folio->page, 0); 317f6e0e173SMatthew Wilcox (Oracle) folio_unlock(dfolio); 318f6e0e173SMatthew Wilcox (Oracle) folio_put(dfolio); 319f6e0e173SMatthew Wilcox (Oracle) /* Do we not need to remove folio from smap here? */ 3200bd49f94SRyusuke Konishi } else { 321f6e0e173SMatthew Wilcox (Oracle) struct folio *f; 3220bd49f94SRyusuke Konishi 323f6e0e173SMatthew Wilcox (Oracle) /* move the folio to the destination cache */ 324b93b0163SMatthew Wilcox xa_lock_irq(&smap->i_pages); 325f6e0e173SMatthew Wilcox (Oracle) f = __xa_erase(&smap->i_pages, index); 326f6e0e173SMatthew Wilcox (Oracle) WARN_ON(folio != f); 3270bd49f94SRyusuke Konishi smap->nrpages--; 328b93b0163SMatthew Wilcox xa_unlock_irq(&smap->i_pages); 3290bd49f94SRyusuke Konishi 330b93b0163SMatthew Wilcox xa_lock_irq(&dmap->i_pages); 331f6e0e173SMatthew Wilcox (Oracle) f = __xa_store(&dmap->i_pages, index, folio, GFP_NOFS); 332f6e0e173SMatthew Wilcox (Oracle) if (unlikely(f)) { 333f611ff63SMatthew Wilcox /* Probably -ENOMEM */ 334f6e0e173SMatthew Wilcox (Oracle) folio->mapping = NULL; 335f6e0e173SMatthew Wilcox (Oracle) folio_put(folio); 3360bd49f94SRyusuke Konishi } else { 337f6e0e173SMatthew Wilcox (Oracle) folio->mapping = dmap; 3380bd49f94SRyusuke Konishi dmap->nrpages++; 339f6e0e173SMatthew Wilcox (Oracle) if (folio_test_dirty(folio)) 340f6e0e173SMatthew Wilcox (Oracle) __xa_set_mark(&dmap->i_pages, index, 3410bd49f94SRyusuke Konishi PAGECACHE_TAG_DIRTY); 3420bd49f94SRyusuke Konishi } 343b93b0163SMatthew Wilcox xa_unlock_irq(&dmap->i_pages); 3440bd49f94SRyusuke Konishi } 345f6e0e173SMatthew Wilcox (Oracle) folio_unlock(folio); 3460bd49f94SRyusuke Konishi } 347f6e0e173SMatthew Wilcox (Oracle) folio_batch_release(&fbatch); 3480bd49f94SRyusuke Konishi cond_resched(); 3490bd49f94SRyusuke Konishi 3500bd49f94SRyusuke Konishi goto repeat; 3510bd49f94SRyusuke Konishi } 3520bd49f94SRyusuke Konishi 3538c26c4e2SVyacheslav Dubeyko /** 3548c26c4e2SVyacheslav Dubeyko * nilfs_clear_dirty_pages - discard dirty pages in address space 3558c26c4e2SVyacheslav Dubeyko * @mapping: address space with dirty pages for discarding 3568c26c4e2SVyacheslav Dubeyko * @silent: suppress [true] or print [false] warning messages 3578c26c4e2SVyacheslav Dubeyko */ 3588c26c4e2SVyacheslav Dubeyko void nilfs_clear_dirty_pages(struct address_space *mapping, bool silent) 3590bd49f94SRyusuke Konishi { 3600bd49f94SRyusuke Konishi struct pagevec pvec; 3610bd49f94SRyusuke Konishi unsigned int i; 3620bd49f94SRyusuke Konishi pgoff_t index = 0; 3630bd49f94SRyusuke Konishi 36486679820SMel Gorman pagevec_init(&pvec); 3650bd49f94SRyusuke Konishi 36667fd707fSJan Kara while (pagevec_lookup_tag(&pvec, mapping, &index, 36767fd707fSJan Kara PAGECACHE_TAG_DIRTY)) { 3680bd49f94SRyusuke Konishi for (i = 0; i < pagevec_count(&pvec); i++) { 3690bd49f94SRyusuke Konishi struct page *page = pvec.pages[i]; 3700bd49f94SRyusuke Konishi 3710bd49f94SRyusuke Konishi lock_page(page); 3728c26c4e2SVyacheslav Dubeyko nilfs_clear_dirty_page(page, silent); 3738c26c4e2SVyacheslav Dubeyko unlock_page(page); 3748c26c4e2SVyacheslav Dubeyko } 3758c26c4e2SVyacheslav Dubeyko pagevec_release(&pvec); 3768c26c4e2SVyacheslav Dubeyko cond_resched(); 3778c26c4e2SVyacheslav Dubeyko } 3788c26c4e2SVyacheslav Dubeyko } 3798c26c4e2SVyacheslav Dubeyko 3808c26c4e2SVyacheslav Dubeyko /** 3818c26c4e2SVyacheslav Dubeyko * nilfs_clear_dirty_page - discard dirty page 3828c26c4e2SVyacheslav Dubeyko * @page: dirty page that will be discarded 3838c26c4e2SVyacheslav Dubeyko * @silent: suppress [true] or print [false] warning messages 3848c26c4e2SVyacheslav Dubeyko */ 3858c26c4e2SVyacheslav Dubeyko void nilfs_clear_dirty_page(struct page *page, bool silent) 3868c26c4e2SVyacheslav Dubeyko { 3878c26c4e2SVyacheslav Dubeyko struct inode *inode = page->mapping->host; 3888c26c4e2SVyacheslav Dubeyko struct super_block *sb = inode->i_sb; 3898c26c4e2SVyacheslav Dubeyko 390dc33f5f3SVyacheslav Dubeyko BUG_ON(!PageLocked(page)); 3918c26c4e2SVyacheslav Dubeyko 392d6517debSRyusuke Konishi if (!silent) 393a1d0747aSJoe Perches nilfs_warn(sb, "discard dirty page: offset=%lld, ino=%lu", 3948c26c4e2SVyacheslav Dubeyko page_offset(page), inode->i_ino); 3958c26c4e2SVyacheslav Dubeyko 3960bd49f94SRyusuke Konishi ClearPageUptodate(page); 3970bd49f94SRyusuke Konishi ClearPageMappedToDisk(page); 3988c26c4e2SVyacheslav Dubeyko 3998c26c4e2SVyacheslav Dubeyko if (page_has_buffers(page)) { 4008c26c4e2SVyacheslav Dubeyko struct buffer_head *bh, *head; 401ead8ecffSRyusuke Konishi const unsigned long clear_bits = 4024ce5c342SRyusuke Konishi (BIT(BH_Uptodate) | BIT(BH_Dirty) | BIT(BH_Mapped) | 4034ce5c342SRyusuke Konishi BIT(BH_Async_Write) | BIT(BH_NILFS_Volatile) | 4044ce5c342SRyusuke Konishi BIT(BH_NILFS_Checked) | BIT(BH_NILFS_Redirected)); 4058c26c4e2SVyacheslav Dubeyko 4060bd49f94SRyusuke Konishi bh = head = page_buffers(page); 4070bd49f94SRyusuke Konishi do { 4080bd49f94SRyusuke Konishi lock_buffer(bh); 409d6517debSRyusuke Konishi if (!silent) 410a1d0747aSJoe Perches nilfs_warn(sb, 411d6517debSRyusuke Konishi "discard dirty block: blocknr=%llu, size=%zu", 4128c26c4e2SVyacheslav Dubeyko (u64)bh->b_blocknr, bh->b_size); 413d6517debSRyusuke Konishi 414ead8ecffSRyusuke Konishi set_mask_bits(&bh->b_state, clear_bits, 0); 4150bd49f94SRyusuke Konishi unlock_buffer(bh); 4168c26c4e2SVyacheslav Dubeyko } while (bh = bh->b_this_page, bh != head); 4178c26c4e2SVyacheslav Dubeyko } 4180bd49f94SRyusuke Konishi 4190bd49f94SRyusuke Konishi __nilfs_clear_page_dirty(page); 4200bd49f94SRyusuke Konishi } 4210bd49f94SRyusuke Konishi 4220c6c44cbSRyusuke Konishi unsigned int nilfs_page_count_clean_buffers(struct page *page, 4230c6c44cbSRyusuke Konishi unsigned int from, unsigned int to) 4240bd49f94SRyusuke Konishi { 4250c6c44cbSRyusuke Konishi unsigned int block_start, block_end; 4260bd49f94SRyusuke Konishi struct buffer_head *bh, *head; 4270c6c44cbSRyusuke Konishi unsigned int nc = 0; 4280bd49f94SRyusuke Konishi 4290bd49f94SRyusuke Konishi for (bh = head = page_buffers(page), block_start = 0; 4300bd49f94SRyusuke Konishi bh != head || !block_start; 4310bd49f94SRyusuke Konishi block_start = block_end, bh = bh->b_this_page) { 4320bd49f94SRyusuke Konishi block_end = block_start + bh->b_size; 4330bd49f94SRyusuke Konishi if (block_end > from && block_start < to && !buffer_dirty(bh)) 4340bd49f94SRyusuke Konishi nc++; 4350bd49f94SRyusuke Konishi } 4360bd49f94SRyusuke Konishi return nc; 4370bd49f94SRyusuke Konishi } 438ebdfed4dSRyusuke Konishi 4390bd49f94SRyusuke Konishi /* 4400bd49f94SRyusuke Konishi * NILFS2 needs clear_page_dirty() in the following two cases: 4410bd49f94SRyusuke Konishi * 442e897be17SRyusuke Konishi * 1) For B-tree node pages and data pages of DAT file, NILFS2 clears dirty 443e897be17SRyusuke Konishi * flag of pages when it copies back pages from shadow cache to the 444e897be17SRyusuke Konishi * original cache. 4450bd49f94SRyusuke Konishi * 4460bd49f94SRyusuke Konishi * 2) Some B-tree operations like insertion or deletion may dispose buffers 4470bd49f94SRyusuke Konishi * in dirty state, and this needs to cancel the dirty state of their pages. 4480bd49f94SRyusuke Konishi */ 4490bd49f94SRyusuke Konishi int __nilfs_clear_page_dirty(struct page *page) 4500bd49f94SRyusuke Konishi { 4510bd49f94SRyusuke Konishi struct address_space *mapping = page->mapping; 4520bd49f94SRyusuke Konishi 4530bd49f94SRyusuke Konishi if (mapping) { 454b93b0163SMatthew Wilcox xa_lock_irq(&mapping->i_pages); 4550bd49f94SRyusuke Konishi if (test_bit(PG_dirty, &page->flags)) { 456f611ff63SMatthew Wilcox __xa_clear_mark(&mapping->i_pages, page_index(page), 4570bd49f94SRyusuke Konishi PAGECACHE_TAG_DIRTY); 458b93b0163SMatthew Wilcox xa_unlock_irq(&mapping->i_pages); 4590bd49f94SRyusuke Konishi return clear_page_dirty_for_io(page); 4600bd49f94SRyusuke Konishi } 461b93b0163SMatthew Wilcox xa_unlock_irq(&mapping->i_pages); 4620bd49f94SRyusuke Konishi return 0; 4630bd49f94SRyusuke Konishi } 4640bd49f94SRyusuke Konishi return TestClearPageDirty(page); 4650bd49f94SRyusuke Konishi } 466622daaffSRyusuke Konishi 467622daaffSRyusuke Konishi /** 468622daaffSRyusuke Konishi * nilfs_find_uncommitted_extent - find extent of uncommitted data 469622daaffSRyusuke Konishi * @inode: inode 470622daaffSRyusuke Konishi * @start_blk: start block offset (in) 471622daaffSRyusuke Konishi * @blkoff: start offset of the found extent (out) 472622daaffSRyusuke Konishi * 473622daaffSRyusuke Konishi * This function searches an extent of buffers marked "delayed" which 474622daaffSRyusuke Konishi * starts from a block offset equal to or larger than @start_blk. If 475622daaffSRyusuke Konishi * such an extent was found, this will store the start offset in 476622daaffSRyusuke Konishi * @blkoff and return its length in blocks. Otherwise, zero is 477622daaffSRyusuke Konishi * returned. 478622daaffSRyusuke Konishi */ 479622daaffSRyusuke Konishi unsigned long nilfs_find_uncommitted_extent(struct inode *inode, 480622daaffSRyusuke Konishi sector_t start_blk, 481622daaffSRyusuke Konishi sector_t *blkoff) 482622daaffSRyusuke Konishi { 483*24a1efb4SVishal Moola (Oracle) unsigned int i, nr_folios; 484622daaffSRyusuke Konishi pgoff_t index; 485622daaffSRyusuke Konishi unsigned long length = 0; 486*24a1efb4SVishal Moola (Oracle) struct folio_batch fbatch; 487*24a1efb4SVishal Moola (Oracle) struct folio *folio; 488622daaffSRyusuke Konishi 489622daaffSRyusuke Konishi if (inode->i_mapping->nrpages == 0) 490622daaffSRyusuke Konishi return 0; 491622daaffSRyusuke Konishi 49209cbfeafSKirill A. Shutemov index = start_blk >> (PAGE_SHIFT - inode->i_blkbits); 493622daaffSRyusuke Konishi 494*24a1efb4SVishal Moola (Oracle) folio_batch_init(&fbatch); 495622daaffSRyusuke Konishi 496622daaffSRyusuke Konishi repeat: 497*24a1efb4SVishal Moola (Oracle) nr_folios = filemap_get_folios_contig(inode->i_mapping, &index, ULONG_MAX, 498*24a1efb4SVishal Moola (Oracle) &fbatch); 499*24a1efb4SVishal Moola (Oracle) if (nr_folios == 0) 500622daaffSRyusuke Konishi return length; 501622daaffSRyusuke Konishi 502622daaffSRyusuke Konishi i = 0; 503622daaffSRyusuke Konishi do { 504*24a1efb4SVishal Moola (Oracle) folio = fbatch.folios[i]; 505622daaffSRyusuke Konishi 506*24a1efb4SVishal Moola (Oracle) folio_lock(folio); 507*24a1efb4SVishal Moola (Oracle) if (folio_buffers(folio)) { 508622daaffSRyusuke Konishi struct buffer_head *bh, *head; 509*24a1efb4SVishal Moola (Oracle) sector_t b; 510622daaffSRyusuke Konishi 511*24a1efb4SVishal Moola (Oracle) b = folio->index << (PAGE_SHIFT - inode->i_blkbits); 512*24a1efb4SVishal Moola (Oracle) bh = head = folio_buffers(folio); 513622daaffSRyusuke Konishi do { 514622daaffSRyusuke Konishi if (b < start_blk) 515622daaffSRyusuke Konishi continue; 516622daaffSRyusuke Konishi if (buffer_delay(bh)) { 517622daaffSRyusuke Konishi if (length == 0) 518622daaffSRyusuke Konishi *blkoff = b; 519622daaffSRyusuke Konishi length++; 520622daaffSRyusuke Konishi } else if (length > 0) { 521622daaffSRyusuke Konishi goto out_locked; 522622daaffSRyusuke Konishi } 523622daaffSRyusuke Konishi } while (++b, bh = bh->b_this_page, bh != head); 524622daaffSRyusuke Konishi } else { 525622daaffSRyusuke Konishi if (length > 0) 526622daaffSRyusuke Konishi goto out_locked; 527622daaffSRyusuke Konishi } 528*24a1efb4SVishal Moola (Oracle) folio_unlock(folio); 529622daaffSRyusuke Konishi 530*24a1efb4SVishal Moola (Oracle) } while (++i < nr_folios); 531622daaffSRyusuke Konishi 532*24a1efb4SVishal Moola (Oracle) folio_batch_release(&fbatch); 533622daaffSRyusuke Konishi cond_resched(); 534622daaffSRyusuke Konishi goto repeat; 535622daaffSRyusuke Konishi 536622daaffSRyusuke Konishi out_locked: 537*24a1efb4SVishal Moola (Oracle) folio_unlock(folio); 538*24a1efb4SVishal Moola (Oracle) folio_batch_release(&fbatch); 539622daaffSRyusuke Konishi return length; 540622daaffSRyusuke Konishi } 541