From patchwork Wed Oct 7 04:57:31 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 7342071 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id F1AB5BEEA4 for ; Wed, 7 Oct 2015 04:57:42 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D7DED2066D for ; Wed, 7 Oct 2015 04:57:41 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9760220504 for ; Wed, 7 Oct 2015 04:57:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752990AbbJGE5j (ORCPT ); Wed, 7 Oct 2015 00:57:39 -0400 Received: from userp1040.oracle.com ([156.151.31.81]:44337 "EHLO userp1040.oracle.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752928AbbJGE5j (ORCPT ); Wed, 7 Oct 2015 00:57:39 -0400 Received: from userv0022.oracle.com (userv0022.oracle.com [156.151.31.74]) by userp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id t974vZSG011683 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 7 Oct 2015 04:57:35 GMT Received: from userv0121.oracle.com (userv0121.oracle.com [156.151.31.72]) by userv0022.oracle.com (8.13.8/8.13.8) with ESMTP id t974vZZv005397 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL); Wed, 7 Oct 2015 04:57:35 GMT Received: from abhmp0016.oracle.com (abhmp0016.oracle.com [141.146.116.22]) by userv0121.oracle.com (8.13.8/8.13.8) with ESMTP id t974vZM8018807; Wed, 7 Oct 2015 04:57:35 GMT Received: from localhost (/24.21.154.84) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Tue, 06 Oct 2015 21:57:33 -0700 Subject: [PATCH 22/58] xfs: remove an extent from the rmap btree From: "Darrick J. Wong" To: david@fromorbit.com, darrick.wong@oracle.com Cc: linux-fsdevel@vger.kernel.org, xfs@oss.sgi.com, Dave Chinner Date: Tue, 06 Oct 2015 21:57:31 -0700 Message-ID: <20151007045731.30457.22109.stgit@birch.djwong.org> In-Reply-To: <20151007045443.30457.47038.stgit@birch.djwong.org> References: <20151007045443.30457.47038.stgit@birch.djwong.org> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Source-IP: userv0022.oracle.com [156.151.31.74] Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP >From : Dave Chinner Now that we have records in the rmap btree, we need to remove them when extents are freed. This needs to find the relevant record in the btree and remove/trim/split it accordingly. Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_rmap.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+), 1 deletion(-) -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/fs/xfs/libxfs/xfs_rmap.c b/fs/xfs/libxfs/xfs_rmap.c index bc25f9c..92e417d 100644 --- a/fs/xfs/libxfs/xfs_rmap.c +++ b/fs/xfs/libxfs/xfs_rmap.c @@ -118,6 +118,31 @@ xfs_rmap_get_rec( return 0; } +/* + * Find the extent in the rmap btree and remove it. + * + * The record we find should always span a range greater than or equal to the + * the extent being freed. This makes the code simple as, in theory, we do not + * have to handle ranges that are split across multiple records as extents that + * result in bmap btree extent merges should also result in rmap btree extent + * merges. The owner field ensures we don't merge extents from different + * structures into the same record, hence this property should always hold true + * if we ensure that the rmap btree supports at least the same size maximum + * extent as the bmap btree (bmbt MAXEXTLEN is 2^21 blocks at present, rmap + * btree record can hold 2^32 blocks in a single extent). + * + * Special Case #1: when growing the filesystem, we "free" an extent when + * growing the last AG. This extent is new space and so it is not tracked as + * used space in the btree. The growfs code will pass in an owner of + * XFS_RMAP_OWN_NULL to indicate that it expected that there is no owner of this + * extent. We verify that - the extent lookup result in a record that does not + * overlap. + * + * Special Case #2: EFIs do not record the owner of the extent, so when + * recovering EFIs from the log we pass in XFS_RMAP_OWN_UNKNOWN to tell the rmap + * btree to ignore the owner (i.e. wildcard match) so we don't trigger + * corruption checks during log recovery. + */ int xfs_rmap_free( struct xfs_trans *tp, @@ -128,19 +153,146 @@ xfs_rmap_free( struct xfs_owner_info *oinfo) { struct xfs_mount *mp = tp->t_mountp; + struct xfs_btree_cur *cur; + struct xfs_rmap_irec ltrec; int error = 0; + int i; if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) return 0; trace_xfs_rmap_free_extent(mp, agno, bno, len, oinfo); - if (1) + cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); + + /* + * We should always have a left record because there's a static record + * for the AG headers at rm_startblock == 0 created by mkfs/growfs that + * will not ever be removed from the tree. + */ + error = xfs_rmap_lookup_le(cur, bno, len, owner, &i); + if (error) + goto out_error; + XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); + + error = xfs_rmap_get_rec(cur, <rec, &i); + if (error) goto out_error; + XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); + + /* + * For growfs, the incoming extent must be beyond the left record we + * just found as it is new space and won't be used by anyone. This is + * just a corruption check as we don't actually do anything with this + * extent. + */ + if (owner == XFS_RMAP_OWN_NULL) { + XFS_WANT_CORRUPTED_GOTO(mp, bno > ltrec.rm_startblock + + ltrec.rm_blockcount, out_error); + goto out_done; + } + +/* + if (owner != ltrec.rm_owner || + bno > ltrec.rm_startblock + ltrec.rm_blockcount) + */ + //printk("rmfree ag %d bno 0x%x/0x%x/0x%llx, ltrec 0x%x/0x%x/0x%llx\n", + // agno, bno, len, owner, ltrec.rm_startblock, + // ltrec.rm_blockcount, ltrec.rm_owner); + + /* make sure the extent we found covers the entire freeing range. */ + XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno, out_error); + XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_blockcount >= len, out_error); + XFS_WANT_CORRUPTED_GOTO(mp, + bno <= ltrec.rm_startblock + ltrec.rm_blockcount, out_error); + + /* make sure the owner matches what we expect to find in the tree */ + XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner || + (owner < XFS_RMAP_OWN_NULL && + owner >= XFS_RMAP_OWN_MIN), out_error); + + if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) { + //printk("remove exact\n"); + /* exact match, simply remove the record from rmap tree */ + error = xfs_btree_delete(cur, &i); + if (error) + goto out_error; + XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); + } else if (ltrec.rm_startblock == bno) { + //printk("remove left\n"); + /* + * overlap left hand side of extent: move the start, trim the + * length and update the current record. + * + * ltbno ltlen + * Orig: |oooooooooooooooooooo| + * Freeing: |fffffffff| + * Result: |rrrrrrrrrr| + * bno len + */ + ltrec.rm_startblock += len; + ltrec.rm_blockcount -= len; + error = xfs_rmap_update(cur, <rec); + if (error) + goto out_error; + } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) { + //printk("remove right\n"); + /* + * overlap right hand side of extent: trim the length and update + * the current record. + * + * ltbno ltlen + * Orig: |oooooooooooooooooooo| + * Freeing: |fffffffff| + * Result: |rrrrrrrrrr| + * bno len + */ + ltrec.rm_blockcount -= len; + error = xfs_rmap_update(cur, <rec); + if (error) + goto out_error; + } else { + + /* + * overlap middle of extent: trim the length of the existing + * record to the length of the new left-extent size, increment + * the insertion position so we can insert a new record + * containing the remaining right-extent space. + * + * ltbno ltlen + * Orig: |oooooooooooooooooooo| + * Freeing: |fffffffff| + * Result: |rrrrr| |rrrr| + * bno len + */ + xfs_extlen_t orig_len = ltrec.rm_blockcount; + //printk("remove middle\n"); + + ltrec.rm_blockcount = bno - ltrec.rm_startblock;; + error = xfs_rmap_update(cur, <rec); + if (error) + goto out_error; + + error = xfs_btree_increment(cur, 0, &i); + if (error) + goto out_error; + + cur->bc_rec.r.rm_startblock = bno + len; + cur->bc_rec.r.rm_blockcount = orig_len - len - + ltrec.rm_blockcount; + cur->bc_rec.r.rm_owner = ltrec.rm_owner; + error = xfs_btree_insert(cur, &i); + if (error) + goto out_error; + } + +out_done: trace_xfs_rmap_free_extent_done(mp, agno, bno, len, oinfo); + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); return 0; out_error: trace_xfs_rmap_free_extent_error(mp, agno, bno, len, oinfo); + xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); return error; }