diff options
| author | Andrew Morton <akpm@digeo.com> | 2002-12-14 03:18:17 -0800 |
|---|---|---|
| committer | Jaroslav Kysela <perex@suse.cz> | 2002-12-14 03:18:17 -0800 |
| commit | 577c516f30df0f8a3d91e3beb68be3374ad25a8c (patch) | |
| tree | 15589afab70e86c73244f0beba07ab5200bdedff | |
| parent | 8725c3fccdf07ee30d1e5bac5b065c16e4632982 (diff) | |
[PATCH] remove PF_SYNC
current->flags:PF_SYNC was a hack I added because I didn't want to
change all ->writepage implementations.
It's foul. And it means that if someone happens to run direct page
reclaim within the context of (say) sys_sync, the writepage invokations
from the VM will be treated as "data integrity" operations, not "memory
cleansing" operations, which would cause latency.
So the patch removes PF_SYNC and adds an extra arg to a_ops->writepage.
It is the `writeback_control' structure which contains the full context
information about why writepage was called.
The initial version of this patch just passed in a bare `int sync', but
the XFS team need more info so they can perform writearound from within
page reclaim.
The patch also adds writeback_control.for_reclaim, so writepage
implementations can inspect that to work out the call context rather
than peeking at current->flags:PF_MEMALLOC.
39 files changed, 107 insertions, 94 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 66d727bb9ce7..fa7c6091b5d2 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking @@ -133,10 +133,10 @@ unlocks and drops the reference. --------------------------- address_space_operations -------------------------- prototypes: - int (*writepage)(struct page *); + int (*writepage)(struct page *page, struct writeback_control *wbc); int (*readpage)(struct file *, struct page *); int (*sync_page)(struct page *); - int (*writepages)(struct address_space *, int *nr_to_write); + int (*writepages)(struct address_space *, struct writeback_control *); int (*set_page_dirty)(struct page *page); int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); int (*commit_write)(struct file *, struct page *, unsigned, unsigned); @@ -172,15 +172,16 @@ I/O against them. They come unlocked upon I/O completion. ->writepage() is used for two purposes: for "memory cleansing" and for "sync". These are quite different operations and the behaviour may differ -depending upon the mode. (Yes, there should be two a_ops for this, or -writepage should take a writeback_control*) +depending upon the mode. -If writepage is called for sync (current->flags & PF_SYNC) then it *must* -write the page, even if that would involve blocking on in-progress I/O. +If writepage is called for sync (wbc->sync_mode != WBC_SYNC_NONE) then +it *must* start I/O against the page, even if that would involve +blocking on in-progress I/O. -If writepage is called for memory cleansing (!(current->flags & PF_SYNC)) -then its role is to get as much writeout underway as possible. So writepage -should try to avoid blocking against currently-in-progress I/O. +If writepage is called for memory cleansing (sync_mode == +WBC_SYNC_NONE) then its role is to get as much writeout underway as +possible. So writepage should try to avoid blocking against +currently-in-progress I/O. If the filesystem is not called for "sync" and it determines that it would need to block against in-progress I/O to be able to start new I/O diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 09c219cfb284..ab67bdd0f6dc 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -264,7 +264,7 @@ struct inode_operations { int (*readlink) (struct dentry *, char *,int); struct dentry * (*follow_link) (struct dentry *, struct dentry *); int (*readpage) (struct file *, struct page *); - int (*writepage) (struct file *, struct page *); + int (*writepage) (struct page *page, struct writeback_control *wbc); int (*bmap) (struct inode *,int); void (*truncate) (struct inode *); int (*permission) (struct inode *, int); diff --git a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c index 39f09c9c0039..4b9c704fd737 100644 --- a/drivers/mtd/devices/blkmtd.c +++ b/drivers/mtd/devices/blkmtd.c @@ -151,9 +151,10 @@ MODULE_PARM(wqs, "i"); /* Page cache stuff */ /* writepage() - should never be called - catch it anyway */ -static int blkmtd_writepage(struct page *page) +static int blkmtd_writepage(struct page *page, struct writeback_control *wbc) { printk("blkmtd: writepage called!!!\n"); + unlock_page(page); return -EIO; } diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index b139e7a1f8d0..c1a4bf8d7bb8 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c @@ -51,9 +51,9 @@ abort_toobig: return 0; } -static int adfs_writepage(struct page *page) +static int adfs_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page, adfs_get_block); + return block_write_full_page(page, adfs_get_block, wbc); } static int adfs_readpage(struct file *file, struct page *page) diff --git a/fs/affs/file.c b/fs/affs/file.c index 8db6f186a42b..93c545e071ca 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -407,9 +407,9 @@ err_alloc: return -ENOSPC; } -static int affs_writepage(struct page *page) +static int affs_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page, affs_get_block); + return block_write_full_page(page, affs_get_block, wbc); } static int affs_readpage(struct file *file, struct page *page) { diff --git a/fs/bfs/file.c b/fs/bfs/file.c index 8f8dbde4636f..747fd1ea55e0 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c @@ -130,9 +130,9 @@ out: return err; } -static int bfs_writepage(struct page *page) +static int bfs_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page, bfs_get_block); + return block_write_full_page(page, bfs_get_block, wbc); } static int bfs_readpage(struct file *file, struct page *page) diff --git a/fs/block_dev.c b/fs/block_dev.c index 02ab29042036..8715fead5101 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -126,9 +126,9 @@ blkdev_direct_IO(int rw, struct file *file, const struct iovec *iov, nr_segs, blkdev_get_blocks); } -static int blkdev_writepage(struct page * page) +static int blkdev_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page, blkdev_get_block); + return block_write_full_page(page, blkdev_get_block, wbc); } static int blkdev_readpage(struct file * file, struct page * page) diff --git a/fs/buffer.c b/fs/buffer.c index 3de883fc5009..f8018f4eef92 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -1632,8 +1632,8 @@ EXPORT_SYMBOL(unmap_underlying_metadata); * with submit_bh(). At the address_space level PageWriteback prevents this * contention from occurring. */ -static int __block_write_full_page(struct inode *inode, - struct page *page, get_block_t *get_block) +static int __block_write_full_page(struct inode *inode, struct page *page, + get_block_t *get_block, struct writeback_control *wbc) { int err; unsigned long block; @@ -1705,7 +1705,7 @@ static int __block_write_full_page(struct inode *inode, do { get_bh(bh); if (buffer_mapped(bh) && buffer_dirty(bh)) { - if (called_for_sync()) { + if (wbc->sync_mode != WB_SYNC_NONE) { lock_buffer(bh); } else { if (test_set_buffer_locked(bh)) { @@ -2485,7 +2485,8 @@ out: /* * The generic ->writepage function for buffer-backed address_spaces */ -int block_write_full_page(struct page *page, get_block_t *get_block) +int block_write_full_page(struct page *page, get_block_t *get_block, + struct writeback_control *wbc) { struct inode * const inode = page->mapping->host; const unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT; @@ -2494,7 +2495,7 @@ int block_write_full_page(struct page *page, get_block_t *get_block) /* Is the page fully inside i_size? */ if (page->index < end_index) - return __block_write_full_page(inode, page, get_block); + return __block_write_full_page(inode, page, get_block, wbc); /* Is the page fully outside i_size? (truncate in progress) */ offset = inode->i_size & (PAGE_CACHE_SIZE-1); @@ -2514,7 +2515,7 @@ int block_write_full_page(struct page *page, get_block_t *get_block) memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); - return __block_write_full_page(inode, page, get_block); + return __block_write_full_page(inode, page, get_block, wbc); } sector_t generic_block_bmap(struct address_space *mapping, sector_t block, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 0984cb20c826..0e6d0b9515d4 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -415,7 +415,7 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to) } static int -cifs_writepage(struct page* page) +cifs_writepage(struct page* page, struct writeback_control *wbc) { int rc = -EFAULT; int xid; diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 29cccde53b74..f04ec5f0b98e 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -588,9 +588,9 @@ changed: goto reread; } -static int ext2_writepage(struct page *page) +static int ext2_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page,ext2_get_block); + return block_write_full_page(page, ext2_get_block, wbc); } static int ext2_readpage(struct file *file, struct page *page) diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index cf150fed6765..72555eb87b02 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -33,6 +33,7 @@ #include <linux/quotaops.h> #include <linux/string.h> #include <linux/buffer_head.h> +#include <linux/writeback.h> #include <linux/mpage.h> #include <linux/uio.h> #include "xattr.h" @@ -1287,7 +1288,7 @@ static int bget_one(handle_t *handle, struct buffer_head *bh) * disastrous. Any write() or metadata operation will sync the fs for * us. */ -static int ext3_writepage(struct page *page) +static int ext3_writepage(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; struct buffer_head *page_bufs; @@ -1308,7 +1309,7 @@ static int ext3_writepage(struct page *page) goto out_fail; needed = ext3_writepage_trans_blocks(inode); - if (current->flags & PF_MEMALLOC) + if (wbc->for_reclaim) handle = ext3_journal_try_start(inode, needed); else handle = ext3_journal_start(inode, needed); @@ -1339,7 +1340,7 @@ static int ext3_writepage(struct page *page) PAGE_CACHE_SIZE, NULL, bget_one); } - ret = block_write_full_page(page, ext3_get_block); + ret = block_write_full_page(page, ext3_get_block, wbc); /* * The page can become unlocked at any point now, and diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 6ad055bba0b0..f0e05a3c04e0 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1050,9 +1050,9 @@ static int is_exec(char *extension) return 0; } -static int fat_writepage(struct page *page) +static int fat_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page,fat_get_block); + return block_write_full_page(page,fat_get_block, wbc); } static int fat_readpage(struct file *file, struct page *page) { diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index b005f18026d9..21f14fcf8ccf 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -229,9 +229,9 @@ int hfs_notify_change_hdr(struct dentry *dentry, struct iattr * attr) return __hfs_notify_change(dentry, attr, HFS_HDR); } -static int hfs_writepage(struct page *page) +static int hfs_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page,hfs_get_block); + return block_write_full_page(page,hfs_get_block, wbc); } static int hfs_readpage(struct file *file, struct page *page) { diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 4891ce052407..5504d729c3dc 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -98,9 +98,9 @@ int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_ return 0; } -static int hpfs_writepage(struct page *page) +static int hpfs_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page,hpfs_get_block); + return block_write_full_page(page,hpfs_get_block, wbc); } static int hpfs_readpage(struct file *file, struct page *page) { diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 41ffc39e9c54..454b27a20f58 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -277,9 +277,9 @@ static int jfs_get_block(struct inode *ip, sector_t lblock, return jfs_get_blocks(ip, lblock, 1, bh_result, create); } -static int jfs_writepage(struct page *page) +static int jfs_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page, jfs_get_block); + return block_write_full_page(page, jfs_get_block, wbc); } static int jfs_writepages(struct address_space *mapping, diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 18ea5aa41a34..c327d5f03443 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -316,9 +316,9 @@ static int minix_get_block(struct inode *inode, sector_t block, return V2_minix_get_block(inode, block, bh_result, create); } -static int minix_writepage(struct page *page) +static int minix_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page,minix_get_block); + return block_write_full_page(page, minix_get_block, wbc); } static int minix_readpage(struct file *file, struct page *page) { diff --git a/fs/mpage.c b/fs/mpage.c index 7f3043c7ee90..c2e3a2d4e8c4 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -327,7 +327,7 @@ EXPORT_SYMBOL(mpage_readpage); */ static struct bio * mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block, - sector_t *last_block_in_bio, int *ret) + sector_t *last_block_in_bio, int *ret, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; const unsigned blkbits = inode->i_blkbits; @@ -501,7 +501,7 @@ alloc_new: confused: if (bio) bio = mpage_bio_submit(WRITE, bio); - *ret = page->mapping->a_ops->writepage(page); + *ret = page->mapping->a_ops->writepage(page, wbc); out: return bio; } @@ -554,9 +554,8 @@ mpage_writepages(struct address_space *mapping, sector_t last_block_in_bio = 0; int ret = 0; int done = 0; - int sync = called_for_sync(); struct pagevec pvec; - int (*writepage)(struct page *); + int (*writepage)(struct page *page, struct writeback_control *wbc); if (wbc->nonblocking && bdi_write_congested(bdi)) { blk_run_queues(); @@ -574,7 +573,7 @@ mpage_writepages(struct address_space *mapping, struct page *page = list_entry(mapping->io_pages.prev, struct page, list); list_del(&page->list); - if (PageWriteback(page) && !sync) { + if (PageWriteback(page) && wbc->sync_mode == WB_SYNC_NONE) { if (PageDirty(page)) { list_add(&page->list, &mapping->dirty_pages); continue; @@ -600,16 +599,16 @@ mpage_writepages(struct address_space *mapping, lock_page(page); - if (sync) + if (wbc->sync_mode != WB_SYNC_NONE) wait_on_page_writeback(page); if (page->mapping == mapping && !PageWriteback(page) && test_clear_page_dirty(page)) { if (writepage) { - ret = (*writepage)(page); + ret = (*writepage)(page, wbc); } else { bio = mpage_writepage(bio, page, get_block, - &last_block_in_bio, &ret); + &last_block_in_bio, &ret, wbc); } if (ret || (--(wbc->nr_to_write) <= 0)) done = 1; diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 4849ed704570..21d30b3a36e6 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -240,7 +240,7 @@ nfs_writepage_async(struct file *file, struct inode *inode, struct page *page, * Write an mmapped page to the server. */ int -nfs_writepage(struct page *page) +nfs_writepage(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; unsigned long end_index; diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 1c8703416db6..8e80a2be182a 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -792,7 +792,7 @@ lock_retry_remap: * * Return 0 on success and -errno on error. */ -static int ntfs_writepage(struct page *page) +static int ntfs_writepage(struct page *page, struct writeback_control *wbc) { s64 attr_pos; struct inode *vi; diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 37ae3c466e7a..616e97433632 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -424,9 +424,9 @@ static void qnx4_put_super(struct super_block *sb) return; } -static int qnx4_writepage(struct page *page) +static int qnx4_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page,qnx4_get_block); + return block_write_full_page(page,qnx4_get_block, wbc); } static int qnx4_readpage(struct file *file, struct page *page) { diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 795330017bab..817c5c465d19 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1917,7 +1917,7 @@ static inline void submit_bh_for_writepage(struct buffer_head **bhp, int nr) { } } -static int reiserfs_write_full_page(struct page *page) { +static int reiserfs_write_full_page(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host ; unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT ; unsigned last_offset = PAGE_CACHE_SIZE; @@ -2018,11 +2018,11 @@ static int reiserfs_readpage (struct file *f, struct page * page) } -static int reiserfs_writepage (struct page * page) +static int reiserfs_writepage (struct page * page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host ; reiserfs_wait_on_write_block(inode->i_sb) ; - return reiserfs_write_full_page(page) ; + return reiserfs_write_full_page(page, wbc) ; } diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index 9ded6c19c5f1..a174775b2d13 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -170,7 +170,7 @@ smb_writepage_sync(struct inode *inode, struct page *page, * We are called with the page locked and we unlock it when done. */ static int -smb_writepage(struct page *page) +smb_writepage(struct page *page, struct writeback_control *wbc) { struct address_space *mapping = page->mapping; struct inode *inode; diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c index 55e7ff30ed70..a1c0b6361351 100644 --- a/fs/sysv/itree.c +++ b/fs/sysv/itree.c @@ -449,9 +449,9 @@ int sysv_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat return 0; } -static int sysv_writepage(struct page *page) +static int sysv_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page,get_block); + return block_write_full_page(page,get_block,wbc); } static int sysv_readpage(struct file *file, struct page *page) { diff --git a/fs/udf/file.c b/fs/udf/file.c index 4c519798fc1b..9fd46aff63ae 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -62,7 +62,7 @@ static int udf_adinicb_readpage(struct file *file, struct page * page) return 0; } -static int udf_adinicb_writepage(struct page *page) +static int udf_adinicb_writepage(struct page *page, struct writeback_control *wbc) { struct inode *inode = page->mapping->host; char *kaddr; diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 24a197a1eeee..19a6e06cd46e 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -39,6 +39,7 @@ #include <linux/module.h> #include <linux/pagemap.h> #include <linux/buffer_head.h> +#include <linux/writeback.h> #include <linux/slab.h> #include "udf_i.h" @@ -137,9 +138,9 @@ void udf_discard_prealloc(struct inode * inode) } } -static int udf_writepage(struct page *page) +static int udf_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page, udf_get_block); + return block_write_full_page(page, udf_get_block, wbc); } static int udf_readpage(struct file *file, struct page *page) @@ -170,6 +171,10 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err) { struct page *page; char *kaddr; + struct writeback_control udf_wbc = { + .sync_mode = WB_SYNC_NONE, + .nr_to_write = 1, + }; /* from now on we have normal address_space methods */ inode->i_data.a_ops = &udf_aops; @@ -206,7 +211,7 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err) else UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG; - inode->i_data.a_ops->writepage(page); + inode->i_data.a_ops->writepage(page, &udf_wbc); page_cache_release(page); mark_inode_dirty(inode); diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index e9d42f0c2b3f..615f61a0b88d 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -445,9 +445,9 @@ struct buffer_head * ufs_bread (struct inode * inode, unsigned fragment, return NULL; } -static int ufs_writepage(struct page *page) +static int ufs_writepage(struct page *page, struct writeback_control *wbc) { - return block_write_full_page(page,ufs_getfrag_block); + return block_write_full_page(page,ufs_getfrag_block,wbc); } static int ufs_readpage(struct file *file, struct page *page) { diff --git a/fs/xfs/linux/xfs_aops.c b/fs/xfs/linux/xfs_aops.c index 3e2bd1679bb8..15b035f67c8f 100644 --- a/fs/xfs/linux/xfs_aops.c +++ b/fs/xfs/linux/xfs_aops.c @@ -691,7 +691,8 @@ count_page_state( STATIC int linvfs_writepage( - struct page *page) + struct page *page, + struct writeback_control *wbc) { int error; int need_trans = 1; diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 4e7a9bbf99dd..e9d6251fa168 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -178,7 +178,7 @@ extern int buffer_heads_over_limit; */ int try_to_release_page(struct page * page, int gfp_mask); int block_invalidatepage(struct page *page, unsigned long offset); -int block_write_full_page(struct page*, get_block_t*); +int block_write_full_page(struct page *page, get_block_t *get_block, struct writeback_control *wbc); int block_read_full_page(struct page*, get_block_t*); int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*); int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*, diff --git a/include/linux/fs.h b/include/linux/fs.h index afbb9474f25b..bd133801c3e0 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -278,7 +278,7 @@ struct address_space; struct writeback_control; struct address_space_operations { - int (*writepage)(struct page *); + int (*writepage)(struct page *page, struct writeback_control *wbc); int (*readpage)(struct file *, struct page *); int (*sync_page)(struct page *); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 8d15e17c0b94..2673e32cc4ba 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -291,7 +291,7 @@ extern void nfs_complete_unlink(struct dentry *); /* * linux/fs/nfs/write.c */ -extern int nfs_writepage(struct page *); +extern int nfs_writepage(struct page *page, struct writeback_control *wbc); extern int nfs_writepages(struct address_space *, struct writeback_control *); extern int nfs_flush_incompatible(struct file *file, struct page *page); extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); diff --git a/include/linux/sched.h b/include/linux/sched.h index 80a9836df919..d0726cb87145 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -424,9 +424,8 @@ do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0) #define PF_FREEZE 0x00008000 /* this task should be frozen for suspend */ #define PF_IOTHREAD 0x00010000 /* this thread is needed for doing I/O to swap */ #define PF_FROZEN 0x00020000 /* frozen for system suspend */ -#define PF_SYNC 0x00040000 /* performing fsync(), etc */ -#define PF_FSTRANS 0x00080000 /* inside a filesystem transaction */ -#define PF_KSWAPD 0x00100000 /* I am kswapd */ +#define PF_FSTRANS 0x00040000 /* inside a filesystem transaction */ +#define PF_KSWAPD 0x00080000 /* I am kswapd */ /* * Ptrace flags diff --git a/include/linux/swap.h b/include/linux/swap.h index f6b1421f86b0..c635f392d6c1 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -65,6 +65,7 @@ typedef struct { struct sysinfo; struct address_space; struct zone; +struct writeback_control; /* * A swap extent maps a range of a swapfile's PAGE_SIZE pages onto a range of @@ -180,7 +181,7 @@ extern int shmem_unuse(swp_entry_t entry, struct page *page); #ifdef CONFIG_SWAP /* linux/mm/page_io.c */ extern int swap_readpage(struct file *, struct page *); -extern int swap_writepage(struct page *); +extern int swap_writepage(struct page *page, struct writeback_control *wbc); extern int rw_swap_page_sync(int, swp_entry_t, struct page *); /* linux/mm/swap_state.c */ diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 351e5851c041..620f18f5ceeb 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -42,6 +42,7 @@ struct writeback_control { int nonblocking; /* Don't get stuck on request queues */ int encountered_congestion; /* An output: a queue is full */ int for_kupdate; /* A kupdate writeback */ + int for_reclaim; /* Invoked from the page allocator */ }; /* @@ -88,13 +89,4 @@ extern int nr_pdflush_threads; /* Global so it can be exported to sysctl read-only. */ -/* - * Tell the writeback paths that they are being called for a "data integrity" - * operation such as fsync(). - */ -static inline int called_for_sync(void) -{ - return current->flags & PF_SYNC; -} - #endif /* WRITEBACK_H */ diff --git a/mm/filemap.c b/mm/filemap.c index 50b05fe9a2e0..cacecf650277 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -117,10 +117,6 @@ static inline int sync_page(struct page *page) * cleansing writeback. The difference between these two operations is that * if a dirty page/buffer is encountered, it must be waited upon, and not just * skipped over. - * - * The PF_SYNC flag is set across this operation and the various functions - * which care about this distinction must use called_for_sync() to find out - * which behaviour they should implement. */ int filemap_fdatawrite(struct address_space *mapping) { @@ -133,12 +129,10 @@ int filemap_fdatawrite(struct address_space *mapping) if (mapping->backing_dev_info->memory_backed) return 0; - current->flags |= PF_SYNC; write_lock(&mapping->page_lock); list_splice_init(&mapping->dirty_pages, &mapping->io_pages); write_unlock(&mapping->page_lock); ret = do_writepages(mapping, &wbc); - current->flags &= ~PF_SYNC; return ret; } diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 3880394c8562..1111f37feb4b 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -412,6 +412,9 @@ int write_one_page(struct page *page, int wait) { struct address_space *mapping = page->mapping; int ret = 0; + struct writeback_control wbc = { + .sync_mode = WB_SYNC_ALL, + }; BUG_ON(!PageLocked(page)); @@ -424,7 +427,7 @@ int write_one_page(struct page *page, int wait) list_add(&page->list, &mapping->locked_pages); page_cache_get(page); write_unlock(&mapping->page_lock); - ret = mapping->a_ops->writepage(page); + ret = mapping->a_ops->writepage(page, &wbc); if (ret == 0 && wait) { wait_on_page_writeback(page); if (PageError(page)) diff --git a/mm/page_io.c b/mm/page_io.c index 5d3bfdce334f..faf3e211a33a 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -18,6 +18,7 @@ #include <linux/swapops.h> #include <linux/buffer_head.h> /* for block_sync_page() */ #include <linux/mpage.h> +#include <linux/writeback.h> #include <asm/pgtable.h> static struct bio * @@ -86,7 +87,7 @@ static int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err) * We may have stale swap cache pages in memory: notice * them here and get rid of the unnecessary final write. */ -int swap_writepage(struct page *page) +int swap_writepage(struct page *page, struct writeback_control *wbc) { struct bio *bio; int ret = 0; @@ -143,6 +144,9 @@ struct address_space_operations swap_aops = { int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page) { int ret; + struct writeback_control swap_wbc = { + .sync_mode = WB_SYNC_ALL, + }; lock_page(page); @@ -154,7 +158,7 @@ int rw_swap_page_sync(int rw, swp_entry_t entry, struct page *page) ret = swap_readpage(NULL, page); wait_on_page_locked(page); } else { - ret = swap_writepage(page); + ret = swap_writepage(page, &swap_wbc); wait_on_page_writeback(page); } page->mapping = NULL; diff --git a/mm/shmem.c b/mm/shmem.c index cb8bd154df8f..987203cb2a41 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -671,7 +671,7 @@ int shmem_unuse(swp_entry_t entry, struct page *page) /* * Move the page from the page cache to the swap cache. */ -static int shmem_writepage(struct page *page) +static int shmem_writepage(struct page *page, struct writeback_control *wbc) { struct shmem_inode_info *info; swp_entry_t *entry, swap; diff --git a/mm/swapfile.c b/mm/swapfile.c index 0ad388eaf542..067c3095225a 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -16,6 +16,7 @@ #include <linux/shm.h> #include <linux/blkdev.h> #include <linux/buffer_head.h> +#include <linux/writeback.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/init.h> @@ -696,7 +697,11 @@ static int try_to_unuse(unsigned int type) * and now we must reincrement count to try again later. */ if ((*swap_map > 1) && PageDirty(page) && PageSwapCache(page)) { - swap_writepage(page); + struct writeback_control wbc = { + .sync_mode = WB_SYNC_NONE, + }; + + swap_writepage(page, &wbc); lock_page(page); wait_on_page_writeback(page); } diff --git a/mm/vmscan.c b/mm/vmscan.c index 8243646bf5c5..d2add0ef819d 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -319,13 +319,19 @@ shrink_list(struct list_head *page_list, unsigned int gfp_mask, goto keep_locked; if (test_clear_page_dirty(page)) { int res; + struct writeback_control wbc = { + .sync_mode = WB_SYNC_NONE, + .nr_to_write = SWAP_CLUSTER_MAX, + .nonblocking = 1, + .for_reclaim = 1, + }; write_lock(&mapping->page_lock); list_move(&page->list, &mapping->locked_pages); write_unlock(&mapping->page_lock); SetPageReclaim(page); - res = mapping->a_ops->writepage(page); + res = mapping->a_ops->writepage(page, &wbc); if (res == WRITEPAGE_ACTIVATE) { ClearPageReclaim(page); |
