From patchwork Thu Dec 19 19:21:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13915542 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 15C211A0AFE for ; Thu, 19 Dec 2024 19:21:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636064; cv=none; b=h64XDPqv5Zmds9eWO45qPwFQyWE0818tl64WbrFrtkyO6yjYyvUyNbpR9h1BeQFA93n9Elo7Nb6ikwbEs6T6uNjbiFzpybPjkWcDD5z5294IucrzD7JK3KRU+z0nOmUOQFSZKc0KvdUg19KO15IK4u8BB7y1mi8xUyusQ1+y8xk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636064; c=relaxed/simple; bh=5XM9eyAqCdMecumvdfR3x9tV+L4CxWKFxVCfCmI9bfk=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=f1dW18dxZWk4UsKz57QNs5FxA3MksdLuj13ykJnD8vx68tYC78OAbASq10qDH6h3cQJcRehmTKsRE9cpogy4lqG0kEp+uPAtPSNhq5+c5JgstgE9lRXJlUyl87ECiceAxMRz+n2wuTf3olGOl2sIzQ1N9o5pg9BIox6LKr8IFes= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Indv2bwF; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Indv2bwF" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A2F14C4CECE; Thu, 19 Dec 2024 19:21:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734636063; bh=5XM9eyAqCdMecumvdfR3x9tV+L4CxWKFxVCfCmI9bfk=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=Indv2bwFQU/UEnBAZrHuLS1g9kKOGoYGM0BG/9hItIlMrylm5edndYLmsg1IvPuOc auMCYH9vR0llPawpvtzN2/foJ+TGvdyMbwWGsmLTjwcQ/NP01behOkh2Ux5W2/dlVO S5mnJLgFZc9eixC2qSNaDz8jcNIo/F7GIba0y+6br7QZOYRjxzcDDt6werfxDYjWCf kOcpVFAmGsq5PaQ56AGZ3dTOVbeV8aakN5rPMftIKhvR8SHh9FPBPZgvofJZmMh6in h06qsllmwDZDtbhwbZaKosKrE90hrvVk1faLqQ9fl97NUMai1rW087uosZSnxlGbma wEtJA3wCHz8zQ== Date: Thu, 19 Dec 2024 11:21:03 -0800 Subject: [PATCH 1/8] xfs: tidy up xfs_iroot_realloc From: "Darrick J. Wong" To: djwong@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org, hch@lst.de Message-ID: <173463578667.1571062.14494736624608834807.stgit@frogsfrogsfrogs> In-Reply-To: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> References: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Tidy up this function a bit before we start refactoring the memory handling and move the function to the bmbt code. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_inode_fork.c | 83 +++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c index 1158ca48626b71..7f865479c4159f 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.c +++ b/fs/xfs/libxfs/xfs_inode_fork.c @@ -382,33 +382,32 @@ xfs_iformat_attr_fork( */ void xfs_iroot_realloc( - xfs_inode_t *ip, + struct xfs_inode *ip, int rec_diff, int whichfork) { struct xfs_mount *mp = ip->i_mount; - int cur_max; - struct xfs_ifork *ifp; + struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork); struct xfs_btree_block *new_broot; - int new_max; - size_t new_size; char *np; char *op; + size_t new_size; + short old_size = ifp->if_broot_bytes; + int cur_max; + int new_max; /* * Handle the degenerate case quietly. */ - if (rec_diff == 0) { + if (rec_diff == 0) return; - } - ifp = xfs_ifork_ptr(ip, whichfork); if (rec_diff > 0) { /* * If there wasn't any memory allocated before, just * allocate it now and get out. */ - if (ifp->if_broot_bytes == 0) { + if (old_size == 0) { new_size = xfs_bmap_broot_space_calc(mp, rec_diff); ifp->if_broot = kmalloc(new_size, GFP_KERNEL | __GFP_NOFAIL); @@ -422,13 +421,13 @@ xfs_iroot_realloc( * location. The records don't change location because * they are kept butted up against the btree block header. */ - cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, false); + cur_max = xfs_bmbt_maxrecs(mp, old_size, false); new_max = cur_max + rec_diff; new_size = xfs_bmap_broot_space_calc(mp, new_max); ifp->if_broot = krealloc(ifp->if_broot, new_size, GFP_KERNEL | __GFP_NOFAIL); op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, - ifp->if_broot_bytes); + old_size); np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, (int)new_size); ifp->if_broot_bytes = (int)new_size; @@ -443,52 +442,50 @@ xfs_iroot_realloc( * if_broot buffer. It must already exist. If we go to zero * records, just get rid of the root and clear the status bit. */ - ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0)); - cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, false); + ASSERT(ifp->if_broot != NULL && old_size > 0); + cur_max = xfs_bmbt_maxrecs(mp, old_size, false); new_max = cur_max + rec_diff; ASSERT(new_max >= 0); if (new_max > 0) new_size = xfs_bmap_broot_space_calc(mp, new_max); else new_size = 0; - if (new_size > 0) { - new_broot = kmalloc(new_size, GFP_KERNEL | __GFP_NOFAIL); - /* - * First copy over the btree block header. - */ - memcpy(new_broot, ifp->if_broot, - xfs_bmbt_block_len(ip->i_mount)); - } else { - new_broot = NULL; + if (new_size == 0) { + ifp->if_broot = NULL; + ifp->if_broot_bytes = 0; + return; } /* - * Only copy the keys and pointers if there are any. + * Shrink the btree root by allocating a smaller object and copying the + * fields from the old object to the new object. krealloc does nothing + * if we realloc downwards. */ - if (new_max > 0) { - /* - * First copy the keys. - */ - op = (char *)xfs_bmbt_key_addr(mp, ifp->if_broot, 1); - np = (char *)xfs_bmbt_key_addr(mp, new_broot, 1); - memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_key_t)); + new_broot = kmalloc(new_size, GFP_KERNEL | __GFP_NOFAIL); + /* + * First copy over the btree block header. + */ + memcpy(new_broot, ifp->if_broot, xfs_bmbt_block_len(ip->i_mount)); + + /* + * First copy the keys. + */ + op = (char *)xfs_bmbt_key_addr(mp, ifp->if_broot, 1); + np = (char *)xfs_bmbt_key_addr(mp, new_broot, 1); + memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_key_t)); + + /* + * Then copy the pointers. + */ + op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, old_size); + np = (char *)xfs_bmap_broot_ptr_addr(mp, new_broot, 1, (int)new_size); + memcpy(np, op, new_max * (uint)sizeof(xfs_fsblock_t)); - /* - * Then copy the pointers. - */ - op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, - ifp->if_broot_bytes); - np = (char *)xfs_bmap_broot_ptr_addr(mp, new_broot, 1, - (int)new_size); - memcpy(np, op, new_max * (uint)sizeof(xfs_fsblock_t)); - } kfree(ifp->if_broot); ifp->if_broot = new_broot; ifp->if_broot_bytes = (int)new_size; - if (ifp->if_broot) - ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <= - xfs_inode_fork_size(ip, whichfork)); - return; + ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <= + xfs_inode_fork_size(ip, whichfork)); } From patchwork Thu Dec 19 19:21:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13915543 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C116A1A0AFE for ; Thu, 19 Dec 2024 19:21:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636079; cv=none; b=YTFkLyrL/UA6FXynfaiX8kceaGDvzse4Gy42ig81hzS9Si3NylPG9V+YU4WmeGEAvMCw5aB+v7yq1Bg21oxkZ0fLXsblY1xf3wlVO81kw9uW2zDHnMBCwZX+LziTQ+ec/CUeUU0acHUFKrkoymmIYbcppyVEv80xoTOiOeaWkuE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636079; c=relaxed/simple; bh=7vv/cxmogTtrSII49b6BX2a3DxKpCyesOxdqRKe7M+E=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=m1ENVsOfPXvVcE0aO1MNlMLI8phFJ/mzxCLICM7+hbk9V8BmJzSHa6HWghPsgHGYEX3qYk6sDNPEI8HcWnO/wdFszJAT33lif16HnuzWESc9BfX9xFK3t+j8YKufXAWx8UsV8t1D3wOcq+9gTMieQq9oKks066DYlrSbN2QiZFg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nH43nGcP; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="nH43nGcP" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5BC5CC4CECE; Thu, 19 Dec 2024 19:21:19 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734636079; bh=7vv/cxmogTtrSII49b6BX2a3DxKpCyesOxdqRKe7M+E=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=nH43nGcPJBSBLj10GAxpdHrlp9PXBqaAYJ2G5gp2Cf1FwGVA69BnepM0uIkF7BiXs 7Hcq34hovpSiPTKGVZI7vfiZLjlkGGUZrTdEWwHWCohAFuKHSaTFe8Rmi4J1Cnjr3+ CRgqqjwpdezlH47m+I3Pr93AiHS84kETHK8fbqEtYqn8s+TBjJtU0Bwj3MNDIwf7+A V+zm9VlBWJ6qVvanJhQ+7/ase2JQsglqQfXdo0qcet3/fkLOdvzDUhrubJQa2QyuUZ 6ttCr8My5ncScE64poVYtNA5b+7LLNYOfukwY4rw6feoFrO1h4kCYtkTgeYhd3VYKA +IouwOZTb0LYQ== Date: Thu, 19 Dec 2024 11:21:18 -0800 Subject: [PATCH 2/8] xfs: refactor the inode fork memory allocation functions From: "Darrick J. Wong" To: djwong@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org, hch@lst.de Message-ID: <173463578684.1571062.14125639569728967124.stgit@frogsfrogsfrogs> In-Reply-To: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> References: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Hoist the code that allocates, frees, and reallocates if_broot into a single xfs_iroot_krealloc function. Eventually we're going to push xfs_iroot_realloc into the btree ops structure to handle multiple inode-rooted btrees, but first let's separate out the bits that should stay in xfs_inode_fork.c. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_inode_fork.c | 116 +++++++++++++++++++++++++++------------- fs/xfs/libxfs/xfs_inode_fork.h | 5 ++ 2 files changed, 82 insertions(+), 39 deletions(-) diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c index 7f865479c4159f..294c3c5556836e 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.c +++ b/fs/xfs/libxfs/xfs_inode_fork.c @@ -178,7 +178,7 @@ xfs_iformat_btree( struct xfs_mount *mp = ip->i_mount; xfs_bmdr_block_t *dfp; struct xfs_ifork *ifp; - /* REFERENCED */ + struct xfs_btree_block *broot; int nrecs; int size; int level; @@ -211,16 +211,13 @@ xfs_iformat_btree( return -EFSCORRUPTED; } - ifp->if_broot_bytes = size; - ifp->if_broot = kmalloc(size, - GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOFAIL); - ASSERT(ifp->if_broot != NULL); + broot = xfs_broot_alloc(ifp, size); /* * Copy and convert from the on-disk structure * to the in-memory structure. */ xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork), - ifp->if_broot, size); + broot, size); ifp->if_bytes = 0; ifp->if_data = NULL; @@ -362,6 +359,69 @@ xfs_iformat_attr_fork( return error; } +/* + * Allocate the if_broot component of an inode fork so that it is @new_size + * bytes in size, using __GFP_NOLOCKDEP like all the other code that + * initializes a broot during inode load. Returns if_broot. + */ +struct xfs_btree_block * +xfs_broot_alloc( + struct xfs_ifork *ifp, + size_t new_size) +{ + ASSERT(ifp->if_broot == NULL); + + ifp->if_broot = kmalloc(new_size, + GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOFAIL); + ifp->if_broot_bytes = new_size; + return ifp->if_broot; +} + +/* + * Reallocate the if_broot component of an inode fork so that it is @new_size + * bytes in size. Returns if_broot. + */ +struct xfs_btree_block * +xfs_broot_realloc( + struct xfs_ifork *ifp, + size_t new_size) +{ + /* No size change? No action needed. */ + if (new_size == ifp->if_broot_bytes) + return ifp->if_broot; + + /* New size is zero, free it. */ + if (new_size == 0) { + ifp->if_broot_bytes = 0; + kfree(ifp->if_broot); + ifp->if_broot = NULL; + return NULL; + } + + /* + * Shrinking the iroot means we allocate a new smaller object and copy + * it. We don't trust krealloc not to nop on realloc-down. + */ + if (ifp->if_broot_bytes > 0 && ifp->if_broot_bytes > new_size) { + struct xfs_btree_block *old_broot = ifp->if_broot; + + ifp->if_broot = kmalloc(new_size, GFP_KERNEL | __GFP_NOFAIL); + ifp->if_broot_bytes = new_size; + memcpy(ifp->if_broot, old_broot, new_size); + kfree(old_broot); + return ifp->if_broot; + } + + /* + * Growing the iroot means we can krealloc. This may get us the same + * object. + */ + ifp->if_broot = krealloc(ifp->if_broot, new_size, + GFP_KERNEL | __GFP_NOFAIL); + ifp->if_broot_bytes = new_size; + return ifp->if_broot; +} + /* * Reallocate the space for if_broot based on the number of records * being added or deleted as indicated in rec_diff. Move the records @@ -388,7 +448,6 @@ xfs_iroot_realloc( { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork); - struct xfs_btree_block *new_broot; char *np; char *op; size_t new_size; @@ -409,9 +468,7 @@ xfs_iroot_realloc( */ if (old_size == 0) { new_size = xfs_bmap_broot_space_calc(mp, rec_diff); - ifp->if_broot = kmalloc(new_size, - GFP_KERNEL | __GFP_NOFAIL); - ifp->if_broot_bytes = (int)new_size; + xfs_broot_realloc(ifp, new_size); return; } @@ -424,13 +481,12 @@ xfs_iroot_realloc( cur_max = xfs_bmbt_maxrecs(mp, old_size, false); new_max = cur_max + rec_diff; new_size = xfs_bmap_broot_space_calc(mp, new_max); - ifp->if_broot = krealloc(ifp->if_broot, new_size, - GFP_KERNEL | __GFP_NOFAIL); + + xfs_broot_realloc(ifp, new_size); op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, old_size); np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, (int)new_size); - ifp->if_broot_bytes = (int)new_size; ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <= xfs_inode_fork_size(ip, whichfork)); memmove(np, op, cur_max * (uint)sizeof(xfs_fsblock_t)); @@ -451,39 +507,21 @@ xfs_iroot_realloc( else new_size = 0; if (new_size == 0) { - ifp->if_broot = NULL; - ifp->if_broot_bytes = 0; + xfs_broot_realloc(ifp, 0); return; } /* - * Shrink the btree root by allocating a smaller object and copying the - * fields from the old object to the new object. krealloc does nothing - * if we realloc downwards. - */ - new_broot = kmalloc(new_size, GFP_KERNEL | __GFP_NOFAIL); - /* - * First copy over the btree block header. - */ - memcpy(new_broot, ifp->if_broot, xfs_bmbt_block_len(ip->i_mount)); - - /* - * First copy the keys. - */ - op = (char *)xfs_bmbt_key_addr(mp, ifp->if_broot, 1); - np = (char *)xfs_bmbt_key_addr(mp, new_broot, 1); - memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_key_t)); - - /* - * Then copy the pointers. + * Shrink the btree root by moving the bmbt pointers, since they are + * not butted up against the btree block header, then reallocating + * broot. */ op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, old_size); - np = (char *)xfs_bmap_broot_ptr_addr(mp, new_broot, 1, (int)new_size); - memcpy(np, op, new_max * (uint)sizeof(xfs_fsblock_t)); + np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, + (int)new_size); + memmove(np, op, new_max * (uint)sizeof(xfs_fsblock_t)); - kfree(ifp->if_broot); - ifp->if_broot = new_broot; - ifp->if_broot_bytes = (int)new_size; + xfs_broot_realloc(ifp, new_size); ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <= xfs_inode_fork_size(ip, whichfork)); } diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h index 2373d12fd474f0..e3c5c9121044fd 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.h +++ b/fs/xfs/libxfs/xfs_inode_fork.h @@ -170,6 +170,11 @@ void xfs_iflush_fork(struct xfs_inode *, struct xfs_dinode *, void xfs_idestroy_fork(struct xfs_ifork *ifp); void * xfs_idata_realloc(struct xfs_inode *ip, int64_t byte_diff, int whichfork); +struct xfs_btree_block *xfs_broot_alloc(struct xfs_ifork *ifp, + size_t new_size); +struct xfs_btree_block *xfs_broot_realloc(struct xfs_ifork *ifp, + size_t new_size); + void xfs_iroot_realloc(struct xfs_inode *, int, int); int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int); int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *, From patchwork Thu Dec 19 19:21:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13915544 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6FEC519E985 for ; Thu, 19 Dec 2024 19:21:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636095; cv=none; b=D0VY5wnWHT1QmyopJBtEU1E62lpW8GPiTXi/XksYVCLE8V1KCxlpxAWpyrkLXa5qroRC4LJp9ReC65XALAH3hiIuMFcJCJ6pCXndCMNT7ojqTpGju4s4R+A/8MwxPF1AcVKjpuO4e6sUMk9U9cCWZ+HNMTDD/mmm2uOW3A/bfII= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636095; c=relaxed/simple; bh=KxCSuG/2nAkkKD/two6UhnzmDz+zJaqqbeOzrcKaMsI=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=efa+cml1G43kxdueI2LLzsdmneWorhqQW3qp6/1Yo48RzFNFrVEa26qt2zOMkxSV0LvoVFk1tMCYc3dMWMg18qVeyaYK5Jbsl5f6efcgvXjFKTLRbFXgr7vhvh9r8xkOD6uLfkPuDFlOIy2W2vFe/hxGL5jxBREjBadbZlzquhc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=B50zgMgg; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="B50zgMgg" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F0C40C4CECE; Thu, 19 Dec 2024 19:21:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734636095; bh=KxCSuG/2nAkkKD/two6UhnzmDz+zJaqqbeOzrcKaMsI=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=B50zgMggGH7ikSd+Bkoi/2daZUaf9hKTWMQmjVSvjdljA1fRpzmOWRCom0vjy1Utc uex7mZ51Njqf0wvzodIBqBOmi1bmbOFZ+artcSY1+y4BLZzgEt8mQWEAek9ZDhR6lT b4FhKL8bp+iGtbpJwnXL5am9vAdCSKwxmHkLEsaiqIMaXOy46Kh77C6k/+3/Gr7x/f cCc2FCSyvrG7rfSWqujMPba4S87ud+sMHjF8617wE+p/9Sm+rEPqcJer6i5+TINXOL 8b4aEw9PxPyCiaR4BLvOKkXmCocXU9rhOieDVXz4l+l6sSxnERmZryEBykQsTx9M1Y Owl/IZ6qzvkCQ== Date: Thu, 19 Dec 2024 11:21:34 -0800 Subject: [PATCH 3/8] xfs: make xfs_iroot_realloc take the new numrecs instead of deltas From: "Darrick J. Wong" To: djwong@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org, hch@lst.de Message-ID: <173463578701.1571062.13432669884045060046.stgit@frogsfrogsfrogs> In-Reply-To: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> References: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Change the calling signature of xfs_iroot_realloc to take the ifork and the new number of records in the btree block, not a diff against the current number. This will make the callsites easier to understand. Note that this function is misnamed because it is very specific to the single type of inode-rooted btree supported. This will be addressed in a subsequent patch. Return the new btree root to reduce the amount of code clutter. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_bmap.c | 7 +-- fs/xfs/libxfs/xfs_btree.c | 25 ++++-------- fs/xfs/libxfs/xfs_inode_fork.c | 83 ++++++++++++++++++---------------------- fs/xfs/libxfs/xfs_inode_fork.h | 3 + 4 files changed, 51 insertions(+), 67 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 5255f93bae31f3..8ab38f07cb78dd 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -615,7 +615,7 @@ xfs_bmap_btree_to_extents( xfs_trans_binval(tp, cbp); if (cur->bc_levels[0].bp == cbp) cur->bc_levels[0].bp = NULL; - xfs_iroot_realloc(ip, -1, whichfork); + xfs_iroot_realloc(ip, whichfork, 0); ASSERT(ifp->if_broot == NULL); ifp->if_format = XFS_DINODE_FMT_EXTENTS; *logflagsp |= XFS_ILOG_CORE | xfs_ilog_fext(whichfork); @@ -659,12 +659,11 @@ xfs_bmap_extents_to_btree( * Make space in the inode incore. This needs to be undone if we fail * to expand the root. */ - xfs_iroot_realloc(ip, 1, whichfork); + block = xfs_iroot_realloc(ip, whichfork, 1); /* * Fill in the root. */ - block = ifp->if_broot; xfs_bmbt_init_block(ip, block, NULL, 1, 1); /* * Need a cursor. Can't allocate until bb_level is filled in. @@ -746,7 +745,7 @@ xfs_bmap_extents_to_btree( out_unreserve_dquot: xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); out_root_realloc: - xfs_iroot_realloc(ip, -1, whichfork); + xfs_iroot_realloc(ip, whichfork, 0); ifp->if_format = XFS_DINODE_FMT_EXTENTS; ASSERT(ifp->if_broot == NULL); xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index 68ee1c299c25fd..5714bec26c2084 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -3161,9 +3161,7 @@ xfs_btree_new_iroot( xfs_btree_copy_ptrs(cur, pp, &nptr, 1); - xfs_iroot_realloc(cur->bc_ino.ip, - 1 - xfs_btree_get_numrecs(cblock), - cur->bc_ino.whichfork); + xfs_iroot_realloc(cur->bc_ino.ip, cur->bc_ino.whichfork, 1); xfs_btree_setbuf(cur, level, cbp); @@ -3347,7 +3345,8 @@ xfs_btree_make_block_unfull( if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) { /* A root block that can be made bigger. */ - xfs_iroot_realloc(ip, 1, cur->bc_ino.whichfork); + xfs_iroot_realloc(ip, cur->bc_ino.whichfork, + numrecs + 1); *stat = 1; } else { /* A root block that needs replacing */ @@ -3705,9 +3704,7 @@ STATIC int xfs_btree_kill_iroot( struct xfs_btree_cur *cur) { - int whichfork = cur->bc_ino.whichfork; struct xfs_inode *ip = cur->bc_ino.ip; - struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork); struct xfs_btree_block *block; struct xfs_btree_block *cblock; union xfs_btree_key *kp; @@ -3716,7 +3713,6 @@ xfs_btree_kill_iroot( union xfs_btree_ptr *cpp; struct xfs_buf *cbp; int level; - int index; int numrecs; int error; #ifdef DEBUG @@ -3762,14 +3758,10 @@ xfs_btree_kill_iroot( ASSERT(xfs_btree_ptr_is_null(cur, &ptr)); #endif - index = numrecs - cur->bc_ops->get_maxrecs(cur, level); - if (index) { - xfs_iroot_realloc(cur->bc_ino.ip, index, - cur->bc_ino.whichfork); - block = ifp->if_broot; - } + block = xfs_iroot_realloc(cur->bc_ino.ip, cur->bc_ino.whichfork, + numrecs); - be16_add_cpu(&block->bb_numrecs, index); + block->bb_numrecs = be16_to_cpu(numrecs); ASSERT(block->bb_numrecs == cblock->bb_numrecs); kp = xfs_btree_key_addr(cur, 1, block); @@ -3949,10 +3941,11 @@ xfs_btree_delrec( /* * We're at the root level. First, shrink the root block in-memory. * Try to get rid of the next level down. If we can't then there's - * nothing left to do. + * nothing left to do. numrecs was decremented above. */ if (xfs_btree_at_iroot(cur, level)) { - xfs_iroot_realloc(cur->bc_ino.ip, -1, cur->bc_ino.whichfork); + xfs_iroot_realloc(cur->bc_ino.ip, cur->bc_ino.whichfork, + numrecs); error = xfs_btree_kill_iroot(cur); if (error) diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c index 294c3c5556836e..53bfdf422ad820 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.c +++ b/fs/xfs/libxfs/xfs_inode_fork.c @@ -423,12 +423,10 @@ xfs_broot_realloc( } /* - * Reallocate the space for if_broot based on the number of records - * being added or deleted as indicated in rec_diff. Move the records - * and pointers in if_broot to fit the new size. When shrinking this - * will eliminate holes between the records and pointers created by - * the caller. When growing this will create holes to be filled in - * by the caller. + * Reallocate the space for if_broot based on the number of records. Move the + * records and pointers in if_broot to fit the new size. When shrinking this + * will eliminate holes between the records and pointers created by the caller. + * When growing this will create holes to be filled in by the caller. * * The caller must not request to add more records than would fit in * the on-disk inode root. If the if_broot is currently NULL, then @@ -437,40 +435,47 @@ xfs_broot_realloc( * it can go to zero. * * ip -- the inode whose if_broot area is changing - * ext_diff -- the change in the number of records, positive or negative, - * requested for the if_broot array. + * whichfork -- which inode fork to change + * new_numrecs -- the new number of records requested for the if_broot array + * + * Returns the incore btree root block. */ -void +struct xfs_btree_block * xfs_iroot_realloc( struct xfs_inode *ip, - int rec_diff, - int whichfork) + int whichfork, + unsigned int new_numrecs) { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork); char *np; char *op; - size_t new_size; - short old_size = ifp->if_broot_bytes; - int cur_max; - int new_max; + unsigned int new_size; + unsigned int old_size = ifp->if_broot_bytes; /* - * Handle the degenerate case quietly. + * Block mapping btrees do not support storing zero records; if this + * happens, the fork is being changed to FMT_EXTENTS. Free the broot + * and get out. */ - if (rec_diff == 0) - return; + if (new_numrecs == 0) + return xfs_broot_realloc(ifp, 0); + + new_size = xfs_bmap_broot_space_calc(mp, new_numrecs); + + /* Handle the nop case quietly. */ + if (new_size == old_size) + return ifp->if_broot; + + if (new_size > old_size) { + unsigned int old_numrecs; - if (rec_diff > 0) { /* * If there wasn't any memory allocated before, just * allocate it now and get out. */ - if (old_size == 0) { - new_size = xfs_bmap_broot_space_calc(mp, rec_diff); - xfs_broot_realloc(ifp, new_size); - return; - } + if (old_size == 0) + return xfs_broot_realloc(ifp, new_size); /* * If there is already an existing if_broot, then we need @@ -478,10 +483,7 @@ xfs_iroot_realloc( * location. The records don't change location because * they are kept butted up against the btree block header. */ - cur_max = xfs_bmbt_maxrecs(mp, old_size, false); - new_max = cur_max + rec_diff; - new_size = xfs_bmap_broot_space_calc(mp, new_max); - + old_numrecs = xfs_bmbt_maxrecs(mp, old_size, false); xfs_broot_realloc(ifp, new_size); op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, old_size); @@ -489,27 +491,15 @@ xfs_iroot_realloc( (int)new_size); ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <= xfs_inode_fork_size(ip, whichfork)); - memmove(np, op, cur_max * (uint)sizeof(xfs_fsblock_t)); - return; + memmove(np, op, old_numrecs * (uint)sizeof(xfs_fsblock_t)); + return ifp->if_broot; } /* - * rec_diff is less than 0. In this case, we are shrinking the - * if_broot buffer. It must already exist. If we go to zero - * records, just get rid of the root and clear the status bit. + * We're reducing, but not totally eliminating, numrecs. In this case, + * we are shrinking the if_broot buffer, so it must already exist. */ - ASSERT(ifp->if_broot != NULL && old_size > 0); - cur_max = xfs_bmbt_maxrecs(mp, old_size, false); - new_max = cur_max + rec_diff; - ASSERT(new_max >= 0); - if (new_max > 0) - new_size = xfs_bmap_broot_space_calc(mp, new_max); - else - new_size = 0; - if (new_size == 0) { - xfs_broot_realloc(ifp, 0); - return; - } + ASSERT(ifp->if_broot != NULL && old_size > 0 && new_size > 0); /* * Shrink the btree root by moving the bmbt pointers, since they are @@ -519,11 +509,12 @@ xfs_iroot_realloc( op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, old_size); np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, (int)new_size); - memmove(np, op, new_max * (uint)sizeof(xfs_fsblock_t)); + memmove(np, op, new_numrecs * (uint)sizeof(xfs_fsblock_t)); xfs_broot_realloc(ifp, new_size); ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <= xfs_inode_fork_size(ip, whichfork)); + return ifp->if_broot; } diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h index e3c5c9121044fd..d05eb0bad864e1 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.h +++ b/fs/xfs/libxfs/xfs_inode_fork.h @@ -175,7 +175,8 @@ struct xfs_btree_block *xfs_broot_alloc(struct xfs_ifork *ifp, struct xfs_btree_block *xfs_broot_realloc(struct xfs_ifork *ifp, size_t new_size); -void xfs_iroot_realloc(struct xfs_inode *, int, int); +struct xfs_btree_block *xfs_iroot_realloc(struct xfs_inode *ip, int whichfork, + unsigned int new_numrecs); int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int); int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *, int); From patchwork Thu Dec 19 19:21:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13915545 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0FCF0194A73 for ; Thu, 19 Dec 2024 19:21:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636111; cv=none; b=gDgE4CwHjuXOM9QFCqSYDJacmds5UDcmJpTocpLOf7SxquuDirg5gdcj/1uAAoQpPHshIxtRaC6U+UuohhR96W3qtoapXraAV5C0BJ7FuaD8hsSKSNMr+mjob9T3I20Bkc3DrT9Z6YC/8pedKCvtN+1b8M28zXce5j3mBTzDGvg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636111; c=relaxed/simple; bh=IX1v6P+yhVBBre45Tupl1mNIKWZhEafHgMu9cgq3+e8=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=PRy27BkEj8NoPXka8NY0xfl/Q9AyI8YHYChBRXcp5lQQrmkNSnY0VCtko9uraMJf66nHb6JIYQkU8mGTgDGlNjK6esRX9rzC/ZEmlVLWYrS2Zc4C11Vag3h3rQTBThWHWa7MTXl75vGtTzokaaKODLV/BoTI6BXNl5Uvkn7//2o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=e+5Zn/H6; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="e+5Zn/H6" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9AA34C4CECE; Thu, 19 Dec 2024 19:21:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734636110; bh=IX1v6P+yhVBBre45Tupl1mNIKWZhEafHgMu9cgq3+e8=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=e+5Zn/H6xpBLzpp4Di942Rqdzm+eVNq1l3ttddMLw3cbgdoE+jFigZOHHm4QC0pTX 12qIla/SWrYWYErNmXMbNW+0dlFMY11rWqtrw/ELSt8QnKnLfJrSSLPcbACPljaRlc 49Ovm2Je2pCvFF8m0kBDUuekrh5gVJxKfEYYFmiuSKjVkbD4VLcbYAAAFsqAsVHcBk CialgtAAt9BhoiYz/rF8hdUEpMZOMrV5G9rjU0wOrtU7cs/5bxXb8V1yGfJBX6vrUy PYKmZeRQ2sx2EWMHNL9HHNEizzHVE1kDWaiy2cUOGA7GIzA+iCQ4OHN+2UiBxEmkh2 fk2+hqPJr9WiQ== Date: Thu, 19 Dec 2024 11:21:50 -0800 Subject: [PATCH 4/8] xfs: make xfs_iroot_realloc a bmap btree function From: "Darrick J. Wong" To: djwong@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org, hch@lst.de Message-ID: <173463578718.1571062.14660765119751061902.stgit@frogsfrogsfrogs> In-Reply-To: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> References: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Move the inode fork btree root reallocation function part of the btree ops because it's now mostly bmbt-specific code. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_bmap.c | 6 +- fs/xfs/libxfs/xfs_bmap_btree.c | 104 ++++++++++++++++++++++++++++++++++++++++ fs/xfs/libxfs/xfs_bmap_btree.h | 3 + fs/xfs/libxfs/xfs_btree.c | 11 ++-- fs/xfs/libxfs/xfs_btree.h | 16 ++++++ fs/xfs/libxfs/xfs_inode_fork.c | 96 ------------------------------------- fs/xfs/libxfs/xfs_inode_fork.h | 2 - 7 files changed, 130 insertions(+), 108 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 8ab38f07cb78dd..0842577755f7bb 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -615,7 +615,7 @@ xfs_bmap_btree_to_extents( xfs_trans_binval(tp, cbp); if (cur->bc_levels[0].bp == cbp) cur->bc_levels[0].bp = NULL; - xfs_iroot_realloc(ip, whichfork, 0); + xfs_bmap_broot_realloc(ip, whichfork, 0); ASSERT(ifp->if_broot == NULL); ifp->if_format = XFS_DINODE_FMT_EXTENTS; *logflagsp |= XFS_ILOG_CORE | xfs_ilog_fext(whichfork); @@ -659,7 +659,7 @@ xfs_bmap_extents_to_btree( * Make space in the inode incore. This needs to be undone if we fail * to expand the root. */ - block = xfs_iroot_realloc(ip, whichfork, 1); + block = xfs_bmap_broot_realloc(ip, whichfork, 1); /* * Fill in the root. @@ -745,7 +745,7 @@ xfs_bmap_extents_to_btree( out_unreserve_dquot: xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); out_root_realloc: - xfs_iroot_realloc(ip, whichfork, 0); + xfs_bmap_broot_realloc(ip, whichfork, 0); ifp->if_format = XFS_DINODE_FMT_EXTENTS; ASSERT(ifp->if_broot == NULL); xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c index 3464be771f95d8..22cf2059d54dd4 100644 --- a/fs/xfs/libxfs/xfs_bmap_btree.c +++ b/fs/xfs/libxfs/xfs_bmap_btree.c @@ -516,6 +516,109 @@ xfs_bmbt_keys_contiguous( be64_to_cpu(key2->bmbt.br_startoff)); } +/* + * Reallocate the space for if_broot based on the number of records. Move the + * records and pointers in if_broot to fit the new size. When shrinking this + * will eliminate holes between the records and pointers created by the caller. + * When growing this will create holes to be filled in by the caller. + * + * The caller must not request to add more records than would fit in the + * on-disk inode root. If the if_broot is currently NULL, then if we are + * adding records, one will be allocated. The caller must also not request + * that the number of records go below zero, although it can go to zero. + * + * ip -- the inode whose if_broot area is changing + * whichfork -- which inode fork to change + * new_numrecs -- the new number of records requested for the if_broot array + * + * Returns the incore btree root block. + */ +struct xfs_btree_block * +xfs_bmap_broot_realloc( + struct xfs_inode *ip, + int whichfork, + unsigned int new_numrecs) +{ + struct xfs_mount *mp = ip->i_mount; + struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork); + char *np; + char *op; + unsigned int new_size; + unsigned int old_size = ifp->if_broot_bytes; + + /* + * Block mapping btrees do not support storing zero records; if this + * happens, the fork is being changed to FMT_EXTENTS. Free the broot + * and get out. + */ + if (new_numrecs == 0) + return xfs_broot_realloc(ifp, 0); + + new_size = xfs_bmap_broot_space_calc(mp, new_numrecs); + + /* Handle the nop case quietly. */ + if (new_size == old_size) + return ifp->if_broot; + + if (new_size > old_size) { + unsigned int old_numrecs; + + /* + * If there wasn't any memory allocated before, just + * allocate it now and get out. + */ + if (old_size == 0) + return xfs_broot_realloc(ifp, new_size); + + /* + * If there is already an existing if_broot, then we need + * to realloc() it and shift the pointers to their new + * location. The records don't change location because + * they are kept butted up against the btree block header. + */ + old_numrecs = xfs_bmbt_maxrecs(mp, old_size, false); + xfs_broot_realloc(ifp, new_size); + op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, + old_size); + np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, + (int)new_size); + ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <= + xfs_inode_fork_size(ip, whichfork)); + memmove(np, op, old_numrecs * (uint)sizeof(xfs_fsblock_t)); + return ifp->if_broot; + } + + /* + * We're reducing, but not totally eliminating, numrecs. In this case, + * we are shrinking the if_broot buffer, so it must already exist. + */ + ASSERT(ifp->if_broot != NULL && old_size > 0 && new_size > 0); + + /* + * Shrink the btree root by moving the bmbt pointers, since they are + * not butted up against the btree block header, then reallocating + * broot. + */ + op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, old_size); + np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, + (int)new_size); + memmove(np, op, new_numrecs * (uint)sizeof(xfs_fsblock_t)); + + xfs_broot_realloc(ifp, new_size); + ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <= + xfs_inode_fork_size(ip, whichfork)); + return ifp->if_broot; +} + +static struct xfs_btree_block * +xfs_bmbt_broot_realloc( + struct xfs_btree_cur *cur, + unsigned int new_numrecs) +{ + return xfs_bmap_broot_realloc(cur->bc_ino.ip, cur->bc_ino.whichfork, + new_numrecs); +} + const struct xfs_btree_ops xfs_bmbt_ops = { .name = "bmap", .type = XFS_BTREE_TYPE_INODE, @@ -543,6 +646,7 @@ const struct xfs_btree_ops xfs_bmbt_ops = { .keys_inorder = xfs_bmbt_keys_inorder, .recs_inorder = xfs_bmbt_recs_inorder, .keys_contiguous = xfs_bmbt_keys_contiguous, + .broot_realloc = xfs_bmbt_broot_realloc, }; /* diff --git a/fs/xfs/libxfs/xfs_bmap_btree.h b/fs/xfs/libxfs/xfs_bmap_btree.h index 49a3bae3f6ecec..b238d559ab0369 100644 --- a/fs/xfs/libxfs/xfs_bmap_btree.h +++ b/fs/xfs/libxfs/xfs_bmap_btree.h @@ -198,4 +198,7 @@ xfs_bmap_bmdr_space(struct xfs_btree_block *bb) return xfs_bmdr_space_calc(be16_to_cpu(bb->bb_numrecs)); } +struct xfs_btree_block *xfs_bmap_broot_realloc(struct xfs_inode *ip, + int whichfork, unsigned int new_numrecs); + #endif /* __XFS_BMAP_BTREE_H__ */ diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index 5714bec26c2084..672746f7217cff 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -3161,7 +3161,7 @@ xfs_btree_new_iroot( xfs_btree_copy_ptrs(cur, pp, &nptr, 1); - xfs_iroot_realloc(cur->bc_ino.ip, cur->bc_ino.whichfork, 1); + cur->bc_ops->broot_realloc(cur, 1); xfs_btree_setbuf(cur, level, cbp); @@ -3345,8 +3345,7 @@ xfs_btree_make_block_unfull( if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) { /* A root block that can be made bigger. */ - xfs_iroot_realloc(ip, cur->bc_ino.whichfork, - numrecs + 1); + cur->bc_ops->broot_realloc(cur, numrecs + 1); *stat = 1; } else { /* A root block that needs replacing */ @@ -3758,8 +3757,7 @@ xfs_btree_kill_iroot( ASSERT(xfs_btree_ptr_is_null(cur, &ptr)); #endif - block = xfs_iroot_realloc(cur->bc_ino.ip, cur->bc_ino.whichfork, - numrecs); + block = cur->bc_ops->broot_realloc(cur, numrecs); block->bb_numrecs = be16_to_cpu(numrecs); ASSERT(block->bb_numrecs == cblock->bb_numrecs); @@ -3944,8 +3942,7 @@ xfs_btree_delrec( * nothing left to do. numrecs was decremented above. */ if (xfs_btree_at_iroot(cur, level)) { - xfs_iroot_realloc(cur->bc_ino.ip, cur->bc_ino.whichfork, - numrecs); + cur->bc_ops->broot_realloc(cur, numrecs); error = xfs_btree_kill_iroot(cur); if (error) diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h index c5bff273cae255..8380ae0a64dd5e 100644 --- a/fs/xfs/libxfs/xfs_btree.h +++ b/fs/xfs/libxfs/xfs_btree.h @@ -213,6 +213,22 @@ struct xfs_btree_ops { const union xfs_btree_key *key1, const union xfs_btree_key *key2, const union xfs_btree_key *mask); + + /* + * Reallocate the space for if_broot to fit the number of records. + * Move the records and pointers in if_broot to fit the new size. When + * shrinking this will eliminate holes between the records and pointers + * created by the caller. When growing this will create holes to be + * filled in by the caller. + * + * The caller must not request to add more records than would fit in + * the on-disk inode root. If the if_broot is currently NULL, then if + * we are adding records, one will be allocated. The caller must also + * not request that the number of records go below zero, although it + * can go to zero. + */ + struct xfs_btree_block *(*broot_realloc)(struct xfs_btree_cur *cur, + unsigned int new_numrecs); }; /* btree geometry flags */ diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c index 53bfdf422ad820..60853bac289a39 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.c +++ b/fs/xfs/libxfs/xfs_inode_fork.c @@ -422,102 +422,6 @@ xfs_broot_realloc( return ifp->if_broot; } -/* - * Reallocate the space for if_broot based on the number of records. Move the - * records and pointers in if_broot to fit the new size. When shrinking this - * will eliminate holes between the records and pointers created by the caller. - * When growing this will create holes to be filled in by the caller. - * - * The caller must not request to add more records than would fit in - * the on-disk inode root. If the if_broot is currently NULL, then - * if we are adding records, one will be allocated. The caller must also - * not request that the number of records go below zero, although - * it can go to zero. - * - * ip -- the inode whose if_broot area is changing - * whichfork -- which inode fork to change - * new_numrecs -- the new number of records requested for the if_broot array - * - * Returns the incore btree root block. - */ -struct xfs_btree_block * -xfs_iroot_realloc( - struct xfs_inode *ip, - int whichfork, - unsigned int new_numrecs) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork); - char *np; - char *op; - unsigned int new_size; - unsigned int old_size = ifp->if_broot_bytes; - - /* - * Block mapping btrees do not support storing zero records; if this - * happens, the fork is being changed to FMT_EXTENTS. Free the broot - * and get out. - */ - if (new_numrecs == 0) - return xfs_broot_realloc(ifp, 0); - - new_size = xfs_bmap_broot_space_calc(mp, new_numrecs); - - /* Handle the nop case quietly. */ - if (new_size == old_size) - return ifp->if_broot; - - if (new_size > old_size) { - unsigned int old_numrecs; - - /* - * If there wasn't any memory allocated before, just - * allocate it now and get out. - */ - if (old_size == 0) - return xfs_broot_realloc(ifp, new_size); - - /* - * If there is already an existing if_broot, then we need - * to realloc() it and shift the pointers to their new - * location. The records don't change location because - * they are kept butted up against the btree block header. - */ - old_numrecs = xfs_bmbt_maxrecs(mp, old_size, false); - xfs_broot_realloc(ifp, new_size); - op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, - old_size); - np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, - (int)new_size); - ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <= - xfs_inode_fork_size(ip, whichfork)); - memmove(np, op, old_numrecs * (uint)sizeof(xfs_fsblock_t)); - return ifp->if_broot; - } - - /* - * We're reducing, but not totally eliminating, numrecs. In this case, - * we are shrinking the if_broot buffer, so it must already exist. - */ - ASSERT(ifp->if_broot != NULL && old_size > 0 && new_size > 0); - - /* - * Shrink the btree root by moving the bmbt pointers, since they are - * not butted up against the btree block header, then reallocating - * broot. - */ - op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, old_size); - np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, - (int)new_size); - memmove(np, op, new_numrecs * (uint)sizeof(xfs_fsblock_t)); - - xfs_broot_realloc(ifp, new_size); - ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <= - xfs_inode_fork_size(ip, whichfork)); - return ifp->if_broot; -} - - /* * This is called when the amount of space needed for if_data * is increased or decreased. The change in size is indicated by diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h index d05eb0bad864e1..69ed0919d60b12 100644 --- a/fs/xfs/libxfs/xfs_inode_fork.h +++ b/fs/xfs/libxfs/xfs_inode_fork.h @@ -175,8 +175,6 @@ struct xfs_btree_block *xfs_broot_alloc(struct xfs_ifork *ifp, struct xfs_btree_block *xfs_broot_realloc(struct xfs_ifork *ifp, size_t new_size); -struct xfs_btree_block *xfs_iroot_realloc(struct xfs_inode *ip, int whichfork, - unsigned int new_numrecs); int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int); int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *, int); From patchwork Thu Dec 19 19:22:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13915546 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C3ADF1A7265 for ; Thu, 19 Dec 2024 19:22:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636126; cv=none; b=KSBehCPewXBC+nIA6wGMr5qtyuSZOFDxveJCZYfbJcPhuiwyn6aAx0/xuu2ee4GFIlML0PHNkH3CHHZNZ8j2f97zuNpyEY5Z1IElWf0ZI4Ro1fJjKDKAmyE7W6DsOtW1ukDHqyfv90n9HQjj+/41Q3CdHAYzZv5EuVTktEhYU2c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636126; c=relaxed/simple; bh=P9yJ0kIPlRIXKJ7tn3ftFvACzfTVvwdlMN/DmEblveo=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=pmOByFSDH08fDF4DZoHrQDBg+8JCvy/vpdLrwztxnnpxylGMjZ22DTA30dRhD5aj4475npVLBzMNqZLfE10ncK1+GnIs/9OVpxmSCZQTTrfTNdYtm9B5Od/SPfbfJUjdMf9nfwDuiwXdbU0RHpSKAaoUYTJAH0npoDOsZB4gvOY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mF+2bSy5; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mF+2bSy5" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 46448C4CED0; Thu, 19 Dec 2024 19:22:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734636126; bh=P9yJ0kIPlRIXKJ7tn3ftFvACzfTVvwdlMN/DmEblveo=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=mF+2bSy59B4lsKKtkYXZATbop+tajoRJEvi3Bw9epbVGWrfuPAqO8Mk2OXrwh30Nr 8S2UIxOq7Yot7kROoATuIS6RMe5rj8iUvhsyDCTGB2Nx8kHZ1Qe8mf7GiLglCRkZeH ftV1frnTxXIiKWz9BKhqV6NSTnvjj7oBjK+WNjTkvhRoIgkw6JisSyYbgfXISg5H8g KD7IrhIbxFXICRfXM0JN7qqPb+CnqFJRlS8jgt9SDsYAK43Neo1AgNcsURzfuJVxuF tr8/mNCZqjScvstMJZy06kmBjQy5gksFMmj1NxIBQRUjNM9hhkCSozWD2g2zPT9/Gv tFT8FgPgwbrmw== Date: Thu, 19 Dec 2024 11:22:05 -0800 Subject: [PATCH 5/8] xfs: tidy up xfs_bmap_broot_realloc a bit From: "Darrick J. Wong" To: djwong@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org, hch@lst.de Message-ID: <173463578736.1571062.9995423761448974235.stgit@frogsfrogsfrogs> In-Reply-To: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> References: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Hoist out the code that migrates broot pointers during a resize operation to avoid code duplication and streamline the caller. Also use the correct bmbt pointer type for the sizeof operation. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_bmap_btree.c | 43 +++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/fs/xfs/libxfs/xfs_bmap_btree.c b/fs/xfs/libxfs/xfs_bmap_btree.c index 22cf2059d54dd4..908d7b050e9ce0 100644 --- a/fs/xfs/libxfs/xfs_bmap_btree.c +++ b/fs/xfs/libxfs/xfs_bmap_btree.c @@ -516,6 +516,22 @@ xfs_bmbt_keys_contiguous( be64_to_cpu(key2->bmbt.br_startoff)); } +static inline void +xfs_bmbt_move_ptrs( + struct xfs_mount *mp, + struct xfs_btree_block *broot, + short old_size, + size_t new_size, + unsigned int numrecs) +{ + void *dptr; + void *sptr; + + sptr = xfs_bmap_broot_ptr_addr(mp, broot, 1, old_size); + dptr = xfs_bmap_broot_ptr_addr(mp, broot, 1, new_size); + memmove(dptr, sptr, numrecs * sizeof(xfs_bmbt_ptr_t)); +} + /* * Reallocate the space for if_broot based on the number of records. Move the * records and pointers in if_broot to fit the new size. When shrinking this @@ -541,8 +557,7 @@ xfs_bmap_broot_realloc( { struct xfs_mount *mp = ip->i_mount; struct xfs_ifork *ifp = xfs_ifork_ptr(ip, whichfork); - char *np; - char *op; + struct xfs_btree_block *broot; unsigned int new_size; unsigned int old_size = ifp->if_broot_bytes; @@ -577,15 +592,11 @@ xfs_bmap_broot_realloc( * they are kept butted up against the btree block header. */ old_numrecs = xfs_bmbt_maxrecs(mp, old_size, false); - xfs_broot_realloc(ifp, new_size); - op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, - old_size); - np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, - (int)new_size); - ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <= + broot = xfs_broot_realloc(ifp, new_size); + ASSERT(xfs_bmap_bmdr_space(broot) <= xfs_inode_fork_size(ip, whichfork)); - memmove(np, op, old_numrecs * (uint)sizeof(xfs_fsblock_t)); - return ifp->if_broot; + xfs_bmbt_move_ptrs(mp, broot, old_size, new_size, old_numrecs); + return broot; } /* @@ -599,15 +610,11 @@ xfs_bmap_broot_realloc( * not butted up against the btree block header, then reallocating * broot. */ - op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, old_size); - np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1, - (int)new_size); - memmove(np, op, new_numrecs * (uint)sizeof(xfs_fsblock_t)); - - xfs_broot_realloc(ifp, new_size); - ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <= + xfs_bmbt_move_ptrs(mp, ifp->if_broot, old_size, new_size, new_numrecs); + broot = xfs_broot_realloc(ifp, new_size); + ASSERT(xfs_bmap_bmdr_space(broot) <= xfs_inode_fork_size(ip, whichfork)); - return ifp->if_broot; + return broot; } static struct xfs_btree_block * From patchwork Thu Dec 19 19:22:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13915547 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 632C7194A73 for ; Thu, 19 Dec 2024 19:22:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636142; cv=none; b=GGY5BjMo5qY/2sr76yOloq27u90y8MCjRFcng9nk+B8Gs2QArbGKW0EoB4Jgmy3Khw8pf8efOsOYJBxAHbBGgGcmVhDacaqJkr3QJegvRcGHwnyNYZyz3oN7AmVYiZ7S9s46NJnS7aTDPU1WEOPQpZrOVSkBHAxmhYWp7XigmLE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636142; c=relaxed/simple; bh=85JbGjkkPI2HkN089DZD0SSmdQV7DjxhJMd0rku1rso=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=TrrEI2Smaijx0Ws7SLV+hPPBod/U9Cwse9RaI/KDJ7NSqrqCNmqPYC+uhchdfCymr5MXEESCgArz5x/zTLMHuBUYgeqPT3E4DTDWyY2ut2GRZfrUdvtuoiPLHDdm7B5sZyf6LGmpnqtl3LA0qiWxdXup8bz+J7k0y3bgLy64JIY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZFuPPG8l; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZFuPPG8l" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DC53DC4CECE; Thu, 19 Dec 2024 19:22:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734636141; bh=85JbGjkkPI2HkN089DZD0SSmdQV7DjxhJMd0rku1rso=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=ZFuPPG8l43BUFVLT9PuX6E7LAxsWEXj1UQ0ew4WCJHf7JsUwK8dtHOKW1pWVDx9TB WqEmprbaDvOGqlIVOJlv/GdKVdIjTuo+sjHg91bGoeWMJfvy1Af3RE9W+uP/OWUmnu kXdDZj+fAI1vLt6wDg3me4OJdm/z7kK79R9cCP9b3iUr5fTeeY1QGM88Y389tVZkDf 4Cr+YNeX+DELhgdT6EekZi81Egjz4E7Z0pCvIJ/c7WDj8jAZ2BGj+sQgI93nBa96KT Iz5Dp1UGrK21WaCN4aE1k5hcbXw+BJna5qXXQIISo5jK2D59GMn6OITyIXDOqhcZtq MurdZwM6SNDoQ== Date: Thu, 19 Dec 2024 11:22:21 -0800 Subject: [PATCH 6/8] xfs: hoist the node iroot update code out of xfs_btree_new_iroot From: "Darrick J. Wong" To: djwong@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org, hch@lst.de Message-ID: <173463578753.1571062.4558580052014705437.stgit@frogsfrogsfrogs> In-Reply-To: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> References: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong In preparation for allowing records in an inode btree root, hoist the code that copies keyptrs from an existing node root into a child block to a separate function. Note that the new function explicitly computes the keys of the new child block and stores that in the root block; while the bmap btree could rely on leaving the key alone, realtime rmap needs to set the new high key. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_btree.c | 117 +++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 41 deletions(-) diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index 672746f7217cff..ed09eeee916160 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -3078,6 +3078,78 @@ xfs_btree_split( #define xfs_btree_split __xfs_btree_split #endif /* __KERNEL__ */ +/* + * Move the keys and pointers from a root block to a separate block. + * + * Since the keyptr size does not change, all we have to do is increase the + * tree height, copy the keyptrs to the new internal node (cblock), shrink + * the root, and copy the pointers there. + */ +STATIC int +xfs_btree_promote_node_iroot( + struct xfs_btree_cur *cur, + struct xfs_btree_block *block, + int level, + struct xfs_buf *cbp, + union xfs_btree_ptr *cptr, + struct xfs_btree_block *cblock) +{ + union xfs_btree_key *ckp; + union xfs_btree_key *kp; + union xfs_btree_ptr *cpp; + union xfs_btree_ptr *pp; + int i; + int error; + int numrecs = xfs_btree_get_numrecs(block); + + /* + * Increase tree height, adjusting the root block level to match. + * We cannot change the root btree node size until we've copied the + * block contents to the new child block. + */ + be16_add_cpu(&block->bb_level, 1); + cur->bc_nlevels++; + cur->bc_levels[level + 1].ptr = 1; + + /* + * Adjust the root btree record count, then copy the keys from the old + * root to the new child block. + */ + xfs_btree_set_numrecs(block, 1); + kp = xfs_btree_key_addr(cur, 1, block); + ckp = xfs_btree_key_addr(cur, 1, cblock); + xfs_btree_copy_keys(cur, ckp, kp, numrecs); + + /* Check the pointers and copy them to the new child block. */ + pp = xfs_btree_ptr_addr(cur, 1, block); + cpp = xfs_btree_ptr_addr(cur, 1, cblock); + for (i = 0; i < numrecs; i++) { + error = xfs_btree_debug_check_ptr(cur, pp, i, level); + if (error) + return error; + } + xfs_btree_copy_ptrs(cur, cpp, pp, numrecs); + + /* + * Set the first keyptr to point to the new child block, then shrink + * the memory buffer for the root block. + */ + error = xfs_btree_debug_check_ptr(cur, cptr, 0, level); + if (error) + return error; + xfs_btree_copy_ptrs(cur, pp, cptr, 1); + xfs_btree_get_keys(cur, cblock, kp); + + cur->bc_ops->broot_realloc(cur, 1); + + /* Attach the new block to the cursor and log it. */ + xfs_btree_setbuf(cur, level, cbp); + xfs_btree_log_block(cur, cbp, XFS_BB_ALL_BITS); + xfs_btree_log_keys(cur, cbp, 1, numrecs); + xfs_btree_log_ptrs(cur, cbp, 1, numrecs); + return 0; +} + /* * Copy the old inode root contents into a real block and make the * broot point to it. @@ -3091,14 +3163,10 @@ xfs_btree_new_iroot( struct xfs_buf *cbp; /* buffer for cblock */ struct xfs_btree_block *block; /* btree block */ struct xfs_btree_block *cblock; /* child btree block */ - union xfs_btree_key *ckp; /* child key pointer */ - union xfs_btree_ptr *cpp; /* child ptr pointer */ - union xfs_btree_key *kp; /* pointer to btree key */ - union xfs_btree_ptr *pp; /* pointer to block addr */ + union xfs_btree_ptr *pp; union xfs_btree_ptr nptr; /* new block addr */ int level; /* btree level */ int error; /* error return code */ - int i; /* loop counter */ XFS_BTREE_STATS_INC(cur, newroot); @@ -3136,45 +3204,12 @@ xfs_btree_new_iroot( cblock->bb_u.s.bb_blkno = bno; } - be16_add_cpu(&block->bb_level, 1); - xfs_btree_set_numrecs(block, 1); - cur->bc_nlevels++; - ASSERT(cur->bc_nlevels <= cur->bc_maxlevels); - cur->bc_levels[level + 1].ptr = 1; - - kp = xfs_btree_key_addr(cur, 1, block); - ckp = xfs_btree_key_addr(cur, 1, cblock); - xfs_btree_copy_keys(cur, ckp, kp, xfs_btree_get_numrecs(cblock)); - - cpp = xfs_btree_ptr_addr(cur, 1, cblock); - for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) { - error = xfs_btree_debug_check_ptr(cur, pp, i, level); - if (error) - goto error0; - } - - xfs_btree_copy_ptrs(cur, cpp, pp, xfs_btree_get_numrecs(cblock)); - - error = xfs_btree_debug_check_ptr(cur, &nptr, 0, level); + error = xfs_btree_promote_node_iroot(cur, block, level, cbp, &nptr, + cblock); if (error) goto error0; - xfs_btree_copy_ptrs(cur, pp, &nptr, 1); - - cur->bc_ops->broot_realloc(cur, 1); - - xfs_btree_setbuf(cur, level, cbp); - - /* - * Do all this logging at the end so that - * the root is at the right level. - */ - xfs_btree_log_block(cur, cbp, XFS_BB_ALL_BITS); - xfs_btree_log_keys(cur, cbp, 1, be16_to_cpu(cblock->bb_numrecs)); - xfs_btree_log_ptrs(cur, cbp, 1, be16_to_cpu(cblock->bb_numrecs)); - - *logflags |= - XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_ino.whichfork); + *logflags |= XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_ino.whichfork); *stat = 1; return 0; error0: From patchwork Thu Dec 19 19:22:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13915548 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0A21419E985 for ; Thu, 19 Dec 2024 19:22:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636158; cv=none; b=aIUUdphgyqyumuyjbYO1cHpxVfIgaCtyOypED9C7MypUowI/Qk8C28/mEmU/O8jwO/LSfMQ6hpcmlpby5Y9EFaL+APBFaW/YLF75JV/PZwpyOMaf8kNx0Hv0zYeaLySdtSkb9MV209aL6FUEqXtUmVsPuk2a4KAL2WamlOQDsp8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636158; c=relaxed/simple; bh=is33j7my9Q1gLEW+Pwd/LiMHK9XqVMb325AJdQg9TQg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=bu7kGF1iCRKFXSiqU/+5kGFakj5pJ4eVamdKD/z3d/DGzXLvEPvmNFkCfH6d09rzy5ZjNOz29i7oAqs7O9aTPJoKGE0lVzR+NSRgMjoVM1T9+skek8mkCszPuBbjVQR1pf1OzWQObH9I/pVYqIO4RDylU6lRLyuEHPYIJYjSuww= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=d9mK6hru; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="d9mK6hru" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7DE7CC4CECE; Thu, 19 Dec 2024 19:22:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734636157; bh=is33j7my9Q1gLEW+Pwd/LiMHK9XqVMb325AJdQg9TQg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=d9mK6hruVpmPQxGj03KLuoXLPrAY7xXpSIQB71OFGu8arLjr004twEHjkIvGsx4SJ msyL3oZfDrIJXvUv6FxSHgYuDIsI8wbDOI0fw6Vz22/JJ44Qvw5cwQWON2aA+h/qVe gA0Gl3BedIe1JQvkFzPNMyuw1LqWodf2CiCCk9AmKkULKYm95ribVHYCoLk9xF0SKq 2QcDE3tvS6TVH/dNN1sGxNIRijnOGT0Fwwa5jPG8ic7MPdls8E3h6/mHfIRlGyV7ib 2zDztDJhU8T86+X9/BUhWeaZeOGRa/dmMTLbcCLgdxhmHJwDgJ+5irSYyyzBvWjYX6 vAVQ7166RmgAw== Date: Thu, 19 Dec 2024 11:22:37 -0800 Subject: [PATCH 7/8] xfs: hoist the node iroot update code out of xfs_btree_kill_iroot From: "Darrick J. Wong" To: djwong@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org, hch@lst.de Message-ID: <173463578770.1571062.10151970909407600917.stgit@frogsfrogsfrogs> In-Reply-To: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> References: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong In preparation for allowing records in an inode btree root, hoist the code that copies keyptrs from an existing node child into the root block to a separate function. Remove some unnecessary conditionals and clean up a few function calls in the new function. Note that this change reorders the ->free_block call with respect to the change in bc_nlevels to make it easier to support inode root leaf blocks in the next patch. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_btree.c | 84 +++++++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index ed09eeee916160..e83a8de5fb8746 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -3726,6 +3726,60 @@ xfs_btree_insert( return error; } +/* + * Move the keyptrs from a child node block to the root block. + * + * Since the keyptr size does not change, all we have to do is increase the + * tree height, copy the keyptrs to the new internal node (cblock), shrink + * the root, and copy the pointers there. + */ +STATIC int +xfs_btree_demote_node_child( + struct xfs_btree_cur *cur, + struct xfs_btree_block *cblock, + int level, + int numrecs) +{ + struct xfs_btree_block *block; + union xfs_btree_key *ckp; + union xfs_btree_key *kp; + union xfs_btree_ptr *cpp; + union xfs_btree_ptr *pp; + int i; + int error; + + /* + * Adjust the root btree node size and the record count to match the + * doomed child so that we can copy the keyptrs ahead of changing the + * tree shape. + */ + block = cur->bc_ops->broot_realloc(cur, numrecs); + + xfs_btree_set_numrecs(block, numrecs); + ASSERT(block->bb_numrecs == cblock->bb_numrecs); + + /* Copy keys from the doomed block. */ + kp = xfs_btree_key_addr(cur, 1, block); + ckp = xfs_btree_key_addr(cur, 1, cblock); + xfs_btree_copy_keys(cur, kp, ckp, numrecs); + + /* Copy pointers from the doomed block. */ + pp = xfs_btree_ptr_addr(cur, 1, block); + cpp = xfs_btree_ptr_addr(cur, 1, cblock); + for (i = 0; i < numrecs; i++) { + error = xfs_btree_debug_check_ptr(cur, cpp, i, level - 1); + if (error) + return error; + } + xfs_btree_copy_ptrs(cur, pp, cpp, numrecs); + + /* Decrease tree height, adjusting the root block level to match. */ + cur->bc_levels[level - 1].bp = NULL; + be16_add_cpu(&block->bb_level, -1); + cur->bc_nlevels--; + return 0; +} + /* * Try to merge a non-leaf block back into the inode root. * @@ -3741,10 +3795,6 @@ xfs_btree_kill_iroot( struct xfs_inode *ip = cur->bc_ino.ip; struct xfs_btree_block *block; struct xfs_btree_block *cblock; - union xfs_btree_key *kp; - union xfs_btree_key *ckp; - union xfs_btree_ptr *pp; - union xfs_btree_ptr *cpp; struct xfs_buf *cbp; int level; int numrecs; @@ -3752,7 +3802,6 @@ xfs_btree_kill_iroot( #ifdef DEBUG union xfs_btree_ptr ptr; #endif - int i; ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_INODE); ASSERT(cur->bc_nlevels > 1); @@ -3792,35 +3841,16 @@ xfs_btree_kill_iroot( ASSERT(xfs_btree_ptr_is_null(cur, &ptr)); #endif - block = cur->bc_ops->broot_realloc(cur, numrecs); - - block->bb_numrecs = be16_to_cpu(numrecs); - ASSERT(block->bb_numrecs == cblock->bb_numrecs); - - kp = xfs_btree_key_addr(cur, 1, block); - ckp = xfs_btree_key_addr(cur, 1, cblock); - xfs_btree_copy_keys(cur, kp, ckp, numrecs); - - pp = xfs_btree_ptr_addr(cur, 1, block); - cpp = xfs_btree_ptr_addr(cur, 1, cblock); - - for (i = 0; i < numrecs; i++) { - error = xfs_btree_debug_check_ptr(cur, cpp, i, level - 1); - if (error) - return error; - } - - xfs_btree_copy_ptrs(cur, pp, cpp, numrecs); + error = xfs_btree_demote_node_child(cur, cblock, level, numrecs); + if (error) + return error; error = xfs_btree_free_block(cur, cbp); if (error) return error; - cur->bc_levels[level - 1].bp = NULL; - be16_add_cpu(&block->bb_level, -1); xfs_trans_log_inode(cur->bc_tp, ip, XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_ino.whichfork)); - cur->bc_nlevels--; out0: return 0; } From patchwork Thu Dec 19 19:22:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Darrick J. Wong" X-Patchwork-Id: 13915549 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 89C081A76CB for ; Thu, 19 Dec 2024 19:22:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636173; cv=none; b=M13JgcjH2uxI9Vy/teatrylyNenhHqKs3+8kyCZE1o04S0I9jRPtdP3iQeL7jx4Z7kZOO8MTgncwNP/E5vLvzZ4FSgu9hyxbbOlI9kyYNpFdNSnyGDgnWyoQoUSeDHQFwsoLN4m9Z0B2A2URzaT9N/rd4pr/fuVLDbuEQt3TRfs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734636173; c=relaxed/simple; bh=IQo0YLpuPwfjv8xCc70oAzX4ni/s7NNXEWcsXuKLBHg=; h=Date:Subject:From:To:Cc:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Ox4Wg1WOe87toUZTPYTgkHv5jdWLlegTfMjV/5zj44ZmbGG7TlOex9ihVW8rULtjvn55N9JWXmc9ueBQOWdd2ZwB3hsQTstBCM/GSqjdr4JbHUFdB+rYw36ajatPl9NydZAOOCY7QWsXvgU9p7qT+65xKyDXQ3EV79Her5WT6IY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=XBnvZCza; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="XBnvZCza" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 23430C4CECE; Thu, 19 Dec 2024 19:22:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734636173; bh=IQo0YLpuPwfjv8xCc70oAzX4ni/s7NNXEWcsXuKLBHg=; h=Date:Subject:From:To:Cc:In-Reply-To:References:From; b=XBnvZCzaMS/nmSdBl0QIWn/2mjWt79GWO6GqsJjznsYRVXnaAyKWaox2MxNc0M0lG cniGMRwNo77cv3plCEjNLj4ovGC8GB9pqKZU0xPN1KuwC/0o/MiKL2YyqgQuCY4374 qP8Sx2ktguFf1kp98PXlYmcDorIryKZJD0eXPbLGAj32FFgH9cogLnG6rn6hHirYtV yzt8sCKXxA/wVwlKgD6zkpQx/80sFBFPSAkE5YptQfT7zR/gGinJn134wJeZpdKNiJ s0Rc6l+Xbt4oTbWQmzvOpN+XeQLjT8+99vYVsSg8Wlf2opCY5M2g/jOGNO5k8eGjwX wNZTRfXcsG7Mg== Date: Thu, 19 Dec 2024 11:22:52 -0800 Subject: [PATCH 8/8] xfs: support storing records in the inode core root From: "Darrick J. Wong" To: djwong@kernel.org Cc: hch@lst.de, linux-xfs@vger.kernel.org, hch@lst.de Message-ID: <173463578787.1571062.1172893721532300431.stgit@frogsfrogsfrogs> In-Reply-To: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> References: <173463578631.1571062.6149474539778937307.stgit@frogsfrogsfrogs> Precedence: bulk X-Mailing-List: linux-xfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: Darrick J. Wong Add the necessary flags and code so that we can support storing leaf records in the inode root block of a btree. This hasn't been necessary before, but the realtime rmapbt will need to be able to do this. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_btree.c | 138 ++++++++++++++++++++++++++++++++++--- fs/xfs/libxfs/xfs_btree.h | 2 - fs/xfs/libxfs/xfs_btree_staging.c | 9 ++ 3 files changed, 132 insertions(+), 17 deletions(-) diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c index e83a8de5fb8746..5ab201ef041e7d 100644 --- a/fs/xfs/libxfs/xfs_btree.c +++ b/fs/xfs/libxfs/xfs_btree.c @@ -1537,12 +1537,16 @@ xfs_btree_log_recs( int first, int last) { + if (!bp) { + xfs_trans_log_inode(cur->bc_tp, cur->bc_ino.ip, + xfs_ilog_fbroot(cur->bc_ino.whichfork)); + return; + } xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); xfs_trans_log_buf(cur->bc_tp, bp, xfs_btree_rec_offset(cur, first), xfs_btree_rec_offset(cur, last + 1) - 1); - } /* @@ -3078,6 +3082,59 @@ xfs_btree_split( #define xfs_btree_split __xfs_btree_split #endif /* __KERNEL__ */ +/* Move the records from a root leaf block to a separate block. */ +STATIC void +xfs_btree_promote_leaf_iroot( + struct xfs_btree_cur *cur, + struct xfs_btree_block *block, + struct xfs_buf *cbp, + union xfs_btree_ptr *cptr, + struct xfs_btree_block *cblock) +{ + union xfs_btree_rec *rp; + union xfs_btree_rec *crp; + union xfs_btree_key *kp; + union xfs_btree_ptr *pp; + struct xfs_btree_block *broot; + int numrecs = xfs_btree_get_numrecs(block); + + /* Copy the records from the leaf broot into the new child block. */ + rp = xfs_btree_rec_addr(cur, 1, block); + crp = xfs_btree_rec_addr(cur, 1, cblock); + xfs_btree_copy_recs(cur, crp, rp, numrecs); + + /* + * Increment the tree height. + * + * Trickery here: The amount of memory that we need per record for the + * ifork's btree root block may change when we convert the broot from a + * leaf to a node block. Free the existing leaf broot so that nobody + * thinks we need to migrate node pointers when we realloc the broot + * buffer after bumping nlevels. + */ + cur->bc_ops->broot_realloc(cur, 0); + cur->bc_nlevels++; + cur->bc_levels[1].ptr = 1; + + /* + * Allocate a new node broot and initialize it to point to the new + * child block. + */ + broot = cur->bc_ops->broot_realloc(cur, 1); + xfs_btree_init_block(cur->bc_mp, broot, cur->bc_ops, + cur->bc_nlevels - 1, 1, cur->bc_ino.ip->i_ino); + + pp = xfs_btree_ptr_addr(cur, 1, broot); + kp = xfs_btree_key_addr(cur, 1, broot); + xfs_btree_copy_ptrs(cur, pp, cptr, 1); + xfs_btree_get_keys(cur, cblock, kp); + + /* Attach the new block to the cursor and log it. */ + xfs_btree_setbuf(cur, 0, cbp); + xfs_btree_log_block(cur, cbp, XFS_BB_ALL_BITS); + xfs_btree_log_recs(cur, cbp, 1, numrecs); +} + /* * Move the keys and pointers from a root block to a separate block. * @@ -3163,7 +3220,7 @@ xfs_btree_new_iroot( struct xfs_buf *cbp; /* buffer for cblock */ struct xfs_btree_block *block; /* btree block */ struct xfs_btree_block *cblock; /* child btree block */ - union xfs_btree_ptr *pp; + union xfs_btree_ptr aptr; union xfs_btree_ptr nptr; /* new block addr */ int level; /* btree level */ int error; /* error return code */ @@ -3175,10 +3232,15 @@ xfs_btree_new_iroot( level = cur->bc_nlevels - 1; block = xfs_btree_get_iroot(cur); - pp = xfs_btree_ptr_addr(cur, 1, block); + ASSERT(level > 0 || (cur->bc_ops->geom_flags & XFS_BTGEO_IROOT_RECORDS)); + if (level > 0) + aptr = *xfs_btree_ptr_addr(cur, 1, block); + else + aptr.l = cpu_to_be64(XFS_INO_TO_FSB(cur->bc_mp, + cur->bc_ino.ip->i_ino)); /* Allocate the new block. If we can't do it, we're toast. Give up. */ - error = xfs_btree_alloc_block(cur, pp, &nptr, stat); + error = xfs_btree_alloc_block(cur, &aptr, &nptr, stat); if (error) goto error0; if (*stat == 0) @@ -3204,10 +3266,14 @@ xfs_btree_new_iroot( cblock->bb_u.s.bb_blkno = bno; } - error = xfs_btree_promote_node_iroot(cur, block, level, cbp, &nptr, - cblock); - if (error) - goto error0; + if (level > 0) { + error = xfs_btree_promote_node_iroot(cur, block, level, cbp, + &nptr, cblock); + if (error) + goto error0; + } else { + xfs_btree_promote_leaf_iroot(cur, block, cbp, &nptr, cblock); + } *logflags |= XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_ino.whichfork); *stat = 1; @@ -3726,6 +3792,43 @@ xfs_btree_insert( return error; } +/* Move the records from a child leaf block to the root block. */ +STATIC void +xfs_btree_demote_leaf_child( + struct xfs_btree_cur *cur, + struct xfs_btree_block *cblock, + int numrecs) +{ + union xfs_btree_rec *rp; + union xfs_btree_rec *crp; + struct xfs_btree_block *broot; + + /* + * Decrease the tree height. + * + * Trickery here: The amount of memory that we need per record for the + * ifork's btree root block may change when we convert the broot from a + * node to a leaf. Free the old node broot so that we can get a fresh + * leaf broot. + */ + cur->bc_ops->broot_realloc(cur, 0); + cur->bc_nlevels--; + + /* + * Allocate a new leaf broot and copy the records from the old child. + * Detach the old child from the cursor. + */ + broot = cur->bc_ops->broot_realloc(cur, numrecs); + xfs_btree_init_block(cur->bc_mp, broot, cur->bc_ops, 0, numrecs, + cur->bc_ino.ip->i_ino); + + rp = xfs_btree_rec_addr(cur, 1, broot); + crp = xfs_btree_rec_addr(cur, 1, cblock); + xfs_btree_copy_recs(cur, rp, crp, numrecs); + + cur->bc_levels[0].bp = NULL; +} + /* * Move the keyptrs from a child node block to the root block. * @@ -3804,14 +3907,19 @@ xfs_btree_kill_iroot( #endif ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_INODE); - ASSERT(cur->bc_nlevels > 1); + ASSERT((cur->bc_ops->geom_flags & XFS_BTGEO_IROOT_RECORDS) || + cur->bc_nlevels > 1); /* * Don't deal with the root block needs to be a leaf case. * We're just going to turn the thing back into extents anyway. */ level = cur->bc_nlevels - 1; - if (level == 1) + if (level == 1 && !(cur->bc_ops->geom_flags & XFS_BTGEO_IROOT_RECORDS)) + goto out0; + + /* If we're already a leaf, jump out. */ + if (level == 0) goto out0; /* @@ -3841,9 +3949,13 @@ xfs_btree_kill_iroot( ASSERT(xfs_btree_ptr_is_null(cur, &ptr)); #endif - error = xfs_btree_demote_node_child(cur, cblock, level, numrecs); - if (error) - return error; + if (level > 1) { + error = xfs_btree_demote_node_child(cur, cblock, level, + numrecs); + if (error) + return error; + } else + xfs_btree_demote_leaf_child(cur, cblock, numrecs); error = xfs_btree_free_block(cur, cbp); if (error) diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h index 8380ae0a64dd5e..3b8c2ccad90847 100644 --- a/fs/xfs/libxfs/xfs_btree.h +++ b/fs/xfs/libxfs/xfs_btree.h @@ -233,7 +233,7 @@ struct xfs_btree_ops { /* btree geometry flags */ #define XFS_BTGEO_OVERLAPPING (1U << 0) /* overlapping intervals */ - +#define XFS_BTGEO_IROOT_RECORDS (1U << 1) /* iroot can store records */ union xfs_btree_irec { struct xfs_alloc_rec_incore a; diff --git a/fs/xfs/libxfs/xfs_btree_staging.c b/fs/xfs/libxfs/xfs_btree_staging.c index 6949297031529e..58c146b5c9d479 100644 --- a/fs/xfs/libxfs/xfs_btree_staging.c +++ b/fs/xfs/libxfs/xfs_btree_staging.c @@ -573,6 +573,7 @@ xfs_btree_bload_compute_geometry( struct xfs_btree_bload *bbl, uint64_t nr_records) { + const struct xfs_btree_ops *ops = cur->bc_ops; uint64_t nr_blocks = 0; uint64_t nr_this_level; @@ -599,7 +600,7 @@ xfs_btree_bload_compute_geometry( xfs_btree_bload_level_geometry(cur, bbl, level, nr_this_level, &avg_per_block, &level_blocks, &dontcare64); - if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE) { + if (ops->type == XFS_BTREE_TYPE_INODE) { /* * If all the items we want to store at this level * would fit in the inode root block, then we have our @@ -607,7 +608,9 @@ xfs_btree_bload_compute_geometry( * * Note that bmap btrees forbid records in the root. */ - if (level != 0 && nr_this_level <= avg_per_block) { + if ((level != 0 || + (ops->geom_flags & XFS_BTGEO_IROOT_RECORDS)) && + nr_this_level <= avg_per_block) { nr_blocks++; break; } @@ -658,7 +661,7 @@ xfs_btree_bload_compute_geometry( return -EOVERFLOW; bbl->btree_height = cur->bc_nlevels; - if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE) + if (ops->type == XFS_BTREE_TYPE_INODE) bbl->nr_blocks = nr_blocks - 1; else bbl->nr_blocks = nr_blocks;