mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Hugh Dickins <hughd@google.com>
To: Greg KH <gregkh@suse.de>
Cc: linux-kernel@vger.kernel.org, stable@kernel.org,
	stable-review@kernel.org, torvalds@linux-foundation.org,
	akpm@linux-foundation.org, alan@lxorguk.ukuu.org.uk,
	Konstantin Khlebnikov <khlebnikov@openvz.org>
Subject: Re: [15/24] tmpfs: fix spurious ENOSPC when racing with unswap
Date: Fri, 20 May 2011 10:49:59 -0700 (PDT)	[thread overview]
Message-ID: <alpine.LSU.2.00.1105201026430.9887@sister.anvils> (raw)
In-Reply-To: <20110519183127.122729561@clark.kroah.org>

On Thu, 19 May 2011, Greg KH wrote:
> 2.6.33-longterm review patch.  If anyone has any objections, please let us know.

We've got in a muddle on this one: too many tmpfs races and too many trees!

> 
> ------------------
> Content-Length: 3111
> Lines: 91
> 
> From: Hugh Dickins <hughd@google.com>
> 
> commit 59a16ead572330deb38e5848151d30ed1af754bc upstream.
> 
> Testing the shmem_swaplist replacements for igrab() revealed another bug:
> writes to /dev/loop0 on a tmpfs file which fills its filesystem were
> sometimes failing with "Buffer I/O error"s.
> 
> These came from ENOSPC failures of shmem_getpage(), when racing with
> swapoff: the same could happen when racing with another shmem_getpage(),
> pulling the page in from swap in between our find_lock_page() and our
> taking the info->lock (though not in the single-threaded loop case).
> 
> This is unacceptable, and surprising that I've not noticed it before:
> it dates back many years, but (presumably) was made a lot easier to
> reproduce in 2.6.36, which sited a page preallocation in the race window.
> 
> Fix it by rechecking the page cache before settling on an ENOSPC error.
> 
> Signed-off-by: Hugh Dickins <hughd@google.com>
> Cc: Konstantin Khlebnikov <khlebnikov@openvz.org>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

So far, so good: indeed let's have the spurious ENOSPC fix in
33-longterm.

But here this 15/24 patch veers off into a quite different patch,
for "tmpfs: fix race between umount and writepage" (46/71 in the
38-stable series).  I've appended the actual ENOSPC backport at the end.

Yes, let's have this writepage fix in 33-longterm too (the 38-stable
patch should apply), but it does need "tmpfs: fix race between swapoff
and writepage" (47/71 in the 38-stable series) on top to correct it,
please add that in too.

For differing reasons, none of these races is as likely in 2.6.33
as in 2.6.38, but good to include the fixes anyway; whereas 2.6.32
gets more complicated for some of them, so I haven't bothered there.

(I think I'm reading the mails right, but of course made a fool of
myself in the past, because of how gmail "rationalized" my view of
them: I hope this won't be another such case.)

> 
> 
> ---
>  mm/shmem.c |   31 ++++++++++++++++++++-----------
>  1 file changed, 20 insertions(+), 11 deletions(-)
> 
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -1035,6 +1035,7 @@ static int shmem_writepage(struct page *
>  	struct address_space *mapping;
>  	unsigned long index;
>  	struct inode *inode;
> +	bool unlock_mutex = false;
>  
>  	BUG_ON(!PageLocked(page));
>  	mapping = page->mapping;
> @@ -1060,7 +1061,26 @@ static int shmem_writepage(struct page *
>  	else
>  		swap.val = 0;
>  
> +	/*
> +	 * Add inode to shmem_unuse()'s list of swapped-out inodes,
> +	 * if it's not already there.  Do it now because we cannot take
> +	 * mutex while holding spinlock, and must do so before the page
> +	 * is moved to swap cache, when its pagelock no longer protects
> +	 * the inode from eviction.  But don't unlock the mutex until
> +	 * we've taken the spinlock, because shmem_unuse_inode() will
> +	 * prune a !swapped inode from the swaplist under both locks.
> +	 */
> +	if (swap.val && list_empty(&info->swaplist)) {
> +		mutex_lock(&shmem_swaplist_mutex);
> +		/* move instead of add in case we're racing */
> +		list_move_tail(&info->swaplist, &shmem_swaplist);
> +		unlock_mutex = true;
> +	}
> +
>  	spin_lock(&info->lock);
> +	if (unlock_mutex)
> +		mutex_unlock(&shmem_swaplist_mutex);
> +
>  	if (index >= info->next_index) {
>  		BUG_ON(!(info->flags & SHMEM_TRUNCATE));
>  		goto unlock;
> @@ -1080,22 +1100,11 @@ static int shmem_writepage(struct page *
>  		remove_from_page_cache(page);
>  		shmem_swp_set(info, entry, swap.val);
>  		shmem_swp_unmap(entry);
> -		if (list_empty(&info->swaplist))
> -			inode = igrab(inode);
> -		else
> -			inode = NULL;
>  		spin_unlock(&info->lock);
>  		swap_shmem_alloc(swap);
>  		BUG_ON(page_mapped(page));
>  		page_cache_release(page);	/* pagecache ref */
>  		swap_writepage(page, wbc);
> -		if (inode) {
> -			mutex_lock(&shmem_swaplist_mutex);
> -			/* move instead of add in case we're racing */
> -			list_move_tail(&info->swaplist, &shmem_swaplist);
> -			mutex_unlock(&shmem_swaplist_mutex);
> -			iput(inode);
> -		}
>  		return 0;
>  	}
>  

Here's that ENOSPC backport again:

commit 59a16ead572330deb38e5848151d30ed1af754bc backported
Author: Hugh Dickins <hughd@google.com>
Date:   Wed May 11 15:13:38 2011 -0700
Subject: [PATCH] tmpfs: fix spurious ENOSPC when racing with unswap
    
    Testing the shmem_swaplist replacements for igrab() revealed another bug:
    writes to /dev/loop0 on a tmpfs file which fills its filesystem were
    sometimes failing with "Buffer I/O error"s.
    
    These came from ENOSPC failures of shmem_getpage(), when racing with
    swapoff: the same could happen when racing with another shmem_getpage(),
    pulling the page in from swap in between our find_lock_page() and our
    taking the info->lock (though not in the single-threaded loop case).
    
    This is unacceptable, and surprising that I've not noticed it before:
    it dates back many years, but (presumably) was made a lot easier to
    reproduce in 2.6.36, which sited a page preallocation in the race window.
    
    Fix it by rechecking the page cache before settling on an ENOSPC error.
    
    Signed-off-by: Hugh Dickins <hughd@google.com>
    Cc: Konstantin Khlebnikov <khlebnikov@openvz.org>
    Cc: <stable@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1396,18 +1396,13 @@ repeat:
 			if (sbinfo->free_blocks == 0 ||
 			    shmem_acct_block(info->flags)) {
 				spin_unlock(&sbinfo->stat_lock);
-				spin_unlock(&info->lock);
-				error = -ENOSPC;
-				goto failed;
+				goto nospace;
 			}
 			sbinfo->free_blocks--;
 			inode->i_blocks += BLOCKS_PER_PAGE;
 			spin_unlock(&sbinfo->stat_lock);
-		} else if (shmem_acct_block(info->flags)) {
-			spin_unlock(&info->lock);
-			error = -ENOSPC;
-			goto failed;
-		}
+		} else if (shmem_acct_block(info->flags))
+			goto nospace;
 
 		if (!filepage) {
 			int ret;
@@ -1476,6 +1471,24 @@ done:
 	*pagep = filepage;
 	return 0;
 
+nospace:
+	/*
+	 * Perhaps the page was brought in from swap between find_lock_page
+	 * and taking info->lock?  We allow for that at add_to_page_cache_lru,
+	 * but must also avoid reporting a spurious ENOSPC while working on a
+	 * full tmpfs.  (When filepage has been passed in to shmem_getpage, it
+	 * is already in page cache, which prevents this race from occurring.)
+	 */
+	if (!filepage) {
+		struct page *page = find_get_page(mapping, idx);
+		if (page) {
+			spin_unlock(&info->lock);
+			page_cache_release(page);
+			goto repeat;
+		}
+	}
+	spin_unlock(&info->lock);
+	error = -ENOSPC;
 failed:
 	if (*pagep != filepage) {
 		unlock_page(filepage);

  reply	other threads:[~2011-05-20 17:50 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-19 18:24 [00/21] 2.6.32.41-longterm review Greg KH
2011-05-19 18:23 ` [01/21] cifs: check for bytes_remaining going to zero in CIFS_SessSetup Greg KH
2011-05-19 18:23 ` [02/21] Validate size of EFI GUID partition entries Greg KH
2011-05-19 18:23 ` [03/21] dccp: handle invalid feature options length Greg KH
2011-05-19 18:23 ` [04/21] CIFS: Fix memory over bound bug in cifs_parse_mount_options Greg KH
2011-05-19 18:23 ` [05/21] Fix time() inconsistencies caused by intermediate xtime_cache values being read Greg KH
2011-05-19 20:33   ` [Stable-review] " Ben Hutchings
2011-05-19 18:23 ` [06/21] ehea: fix wrongly reported speed and port Greg KH
2011-05-19 18:23 ` [07/21] NET: slip, fix ldisc->open retval Greg KH
2011-05-19 18:23 ` [08/21] ne-h8300: Fix regression caused during net_device_ops conversion Greg KH
2011-05-19 18:23 ` [09/21] hydra: " Greg KH
2011-05-19 18:23 ` [10/21] libertas: fix cmdpendingq locking Greg KH
2011-05-19 18:23 ` [11/21] zorro8390: Fix regression caused during net_device_ops conversion Greg KH
2011-05-19 18:23 ` [12/21] cifs: add fallback in is_path_accessible for old servers Greg KH
2011-05-19 18:23 ` [13/21] Revert "x86, AMD: Fix APIC timer erratum 400 affecting K8 Rev.A-E processors" Greg KH
2011-05-19 18:23 ` [14/21] x86, AMD: Fix ARAT feature setting again Greg KH
2011-05-19 18:23 ` [15/21] clocksource: Install completely before selecting Greg KH
2011-05-19 18:23 ` [16/21] tick: Clear broadcast active bit when switching to oneshot Greg KH
2011-05-19 18:23 ` [17/21] x86, apic: Fix spurious error interrupts triggering on all non-boot APs Greg KH
2011-05-19 18:23 ` [18/21] x86, mce, AMD: Fix leaving freed data in a list Greg KH
2011-05-19 18:23 ` [19/21] [SCSI] megaraid_sas: Sanity check user supplied length before passing it to dma_alloc_coherent() Greg KH
2011-05-19 18:23 ` [20/21] vmxnet3: Fix inconsistent LRO state after initialization Greg KH
2011-05-19 18:23 ` [21/21] netxen: Remove references to unified firmware file Greg KH
2011-05-19 18:30 ` [01/24] cifs: check for bytes_remaining going to zero in CIFS_SessSetup Greg KH
2011-05-19 18:30 ` [02/24] Validate size of EFI GUID partition entries Greg KH
2011-05-19 18:30 ` [03/24] x86, hw_breakpoints: Fix racy access to ptrace breakpoints Greg KH
2011-05-19 18:30 ` [04/24] ptrace: Prepare to fix racy accesses on task breakpoints Greg KH
2011-05-19 18:30 ` [05/24] dccp: handle invalid feature options length Greg KH
2011-05-19 18:30 ` [06/24] CIFS: Fix memory over bound bug in cifs_parse_mount_options Greg KH
2011-05-19 18:30 ` [07/24] tmpfs: fix race between umount and swapoff Greg KH
2011-05-21  4:52   ` Hugh Dickins
2011-05-19 18:30 ` [08/24] ehea: fix wrongly reported speed and port Greg KH
2011-05-19 18:30 ` [09/24] NET: slip, fix ldisc->open retval Greg KH
2011-05-19 18:30 ` [10/24] ne-h8300: Fix regression caused during net_device_ops conversion Greg KH
2011-05-19 18:30 ` [11/24] hydra: " Greg KH
2011-05-19 18:30 ` [12/24] libertas: fix cmdpendingq locking Greg KH
2011-05-19 18:30 ` [13/24] zorro8390: Fix regression caused during net_device_ops conversion Greg KH
2011-05-19 18:30 ` [14/24] fixes for using make 3.82 Greg KH
2011-05-19 18:30 ` [15/24] tmpfs: fix spurious ENOSPC when racing with unswap Greg KH
2011-05-20 17:49   ` Hugh Dickins [this message]
2011-05-21 21:49     ` Greg KH
2011-05-22  0:15       ` Hugh Dickins
2011-05-19 18:30 ` [16/24] cifs: add fallback in is_path_accessible for old servers Greg KH
2011-05-19 18:30 ` [17/24] Revert "x86, AMD: Fix APIC timer erratum 400 affecting K8 Rev.A-E processors" Greg KH
2011-05-19 18:30 ` [18/24] x86, AMD: Fix ARAT feature setting again Greg KH
2011-05-19 18:30 ` [19/24] clocksource: Install completely before selecting Greg KH
2011-05-19 18:30 ` [20/24] tick: Clear broadcast active bit when switching to oneshot Greg KH
2011-05-19 18:30 ` [21/24] x86, apic: Fix spurious error interrupts triggering on all non-boot APs Greg KH
2011-05-19 18:30 ` [22/24] x86, mce, AMD: Fix leaving freed data in a list Greg KH
2011-05-19 18:30 ` [23/24] [SCSI] megaraid_sas: Sanity check user supplied length before passing it to dma_alloc_coherent() Greg KH
2011-05-19 18:30 ` [24/24] vmxnet3: Fix inconsistent LRO state after initialization Greg KH

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=alpine.LSU.2.00.1105201026430.9887@sister.anvils \
    --to=hughd@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=gregkh@suse.de \
    --cc=khlebnikov@openvz.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=stable-review@kernel.org \
    --cc=stable@kernel.org \
    --cc=torvalds@linux-foundation.org \
    /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

all inboxes | Powered by JetHome®