[PATCH 6/8] rpdfs: add file data allocation and lookup routines
Valerie Aurora <[email protected]> Fri, 24 Apr 2026 16:05:18 +0200
| Newsgroups | dev.linux.lists.rpdfs-devel |
|---|---|
| Message-ID | <[email protected]> |
Add routines to lookup and allocate file data and mapping blocks. Signed-off-by: Valerie Aurora <[email protected]> --- fs/rpdfs/data.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) diff --git a/fs/rpdfs/data.c b/fs/rpdfs/data.c index b7538004d14a..3a6e9560b32f 100644 --- a/fs/rpdfs/data.c +++ b/fs/rpdfs/data.c @@ -88,3 +88,223 @@ 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, + struct rpdfs_block_ref *ref, struct rpdfs_block_handle **blk_hnd) +{ + int ret; + + ret = rpdfs_txn_acquire_alloc(rfi, txn, blk_hnd); + if (ret < 0) + goto out; + + memset((*blk_hnd)->data, 0, RPDFS_BLOCK_SIZE); + + ref->bnr = cpu_to_le64((*blk_hnd)->bnr); + ref->alloc_counter = 0; /* XXX */ +out: + rpdfs_prd("ret %d bnr %llu", ret, ref->bnr); + return ret; +} + +static int grow_height(struct rpdfs_fs_info *rfi, struct rpdfs_transaction *txn, + struct inode *inode, struct rpdfs_block_handle *inode_hnd, int height) +{ + struct rpdfs_inode_info *ri = RPDFS_I(inode); + struct rpdfs_block_handle *hnd = NULL; + struct rpdfs_block_ref *ref; + struct rpdfs_map_block *iblk; + struct rpdfs_data_root *dr; + struct rpdfs_block_ref orig_root; + u8 level; + int ret; + + dr = &ri->data_root; + + rpdfs_prd("dr->height %u goal height %u", dr->height, height); + + ret = 0; + if (height > dr->height) { + /* start at root and fill in till we get to existing tree */ + level = height; + orig_root = dr->ref; /* save current root of tree */ + ref = &dr->ref; + + while (level-- > dr->height) { + rpdfs_prd("allocing block at level %d", level + 1); + hnd = NULL; + ret = alloc_block_ref(rfi, txn, &dr->ref, &hnd); + if (ret < 0) + goto out; + iblk = hnd->data; + /* growing height will always index old data to 0 */ + ref = &iblk->refs[0]; + rpdfs_block_release(rfi, &hnd); + } + rpdfs_prd("grafting old height %d tree to new %d height tree", + dr->height, height); + /* now put existing tree in mapping block */ + *ref = orig_root; + /* and update the height in the data root in the inode */ + ri->data_root.height = height; + } +out: + return ret; +} + +/* + * Return an array of block references in mapping blocks, beginning with + * the one containing the requested offset. If it is a write, allocate + * the mapping blocks for that file data offset if necessary. If it is a + * read for an unallocated but valid offset, return a null range. 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. + * + * This function is only called after checking that a read is from a + * valid range of the file. + * + * XXX: Takes write access on map blocks on write even when it only + * needs to read them. Redescend with write when we know we have to + * allocate? + */ +static int get_or_alloc_map_blk(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; + struct rpdfs_data_root *dr; + rbaf_t map_rbaf; + u8 min_height; + u8 level; + u8 ind; + u64 bnr; + int write; + int nr; + int ret; + + map_rbaf = rbaf & RBAF_WRITE ? RBAF_WRITE : 0; + write = rbaf & RBAF_WRITE ? 1 : 0; + + dr = &ri->data_root; + min_height = height_from_lblk(lblk); + + rpdfs_prd("ino %llu dr->height %u dr->ref.bnr %llu lblk %llu lblk height %u map_rbaf %x write %d", + ri->ig.ino, dr->height, dr->ref.bnr, lblk, min_height, map_rbaf, write); + + /* grow the height of existing data, if any */ + if ((min_height > 1) && + (min_height > dr->height)) { + ret = grow_height(rfi, txn, inode, inode_hnd, min_height); + if (ret < 0) + goto out; + } + + /* start with the root of the mapping tree in the inode */ + parent_hnd = inode_hnd; + refs = &dr->ref; + bnr = le64_to_cpu(dr->ref.bnr); + ind = 0; + nr = 1; + ret = 0; + + level = dr->height; + + /* allocate all map blocks but not the data block itself */ + while (level-- > 1) { + rpdfs_prd("level %d bnr %llu", level + 1, bnr); + + if (bnr == 0 && !write) { + rpdfs_prd("read of unallocated block"); + break; + } + + if (bnr) { + /* TODO: be smarter about needing write */ + ret = rpdfs_block_acquire(rfi, txn, bnr, &blk_hnd, map_rbaf); + if (ret < 0) + goto out; + } else { + + ret = alloc_block_ref(rfi, txn, refs, &blk_hnd); + if (ret < 0) + goto out; /* XXX do error/recovery now */ + } + + 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; + }; + + /* XXX make this a struct? */ + *hnd_ret = parent_hnd; + *refs_ret = refs; + *nr_ret = nr; + + if (dr->height < min_height) + dr->height = min_height; + +out: + rpdfs_prd("dr->height %u bnr %llu ind %d refs %p nr %d", + dr->height, *refs_ret ? (*refs_ret)[0].bnr : 0, ind, refs_ret, *nr_ret); + return ret; +} + +static int get_or_alloc_file_block(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_handle *parent_hnd = NULL; + struct rpdfs_block_handle *blk_hnd = NULL; + struct rpdfs_block_ref *refs; + int write; + int nr; + u64 bnr; + int ret; + + write = rbaf & RBAF_WRITE ? 1 : 0; + + rpdfs_prd("ino %llu lblk %llu rbaf %x", rpdfs_inode_ino(inode), lblk, rbaf); + + ret = get_or_alloc_map_blk(rfi, txn, inode, inode_hnd, lblk, rbaf, &parent_hnd, &refs, &nr); + if (ret < 0) + goto out; + + bnr = le64_to_cpu(refs[0].bnr); + + if (bnr == 0) { + /* read from/write to unallocated range */ + if (write) { + ret = alloc_block_ref(rfi, txn, refs, &blk_hnd); + if (ret < 0) + goto out; + } + } else { + ret = rpdfs_block_acquire(rfi, txn, bnr, &blk_hnd, rbaf); + if (ret < 0) + goto out; + } + + if (parent_hnd != inode_hnd) + rpdfs_block_release(rfi, &parent_hnd); + + *hnd_ret = blk_hnd; +out: + rpdfs_prd("ret %d ino %llu lblk %llu bnr %llu *hnd_ret %p", + ret, rpdfs_inode_ino(inode), lblk, bnr, *hnd_ret); + return ret; +} -- 2.49.0