All of lore.kernel.org
 help / color / mirror / Atom feed
From: Valerie Aurora <val@versity.com>
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	[thread overview]
Message-ID: <20260507132153.1161324-5-val@versity.com> (raw)
In-Reply-To: <20260507132153.1161324-1-val@versity.com>

Add routines to lookup and allocate file data and mapping blocks.

Signed-off-by: Valerie Aurora <val@versity.com>
---
 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


  parent reply	other threads:[~2026-05-07 13:22 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-07 13:21 [PATCH 0/6] File data read/write version 2 Valerie Aurora
2026-05-07 13:21 ` [PATCH 1/6] rpdfs: add rpdfs_file_llseek Valerie Aurora
2026-05-07 13:21 ` [PATCH 2/6] rpdfs: add inode change debugging routine Valerie Aurora
2026-05-07 13:21 ` [PATCH 3/6] rpdfs: add basic file data initialization Valerie Aurora
2026-05-07 13:21 ` Valerie Aurora [this message]
2026-05-07 13:21 ` [PATCH 5/6] rpdfs: add rpdfs_write_iter/rpdfs_read_iter Valerie Aurora
2026-05-07 13:21 ` [PATCH 6/6] rpdfs: add read_folio, dirty_folio, write_begin, write_end Valerie Aurora

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260507132153.1161324-5-val@versity.com \
    --to=val@versity.com \
    --cc=rpdfs-devel@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.