Received: by 2002:ad5:474a:0:0:0:0:0 with SMTP id i10csp2537230imu; Thu, 29 Nov 2018 06:34:02 -0800 (PST) X-Google-Smtp-Source: AFSGD/VuDXxbeAKddWgYCAto3qTK/j3TuOusau8zqkCEYtpj6hW9aMdisQgeUg+zCc1RlUPRFNbV X-Received: by 2002:a63:181c:: with SMTP id y28mr1399672pgl.75.1543502042756; Thu, 29 Nov 2018 06:34:02 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1543502042; cv=none; d=google.com; s=arc-20160816; b=XA1fSr59DcXxXjx7P8duco6b22wkAixr+VK+A9MAxcJiUorxAXrr5wGGwDYEQqdR77 qKPPdA/OQtT5ozxrkRdzb+zw2T1Lt+YgZQHAgXljRO5z0CQwrSbpTkLOGNHw/M41/HYC pN1alCbPhPNR9bEGW+1NNioBLK48zEQLiC8QdoTF7qLxTqBhLF7Bu8spRKaLWWI5Oj23 nyJKp6FURAVZ7TV8ODSqI2TMyCZ8dBrP0VJI2fjW8yA2/G8aOmFVYBypI/DnK81G4B56 F6CMh1230zKPjMRnJCewSf2CTdZYZpPcTfPZd5qTw3o+F86zOexaJAe4SF7cD+lfBB3q ueww== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=/aKs73YPmQRc6CDV6V4pvy5VsmFQzf2c3gK98jTL3g0=; b=U1CGXEVxmK+5gkAqe9DiUcNxkL04l1Slomeiml96lRlELDgYDHYQPC1ijKwGoAMeRH z6wCtayhFIUe9rfyx1p1fKLMPnW5RXrC+hvjf548MRIElLpTRKNF145c/Fg1Zqi8R7Tn F+hHIPH1n+S4z8EOXL+aaomdeb5dxN9EAei9KJdhzczDxzKdNkd+spB+AQ6swjccRaN+ 5NPFXDmH5dVq9oH/HsI4Hr9+l8Z8NxMfI7Ve3Ur71uOyZD2y8GrSQ/A6LeUrt/Larrgx P5s2BcaHXGwwnvFjdAT78MA6ggtJpKcDJMsafhumQvcEb+euSufnmQRm6Ac3XrjAS7ul JdRQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=HQDSImrJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id ca19si2672485plb.238.2018.11.29.06.33.48; Thu, 29 Nov 2018 06:34:02 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=HQDSImrJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2389415AbeK3Bhw (ORCPT + 99 others); Thu, 29 Nov 2018 20:37:52 -0500 Received: from mail.kernel.org ([198.145.29.99]:41014 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2389406AbeK3Bhv (ORCPT ); Thu, 29 Nov 2018 20:37:51 -0500 Received: from localhost (5356596B.cm-6-7b.dynamic.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 0E1042148E; Thu, 29 Nov 2018 14:32:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1543501937; bh=bfcJBXs7wrFLhyS16YZnO0AylguITDRbUpslJrqkvtg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HQDSImrJnbC8i0nyS5fupgPY8o+LFOh564YP7rbYBvxiWw8F9ydqING+r3j01GQjz UiTErGFJqEhGkeGzHDOPBXbk+RQefjBuTTgmwHK3IyqQxr0Htujqms91COSMEmmq3A nKO+ywxG7RM+f1NEAWajYbNk1aHvt8YHM4UID2Tc= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Andreas Gruenbacher , Linus Torvalds Subject: [PATCH 4.19 103/110] gfs2: Fix iomap buffer head reference counting bug Date: Thu, 29 Nov 2018 15:13:14 +0100 Message-Id: <20181129135925.407006490@linuxfoundation.org> X-Mailer: git-send-email 2.19.2 In-Reply-To: <20181129135921.231283053@linuxfoundation.org> References: <20181129135921.231283053@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.19-stable review patch. If anyone has any objections, please let me know. ------------------ From: Andreas Gruenbacher commit c26b5aa8ef0d46035060fded475e6ab957b9f69f upstream. GFS2 passes the inode buffer head (dibh) from gfs2_iomap_begin to gfs2_iomap_end in iomap->private. It sets that private pointer in gfs2_iomap_get. Users of gfs2_iomap_get other than gfs2_iomap_begin would have to release iomap->private, but this isn't done correctly, leading to a leak of buffer head references. To fix this, move the code for setting iomap->private from gfs2_iomap_get to gfs2_iomap_begin. Fixes: 64bc06bb32 ("gfs2: iomap buffered write support") Cc: stable@vger.kernel.org # v4.19+ Signed-off-by: Andreas Gruenbacher Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/gfs2/bmap.c | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c @@ -826,7 +826,7 @@ static int gfs2_iomap_get(struct inode * ret = gfs2_meta_inode_buffer(ip, &dibh); if (ret) goto unlock; - iomap->private = dibh; + mp->mp_bh[0] = dibh; if (gfs2_is_stuffed(ip)) { if (flags & IOMAP_WRITE) { @@ -863,9 +863,6 @@ unstuff: len = lblock_stop - lblock + 1; iomap->length = len << inode->i_blkbits; - get_bh(dibh); - mp->mp_bh[0] = dibh; - height = ip->i_height; while ((lblock + 1) * sdp->sd_sb.sb_bsize > sdp->sd_heightsize[height]) height++; @@ -898,8 +895,6 @@ out: iomap->bdev = inode->i_sb->s_bdev; unlock: up_read(&ip->i_rw_mutex); - if (ret && dibh) - brelse(dibh); return ret; do_alloc: @@ -980,9 +975,9 @@ static void gfs2_iomap_journaled_page_do static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos, loff_t length, unsigned flags, - struct iomap *iomap) + struct iomap *iomap, + struct metapath *mp) { - struct metapath mp = { .mp_aheight = 1, }; struct gfs2_inode *ip = GFS2_I(inode); struct gfs2_sbd *sdp = GFS2_SB(inode); unsigned int data_blocks = 0, ind_blocks = 0, rblocks; @@ -996,9 +991,9 @@ static int gfs2_iomap_begin_write(struct unstuff = gfs2_is_stuffed(ip) && pos + length > gfs2_max_stuffed_size(ip); - ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp); + ret = gfs2_iomap_get(inode, pos, length, flags, iomap, mp); if (ret) - goto out_release; + goto out_unlock; alloc_required = unstuff || iomap->type == IOMAP_HOLE; @@ -1013,7 +1008,7 @@ static int gfs2_iomap_begin_write(struct ret = gfs2_quota_lock_check(ip, &ap); if (ret) - goto out_release; + goto out_unlock; ret = gfs2_inplace_reserve(ip, &ap); if (ret) @@ -1038,17 +1033,15 @@ static int gfs2_iomap_begin_write(struct ret = gfs2_unstuff_dinode(ip, NULL); if (ret) goto out_trans_end; - release_metapath(&mp); - brelse(iomap->private); - iomap->private = NULL; + release_metapath(mp); ret = gfs2_iomap_get(inode, iomap->offset, iomap->length, - flags, iomap, &mp); + flags, iomap, mp); if (ret) goto out_trans_end; } if (iomap->type == IOMAP_HOLE) { - ret = gfs2_iomap_alloc(inode, iomap, flags, &mp); + ret = gfs2_iomap_alloc(inode, iomap, flags, mp); if (ret) { gfs2_trans_end(sdp); gfs2_inplace_release(ip); @@ -1056,7 +1049,6 @@ static int gfs2_iomap_begin_write(struct goto out_qunlock; } } - release_metapath(&mp); if (!gfs2_is_stuffed(ip) && gfs2_is_jdata(ip)) iomap->page_done = gfs2_iomap_journaled_page_done; return 0; @@ -1069,10 +1061,7 @@ out_trans_fail: out_qunlock: if (alloc_required) gfs2_quota_unlock(ip); -out_release: - if (iomap->private) - brelse(iomap->private); - release_metapath(&mp); +out_unlock: gfs2_write_unlock(inode); return ret; } @@ -1088,10 +1077,10 @@ static int gfs2_iomap_begin(struct inode trace_gfs2_iomap_start(ip, pos, length, flags); if ((flags & IOMAP_WRITE) && !(flags & IOMAP_DIRECT)) { - ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap); + ret = gfs2_iomap_begin_write(inode, pos, length, flags, iomap, &mp); } else { ret = gfs2_iomap_get(inode, pos, length, flags, iomap, &mp); - release_metapath(&mp); + /* * Silently fall back to buffered I/O for stuffed files or if * we've hot a hole (see gfs2_file_direct_write). @@ -1100,6 +1089,11 @@ static int gfs2_iomap_begin(struct inode iomap->type != IOMAP_MAPPED) ret = -ENOTBLK; } + if (!ret) { + get_bh(mp.mp_bh[0]); + iomap->private = mp.mp_bh[0]; + } + release_metapath(&mp); trace_gfs2_iomap_end(ip, iomap, ret); return ret; }