From patchwork Tue Jun 9 09:40:15 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: gregkh@suse.de X-Patchwork-Id: 28298 Return-Path: X-Original-To: patchwork-incoming@bilbo.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from ozlabs.org (ozlabs.org [203.10.76.45]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "mx.ozlabs.org", Issuer "CA Cert Signing Authority" (verified OK)) by bilbo.ozlabs.org (Postfix) with ESMTPS id 2F099B70C3 for ; Tue, 9 Jun 2009 20:25:55 +1000 (EST) Received: by ozlabs.org (Postfix) id 22CF8DDD0B; Tue, 9 Jun 2009 20:25:55 +1000 (EST) Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by ozlabs.org (Postfix) with ESMTP id 9A005DDD04 for ; Tue, 9 Jun 2009 20:25:54 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758267AbZFIKWg (ORCPT ); Tue, 9 Jun 2009 06:22:36 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1758261AbZFIKWg (ORCPT ); Tue, 9 Jun 2009 06:22:36 -0400 Received: from kroah.org ([198.145.64.141]:32952 "EHLO coco.kroah.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758001AbZFIKWf (ORCPT ); Tue, 9 Jun 2009 06:22:35 -0400 Received: from localhost (59-124-51-242.HINET-IP.hinet.net [59.124.51.242]) (using TLSv1 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) by coco.kroah.org (Postfix) with ESMTPSA id 994A34913A; Tue, 9 Jun 2009 03:22:36 -0700 (PDT) X-Mailbox-Line: From greg@blue.kroah.org Tue Jun 9 02:41:13 2009 Message-Id: <20090609094112.789197843@blue.kroah.org> User-Agent: quilt/0.48-1 Date: Tue, 09 Jun 2009 02:40:15 -0700 From: Greg KH To: linux-kernel@vger.kernel.org, stable@kernel.org Cc: Justin Forbes , Zwane Mwaikambo , Theodore Ts'o , Randy Dunlap , Dave Jones , Chuck Wolber , Chris Wedgwood , Michael Krufky , Chuck Ebbert , Domenico Andreoli , Willy Tarreau , Rodrigo Rubira Branco , Jake Edge , Eugene Teo , torvalds@linux-foundation.org, akpm@linux-foundation.org, alan@lxorguk.ukuu.org.uk, linux-ext4@vger.kernel.org, Greg Kroah-Hartman Subject: [patch 87/87] ext4: Fix race in ext4_inode_info.i_cached_extent References: <20090609093848.204935043@blue.kroah.org> Content-Disposition: inline; filename=ext4-fix-race-in-ext4_inode_info.i_cached_extent.patch Lines: 78 In-Reply-To: <20090609094451.GA26439@kroah.com> Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org 2.6.29-stable review patch. If anyone has any objections, please let us know. ------------------ From: "Theodore Ts'o" (cherry picked from commit 2ec0ae3acec47f628179ee95fe2c4da01b5e9fc4) If two CPU's simultaneously call ext4_ext_get_blocks() at the same time, there is nothing protecting the i_cached_extent structure from being used and updated at the same time. This could potentially cause the wrong location on disk to be read or written to, including potentially causing the corruption of the block group descriptors and/or inode table. This bug has been in the ext4 code since almost the very beginning of ext4's development. Fortunately once the data is stored in the page cache cache, ext4_get_blocks() doesn't need to be called, so trying to replicate this problem to the point where we could identify its root cause was *extremely* difficult. Many thanks to Kevin Shanahan for working over several months to be able to reproduce this easily so we could finally nail down the cause of the corruption. Signed-off-by: "Theodore Ts'o" Reviewed-by: "Aneesh Kumar K.V" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/extents.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-ext4" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -1740,11 +1740,13 @@ ext4_ext_put_in_cache(struct inode *inod { struct ext4_ext_cache *cex; BUG_ON(len == 0); + spin_lock(&EXT4_I(inode)->i_block_reservation_lock); cex = &EXT4_I(inode)->i_cached_extent; cex->ec_type = type; cex->ec_block = block; cex->ec_len = len; cex->ec_start = start; + spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); } /* @@ -1801,12 +1803,17 @@ ext4_ext_in_cache(struct inode *inode, e struct ext4_extent *ex) { struct ext4_ext_cache *cex; + int ret = EXT4_EXT_CACHE_NO; + /* + * We borrow i_block_reservation_lock to protect i_cached_extent + */ + spin_lock(&EXT4_I(inode)->i_block_reservation_lock); cex = &EXT4_I(inode)->i_cached_extent; /* has cache valid data? */ if (cex->ec_type == EXT4_EXT_CACHE_NO) - return EXT4_EXT_CACHE_NO; + goto errout; BUG_ON(cex->ec_type != EXT4_EXT_CACHE_GAP && cex->ec_type != EXT4_EXT_CACHE_EXTENT); @@ -1817,11 +1824,11 @@ ext4_ext_in_cache(struct inode *inode, e ext_debug("%u cached by %u:%u:%llu\n", block, cex->ec_block, cex->ec_len, cex->ec_start); - return cex->ec_type; + ret = cex->ec_type; } - - /* not in cache */ - return EXT4_EXT_CACHE_NO; +errout: + spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); + return ret; } /*