2.6.20 fix for PageUptodate memorder problem (try 2)
Subsystems (15)
cover 2.6.20 fix for PageUptodate memorder problem (try 2)
Still no independent confirmation as to whether this is a problem or not. Updated some comments, added diffstats to patches, don't use __SetPageUptodate as an internal page-flags.h private function.
I would like to eventually get an ack from Hugh regarding the anon memory and especially swap side of the equation, and a glance from whoever put the smp_wmb()s into the copy functions (Was it Ben H or Anton maybe?)
Thanks,
Nick
--
SuSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/3 mm: fix PageUptodate memorder
After running SetPageUptodate, preceeding stores to the page contents to actually bring it uptodate may not be ordered with the store to set the page uptodate.
Therefore, another CPU which checks PageUptodate is true, then reads the page contents can get stale data.
Fix this by ensuring SetPageUptodate is always called with the page locked (except in the case of a new page that cannot be visible to other CPUs), and requiring PageUptodate be checked only when the page is locked.
To facilitate lockless checks, SetPageUptodate contains an smp_wmb to order preceeding stores before the store to page flags, and a new PageUptodate_NoLock is introduced, which issues a smp_rmb after the page flags are loaded for the test.
I'm still not sure that a DMA memory barrier is not required, however I think the logical place to put such a barrier would be in the IO completion routines, when they come back to tell us that they have succeeded. (Help? Anyone?)
One thing I like about it is that it unifies the anonymous page handling with the rest of the page management, by marking anon pages as uptodate when they _are_ uptodate, rather than when our implementation requires that they be marked as such. Doing this let me get rid of the smp_wmb's in the page copying functions, which were specially added for anonymous pages for a closely related issue, always vaguely troubled me.
Convert core code and some filesystems to use PageUptodate_NoLock, just for reference (a more complete patch follows).
fs/ext2/dir.c | 2 - fs/namei.c | 2 - fs/partitions/check.c | 2 - fs/splice.c | 4 +-- include/linux/highmem.h | 4 --- include/linux/page-flags.h | 57 +++++++++++++++++++++++++++++++++++++++++---- mm/filemap.c | 28 +++++++++++++++------- mm/hugetlb.c | 2 + mm/memory.c | 9 +++---- mm/page_io.c | 2 - mm/swap_state.c | 2 - mm/swapfile.c | 2 - 12 files changed, 86 insertions(+), 30 deletions(-)
include/linux/highmem.h +0 -4
@@ -57,8 +57,6 @@ static inline void clear_user_highpage(svoid *addr =kmap_atomic (page,KM_USER0 );clear_user_page (addr, vaddr, page);kunmap_atomic (addr,KM_USER0 ); -/* Make sure this page is cleared on other CPU's too before using it */ -smp_wmb (); }#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
@@ -108,8 +106,6 @@ static inline void copy_user_highpage(stcopy_user_page (vto, vfrom, vaddr, to);kunmap_atomic (vfrom,KM_USER0 ); kunmap_atomic(vto, KM_USER1); -/* Make sure this page is cleared on other CPU's too before using it */ - smp_wmb(); }#endif
include/linux/page-flags.h +52 -5
68 lines not on this page · raw message
mm/hugetlb.c +2 -0
@@ -443,6 +443,7 @@ static int hugetlb_cow(struct mm_structspin_unlock (&mm->page_table_lock);copy_huge_page (new_page, old_page, address, vma); +SetNewPageUptodate (new_page);spin_lock (&mm->page_table_lock); ptep =huge_pte_offset (mm, address &HPAGE_MASK );
@@ -506,6 +507,7 @@ retry: }else lock_page (page); } +SetNewPageUptodate (page);spin_lock (&mm->page_table_lock); size =i_size_read (mapping->host) >>HPAGE_SHIFT ;
mm/memory.c +5 -4
@@ -1463,10 +1463,8 @@ static inline void cow_user_page(structmemset (kaddr,0 ,PAGE_SIZE );kunmap_atomic (kaddr,KM_USER0 );flush_dcache_page (dst); -return ; - - } -copy_user_highpage (dst, src, va, vma); + }else +copy_user_highpage (dst, src, va, vma); }/*
@@ -1579,6 +1577,7 @@ gotten: goto oom;cow_user_page (new_page, old_page, address, vma); } +SetNewPageUptodate (new_page);/* * Re-check the pte - we dropped the lock
@@ -2097,6 +2096,7 @@ static int do_anonymous_page(struct mm_s page =alloc_zeroed_user_highpage (vma, address);if (!page) goto oom; +SetNewPageUptodate (page); entry =mk_pte (page, vma->vm_page_prot); entry =maybe_mkwrite (pte_mkdirty (entry), vma);
@@ -2203,6 +2203,7 @@ retry:copy_user_highpage (page, new_page, address, vma);page_cache_release (new_page); new_page = page; +SetNewPageUptodate (new_page); anon =1 ; }else {
mm/filemap.c +19 -9
@@ -932,7 +932,7 @@ find_page:handle_ra_miss (mapping, &ra, index); goto no_cached_page; } -if (!PageUptodate (page)) +if (!PageUptodate_NoLock (page)) goto page_not_up_to_date; page_ok:
@@ -1000,7 +1000,7 @@ readpage: goto readpage_error; } -if (!PageUptodate (page)) { +if (!PageUptodate_NoLock (page)) {lock_page (page);if (!PageUptodate (page)) {if (page->mapping ==NULL ) {
@@ -1417,11 +1417,16 @@ retry_find:* Ok, found a page in the page cache, now we need to check * that it's up-to-date. */ -if (!PageUptodate (page)) +if (!PageUptodate_NoLock (page)) goto page_not_uptodate; success:/* +* Must order memory for the same reason as do_generic_mapping_read +*/ +smp_rmb (); + +/* * Found the page and have a reference on it. */ mark_page_accessed (page);
@@ -1484,7 +1489,7 @@ page_not_uptodate: error = mapping->a_ops->readpage (file, page);if (!error) {wait_on_page_locked (page); -if (PageUptodate (page)) +if (PageUptodate_NoLock (page)) goto success; }else if (error ==AOP_TRUNCATED_PAGE ) {page_cache_release (page);
@@ -1515,7 +1520,7 @@ page_not_uptodate: error = mapping->a_ops->readpage (file, page);if (!error) {wait_on_page_locked (page); -if (PageUptodate (page)) +if (PageUptodate_NoLock (page)) goto success; }else if (error ==AOP_TRUNCATED_PAGE ) {page_cache_release (page);
@@ -1554,7 +1559,7 @@ retry_find:* Ok, found a page in the page cache, now we need to check * that it's up-to-date. */ -if (!PageUptodate (page)) { +if (!PageUptodate_NoLock (page)) {if (nonblock) {page_cache_release (page);return NULL ;
@@ -1564,6 +1569,11 @@ retry_find: success:/* +* Must order memory for the same reason as do_generic_mapping_read +*/ +smp_rmb (); + +/* * Found the page and have a reference on it. */ mark_page_accessed (page);
@@ -1605,7 +1615,7 @@ page_not_uptodate: error = mapping->a_ops->readpage (file, page);if (!error) {wait_on_page_locked (page); -if (PageUptodate (page)) +if (PageUptodate_NoLock (page)) goto success; }else if (error ==AOP_TRUNCATED_PAGE ) {page_cache_release (page);
@@ -1635,7 +1645,7 @@ page_not_uptodate: error = mapping->a_ops->readpage (file, page);if (!error) {wait_on_page_locked (page); -if (PageUptodate (page)) +if (PageUptodate_NoLock (page)) goto success; }else if (error ==AOP_TRUNCATED_PAGE ) {page_cache_release (page);
@@ -1806,7 +1816,7 @@ retry:if (IS_ERR (page)) goto out;mark_page_accessed (page); -if (PageUptodate (page)) +if (PageUptodate_NoLock (page)) goto out;lock_page (page);
mm/page_io.c +1 -1
@@ -134,7 +134,7 @@ int swap_readpage(struct file *file, strint ret =0 ;BUG_ON (!PageLocked (page)); -ClearPageUptodate (page); +BUG_ON (PageUptodate (page)); bio =get_swap_bio (GFP_KERNEL ,page_private (page), page, end_swap_bio_read);if (bio ==NULL ) {
mm/swap_state.c +1 -1
@@ -149,6 +149,7 @@ int add_to_swap(struct page * page, gfp_int err;BUG_ON (!PageLocked (page)); +BUG_ON (!PageUptodate (page));for (;;) { entry =get_swap_page ();
@@ -171,7 +172,6 @@ int add_to_swap(struct page * page, gfp_switch (err) {case 0 :/* Success */ -SetPageUptodate (page);SetPageDirty (page);INC_CACHE_INFO (add_total);return 1 ;
fs/splice.c +2 -2
@@ -107,7 +107,7 @@ static int page_cache_pipe_buf_pin(strucstruct page *page = buf->page;int err; -if (!PageUptodate (page)) { +if (!PageUptodate_NoLock (page)) {lock_page (page);/*
@@ -373,7 +373,7 @@ __generic_file_splice_read(struct file */* * If the page isn't uptodate, we may need to start io on it */ -if (!PageUptodate (page)) { +if (!PageUptodate_NoLock (page)) {/* * If in nonblock mode then dont block on waiting * for an in-flight io page
fs/ext2/dir.c +1 -1
@@ -163,7 +163,7 @@ static struct page * ext2_get_page(strucif (!IS_ERR (page)) {wait_on_page_locked (page);kmap (page); -if (!PageUptodate (page)) +if (!PageUptodate_NoLock (page)) goto fail;if (!PageChecked (page))ext2_check_page (page);
fs/namei.c +1 -1
@@ -2641,7 +2641,7 @@ static char *page_getlink(struct dentryif (IS_ERR (page)) goto sync_fail;wait_on_page_locked (page); -if (!PageUptodate (page)) +if (!PageUptodate_NoLock (page)) goto async_fail; *ppage = page;return kmap (page);
fs/partitions/check.c +1 -1
@@ -562,7 +562,7 @@ unsigned char *read_dev_sector(struct bl NULL);if (!IS_ERR (page)) {wait_on_page_locked (page); -if (!PageUptodate (page)) +if (!PageUptodate_NoLock (page)) goto fail;if (PageError (page)) goto fail;
mm/swapfile.c +1 -1
@@ -1532,7 +1532,7 @@ asmlinkage long sys_swapon(const char __ goto bad_swap; }wait_on_page_locked (page); -if (!PageUptodate (page)) +if (!PageUptodate_NoLock (page)) goto bad_swap;kmap (page); swap_header =page_address (page);
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 2/3 fs: buffer don't PageUptodate without page locked
In reply to Nick Piggin__block_write_full_page is calling SetPageUptodate without the page locked. This is unusual, but not incorrect, as PG_writeback is still set.
However with the previous patch, this is now a problem: so don't bother setting the page uptodate in this case (it is weird that the write path does such a thing anyway). Instead just leave it to the read side to bring the page uptodate when it notices that all buffers are uptodate.
fs/buffer.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-)
fs/buffer.c +1 -10
@@ -1698,17 +1698,8 @@ done:* clean. Someone wrote them back by hand with * ll_rw_block/submit_bh. A rare case. */ -int uptodate =1 ; -do { -if (!buffer_uptodate (bh)) { - uptodate =0 ; -break ; - } - bh = bh->b_this_page; - }while (bh != head); -if (uptodate) -SetPageUptodate (page);end_page_writeback (page); +/* * The page and buffer_heads can be released at any time from * here on.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 3/3 mm: make read_cache_page synchronous
In reply to Nick PigginEnsure pages are uptodate after returning from read_cache_page, which allows us to cut out most of the filesystem-internal PageUptodate_NoLock calls.
I didn't have a great look down the call chains, but this appears to fixes 7 possible use-before uptodate in hfs, 2 in hfsplus, 1 in jfs, a few in ecryptfs, 1 in jffs2, and a possible cleared data overwritten with readpage in block2mtd. All depending on whether the filler is async and/or can return with a !uptodate page.
drivers/mtd/devices/block2mtd.c | 3 -- fs/afs/dir.c | 3 -- fs/afs/mntpt.c | 11 +++------ fs/cramfs/inode.c | 3 +- fs/ecryptfs/mmap.c | 10 -------- fs/ext2/dir.c | 3 -- fs/freevxfs/vxfs_subr.c | 3 -- fs/minix/dir.c | 1 fs/namei.c | 12 ---------- fs/nfs/dir.c | 5 ---- fs/nfs/symlink.c | 6 ----- fs/ntfs/aops.h | 3 -- fs/ntfs/attrib.c | 18 +-------------- fs/ntfs/file.c | 3 -- fs/ntfs/super.c | 30 +++---------------------- fs/ocfs2/symlink.c | 7 ----- fs/partitions/check.c | 3 -- fs/reiserfs/xattr.c | 4 --- fs/sysv/dir.c | 10 -------- fs/ufs/dir.c | 6 ----- fs/ufs/util.c | 6 +---- include/linux/pagemap.h | 11 +++++++++ mm/filemap.c | 48 ++++++++++++++++++++++++++++++---------- mm/swapfile.c | 3 -- 24 files changed, 68 insertions(+), 144 deletions(-)
fs/afs/dir.c +0 -3
@@ -187,10 +187,7 @@ static struct page *afs_dir_get_page(str page =read_mapping_page (dir->i_mapping, index,NULL );if (!IS_ERR (page)) { -wait_on_page_locked (page);kmap (page); -if (!PageUptodate (page)) - goto fail;if (!PageChecked (page))afs_dir_check_page (dir, page);if (PageError (page))
fs/afs/mntpt.c +4 -7
@@ -77,13 +77,11 @@ int afs_mntpt_check_symlink(struct afs_v } ret = -EIO ; -wait_on_page_locked (page); - buf =kmap (page); -if (!PageUptodate (page)) - goto out_free;if (PageError (page)) goto out_free; + buf =kmap (page); +/* examine the symlink's contents */ size = vnode->status.size;_debug ("symlink to %*.*s" , size, (int ) size, buf);
@@ -100,8 +98,8 @@ int afs_mntpt_check_symlink(struct afs_v ret =0 ; - out_free:kunmap (page); + out_free:page_cache_release (page); out:_leave (" = %d" , ret);
@@ -184,8 +182,7 @@ static struct vfsmount *afs_mntpt_do_aut } ret = -EIO ; -wait_on_page_locked (page); -if (!PageUptodate (page) ||PageError (page)) +if (PageError (page)) goto error; buf =kmap (page);
fs/cramfs/inode.c +2 -1
@@ -180,7 +180,8 @@ static void *cramfs_read(struct super_blstruct page *page =NULL ;if (blocknr + i < devsize) { - page =read_mapping_page (mapping, blocknr + i,NULL ); + page =read_mapping_page_async (mapping, blocknr + i, +NULL );/* synchronous error? */ if (IS_ERR (page)) page =NULL ;
fs/ext2/dir.c +0 -3
@@ -161,10 +161,7 @@ static struct page * ext2_get_page(strucstruct address_space *mapping = dir->i_mapping;struct page *page =read_mapping_page (mapping, n,NULL );if (!IS_ERR (page)) { -wait_on_page_locked (page);kmap (page); -if (!PageUptodate_NoLock (page)) - goto fail;if (!PageChecked (page))ext2_check_page (page);if (PageError (page))
fs/freevxfs/vxfs_subr.c +0 -3
@@ -74,10 +74,7 @@ vxfs_get_page(struct address_space *mapp pp =read_mapping_page (mapping, n,NULL );if (!IS_ERR (pp)) { -wait_on_page_locked (pp);kmap (pp); -if (!PageUptodate (pp)) - goto fail;/** if (!PageChecked(pp)) **/ /** vxfs_check_page(pp); **/ if (PageError (pp))
mm/filemap.c +36 -12
73 lines not on this page · raw message
fs/minix/dir.c +0 -1
@@ -62,7 +62,6 @@ static struct page * dir_get_page(structstruct address_space *mapping = dir->i_mapping;struct page *page =read_mapping_page (mapping, n,NULL );if (!IS_ERR (page)) { -wait_on_page_locked (page);kmap (page);if (!PageUptodate (page)) goto fail;
fs/namei.c +1 -11
@@ -2639,19 +2639,9 @@ static char *page_getlink(struct dentrystruct address_space *mapping = dentry->d_inode->i_mapping; page =read_mapping_page (mapping,0 ,NULL );if (IS_ERR (page)) - goto sync_fail; -wait_on_page_locked (page); -if (!PageUptodate_NoLock (page)) - goto async_fail; +return (char *)page; *ppage = page;return kmap (page); - -async_fail: -page_cache_release (page); -return ERR_PTR (-EIO ); - -sync_fail: -return (char *)page; }int page_readlink (struct dentry *dentry,char __user *buffer,int buflen)
fs/ntfs/aops.h +1 -2
@@ -89,9 +89,8 @@ static inline struct page *ntfs_map_pagestruct page *page =read_mapping_page (mapping, index,NULL );if (!IS_ERR (page)) { -wait_on_page_locked (page);kmap (page); -if (PageUptodate (page) && !PageError (page)) +if (!PageError (page))return page;ntfs_unmap_page (page);return ERR_PTR (-EIO );
fs/ntfs/attrib.c +2 -16
@@ -2532,14 +2532,7 @@ int ntfs_attr_set(ntfs_inode *ni, const page =read_mapping_page (mapping, idx,NULL );if (IS_ERR (page)) {ntfs_error (vol->sb,"Failed to read first partial " -"page (sync error, index 0x%lx)." , idx); -return PTR_ERR (page); - } -wait_on_page_locked (page); -if (unlikely (!PageUptodate (page))) { -ntfs_error (vol->sb,"Failed to read first partial page " -"(async error, index 0x%lx)." , idx); -page_cache_release (page); +"page (error, index 0x%lx)." , idx);return PTR_ERR (page); }/*
@@ -2602,14 +2595,7 @@ int ntfs_attr_set(ntfs_inode *ni, const page =read_mapping_page (mapping, idx,NULL );if (IS_ERR (page)) {ntfs_error (vol->sb,"Failed to read last partial page " -"(sync error, index 0x%lx)." , idx); -return PTR_ERR (page); - } -wait_on_page_locked (page); -if (unlikely (!PageUptodate (page))) { -ntfs_error (vol->sb,"Failed to read last partial page " -"(async error, index 0x%lx)." , idx); -page_cache_release (page); +"(error, index 0x%lx)." , idx);return PTR_ERR (page); } kaddr =kmap_atomic (page,KM_USER0 );
fs/ntfs/file.c +1 -2
@@ -236,8 +236,7 @@ do_non_resident_extend: err =PTR_ERR (page); goto init_err_out; } -wait_on_page_locked (page); -if (unlikely (!PageUptodate (page) ||PageError (page))) { +if (unlikely (PageError (page))) {page_cache_release (page); err = -EIO ; goto init_err_out;
fs/ocfs2/symlink.c +0 -7
@@ -67,16 +67,9 @@ static char *ocfs2_page_getlink(struct d page =read_mapping_page (mapping,0 ,NULL );if (IS_ERR (page)) goto sync_fail; -wait_on_page_locked (page); -if (!PageUptodate (page)) - goto async_fail; *ppage = page;return kmap (page); -async_fail: -page_cache_release (page); -return ERR_PTR (-EIO ); - sync_fail:return (char *)page; }
fs/partitions/check.c +0 -3
@@ -561,9 +561,6 @@ unsigned char *read_dev_sector(struct bl page =read_mapping_page (mapping, (pgoff_t)(n >> (PAGE_CACHE_SHIFT -9 )),NULL );if (!IS_ERR (page)) { -wait_on_page_locked (page); -if (!PageUptodate_NoLock (page)) - goto fail;if (PageError (page)) goto fail; p->v = page;
fs/reiserfs/xattr.c +0 -4
@@ -454,11 +454,7 @@ static struct page *reiserfs_get_page(stmapping_set_gfp_mask (mapping,GFP_NOFS ); page =read_mapping_page (mapping, n,NULL );if (!IS_ERR (page)) { -wait_on_page_locked (page);kmap (page); -if (!PageUptodate (page)) - goto fail; -if (PageError (page)) goto fail; }
fs/sysv/dir.c +1 -9
@@ -54,17 +54,9 @@ static struct page * dir_get_page(struct {struct address_space *mapping = dir->i_mapping;struct page *page =read_mapping_page (mapping, n,NULL ); -if (!IS_ERR (page)) { -wait_on_page_locked (page); +if (!IS_ERR (page))kmap (page); -if (!PageUptodate (page)) - goto fail; - }return page; - -fail: -dir_put_page (page); -return ERR_PTR (-EIO ); }static int sysv_readdir (struct file * filp,void * dirent,filldir_t filldir)
mm/swapfile.c +0 -3
@@ -1531,9 +1531,6 @@ asmlinkage long sys_swapon(const char __ error =PTR_ERR (page); goto bad_swap; } -wait_on_page_locked (page); -if (!PageUptodate_NoLock (page)) - goto bad_swap;kmap (page); swap_header =page_address (page);
drivers/mtd/devices/block2mtd.c +1 -2
@@ -88,9 +88,8 @@ static void cache_readahead(struct addrestatic struct page *page_readahead (struct address_space *mapping,int index) { -filler_t *filler = (filler_t *)mapping->a_ops->readpage;cache_readahead (mapping, index); -return read_cache_page (mapping, index, filler,NULL ); +return read_mapping_page (mapping, index,NULL ); }
fs/ecryptfs/mmap.c +1 -9
@@ -54,14 +54,7 @@ static struct page *ecryptfs_get1page(st dentry = file->f_path.dentry; inode = dentry->d_inode; mapping = inode->i_mapping; - page =read_cache_page (mapping, index, - (filler_t *)mapping->a_ops->readpage, - (void *)file); -if (IS_ERR (page)) - goto out; -wait_on_page_locked (page); -out: -return page; +return read_mapping_page (mapping, index, (void *)file); } static
@@ -233,7 +226,6 @@ int ecryptfs_do_readpage(struct file *fiecryptfs_printk (KERN_ERR ,"Error reading from page cache\n" ); goto out; } -wait_on_page_locked (lower_page); page_data = (char *)kmap (page);if (!page_data) { rc = -ENOMEM ;
fs/nfs/dir.c +0 -5
@@ -322,8 +322,6 @@ int find_dirent_page(nfs_readdir_descrip status =PTR_ERR (page); goto out; } -if (!PageUptodate (page)) - goto read_error;/* NOTE: Someone else may have changed the READDIRPLUS flag */ desc->page = page;
@@ -337,9 +335,6 @@ int find_dirent_page(nfs_readdir_descrip out:dfprintk (DIRCACHE ,"NFS: %s: returns %d\n" , __FUNCTION__, status);return status; - read_error: -page_cache_release (page); -return -EIO ; }/*
fs/nfs/symlink.c +0 -6
@@ -61,15 +61,9 @@ static void *nfs_follow_link(struct dent err = page; goto read_failed; } -if (!PageUptodate (page)) { - err =ERR_PTR (-EIO ); - goto getlink_read_error; - }nd_set_link (nd,kmap (page));return page; -getlink_read_error: -page_cache_release (page); read_failed:nd_set_link (nd, err);return NULL ;
fs/ntfs/super.c +4 -26
@@ -2471,7 +2471,6 @@ static s64 get_nr_free_clusters(ntfs_vols64 nr_free = vol->nr_clusters;u32 *kaddr;struct address_space *mapping = vol->lcnbmp_ino->i_mapping; -filler_t *readpage = (filler_t *)mapping->a_ops->readpage;struct page *page;pgoff_t index, max_index;
@@ -2494,24 +2493,14 @@ static s64 get_nr_free_clusters(ntfs_vol* Read the page from page cache, getting it from backing store * if necessary, and increment the use count. */ - page =read_cache_page (mapping, index, (filler_t *)readpage, -NULL ); + page =read_mapping_page (mapping, index,NULL );/* Ignore pages which errored synchronously. */ if (IS_ERR (page)) { -ntfs_debug ("Sync read_cache_page() error. Skipping " +ntfs_debug ("read_mapping_page() error. Skipping " "page (index 0x%lx)." , index); nr_free -=PAGE_CACHE_SIZE *8 ;continue ; } -wait_on_page_locked (page); -/* Ignore pages which errored asynchronously. */ -if (!PageUptodate (page)) { -ntfs_debug ("Async read_cache_page() error. Skipping " -"page (index 0x%lx)." , index); -page_cache_release (page); - nr_free -=PAGE_CACHE_SIZE *8 ; -continue ; - } kaddr = (u32 *)kmap_atomic (page,KM_USER0 );/* * For each 4 bytes, subtract the number of set bits. If this
@@ -2562,7 +2551,6 @@ static unsigned long __get_nr_free_mft_r {u32 *kaddr;struct address_space *mapping = vol->mftbmp_ino->i_mapping; -filler_t *readpage = (filler_t *)mapping->a_ops->readpage;struct page *page;pgoff_t index;
@@ -2576,21 +2564,11 @@ static unsigned long __get_nr_free_mft_r* Read the page from page cache, getting it from backing store * if necessary, and increment the use count. */ - page =read_cache_page (mapping, index, (filler_t *)readpage, -NULL ); + page =read_mapping_page (mapping, index,NULL );/* Ignore pages which errored synchronously. */ if (IS_ERR (page)) { -ntfs_debug ("Sync read_cache_page() error. Skipping " -"page (index 0x%lx)." , index); - nr_free -=PAGE_CACHE_SIZE *8 ; -continue ; - } -wait_on_page_locked (page); -/* Ignore pages which errored asynchronously. */ -if (!PageUptodate (page)) { -ntfs_debug ("Async read_cache_page() error. Skipping " +ntfs_debug ("read_mapping_page() error. Skipping " "page (index 0x%lx)." , index); -page_cache_release (page); nr_free -=PAGE_CACHE_SIZE *8 ;continue ; }
fs/ufs/dir.c +1 -5
@@ -180,13 +180,9 @@ fail:static struct page *ufs_get_page (struct inode *dir,unsigned long n) {struct address_space *mapping = dir->i_mapping; -struct page *page =read_cache_page (mapping, n, - (filler_t *)mapping->a_ops->readpage,NULL ); +struct page *page =read_mapping_page (mapping, n,NULL );if (!IS_ERR (page)) { -wait_on_page_locked (page);kmap (page); -if (!PageUptodate (page)) - goto fail;if (!PageChecked (page))ufs_check_page (page);if (PageError (page))
fs/ufs/util.c +2 -4
@@ -251,13 +251,11 @@ struct page *ufs_get_locked_page(struct page =find_lock_page (mapping, index);if (!page) { - page =read_cache_page (mapping, index, - (filler_t *)mapping->a_ops->readpage, -NULL ); + page =read_mapping_page (mapping, index,NULL );if (IS_ERR (page)) {printk (KERN_ERR "ufs_change_blocknr: " -"read_cache_page error: ino %lu, index: %lu\n" , +"read_mapping_page error: ino %lu, index: %lu\n" , mapping->host->i_ino, index); goto out; }
include/linux/pagemap.h +11 -0
@@ -97,12 +97,23 @@ static inline struct page *grab_cache_paextern struct page *grab_cache_page_nowait (struct address_space *mapping,unsigned long index); +extern struct page *read_cache_page_async (struct address_space *mapping, +unsigned long index,filler_t *filler, +void *data);extern struct page *read_cache_page (struct address_space *mapping,unsigned long index,filler_t *filler,void *data);extern int read_cache_pages (struct address_space *mapping,struct list_head *pages,filler_t *filler,void *data); +static inline struct page *read_mapping_page_async ( +struct address_space *mapping, +unsigned long index,void *data) +{ +filler_t *filler = (filler_t *)mapping->a_ops->readpage; +return read_cache_page_async (mapping, index, filler, data); +} +static inline struct page *read_mapping_page (struct address_space *mapping,unsigned long index,void *data) {
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 7 lines · Nick Piggin
Still no independent confirmation as to whether this is a problem or not. Updated some comments, added diffstats to patches, don't use
__SetPageUptodateas an internalpage-flags.hprivate function.I would like to eventually get an ack from Hugh regarding the anon memory and especially swap side of the equation, and a glance from whoever put the smp_wmb()s into the copy functions (Was it Ben H or Anton maybe?)
I don't remember adding that one ... Anton ?
Ben.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 1 line · Nick Piggin
Still no independent confirmation as to whether this is a problem or not.
I'm trying to convince myself none of your patch is necessary. Probably shall fail. But how come we've survived for years with such an issue?
Quoted 2 lines
Updated some comments, added diffstats to patches, don't use
__SetPageUptodateas an internalpage-flags.hprivate function.
Depressed by profusion of PageUptodate_UpperAndlowercasevariants. Those rmbs, you really only want them when it says "yes", don't you?
Quoted 3 lines
I would like to eventually get an ack from Hugh regarding the anon memory and especially swap side of the equation,
Plea noted. I'm pondering. "Eventually" indeed. OTOH I expect you're right to criticize anon/swap PageUptodate being set where it was needed to get by, rather than where it was natural to do so.
Quoted 2 lines
and a glance from whoever put the
smp_wmb()s into the copy functions (Was it Ben H or Anton maybe?)
From: Linus Torvalds <[email protected]>
Date: Thu, 14 Oct 2004 04:00:06 +0000 (-0700)
Subject: Fix threaded user page write memory ordering
X-Git-Tag: v2.6.9-final~3
X-Git-Url: http://127.0.0.1:1234/?p=.git;a=commitdiff_plain;h=538ce05c0ef4055cf29a92a4abcdf139d180a0f9;hp=8c225dbc5a7b13801a8254aae0ccebab8e4bece7
Fix threaded user page write memory ordering
Make sure we order the writes to a newly created page with the page table update that potentially exposes the page to another CPU.
This is a no-op on any architecture where getting the page table spinlock will already do the ordering (notably x86), but other architectures can care.
---
include/linux/highmem.h +4 -0
@@ -40,6 +40,8 @@ static inline void clear_user_highpage(svoid *addr =kmap_atomic (page,KM_USER0 );clear_user_page (addr, vaddr, page);kunmap_atomic (addr,KM_USER0 ); +/* Make sure this page is cleared on other CPU's too before using it */ +smp_wmb (); }static inline void clear_highpage (struct page *page)
@@ -73,6 +75,8 @@ static inline void copy_user_highpage(stcopy_user_page (vto, vfrom, vaddr, to);kunmap_atomic (vfrom,KM_USER0 );kunmap_atomic (vto,KM_USER1 ); +/* Make sure this page is cleared on other CPU's too before using it */ +smp_wmb (); }static inline void copy_highpage (struct page *to,struct page *from)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 5 lines · Hugh Dickins
Quoted 1 line · Nick Piggin
Still no independent confirmation as to whether this is a problem or not.
I'm trying to convince myself none of your patch is necessary. Probably shall fail. But how come we've survived for years with such an issue?
Well I'm almost sure that the POWER guys hit this with anonymous pages being zeroed out then added to process address space -- they would occasionally see junk (via another thread, I presume).
If that were the case, then I think that a read-vs-read over a hole (for example) should be buggy in the same way.
Quoted 5 lines
Quoted 2 lines
Updated some comments, added diffstats to patches, don't use
__SetPageUptodateas an internalpage-flags.hprivate function.Depressed by profusion of
PageUptodate_UpperAndlowercasevariants. Those rmbs, you really only want them when it says "yes", don't you?
Yeah, any help with naming suggestions would be appreciated. I think we can get rid of the SetPageUptodate_nowarn variant, by making SetNewPageUptodate simply do an smp_wmb + __set_bit on all architectures? This frees us from the extra atomic ops I'd added into the page fault fastpaths as well.
Yes, we do only need the rmb if it is uptodate, that's a good point.
Quoted 6 lines
Quoted 2 lines
I would like to eventually get an ack from Hugh regarding the anon memory and especially swap side of the equation,
Plea noted. I'm pondering. "Eventually" indeed. OTOH I expect you're right to criticize anon/swap PageUptodate being set where it was needed to get by, rather than where it was natural to do so.
Well if I can get you to warm to that aspect of the patch... :) I expect that using non-atomic bitops might help.
Should I make that change into its own patch?
Quoted 10 lines
Quoted 2 lines
and a glance from whoever put the
smp_wmb()s into the copy functions (Was it Ben H or Anton maybe?)From: Linus Torvalds <[email protected]>
Date: Thu, 14 Oct 2004 04:00:06 +0000 (-0700)
Subject: Fix threaded user page write memory ordering
X-Git-Tag: v2.6.9-final~3
X-Git-Url: http://127.0.0.1:1234/?p=.git;a=commitdiff_plain;h=538ce05c0ef4055cf29a92a4abcdf139d180a0f9;hp=8c225dbc5a7b13801a8254aae0ccebab8e4bece7Fix threaded user page write memory ordering
Thanks, I did see that, but I'm sure it must have been prompted by a discussion or another proposed patch from IBM. Maybe I'm wrong though.
Thanks,
Nick
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 5 lines
Quoted 1 line
Fix threaded user page write memory ordering
Thanks, I did see that, but I'm sure it must have been prompted by a discussion or another proposed patch from IBM. Maybe I'm wrong though.
Yes, my initial proposal iirc was to smp_wmb() in set_pte() but after a discussion with Linus, we ended with open coding them.
Ben.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 9 lines
Fix threaded user page write memory ordering
Make sure we order the writes to a newly created page with the page table update that potentially exposes the page to another CPU.
This is a no-op on any architecture where getting the page table spinlock will already do the ordering (notably x86), but other architectures can care.
Ah yes, the clear_* ones I knew about as I'm the one who tracked down that bug on power :-) I though the ones Nick pointed out were different tho.
Ben.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>