From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ej1-f45.google.com (mail-ej1-f45.google.com [209.85.218.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE7563ACF11 for ; Thu, 7 May 2026 13:22:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.45 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778160128; cv=none; b=uPQUJhaceG+i1JFX6gejePtDpCNLvKufrKFTIrsr8D1jPx3/YWF7fwQkZwzUULxOzsTCKMQgCaq0WZsMJsRWeWquBAGMk1zc+uNzmYyR+ARes4ZHLiA0FPeFn72LtYXCXZbxtBDEvGkTu3I23ejCxZQviEk418F925U6jqIQu4Y= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778160128; c=relaxed/simple; bh=L2XJOyZrWrKGbMX76lFk8wxfTP2LjNiKP523L2LKVA0=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Z18/93hb296S36ke7JkVJn2xCPRy3Dz8lIy1/wRVdSG+UQgPmo6pQpgx8I/Q7SuCu4F4GkmKYUe8I80LxGacN3cTgg3Cy6D6a5tKd5hu07fCcJct5SbyA4rl7vaSYhkC0MSJ1l8XUQcr1mcmEX/03fgFN77aZQwlkdOpBIsORZk= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=permerror header.from=versity.com; spf=pass smtp.mailfrom=versity.com; dkim=pass (2048-bit key) header.d=versity.com header.i=@versity.com header.b=UV9Czc/M; arc=none smtp.client-ip=209.85.218.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=permerror header.from=versity.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=versity.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=versity.com header.i=@versity.com header.b="UV9Czc/M" Received: by mail-ej1-f45.google.com with SMTP id a640c23a62f3a-b93698bb57aso151797366b.0 for ; Thu, 07 May 2026 06:22:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=versity.com; s=google; t=1778160125; x=1778764925; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=Eai2cm1gahvYyvBeJ9OmzINsutAHs+9B109UfNvIaSA=; b=UV9Czc/M0j/Jt3jbBJvjqD6awpXh8B+fP1NAxcTRGpCamM4pn/xM0YepeFMw0qr4Lf hgbp21wJg69VJyB0vVmgbFf6nNIcz9M9BtSHk6NS9eXnwsUN6gvu1hVXFdRf4PiL8eUx UWDzBt0lH8Qw0DwqyXLx3s/Z4unZfFkV0iuzWUISLB3h1CLKs3y0dax+8s4Cm0+ysMeW Ya0Ttt/pnszwCaa3tN5L9Zv1oXDk9MpeFWj3VcfVHWJSS4bMjtBeFdPAvdnRFUUNnIz1 oD8QivbHjZjP+yTylbzIynp7as1tO7UDXGqEqdbo9ZAvMbuDNDlv4eq3e2669ABTpxjQ stFg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778160125; x=1778764925; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=Eai2cm1gahvYyvBeJ9OmzINsutAHs+9B109UfNvIaSA=; b=moPQtBJfp5Mle4b8ohH5W92Vm4Z0tmhEbuKptPddasoMntB0UrlLTYVIR0AprlO4mx 40fMniw+iuS/WeYwqCaDEMERc+xFEfxN5M12AyyZR/adPGYdcYGDXPxaysSb32eVp/M9 Zrn2WMVAX/8TXjzgdQcVqrGukZQ8I0TWmWfDfuV6sezdzhOR10KlmA9oYB10VUTcudri GSOJAyq+ZoLAfOb/U2anfIu/9m11HYyJokA/TTwtgz/aU9y8cXYRHgaCaWdxGhHoKZTQ JnY2KELeN0C212SOFU9uTwFMJvj1/TYZuPJWJLbPb9BcWYZoFwLEe/X7AXurgxG6nX1G 5TiQ== X-Gm-Message-State: AOJu0YwmeRqgNBvXTMEjHXQKjp+8pbjfkZdoZMGlEJAAKLoxHstVOmjk v3bticHb410L0NEZj5aNZkaIBlPMAyZC1Gq8x8cjJ0ywyY11Os2SEQ0OBzWuVarjvneZhntLJlp q0vv6EEs= X-Gm-Gg: AeBDietb1xt25VCG+3EOeKdzTI8pRmX1BFtpVeJtA1ISpOX7hpDib/r4P9gUxSMPP4D XdlDzweOo9P9IcdaatXd7v0QzrMjbU6pgN0KtliGicnKQaDKn1vypcLtrlOENF48B5ypG6Sn+ye P/lSuX2nLLp6mmgtcsYBoBGKEnWrhN3w0kFUo/vOFjkRxHoNngrR6E/qGMHGs6HCnGPkmllRsWV Ru9kXZ67Z+SUgdefgGrzov9KOdDSzFdhFuLA9WbluyqTxq52zpX8wqWi1dhDWEy+pNhTAKmM2QJ oFdX7IMRFI357e3HlV1U52xRrKl5toVdSqgWkUMeh7WXmZmCTPzw1CEbyAttec8J2SdZHGBJl+r QnpseiLA2t7ab422MeVFsBEvjqYH9aj3oIp6dFZe+Vsnc95TBp8i61mWAHPpDyOeZbugqofT6b1 mCq3u0gG2I8DVq9yk2ZLu4xygut/IH+vUzujS5tkwrYV1jCZr28mwi4vOPC9ig1NoT55fgyg4vI ks9LgPsvMav8aOunecyKov56PPlXQn1+TUgug== X-Received: by 2002:a17:906:99c3:b0:bc5:2352:555c with SMTP id a640c23a62f3a-bc85c2b4290mr150158266b.14.1778160124960; Thu, 07 May 2026 06:22:04 -0700 (PDT) Received: from localhost.localdomain (46-117-212-87.ftth.glasoperator.nl. [87.212.117.46]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-bc83364c5e3sm80638666b.35.2026.05.07.06.22.04 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 07 May 2026 06:22:04 -0700 (PDT) From: Valerie Aurora To: rpdfs-devel@lists.linux.dev Subject: [PATCH 4/6] rpdfs: add file data allocation and lookup routines Date: Thu, 7 May 2026 15:21:51 +0200 Message-ID: <20260507132153.1161324-5-val@versity.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20260507132153.1161324-1-val@versity.com> References: <20260507132153.1161324-1-val@versity.com> Precedence: bulk X-Mailing-List: rpdfs-devel@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Add routines to lookup and allocate file data and mapping blocks. Signed-off-by: Valerie Aurora --- fs/rpdfs/data.c | 260 ++++++++++++++++++++++++++++++++++++++++++ fs/rpdfs/format-msg.h | 4 + 2 files changed, 264 insertions(+) diff --git a/fs/rpdfs/data.c b/fs/rpdfs/data.c index 65b753886a04..b1ccf77ced7a 100644 --- a/fs/rpdfs/data.c +++ b/fs/rpdfs/data.c @@ -91,3 +91,263 @@ void rpdfs_data_root_init(struct rpdfs_data_root *data) data->ref.bnr = 0; data->ref.alloc_counter = 0; } + +static int alloc_block_ref(struct rpdfs_fs_info *rfi, struct rpdfs_transaction *txn, + u64 lblk, struct rpdfs_block_ref *ref, struct rpdfs_block_handle **hnd) +{ + int ret; + + ret = rpdfs_txn_acquire_alloc(rfi, txn, hnd); + if (ret < 0) + goto out; + + /* XXX let caller write/clear data blocks */ + memset((*hnd)->data, 0, RPDFS_BLOCK_SIZE); + + ref->bnr = cpu_to_le64((*hnd)->bnr); + ref->alloc_counter = cpu_to_le64((*hnd)->alloc_ctr); +out: + rpdfs_prd("ret %d bnr %llu lblk %llu", ret, ref->bnr, lblk); + return ret; +} + +/* + * The place of a mapping or data block should increase as we descend + * towards the data block, and remain constant as the mapping tree grows + * in height. A data block has the maximum depth value. + */ +static inline void set_data_place(struct rpdfs_block_handle *hnd, u64 ino, u8 level, u64 lblk) +{ + rpdfs_block_set_place(hnd, RPDFS_PLACE_DATA, ino, RPDFS_PLACE_DEPTH_MASK - level, lblk); +} + +static int get_or_alloc_block(struct rpdfs_fs_info *rfi, struct rpdfs_transaction *txn, + struct inode *inode, struct rpdfs_block_handle *inode_hnd, + struct rpdfs_block_handle *parent_hnd, u64 bnr, u64 lblk, + u8 level, rbaf_t data_rbaf, struct rpdfs_block_handle **hnd_ret, + struct rpdfs_block_ref *refs) +{ + rbaf_t rbaf; + int write; + int ret; + + if (level != 0) + rbaf = data_rbaf & RBAF_WRITE ? RBAF_WRITE | RBAF_OVERWRITE : 0; + + write = data_rbaf & RBAF_WRITE ? 1 : 0; + + rpdfs_prd("bnr %llu lblk %llu level %u rbaf %x write %d", + bnr, lblk, level, rbaf, write); + + if (bnr == 0 && write) { + /* XXX move this out? */ + if (parent_hnd != inode_hnd) { + /* reacquire with write permissions */ + bnr = parent_hnd->bnr; + rpdfs_block_release(rfi, &parent_hnd); + ret = rpdfs_block_acquire(rfi, txn, bnr, &parent_hnd, RBAF_WRITE); + if (ret < 0) + goto out; + } + ret = alloc_block_ref(rfi, txn, lblk, refs, hnd_ret); + if (ret < 0) + goto out; + set_data_place(*hnd_ret, rpdfs_inode_ino(inode), level, lblk); + } else { + ret = rpdfs_block_acquire(rfi, txn, bnr, hnd_ret, rbaf); + if (ret < 0) + goto out; + } +out: + return ret; +} + +/* + * Grow the height of the existing mapping block tree to that necessary + * to index the logical block lblk. + */ +static int grow_height(struct rpdfs_fs_info *rfi, struct rpdfs_transaction *txn, + struct inode *inode, u64 lblk) +{ + struct rpdfs_inode_info *ri = RPDFS_I(inode); + struct rpdfs_block_handle *hnd = NULL; + struct rpdfs_block_ref ref; + struct rpdfs_map_block *iblk; + u8 min_height; + int ret = 0; + + min_height = height_from_lblk(lblk); + + if ((ri->data_root.height == 0) || + (min_height == 1) || + (min_height <= ri->data_root.height)) + goto out; + + rpdfs_prd("current height %u goal height %u", ri->data_root.height, min_height); + + /* caller allocates the data block, start at first map block */ + if (ri->data_root.height == 0) + ri->data_root.height++; + + while (ri->data_root.height < min_height) { + rpdfs_prd("allocing map block at level %d for lblk %llu", ri->data_root.height, lblk); + + ret = alloc_block_ref(rfi, txn, lblk, &ref, &hnd); + if (ret < 0) + goto out; + + set_data_place(hnd, rpdfs_inode_ino(inode), ri->data_root.height, lblk); + iblk = hnd->data; + /* growing height will always index old data to 0 */ + iblk->refs[0] = ri->data_root.ref; + /* insert new map block into inode */ + ri->data_root.ref = ref; + ri->data_root.height++; + rpdfs_block_release(rfi, &hnd); + } +out: + /* XXX unwind all changes on error */ + return ret; +} + +/* + * Return an array of block references in mapping blocks, beginning with + * the one containing the requested offset. It may be the root block + * reference in the inode. If it is a write, allocate the mapping blocks + * for that file data offset if necessary. + * + * This function is only called after checking that a read is from a + * valid range of the file. If it is a read for an offset with no + * mapping block allocated to point to it, return a null refs pointer + * and number of references equivalent to a block. If it is a read for + * an offset with a mapping block allocated but no data block, return a + * valid refs pointer for the range including the unallocated data block. + * + * The actual data block allocation occurs in the caller. This is so we + * don't have to traverse the mapping blocks for every data block + * access. + */ +static int get_or_alloc_refs(struct rpdfs_fs_info *rfi, struct rpdfs_transaction *txn, + struct inode *inode, struct rpdfs_block_handle *inode_hnd, + u64 lblk, rbaf_t rbaf, struct rpdfs_block_handle **hnd_ret, + struct rpdfs_block_ref **refs_ret, int *nr_ret) +{ + struct rpdfs_inode_info *ri = RPDFS_I(inode); + struct rpdfs_block_handle *parent_hnd; + struct rpdfs_block_handle *blk_hnd = NULL; + struct rpdfs_block_ref *refs; + struct rpdfs_map_block *iblk; + u64 bnr; + int write; + int nr; + u8 level; + u8 ind; + int ret; + + rpdfs_prd("ino %llu ri->data_root.height %u ri->data_root.ref.bnr %llu lblk %llu rbaf %x", + rpdfs_inode_ino(inode), ri->data_root.height, ri->data_root.ref.bnr, lblk, rbaf); + + write = rbaf & RBAF_WRITE ? 1 : 0; + + /* grow the height of existing data, if any */ + ret = grow_height(rfi, txn, inode, lblk); + if (ret < 0) + goto out; + + /* start with the root of the mapping tree in the inode */ + parent_hnd = inode_hnd; + refs = &ri->data_root.ref; + bnr = le64_to_cpu(ri->data_root.ref.bnr); + ind = 0; + nr = 1; + ret = 0; + + level = ri->data_root.height; + + /* lookup/allocate all map blocks but not the data block itself */ + while (level-- > 1) { + rpdfs_prd("level %d bnr %llu", level, bnr); + + if ((bnr == 0) && !write) { + *hnd_ret = NULL; + *refs_ret = NULL; + *nr_ret = RPDFS_DATA_REFS_PER_BLK; + goto out; + } + ret = get_or_alloc_block(rfi, txn, inode, inode_hnd, parent_hnd, bnr, lblk, level, rbaf, &blk_hnd, refs); + if (ret < 0) + goto out; + + iblk = blk_hnd->data; + + /* look up next block reference */ + ind = calc_ref_ind(lblk, level); + bnr = le64_to_cpu(iblk->refs[ind].bnr); + + if (parent_hnd != inode_hnd) + rpdfs_block_release(rfi, &parent_hnd); + + parent_hnd = blk_hnd; + refs = &iblk->refs[ind]; + nr = RPDFS_DATA_REFS_PER_BLK - ind; + blk_hnd = NULL; + }; + + *hnd_ret = parent_hnd; + *refs_ret = refs; + *nr_ret = nr; +out: + rpdfs_prd("ri->data_root.height %u bnr %llu ind %d refs %p nr %d", + ri->data_root.height, *refs_ret ? (*refs_ret)[0].bnr : 0, ind, refs_ret, *nr_ret); + return ret; +} + +static int get_or_alloc_data_block(struct rpdfs_fs_info *rfi, struct rpdfs_transaction *txn, + struct inode *inode, struct rpdfs_block_handle *inode_hnd, + u64 lblk, rbaf_t data_rbaf, struct rpdfs_block_handle **hnd_ret) +{ + struct rpdfs_block_handle *parent_hnd = NULL; + struct rpdfs_block_handle *blk_hnd = NULL; + struct rpdfs_block_ref *refs = NULL; + rbaf_t map_rbaf; + int nr; + u64 bnr; + int ret; + + /* + * Set the mode for the map block acquisition. Non-blocking + * reads do not need to be non-blocking on map blocks since they + * are not in the page cache and cannot have lock inversion + * problems. For writes, map blocks will not be completely + * overwritten. + */ + if (data_rbaf & RBAF_WRITE) + map_rbaf = RBAF_WRITE; + else + map_rbaf = 0; + + rpdfs_prd("ino %llu lblk %llu data rbaf %x map rbaf %x", rpdfs_inode_ino(inode), lblk, data_rbaf, map_rbaf); + + ret = get_or_alloc_refs(rfi, txn, inode, inode_hnd, lblk, map_rbaf, &parent_hnd, &refs, &nr); + if (ret < 0) + goto out; + + /* read of range with unallocated map blocks */ + if (refs == NULL) + goto out; + + bnr = le64_to_cpu(refs[0].bnr); + + ret = get_or_alloc_block(rfi, txn, inode, inode_hnd, parent_hnd, bnr, lblk, 0, data_rbaf, &blk_hnd, refs); + if (ret < 0) + goto out; + + *hnd_ret = blk_hnd; +out: + if (parent_hnd != inode_hnd) + rpdfs_block_release(rfi, &parent_hnd); + + rpdfs_prd("ret %d ino %llu lblk %llu bnr %llu *hnd_ret %p", + ret, rpdfs_inode_ino(inode), lblk, refs ? le64_to_cpu(refs[0].bnr) : 0, *hnd_ret); + return ret; +} diff --git a/fs/rpdfs/format-msg.h b/fs/rpdfs/format-msg.h index 3bee431e96dc..05dee4443a11 100644 --- a/fs/rpdfs/format-msg.h +++ b/fs/rpdfs/format-msg.h @@ -88,9 +88,13 @@ struct rpdfs_msg_block_read { #define RPDFS_PLACE_INO_MASK ((1ULL << RPDFS_PLACE_INO_BITS) - 1) #define RPDFS_PLACE_TYPE_MASK ((1ULL << RPDFS_PLACE_TYPE_BITS) - 1) +#define RPDFS_PLACE_DEPTH_MAX RPDFS_PLACE_DEPTH_MASK + #define RPDFS_PLACE_INODE 4 #define RPDFS_PLACE_XATTR_BTREE 8 #define RPDFS_PLACE_DIRENT_BTREE 12 +#define RPDFS_PLACE_DATA 16 /* includes mapping blocks */ + /* free is always last so that it's flushed after other blocks in its txn */ #define RPDFS_PLACE_FREE RPDFS_PLACE_TYPE_MASK -- 2.49.0