linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Johannes Weiner <hannes@cmpxchg.org>
To: Jan Kara <jack@suse.cz>
Cc: Andrew Morton <akpm@linux-foundation.org>,
	Tejun Heo <tj@kernel.org>, Hugh Dickins <hughd@google.com>,
	Michel Lespinasse <walken@google.com>,
	linux-mm@kvack.org, linux-fsdevel@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [patch 3/3] mm: memory: merge shared-writable dirtying branches in do_wp_page()
Date: Tue, 2 Dec 2014 11:56:07 -0500	[thread overview]
Message-ID: <20141202165607.GD8401@phnom.home.cmpxchg.org> (raw)
In-Reply-To: <20141202091939.GC9092@quack.suse.cz>

On Tue, Dec 02, 2014 at 10:19:39AM +0100, Jan Kara wrote:
> On Mon 01-12-14 17:58:02, Johannes Weiner wrote:
> > Whether there is a vm_ops->page_mkwrite or not, the page dirtying is
> > pretty much the same.  Make sure the page references are the same in
> > both cases, then merge the two branches.
> > 
> > It's tempting to go even further and page-lock the !page_mkwrite case,
> > to get it in line with everybody else setting the page table and thus
> > further simplify the model.  But that's not quite compelling enough to
> > justify dropping the pte lock, then relocking and verifying the entry
> > for filesystems without ->page_mkwrite, which notably includes tmpfs.
> > Leave it for now and lock the page late in the !page_mkwrite case.
> > 
> > Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
> > ---
> >  mm/memory.c | 46 ++++++++++++++++------------------------------
> >  1 file changed, 16 insertions(+), 30 deletions(-)
> > 
> > diff --git a/mm/memory.c b/mm/memory.c
> > index 2a2e3648ed65..ff92abfa5303 100644
> > --- a/mm/memory.c
> > +++ b/mm/memory.c
> ...
> > @@ -2147,42 +2147,28 @@ reuse:
> >  		pte_unmap_unlock(page_table, ptl);
> >  		ret |= VM_FAULT_WRITE;
> >  
> > -		if (!dirty_page)
> > -			return ret;
> > -
> > -		if (!page_mkwrite) {
> > +		if (dirty_shared) {
> >  			struct address_space *mapping;
> >  			int dirtied;
> >  
> > -			lock_page(dirty_page);
> > -			dirtied = set_page_dirty(dirty_page);
> > -			mapping = dirty_page->mapping;
> > -			unlock_page(dirty_page);
> > +			if (!page_mkwrite)
> > +				lock_page(old_page);
> >  
> > -			if (dirtied && mapping) {
> > -				/*
> > -				 * Some device drivers do not set page.mapping
> > -				 * but still dirty their pages
> > -				 */
> > -				balance_dirty_pages_ratelimited(mapping);
> > -			}
> > +			dirtied = set_page_dirty(old_page);
> > +			mapping = old_page->mapping;
> > +			unlock_page(old_page);
> > +			page_cache_release(old_page);
> >  
> > -			file_update_time(vma->vm_file);
> > -		}
> > -		put_page(dirty_page);
> > -		if (page_mkwrite) {
> > -			struct address_space *mapping = dirty_page->mapping;
> > -
> > -			set_page_dirty(dirty_page);
> > -			unlock_page(dirty_page);
> > -			page_cache_release(dirty_page);
> > -			if (mapping)	{
> > +			if ((dirtied || page_mkwrite) && mapping) {
>   Why do we actually call balance_dirty_pages_ratelimited() even if we
> didn't dirty the page when ->page_mkwrite() exists? Is it because
> filesystem may dirty the page in ->page_mkwrite() and we don't want it to
> deal with calling balance_dirty_pages_ratelimited()?

Yes, ->page_mkwrite() can dirty the page, but balance_dirty_pages(),
as you noted, is not allowed under the page lock.  However, it also
can't drop the page lock if that is the final set_page_dirty() as the
pte isn't dirty yet, and clear_page_dirty_for_io() relies on the pte
to be dirtied before the page outside the page lock.

That being said, the page lock semantics in there are strange.  It
seems to me that page_mkwrite semantics inherited fault semantics,
which don't allow the page lock to be dropped between verifying the
page->mapping and installing the page table, to make sure we don't map
a truncated page.  That's why when ->page_mkwrite() returns with the
page unlocked, do_page_mkwrite() locks it and verifies page->mapping,
only to hold the page lock until after the page table update is done.

However, unlike during a nopage fault, we fault against an existing
read-only pte mapping of the page, and truncation needs to unmap it.
Even if we dropped both the page lock and the pte lock, that
pte_same() check after re-locking the page table would reliably tell
us if somebody swooped in and truncated the page behind our backs.

So AFAICS ->page_mkwrite() could safely return with the page unlocked
in terms of correctness.  But OTOH if it locks the page anyway, it's
cheaper to just keep it until we need it again for set_page_dirty().
Either way, I think the truncation verification in do_page_mkwrite()
is unnecessary.

> Otherwise the patch looks good to me.

Thanks!

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

  reply	other threads:[~2014-12-02 16:56 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-01 22:58 [patch 1/3] mm: protect set_page_dirty() from ongoing truncation Johannes Weiner
2014-12-01 22:58 ` [patch 2/3] mm: memory: remove ->vm_file check on shared writable vmas Johannes Weiner
2014-12-02  8:58   ` Jan Kara
2014-12-02 15:18     ` Johannes Weiner
2014-12-02 12:00   ` Kirill A. Shutemov
2014-12-01 22:58 ` [patch 3/3] mm: memory: merge shared-writable dirtying branches in do_wp_page() Johannes Weiner
2014-12-02  9:19   ` Jan Kara
2014-12-02 16:56     ` Johannes Weiner [this message]
2014-12-02 12:08   ` Kirill A. Shutemov
2014-12-02  9:12 ` [patch 1/3] mm: protect set_page_dirty() from ongoing truncation Jan Kara
2014-12-02 15:06   ` Johannes Weiner
2014-12-02 11:56 ` Kirill A. Shutemov
2014-12-02 15:11   ` Johannes Weiner
2014-12-05 14:52 Johannes Weiner
2014-12-05 14:52 ` [patch 3/3] mm: memory: merge shared-writable dirtying branches in do_wp_page() Johannes Weiner
2014-12-09 18:22   ` Jan Kara
2014-12-16 16:18 [patch 0/3 resend] mm: close race between dirtying and truncation Johannes Weiner
2014-12-16 16:18 ` [patch 3/3] mm: memory: merge shared-writable dirtying branches in do_wp_page() Johannes Weiner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20141202165607.GD8401@phnom.home.cmpxchg.org \
    --to=hannes@cmpxchg.org \
    --cc=akpm@linux-foundation.org \
    --cc=hughd@google.com \
    --cc=jack@suse.cz \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=tj@kernel.org \
    --cc=walken@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox