switch from malloc/memcpy to shallow copies

This commit is contained in:
Yehia Hafez
2024-09-18 07:26:47 -05:00
parent 7bb5748836
commit 7098ed75a1
5 changed files with 69 additions and 94 deletions

1
.gitignore vendored
View File

@@ -14,3 +14,4 @@ kernel/freebsd/opt_global.h
kernel/freebsd/vnode_if_typedef.h
kernel/freebsd/vnode_if.h
kernel/freebsd/x86
scratch_notes.txt

View File

@@ -183,11 +183,11 @@ typedef struct BTRFS_UUID {
uint8_t uuid[16];
} btrfs_uuid;
typedef struct KEY {
struct btrfs_key {
uint64_t obj_id;
uint8_t obj_type;
uint64_t offset;
} btrfs_key;
};
#define HEADER_FLAG_WRITTEN 0x000000000000001
#define HEADER_FLAG_SHARED_BACKREF 0x000000000000002
@@ -231,7 +231,7 @@ typedef struct {
Size field of struct btrfs_item indicates how much data is stored.
*/
typedef struct {
btrfs_key key;
struct btrfs_key key;
uint32_t offset;
uint32_t size;
} btrfs_leaf_node;
@@ -246,7 +246,7 @@ typedef struct {
@discussion all non-leaf blocks are nodes, they hold only keys and pointers to other blocks
*/
typedef struct {
btrfs_key key;
struct btrfs_key key;
uint64_t address;
uint64_t generation;
} btrfs_internal_node;
@@ -271,7 +271,7 @@ typedef struct {
@field fs_uuid uuid of FS that owns this device
@discussion `dev_id` matches the dev_id in the filesystem's list of struct btrfs_devices.
*/
typedef struct DEV_ITEM {
struct btrfs_dev_item {
uint64_t dev_id;
uint64_t num_bytes;
uint64_t bytes_used;
@@ -286,7 +286,7 @@ typedef struct DEV_ITEM {
uint8_t bandwidth;
btrfs_uuid device_uuid;
btrfs_uuid fs_uuid;
} btrfs_dev_item;
};
#define SYS_CHUNK_ARRAY_SIZE 0x800
#define BTRFS_NUM_BACKUP_ROOTS 4
@@ -319,7 +319,7 @@ typedef struct DEV_ITEM {
@field reserved2 Reserved for future expansion, and as an alignment
@todo complete documentation
*/
typedef struct {
struct btrfs_superblock_backup {
uint64_t root_tree_addr;
uint64_t root_tree_generation;
uint64_t chunk_tree_addr;
@@ -343,7 +343,7 @@ typedef struct {
uint8_t dev_root_level;
uint8_t csum_root_level;
uint8_t reserved2[10];
} btrfs_superblock_backup;
};
/*!
@struct btrfs_superblock
@@ -388,7 +388,7 @@ typedef struct {
@note Btrfs only recognizes disks with a valid 0x1 0000 superblock; otherwise, there would be confusion with other filesystems.
@todo expand documentation.
*/
typedef struct {
struct btrfs_superblock {
uint8_t checksum[BTRFS_CSUM_SIZE];
btrfs_uuid uuid;
uint64_t sb_phys_addr;
@@ -416,16 +416,16 @@ typedef struct {
uint8_t root_level;
uint8_t chunk_root_level;
uint8_t log_root_level;
btrfs_dev_item dev_item;
struct btrfs_dev_item dev_item;
char label[MAX_LABEL_SIZE];
uint64_t cache_generation;
uint64_t uuid_tree_generation;
btrfs_uuid metadata_uuid;
uint64_t reserved[28];
uint8_t sys_chunk_array[SYS_CHUNK_ARRAY_SIZE];
btrfs_superblock_backup backup[BTRFS_NUM_BACKUP_ROOTS];
struct btrfs_superblock_backup backup[BTRFS_NUM_BACKUP_ROOTS];
// uint8_t reserved2[565];
} __attribute__((__packed__, __aligned__(8))) btrfs_superblock;
} __attribute__((__packed__, __aligned__(8)));
/*!
@struct DIR_ITEM
@@ -450,7 +450,7 @@ typedef struct {
@todo expand documentation. WinBtrfs adds `name`, which is missing from the linux kernel header; possibly a struct packing method.
*/
typedef struct DIR_ITEM {
btrfs_key key;
struct btrfs_key key;
uint64_t transid;
uint16_t extended_attribute_len;
uint16_t name_length;
@@ -548,7 +548,7 @@ typedef struct ROOT_ITEM {
uint64_t last_snapshot_generation;
uint64_t flags;
uint32_t num_references;
btrfs_key drop_progress;
struct btrfs_key drop_progress;
uint8_t drop_level;
uint8_t root_level;
uint64_t generation2;
@@ -585,7 +585,7 @@ typedef struct ROOT_ITEM {
/// @todo Linux kernel header adds a `struct stripe` at the end of this structure, to store additional stripes in the item chunk.
typedef struct CHUNK_ITEM {
struct btrfs_chunk_item {
uint64_t size;
uint64_t root_id;
uint64_t stripe_length;
@@ -595,7 +595,7 @@ typedef struct CHUNK_ITEM {
uint32_t sector_size;
uint16_t num_stripes;
uint16_t sub_stripes;
} btrfs_chunk_item;
};
/*!
@struct btrfs_chunk_item_stripe
@@ -604,11 +604,11 @@ typedef struct CHUNK_ITEM {
@field offset Location of the start of the stripe, in bytes. Size is determined by the stripe_len field in struct btrfs_chunk.
@field dev_uuid UUID of the device that contains this stripe. Used to confirm that the correct device has been retrieved.
*/
typedef struct CHUNK_ITEM_STRIPE {
struct btrfs_chunk_item_stripe {
uint64_t dev_id;
uint64_t offset;
btrfs_uuid dev_uuid;
} btrfs_chunk_item_stripe;
};
/*!
@struct EXTENT_DATA
@@ -687,7 +687,7 @@ typedef struct {
@field level
*/
typedef struct {
btrfs_key firstitem;
struct btrfs_key firstitem;
uint8_t level;
} EXTENT_ITEM2;
@@ -701,7 +701,7 @@ typedef struct {
typedef struct {
EXTENT_ITEM extent_item;
btrfs_key firstitem;
struct btrfs_key firstitem;
uint8_t level;
} EXTENT_ITEM_TREE;
@@ -799,7 +799,7 @@ typedef struct {
@field num_bitmaps
*/
typedef struct {
btrfs_key key;
struct btrfs_key key;
uint64_t generation;
uint64_t num_entries;
uint64_t num_bitmaps;

View File

@@ -1,6 +1,6 @@
#include "btrfs.h"
static int btrfs_comp_keys_by_type(const btrfs_key *k1, const btrfs_key *k2) {
static int btrfs_comp_keys_by_type(const struct btrfs_key *k1, const struct btrfs_key *k2) {
if((k1->obj_id > k2->obj_id) || (k1->obj_type > k2->obj_type) || (k1->offset > k2->offset))
return 1;
if((k1->obj_id < k2->obj_id) || (k1->obj_type < k2->obj_type) || (k1->offset < k2->offset))

View File

@@ -213,7 +213,7 @@ static int mount_btrfs_filesystem(struct vnode *odevvp, struct mount *mp) {
struct buf *bp;
struct cdev *dev;
struct vnode *devvp;
btrfs_superblock *prim_sblock;
struct btrfs_superblock *prim_sblock;
struct bufobj *buf_obj;
int ronly, error;
@@ -259,7 +259,7 @@ static int mount_btrfs_filesystem(struct vnode *odevvp, struct mount *mp) {
if(error)
goto error_exit; // fun times
bp->b_flags |= B_AGE;
prim_sblock = (btrfs_superblock *)bp->b_data;
prim_sblock = (struct btrfs_superblock *)bp->b_data;
if(prim_sblock->magic != BTRFS_MAGIC) {
error = EINVAL;
goto error_exit;
@@ -283,25 +283,16 @@ static int mount_btrfs_filesystem(struct vnode *odevvp, struct mount *mp) {
bmp->pm_mask = bmp->pm_dirmask = S_IXUSR | S_IXGRP | S_IXOTH |
S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR;
// @todo: should we copy the entire superblock to memory, or do we just need
// some references?
// the sector size is certainly important for future block reads, but the
// btrfs superblock has a chunk tree array that we don't really need beyond
// bootstrapping (afaik) if we're gonna write.
// on the other hand, holding on to that array could be useful if we misread
// something, or if there's data corruption. We'll cross that bridge when
// we get to it.
// store superblock in the in-memory structure
bmp->pm_superblock = *prim_sblock;
bmp->pm_sector_size = prim_sblock->sector_size;
bmp->pm_superblock_physical_addr = prim_sblock->sb_phys_addr;
bmp->pm_root_addr = prim_sblock->root_tree_addr;
// read sys_chunk_array to bootstrap the system chunk tree
RB_INIT(&bmp->pm_chunk_bootstrap);
for(int i = 0; i < prim_sblock->sys_chunk_array_valid; i += (sizeof(btrfs_key) + sizeof(btrfs_chunk_item))) {
btrfs_key *fa_key = (btrfs_key *)&prim_sblock->sys_chunk_array[i];
btrfs_chunk_item *fa_chunk = (btrfs_chunk_item *)&prim_sblock->sys_chunk_array[i + sizeof(btrfs_key)];
LIST_INIT(&chunk_bootstrap_list);
bmp->pm_chunk_bootstrap = &chunk_bootstrap_list;
for(int i = 0; i < bmp->pm_superblock.sys_chunk_array_valid; i += (sizeof(struct btrfs_key) + sizeof(struct btrfs_chunk_item))) {
struct btrfs_key *fa_key = (struct btrfs_key *) &prim_sblock->sys_chunk_array[i];
struct btrfs_chunk_item *fa_chunk = (struct btrfs_chunk_item *) &prim_sblock->sys_chunk_array[i + sizeof(struct btrfs_key)];
struct btrfs_chunk_item_stripe *fa_stripe = (struct btrfs_chunk_item_stripe *) &prim_sblock->sys_chunk_array[i + sizeof(struct btrfs_key) + sizeof(struct btrfs_chunk_item)];
// the chunk tree is essential. If we encounter an error, we'll
// simply exit in error.
if(fa_key->obj_type != TYPE_CHUNK_ITEM) {
@@ -312,24 +303,18 @@ static int mount_btrfs_filesystem(struct vnode *odevvp, struct mount *mp) {
if(fa_chunk->num_stripes == 0) {
error = EINVAL;
goto error_exit;
} else if(fa_chunk->num_stripes > 1) {
uprintf("[BTRFS] Found %d stripes, but we're only processing 1\n", fa_chunk->num_stripes);
}
struct b_chunk_bstrap *n_node = malloc(sizeof(struct b_chunk_bstrap), M_BTRFSMOUNT, M_WAITOK | M_ZERO);
memcpy(n_node, &prim_sblock->sys_chunk_array[i], sizeof(btrfs_key) + sizeof(btrfs_chunk_item));
n_node->key = *fa_key;
n_node->chunk_item = *fa_chunk;
n_node->stripe = *fa_stripe;
n_node->stripe_head = malloc(sizeof(struct chunk_stripe_list), M_BTRFSMOUNT, M_WAITOK | M_ZERO);
LIST_INIT(n_node->stripe_head);
for(int j = 0; j < fa_chunk->num_stripes; ++j) {
struct b_stripe_list *n_stripe = malloc(sizeof(struct b_stripe_list), M_BTRFSMOUNT, M_WAITOK | M_ZERO);
memcpy(&n_stripe->val, &prim_sblock->sys_chunk_array[i]
+ (sizeof(btrfs_key) + sizeof(btrfs_chunk_item))
+ (sizeof(btrfs_chunk_item_stripe) * j),
sizeof(btrfs_chunk_item_stripe));
LIST_INSERT_HEAD(n_node->stripe_head, n_stripe, entries);
i += sizeof(btrfs_chunk_item_stripe);
}
LIST_INSERT_HEAD(&chunk_bootstrap_list, n_node, entries);
RB_INSERT(sys_chunk_map, &bmp->pm_chunk_bootstrap, n_node);
i += (sizeof(struct btrfs_chunk_item_stripe) * fa_chunk->num_stripes);
}
// in order for traversal:
@@ -338,11 +323,20 @@ static int mount_btrfs_filesystem(struct vnode *odevvp, struct mount *mp) {
// - Read the root tree root (requires chunk tree for logical->physical mapping)
// - Read the filesystem tree root (will be found under the root tree)
// assign our internal structure to mp
bmp->pm_devvp = devvp;
bmp->pm_odevvp = odevvp;
bmp->pm_dev = dev;
mp->mnt_data = bmp;
return(0);
error_exit:
// release the buffer
brelse(bp);
bp = NULL;
error_exit:
if(bp != NULL)
brelse(bp);
if(cp != NULL) {
@@ -353,7 +347,15 @@ error_exit:
if(bmp != NULL) {
lockdestroy(&bmp->pm_btrfslock);
lockdestroy(&bmp->pm_checkpath_lock);
//free(bmp->)
if(bmp->pm_chunk_bootstrap != NULL) {
struct b_chunk_bstrap *clr_np;
while(!LIST_EMPTY(&chunk_bootstrap_list)) {
clr_np = LIST_FIRST(&chunk_bootstrap_list);
LIST_REMOVE(clr_np, entries);
free(clr_np, M_BTRFSMOUNT);
}
bmp->pm_chunk_bootstrap = NULL;
}
mp->mnt_data = NULL;
}
BO_LOCK(&odevvp->v_bufobj);

View File

@@ -13,44 +13,16 @@
// we're not implementing the RB tree structure correctly, but cleanup will come later
// @todo: use generic RB trees rather than specific trees for key/chunk_item pairs in sys_chunk_array
struct b_stripe_list {
btrfs_chunk_item_stripe val;
LIST_ENTRY(b_stripe_list) entries;
};
LIST_HEAD(chunk_stripe_list, b_stripe_list);
struct b_chunk_bstrap {
btrfs_key key;
btrfs_chunk_item chunk_item;
struct chunk_stripe_list *stripe_head;
RB_ENTRY(b_chunk_bstrap) bt_entry;
struct btrfs_key key;
struct btrfs_chunk_item chunk_item;
// only reading one stripe- no RAID for this implementation (for now)
struct btrfs_chunk_item_stripe stripe;
LIST_ENTRY(b_chunk_bstrap) entries;
};
//@todo: this is a dirty chunk comparison and I don't trust that it actually works.
static int chunk_cmp(struct b_chunk_bstrap *key_1, struct b_chunk_bstrap *key_2) {
if ((key_1->key.offset > key_2->key.offset && key_1->key.offset < (key_2->key.offset + key_2->chunk_item.size)) ||
((key_1->key.offset + key_1->chunk_item.size) > key_2->key.offset &&
(key_1->key.offset + key_1->chunk_item.size) < (key_2->key.offset + key_2->chunk_item.size))) {
return 0; // overlapping ranges
}
// key_1 is completely before key_2
if (key_1->key.offset + key_1->chunk_item.size <= key_2->key.offset) {
return -1;
}
// key_1 is completely after key_2
if (key_1->key.offset >= key_2->key.offset + key_2->chunk_item.size) {
return 1;
}
return 0;
}
RB_HEAD(sys_chunk_map, b_chunk_bstrap);
RB_GENERATE_STATIC(sys_chunk_map, b_chunk_bstrap, bt_entry, chunk_cmp); // comparing chunk key overlapping
LIST_HEAD(sys_chunk_bootstrap, b_chunk_bstrap) chunk_bootstrap_list;
struct btrfsmount_internal {
struct mount *pm_mountp; // vfs mount struct
@@ -63,13 +35,13 @@ struct btrfsmount_internal {
struct vnode *pm_devvp; // vnode for character device we're mounting
struct vnode *pm_odevvp; // msdosfs refers to this as the "real devfs vnode"
// I have yet to understand why, or its purpose
struct cdev *pm_dev; // character device we're mounting
struct lock pm_btrfslock; // protects allocations
struct lock pm_checkpath_lock; // protects checkpath result
uint32_t pm_sector_size; // BTRFS sector size
uint64_t pm_superblock_physical_addr; // store superblock addr in case we're using a backup sblock
uint64_t pm_root_addr; // logical address of root tree root
struct sys_chunk_map pm_chunk_bootstrap;
struct btrfs_superblock pm_superblock; // superblock struct
struct sys_chunk_bootstrap *pm_chunk_bootstrap;
};
struct btrfs_args {