kernel/block-fix-infinite-loop-in-__getblk_slow.patch
2012-06-26 11:38:14 -04:00

154 lines
6.2 KiB
Diff

Delivered-To: jwboyer@gmail.com
Received: by 10.229.191.66 with SMTP id dl2csp36421qcb;
Tue, 26 Jun 2012 07:55:48 -0700 (PDT)
Received: by 10.68.228.136 with SMTP id si8mr53042278pbc.159.1340722548310;
Tue, 26 Jun 2012 07:55:48 -0700 (PDT)
Return-Path: <stable-owner@vger.kernel.org>
Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67])
by mx.google.com with ESMTP id qg1si15735731pbc.300.2012.06.26.07.55.47;
Tue, 26 Jun 2012 07:55:48 -0700 (PDT)
Received-SPF: pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67;
Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of stable-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mail=stable-owner@vger.kernel.org
Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
id S1757370Ab2FZOzp (ORCPT <rfc822;aaditya.kumar.30@gmail.com>
+ 23 others); Tue, 26 Jun 2012 10:55:45 -0400
Received: from mx1.redhat.com ([209.132.183.28]:64097 "EHLO mx1.redhat.com"
rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP
id S1757325Ab2FZOzo (ORCPT <rfc822;stable@vger.kernel.org>);
Tue, 26 Jun 2012 10:55:44 -0400
Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11])
by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q5QEtbK2017450
(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK);
Tue, 26 Jun 2012 10:55:38 -0400
Received: from segfault.boston.devel.redhat.com (segfault.boston.devel.redhat.com [10.16.60.26])
by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id q5QEtZV9023431;
Tue, 26 Jun 2012 10:55:35 -0400
From: Jeff Moyer <jmoyer@redhat.com>
To: Jens Axboe <jaxboe@fusionio.com>, Nick Piggin <npiggin@kernel.dk>
Cc: LKML List <linux-kernel@vger.kernel.org>,
torsten.hilbrich@secunet.com, Richard Jones <rjones@redhat.com>,
stable@vger.kernel.org, Marcos Mello <marcosfrm@gmail.com>
Subject: [patch] block: fix infinite loop in __getblk_slow
X-PGP-KeyID: 1F78E1B4
X-PGP-CertKey: F6FE 280D 8293 F72C 65FD 5A58 1FF8 A7CA 1F78 E1B4
X-PCLoadLetter: What the f**k does that mean?
Date: Tue, 26 Jun 2012 10:55:34 -0400
Message-ID: <x49r4t2rul5.fsf@segfault.boston.devel.redhat.com>
User-Agent: Gnus/5.110011 (No Gnus v0.11) Emacs/23.1 (gnu/linux)
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
X-Scanned-By: MIMEDefang 2.67 on 10.5.11.11
Sender: stable-owner@vger.kernel.org
Precedence: bulk
List-ID: <stable.vger.kernel.org>
X-Mailing-List: stable@vger.kernel.org
Hi,
This commit:
commit 080399aaaf3531f5b8761ec0ac30ff98891e8686
Author: Jeff Moyer <jmoyer@redhat.com>
Date: Fri May 11 16:34:10 2012 +0200
block: don't mark buffers beyond end of disk as mapped
exposed a bug in __getblk_slow that causes mount to hang as it loops
infinitely waiting for a buffer that lies beyond the end of the disk to
become uptodate. The problem was initially reported by Torsten Hilbrich
here: https://lkml.org/lkml/2012/6/18/54, and also reported
independently here:
http://www.sysresccd.org/forums/viewtopic.php?f=13&t=4511, and then
Richard W.M. Jones and Marcos Mello noted a few separate bugzillas also
associated with the same issue.
The main problem is here, in __getblk_slow:
for (;;) {
struct buffer_head * bh;
int ret;
bh = __find_get_block(bdev, block, size);
if (bh)
return bh;
ret = grow_buffers(bdev, block, size);
if (ret < 0)
return NULL;
if (ret == 0)
free_more_memory();
}
__find_get_block does not find the block, since it will not be marked as
mapped, and so grow_buffers is called to fill in the buffers for the
associated page. I believe the for (;;) loop is there primarily to
retry in the case of memory pressure keeping grow_buffers from
succeeding. However, we also continue to loop for other cases, like the
block lying beond the end of the disk. So, the fix I came up with is to
only loop when grow_buffers fails due to memory allocation issues
(return value of 0).
The attached patch was tested by myself, Torsten, and Rich, and was
found to resolve the problem in call cases.
Comments, as always, are appreciated.
Signed-off-by: Jeff Moyer <jmoyer@redhat.com>
Reported-and-Tested-by: Torsten Hilbrich <torsten.hilbrich@secunet.com>
Tested-by: Richard W.M. Jones <rjones@redhat.com>
Cc: Stable <stable@vger.kernel.org>
--
Stable Notes: this patch requires backport to 3.0, 3.2 and 3.3.
diff --git a/fs/buffer.c b/fs/buffer.c
index 838a9cf..c7062c8 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1036,6 +1036,9 @@ grow_buffers(struct block_device *bdev, sector_t block, int size)
static struct buffer_head *
__getblk_slow(struct block_device *bdev, sector_t block, int size)
{
+ int ret;
+ struct buffer_head *bh;
+
/* Size must be multiple of hard sectorsize */
if (unlikely(size & (bdev_logical_block_size(bdev)-1) ||
(size < 512 || size > PAGE_SIZE))) {
@@ -1048,20 +1051,21 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
return NULL;
}
- for (;;) {
- struct buffer_head * bh;
- int ret;
+retry:
+ bh = __find_get_block(bdev, block, size);
+ if (bh)
+ return bh;
+ ret = grow_buffers(bdev, block, size);
+ if (ret == 0) {
+ free_more_memory();
+ goto retry;
+ } else if (ret > 0) {
bh = __find_get_block(bdev, block, size);
if (bh)
return bh;
-
- ret = grow_buffers(bdev, block, size);
- if (ret < 0)
- return NULL;
- if (ret == 0)
- free_more_memory();
}
+ return NULL;
}
/*
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html