From 7098ed75a1aab97ddd6a2267aeb678d4a2ed1f9a Mon Sep 17 00:00:00 2001 From: Yehia Hafez Date: Wed, 18 Sep 2024 07:26:47 -0500 Subject: [PATCH] switch from malloc/memcpy to shallow copies --- .gitignore | 1 + btrfs/include/btrfs.h | 42 +++++++++++----------- kernel/freebsd/btrfs.c | 2 +- kernel/freebsd/btrfs_kmod.c | 70 ++++++++++++++++++------------------ kernel/freebsd/btrfs_mount.h | 48 ++++++------------------- 5 files changed, 69 insertions(+), 94 deletions(-) diff --git a/.gitignore b/.gitignore index c0a4adc..0b25060 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/btrfs/include/btrfs.h b/btrfs/include/btrfs.h index 09a46ba..b74228b 100644 --- a/btrfs/include/btrfs.h +++ b/btrfs/include/btrfs.h @@ -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; diff --git a/kernel/freebsd/btrfs.c b/kernel/freebsd/btrfs.c index dd26389..ea50be1 100644 --- a/kernel/freebsd/btrfs.c +++ b/kernel/freebsd/btrfs.c @@ -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)) diff --git a/kernel/freebsd/btrfs_kmod.c b/kernel/freebsd/btrfs_kmod.c index c993ea1..f6c290f 100644 --- a/kernel/freebsd/btrfs_kmod.c +++ b/kernel/freebsd/btrfs_kmod.c @@ -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); diff --git a/kernel/freebsd/btrfs_mount.h b/kernel/freebsd/btrfs_mount.h index 6f5fa2c..2483892 100644 --- a/kernel/freebsd/btrfs_mount.h +++ b/kernel/freebsd/btrfs_mount.h @@ -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 {